# Headless

Source: https://gokarla.io/docs/guides/shops/headless

# Headless

Karla is headless-first. Every UI we ship — tracking page, portal,
resolve — is a reference implementation built on the same public API you
have access to. If you'd rather build your own storefront, mobile app, or
support dashboard on top of Karla, this guide walks through the data flow
and the endpoints you'll call.

For request/response shapes and live code samples, go to the
[API reference](/docs/api-reference) — it is always in sync with what the
servers actually accept. This page covers **what to call, when, and why**.

## What headless gives you

- **Decoupled**: your frontend(s) can use any stack. Karla cares only about
  the data you send and the events you subscribe to.
- **Omnichannel**: one Karla backend can serve a web storefront, a native
  app, an internal CX dashboard, and an AI agent — all from the same API.
- **Composable**: skip any of our UIs you don't need. Use only the tracking
  API? Fine. Use only resolve? Also fine.
- **Full data ownership**: every field that powers our native UIs is
  available to you. Nothing is hidden behind a proprietary renderer.

## Authentication and shape

Every request is HTTP Basic with your shop's API key. Every endpoint is
scoped to a shop via `{slug}` in the URL:

```text
https://api.gokarla.io/v1/shops/{your-shop-slug}/...
```

You can generate API keys in the [portal](https://portal.gokarla.io) under
**Settings → API Keys**. Pick the smallest role your integration needs
(`viewer`, `editor`, or `admin`).

## The order lifecycle

A full integration typically walks through four phases. Each is a small
number of endpoint calls.

### 1. Create the order

When a customer checks out, create the order in Karla:

- **Endpoint**: **Upsert Order**.
- **When to call**: on order placement in your backend.
- **Why Upsert over Place Order**: Upsert handles creation and subsequent
  updates in one shape, supports directly-fulfilled orders (e.g. digital
  goods), and is the pattern our native integrations use.
- **What to include**: identifiers (`order_number` + optional
  `external_id`), customer email, shipping address, line-item products, and
  `expected_number_of_shipments` if the order will ship in multiple
  packages.

At this point the order is in the **Placed** state with **Draft Shipments**.
Customers see "expected packages" on the tracking page. No carrier tracking
yet.

### 2. Attach tracking

When your fulfillment system gets a tracking number from the carrier:

- **Endpoint**: **Upsert Order** again, with the `trackings` array
  populated.
- **When to call**: the moment a tracking number is issued.
- **Multi-package orders**: include the per-shipment `products` subset so
  customers can tell which items are in which package. Without it, every
  shipment will show every product.
- **Carrier hint**: provide `carrier_reference` (mapped in Karla) for a
  deterministic match; fall back to `tracking_company` (free-form string)
  to let Karla's AI matcher infer the carrier.

Alternatives:

- **Bulk Fulfillment** endpoint — attach tracking numbers to many orders in
  one call. Use for high-volume nightly syncs; respect our batch limits.
- **Update Shipment** endpoint — patch tracking URL or products on an
  already-fulfilled shipment.

### 3. Receive (and emit) events

Karla polls the carrier and normalizes each update into an event
(`shipments/in_transit/...`, `shipments/delivered`, etc.).

- **Subscribe**: create a webhook in the portal or via the
  [Webhooks](/docs/guides/notify/webhooks) API. Webhook receivers get
  signed payloads you can verify with HMAC-SHA256.
- **Event payload shape**: see [Events](/docs/platform/events/overview) for
  the full catalog and the hierarchy (source → ref → phase → event_name).
- **Retry**: Karla retries failed deliveries up to 15 times with
  exponential backoff.
- **Emit your own events**: if a logistics partner, warehouse, or QA
  system reports a state that isn't coming from a Karla-integrated
  carrier, append it to the shipment directly via the
  [API reference](/docs/api-reference). See
  [Shipments](/docs/platform/shipments) for the phase state
  machine your custom events should fit into.

Use events to trigger anything you want — emails, SMS, internal
notifications, status widgets in your own UI, AI agents, data-warehouse
ingestion.

### 4. Handle claims and resolution

When a customer reports an issue (damaged, missing, return), you have two
options:

- **Use the Resolve widget** — embed it via the
  [Browser SDK](/docs/platform/browser-sdk) or its own
  [iframe route](/docs/guides/resolve/integrate-in-your-shop).
- **Use the Claims API directly** — submit claims from your own UI, poll
  for status, drive your own resolution flow. Start with the **Create
  Claim** endpoint in the API reference.

Either path lands the claim in the portal and generates `claims/*` events
you can react to via webhooks.

## Authenticated actions: tokens

Some operations touch user data (change delivery address, initiate a claim
pre-filled with customer details, cancel an order, etc.). Gate them by
requiring a valid **order token** on the request.

- Every notification Karla sends carries a token for its specific order.
- Token-protected URLs can be retrieved via the API for use in your own
  emails, support macros, or mobile app deep links.
- See [Campaign attribution → token callout](/docs/guides/tracking-page/integrate-in-your-shop#test-your-embed)
  for the rationale.

## Attribution

Capture where orders came from in `order_analytics` when you create or
update the order. The field set, the three supported attribution methods,
and their trade-offs are documented in
[Campaign attribution](/docs/guides/tracking-page/attribution).

If your backend is the only thing that knows the attribution (server-side
tracking), use the API-attribution path — include `source`, optional
`campaign`, `medium`, `landing_url`, `landing_path`, `referrer`, and
`captured_at` in the `order_analytics` object, or call **Upsert Order
Analytics** to attach after the fact.

## Best practices for headless integrations

- **Stable external IDs** — always include `external_id` when your system
  has one; it's the key for idempotent updates.
- **Unique order numbers** — `order_number` must be unique per shop. Karla
  will ignore duplicates.
- **Provide product images that load publicly** — Karla renders them on
  the tracking page.
- **Normalize addresses** — use ISO country codes; include
  `address_line_2`, `province_code`, and `zip_code` when available.
- **Currency consistency** — match the currency configured on the shop.
- **Batch with care** — for large syncs use the Bulk Fulfillment endpoint;
  respect request size limits.
- **Retry with exponential backoff** — treat 5xx as retryable; treat 4xx
  as caller errors to fix in code.
- **Subscribe only to the events you need** — fewer webhook events means
  less noise and faster retries. See
  [Events](/docs/platform/events/overview) for the full catalog.

## Where to next

- [Orders](/docs/platform/orders) — entity model and state
  transitions.
- [Shipments](/docs/platform/shipments) — entity detail for
  contained shipments.
- [Events](/docs/platform/events/overview) — event hierarchy, payload, and
  filtering.
- [Webhooks](/docs/guides/notify/webhooks) — subscribing and verifying
  signatures.
- [API reference](/docs/api-reference) — endpoint specs and live samples.
