> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nextintent.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Commerce endpoints

> The cart beacon, the order and refund feeds, the checkout steps and the erasure endpoint on sdk.nextintent.ai: what each takes, how it is authenticated, and what the engine does with it.

The browser SDK sees the page, not the cart's contents or the order. Four public endpoints on `sdk.nextintent.ai` fill that in: the cart from the page, orders and refunds from the store's server, checkout steps from a pixel, and erasure requests. None of them stores anything but the order ledger; each becomes a signal on the bus with `source: "sdk"`.

## Authentication

| Endpoint | Gate |
| - | - |
| `POST /SITE_ID/cart` | `Origin` on the site's allowed list; `user_id` must be a visitor id |
| `POST /SITE_ID/shopify/orders` and `/shopify/refunds` | The site's public key in the `X-NextIntent-Token` header. `?token=` in the query is still accepted for one release and is deprecated: it lands in request logs |
| `POST /SITE_ID/privacy/erase` | Same token |
| `POST /SITE_ID/checkout` | Site id and visitor id; treated as a hint, never as proof of purchase |

Public routes are rate-limited per site and IP.

## The cart beacon

```
POST https://sdk.nextintent.ai/SITE_ID/cart
{
  "user_id": "VISITOR_ID",
  "reason": "load" | "change",
  "item_count": 2,
  "total": 58.00,
  "currency": "USD",
  "country": "US",
  "free_shipping_threshold": 75,
  "items": [{ "handle": "merino-crew-tee", "variant_id": 4471, "quantity": 1, "price": 58.00 }],
  "code_hash": "9f2a...",
  "discount_applied": false
}
```

Send it on every page that has a cart, on load and after every change. Line items travel as handle, variant, quantity and price, never a typed name. A discount code never travels: hash it on the page (SHA-256 of the lower-cased, trimmed code, first 16 hex characters in the reference snippet) and send the hash with whether the platform accepted it. Numbers are clamped to 0 to 10,000,000. The body limit is 8 KB.

The reference snippet also stamps the visitor id on the cart as a hidden attribute (`_nextintent_uid` on Shopify) so the order that follows can name the visitor.

## Orders

```
POST https://sdk.nextintent.ai/SITE_ID/shopify/orders
X-NextIntent-Token: SITE_PUBLIC_KEY
```

The body is the order, reduced. What NextIntent needs: the order id and number, `created_at`, `currency`, `total_price`, `subtotal_price`, `total_discounts`, `total_price_usd` where the platform states one, `financial_status`, `discount_codes`, `line_items` as handle, product and variant ids, price and quantity, the `note_attributes` entry that carries the visitor id, and the customer id as a number. Send nothing else: no name, email, phone, addresses or note. NextIntent hashes the customer id on arrival with a per-site key.

The order lands in the site's ledger whether or not the visitor is known. When the cart carried the visitor id it also becomes an `order` signal, and the engine marks the visitor as bought, withdraws any waiting card, and credits the order to a moment if one qualifies. The order signal is published once per order: a redelivered webhook updates the ledger row and does not count twice.

## Refunds

```
POST https://sdk.nextintent.ai/SITE_ID/shopify/refunds
X-NextIntent-Token: SITE_PUBLIC_KEY
{ "id": 9911, "order_id": 5511, "created_at": "...", "transactions": [{ "kind": "refund", "status": "success", "amount": "20.00", "currency": "USD" }], "refund_line_items": [...] }
```

The ledger row gains a refund total; the store view shows gross and net; a `refund` signal tells the engine the outcome changed. Each refund id is counted once.

## Checkout steps

```
POST https://sdk.nextintent.ai/SITE_ID/checkout
{ "user_id": "VISITOR_ID", "step": "started" | "contact" | "shipping" | "payment" | "completed", "total": 76.00, "currency": "USD", "discount_applied": false, "order_ref": "..." }
```

Sent by a pixel that can see checkout (on Shopify, the app's web pixel). The engine uses the steps to know the visitor is in checkout (no card there) and, on `completed`, to go quiet for that visitor. A `completed` step is never treated as a credited purchase on its own; the order feed is the only source of credit, because anyone who knows a site id and a visitor id can post a step.

## Erasure

```
POST https://sdk.nextintent.ai/SITE_ID/privacy/erase
X-NextIntent-Token: SITE_PUBLIC_KEY
{ "scope": "customer", "customer_id": 8123, "email": "…", "orders": ["5511"] }
{ "scope": "shop" }
```

`scope: "customer"` clears the customer reference and visitor id from the matching ledger rows, removes the visitor records those rows named (and any visitor row that carried the email as a trait), and publishes an `erase` signal so the engine forgets the visitor's fold and moments. `scope: "shop"` erases everything for the site. A failure answers with a 5xx so the caller retries; an erasure is never acknowledged before it has happened.

## Related

* [Data and privacy](/api/data-and-privacy)
* [Install the SDK](/api/install-sdk)
* [Views: the store view](/api/reference/views/store)
