Developer portal

Web embedding API

Keep approved references in sync and give customers private access to your tracking widget. Read or update approved references and authorize private sessions from your backend.

Connect your backend

Create a widget in Integrations → Web embedding. Use an API key created by an active organization administrator, kept in a server environment variable. Existing keys, rotation, revocation and per-key rate limits apply. Keys created by ordinary members cannot manage references or launch private sessions. The widget and key must belong to the same organization; no organization ID is accepted from your request.

Read approved references

GET /api/v1/tracking-widgets/{widgetId}/references

Retrieve the widget’s complete approved-reference list from your backend with the same organization-admin API key. Works for paused widgets too, so you can check configuration before publishing. Returns only the widget UUID and canonical references, with at most 500 entries.

Server terminal
curl \
  "https://api.panvaya.com/api/v1/tracking-widgets/YOUR_WIDGET_ID/references" \
  --header "X-API-Key: $PANVAYA_API_KEY"
200 response
{"id":"YOUR_WIDGET_ID","allowedReferences":["CT:MSKU8094830","BL:YOUR-BILL"]}

This read is free, does not invalidate sessions, and logs safe organization and API-key attribution without storing an audit row. The private key stays on your backend; the public iframe cannot list approved references.

Update approved references

PATCH /api/v1/tracking-widgets/{widgetId}/references

Send add, remove, or both. Use CT:number, BL:number or BK:number. A document reference allows its complete response; append +CT:number to approve only that container within the document. Up to 500 references may remain on a widget.

Server terminal
curl --request PATCH \
  "https://api.panvaya.com/api/v1/tracking-widgets/YOUR_WIDGET_ID/references" \
  --header "X-API-Key: $PANVAYA_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"add":["CT:MSKU8094830","BL:YOUR-BILL"],"remove":["BK:OLD-BOOKING"]}'
200 response
{"id":"YOUR_WIDGET_ID","allowedReferences":["CT:MSKU8094830","BL:YOUR-BILL"]}

Duplicate additions and missing removals are harmless. Concurrent patches merge safely. A changed list invalidates existing sessions and unused launch codes; an unchanged list does not. Pause an enabled widget before removing its final reference in approved-reference mode. Removing references preserves usage history and consumed shipment slots. This API manages the widget allowlist; it does not create or delete dashboard shipments.

Launch private access

Enable Require private access in the widget settings. Keep your allowed website origins configured. Anonymous session creation is blocked, including when hosted-page access is enabled.

POST /api/v1/tracking-widgets/{widgetId}/launch

  1. Your backend authenticates the visitor and chooses references they may view.
  2. It calls Panvaya with its API key, the exact parent website origin, and a nonempty list of authorized references.
  3. Panvaya returns a one-time launch code valid for 60 seconds.
  4. Your website immediately loads a fresh iframe with that code in the URL fragment. Panvaya removes the fragment and exchanges the code for a 15-minute session.
Customer backend · JavaScript
// Server-side only. First authenticate your visitor and determine
// their references from your own records. Never trust a browser-supplied list.
const response = await fetch(
  "https://api.panvaya.com/api/v1/tracking-widgets/YOUR_WIDGET_ID/launch",
  {
    method: "POST",
    headers: {
      "X-API-Key": process.env.PANVAYA_API_KEY,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      parentOrigin: "https://tracking.example.com",
      references: ["CT:MSKU8094830"], // Authorized for this visitor
    }),
    cache: "no-store",
  },
);
if (!response.ok) throw new Error("Could not authorize tracking");
const { launchCode } = await response.json();
// Return only this temporary URL to the authorized visitor. Set your
// backend response to Cache-Control: private, no-store as well.
const iframeUrl = "https://panvaya.com/embed/YOUR_WIDGET_ID#launch="
  + encodeURIComponent(launchCode);
200 response · expiry is UTC
{"launchCode":"ONE_TIME_CODE","expiresAt":"2026-10-11T12:01:00"}
Browser · use the URL returned by your backend
<iframe src="AUTHORIZED_IFRAME_URL" title="Shipment tracking"
  style="width:100%;height:720px;border:0"
  referrerpolicy="strict-origin"></iframe>

Load private iframes immediately rather than lazily. Never place an API key in the iframe URL, browser JavaScript or storage. A session can search only its launch references; approved-reference mode additionally requires every launch reference to be on the widget’s allowlist. Open-search mode still enforces the launch’s visitor-specific scope.

For an authorized direct link, enable hosted-page access and omit parentOrigin when creating the launch. The one-time code is still required. After expiry, a failed exchange or a settings/reference change, obtain a fresh launch from your backend and create a new iframe. Revoking the key or disabling/demoting its owner also blocks pending launches and active sessions.

Security and billing

Reference reads and updates, launch creation and session exchanges are free. Successful tracking costs 5 credits by default, including cache hits, from your shared API balance. Your organization’s configured EMBED_SEA_TRACKING price overrides this default. Existing tracking idempotency, daily budgets and distinct-reference limits apply. Public widgets keep their existing behavior; enable private access when visitor authorization is required.

Retry the same submission after a lost connection. A completed search returns 409 REQUEST_ALREADY_COMPLETED without another carrier request or charge. Responses are not stored for replay; select Start a new search to retrieve tracking again at the configured credit cost.

For account balance and enabled product costs, use GET /api/v1/usage. For embedding-only billed activity, use GET /api/v1/usage/report?productCode=EMBED_SEA_TRACKING with optional from and to dates. These existing APIs are free and use your server-side API key.

Your backend must enforce visitor access before requesting a launch. A public endpoint that issues launches to anyone would make your integration public again. Launch codes and session tokens are temporary bearer credentials: protect them with HTTPS, avoid shared caches and logs, and never share them with another visitor. Website restrictions support this flow but do not replace authentication.

StatusMeaning
400Invalid references, conflicting add/remove, or widget not private
401Missing, expired or revoked API key; invalid, expired or consumed launch code
403Key owner lacks admin access, product disabled, or website not allowed
404Widget unavailable or belongs to another organization; reference outside session scope
409Tracking submission is running, already completed, or conflicts with its original input/session
429API-key, widget rate limit or tracking budget reached

API responses include a request ID and rate-limit headers. Private mutations and launches retain client, widget, key and outcome audits. Reads use safe logs. Permanent keys, launch codes and session tokens are never logged. Download the OpenAPI specification.