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

# Orders API

> Learn how to send order data to Northbeam using the Orders API, with steps for setup, validation, backfilling, and monitoring.

<Warning>
  **The Northbeam Orders API is a customizable solution specific to your business.**

  You will use this API to actively push order data to Northbeam by making POST requests to `https://api.northbeam.io/v2/orders`.

  Full API reference: [/reference/post\_orders-1](/reference/post_orders-1).
</Warning>

## Get API credentials

* In your Northbeam dashboard go to **Settings → API Keys**
* Click **Create new API key** to generate:
  * **Authorization** (API Key)
  * **Data-Client-ID** (Client ID)

<Frame caption="Onboarding Flow: Add Orders > Other E-Commerce Platform">
  <img src="https://mintcdn.com/northbeam/EpMPeQ8Ec2Yrg9EI/images/readme/67c6fc6a-Screenshot_2025-09-29_at_4.04.15_PM.png?fit=max&auto=format&n=EpMPeQ8Ec2Yrg9EI&q=85&s=d2c9f8aad82438045c8ae70fde0f69b1" alt="" width="1560" height="859" data-path="images/readme/67c6fc6a-Screenshot_2025-09-29_at_4.04.15_PM.png" />
</Frame>

<Frame caption="Dashboard: Settings > API Keys">
  <img src="https://mintcdn.com/northbeam/EpMPeQ8Ec2Yrg9EI/images/readme/787d5c49-Screenshot_2025-09-29_at_4.08.07_PM.png?fit=max&auto=format&n=EpMPeQ8Ec2Yrg9EI&q=85&s=6cdc752b725933c0b6da71e0654be0e4" alt="" width="1555" height="930" data-path="images/readme/787d5c49-Screenshot_2025-09-29_at_4.08.07_PM.png" />
</Frame>

| Header | Value | Description |
| - | - | - |
| `Authorization` | `<API_KEY>` | Your Northbeam API key |
| `Data-Client-ID` | `<CLIENT_ID>` | Your Northbeam client ID |
| `Content-Type` | `application/json` | Tells the API you’re sending JSON |

**Production endpoint:** `https://api.northbeam.io/v2/orders`

**Example (cURL):**

```curl theme={null}
curl --request POST \
  --url https://api.northbeam.io/v2/orders \
  --header 'Authorization: <API_KEY>' \
  --header 'Data-Client-ID: <CLIENT_ID>' \
  --header 'Content-Type: application/json' \
  --data @orders.json
```

<Note>
  These headers are **required for every request**. Without them, the Orders API will reject your call.
</Note>

## Build your payload

All of these fields are required for full functionality in Northbeam. Full API reference: [/reference/post\_orders-1](/reference/post_orders-1).

<div className="nb-field-table">
  | Field | Type | Description |
  | :- | :- | :- |
  | `order_id` | string | Unique identifier for the order.<br />Must match the `id` in [firePurchaseEvent](https://northbeam-pixel-api.readme.io/recipes/fire-purchase-event) so we can pair website events with orders. |
  | `customer_id` | string | Must be unique per customer in your OMS. |
  | `customer_email` | string | The email associated with the customer. |
  | `time_of_purchase` | date-time (ISO-8601) | Must be in ISO-8601 format.<br />**Must occur AFTER the frontend [firePurchaseEvent](https://northbeam-pixel-api.readme.io/recipes/fire-purchase-event).**<br />Include a timezone offset if not reporting in UTC.<br />**Example:** FPE timestamp = `2025-09-29T15:30:00Z`<br />❌ `2025-09-29T15:00:00Z` (too early)<br />✅ `2025-09-29T15:31:00Z` (UTC)<br />✅ `2025-09-29T15:31:00-07:00` (with offset) |
  | `currency` | string | ISO-4217 currency code (e.g., USD).<br />All monetary fields assume this currency. |
  | `purchase_total` | number | Total collected including tax, shipping, and fees. |
  | `tax` | number | Amount paid as tax.<br />Required if you want taxes deducted from revenue in reporting. |
  | `shipping_cost` | number | Amount paid for shipping.<br />Required if you want shipping deducted from revenue in reporting. |
  | `products` | array of objects | Must contain at least one product.<br />**Required keys:** `id` (string), `name` (string), `quantity` (number), `price` (number)<br />**Optional keys:** `variant_id` (string), `variant_name` (string) |
  | `order_tags` | array of strings | Required for offline orders.<br />Used to mark subscription stage or exclude orders from attribution. |
  | `refunds` | array of objects | Used to keep revenue calculations correct.<br />**Required keys:** `product_id` (string), `quantity` (number), `refund_amount` (number), `refund_made_at` (date-time)<br />If you want refunds broken out in reporting, you must also include an `order_tag`. |
  | `customer_shipping_address` | object | Enables Customer LTV reporting by region and state.<br />**Required keys if included:** `address1` (string), `address2` (string), `city` (string), `state` (string), `zip` (string), `country_code` (string) |
  | `discount_codes` | array of strings | Enables Customer LTV by discount code. |
  | `discount_amount` | number | Required if you want discounts broken out in dashboard reporting. |
</div>

### Example payload

```json theme={null}
[
  {
    "order_id": "abc-123",
    "customer_id": "def-456",
    "customer_email": "example@gmail.com",
    "time_of_purchase": "2025-09-29T15:31:00Z",
    "currency": "USD",
    "purchase_total": 110.99,
    "tax": 5.00,
    "shipping_cost": 10.99,
    "products": [
      {
        "id": "prod-1",
        "name": "Sample Product",
        "quantity": 1,
        "price": 95.00,
        "variant_id": "var-1",
        "variant_name": "Size M"
      }
    ],
    "order_tags": [
      "Online Order",
      "Subscription First"
    ],
    "refunds": [
      {
        "product_id": "prod-1",
        "quantity": 1,
        "refund_amount": 10.00,
        "refund_made_at": "2025-09-30T10:00:00Z"
      }
    ],
    "customer_shipping_address": {
      "address1": "123 Main St.",
      "address2": "Apt. 1A",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94112",
      "country_code": "USA"
    },
    "discount_codes": [
      "WELCOME10"
    ],
    "discount_amount": 10.00
  }
]
```

## Verify your payload

Before sending the orders, confirm your payload structure and values are valid. Most issues come from malformed payloads or missing fields.

**Common validation checks:**

* ✅ `order_id` must be unique per order and match the `id` used in `firePurchaseEvent`.
* ✅ `time_of_purchase` must be **AFTER** the corresponding `firePurchaseEvent` timestamp and in proper ISO-8601 format with timezone offset.
* ✅ `products` array must include at least one product with `id`, `name`, `quantity`, and `price`.
* ✅ `currency` must be a valid ISO-4217 code (e.g., `USD`, `EUR`).
* ✅ `customer_email` must match the email on the actual order in your OMS (case-sensitive in some systems).
* ✅ `customer_id` accuracy is critical – this is what Northbeam uses to distinguish between new and returning customers. If it’s inconsistent (e.g., mixing Shopify IDs and internal IDs), customer LTV and new/returning logic will be incorrect.
* ✅ `order_tags` are required and used for two main purposes:
  * **Subscriptions** – Use distinct tags to separate:
    1. First-time subscription orders (subscription starts)
    2. Recurring subscription renewals (auto-charges that happen in the backend)
  * **Offline Orders** – Tag any orders not placed through your live production website (and therefore without frontend pixel events). Our team excludes these from diagnostics monitoring.
* ✅ `refunds` objects must include `product_id`, `quantity`, `refund_amount`, and `refund_made_at`.
* ✅ If including `customer_shipping_address`, all required subfields (`address1`, `city`, `state`, `zip`, `country_code`) must be present.

<Warning>
  Order tags are **very important for our data validation phase**.

  We cross-check pixel events against raw order data. If tags are missing or incorrect and large discrepancies appear, we’ll need to investigate further — which can prolong the implementation process.
</Warning>

**Common mistakes to avoid:**

* ❌ Using inconsistent `customer_id`s (e.g., switching between Shopify and internal IDs)
* ❌ `time_of_purchase` set **BEFORE** the frontend pixel fire
* ❌ Untagged **subscription orders**, which prevents [Subscription Analytics](/docs/subscription-analytics) from working correctly
* ❌ Untagged **offline orders**, leading to large discrepancies in pixel vs. order data. This prolongs our data validation process.
* ❌ Missing `products` array or leaving it empty
* ❌ Currency not set as a valid ISO-4217 code (e.g., using “US Dollars” instead of `USD`)

## Backfill historical orders

Backfilling your historical data is extremely important. This ensures your Customer LTV is complete. This is also key for accurate New and Returning Data.

<Note>
  **Accurate New and Returning Data**

  Northbeam determines whether a customer is **new** or **returning** based on the `customer_id` attached to each order. Without historical orders, someone who purchased in the past but buys again today will be counted as a **new** customer — because their first order isn’t in the system.

  **Backfilling ensures repeat customers are recognized correctly.**
</Note>

**What to send**

* Send all historical orders you want in Northbeam (recommended: up to 5 years).
* Use the same payload format from [Build your payload](#build-your-payload).
* Keep `order_id` stable; resending the same `order_id` overwrites the prior record.

**How to send**

* Batch up to **1000 orders per request**.
* Backfill in time windows (for example, month by month).

<Tip>
  Backfilling is only required for new onboards. If your historical orders already exist for any reason (e.g., transition from Shopify to the Orders API), this step isn’t needed.
</Tip>

## Set up ongoing batches

After history is loaded, keep Northbeam up to date with regular batches.

**Cadence**

* Northbeam processes on your plan frequency, not in real time.
* Send **at least 2× more frequently** than your plan’s processing cadence.
  * Example: on a 4× per day plan, send **8× per day**.

**Batching**

* Up to **1000 orders per request**.
* Include new and changed orders since the last run.
* Resend modified orders using the same `order_id`.

**Operational notes**

* **Retries**: if a request fails, retry the same batch; using the same `order_id`s is safe.
* **Idempotency**: the latest record for an `order_id` takes priority.

<Note>
  **Implementation tip:** most teams set this up as a scheduled job (e.g., cron, Airflow, or a serverless function like AWS Lambda).
</Note>

## Test in sandbox (optional)

Use the UAT endpoint to validate payloads before sending real data to production.

**Sandbox endpoint:** `https://api-uat.northbeam.io/v2/orders`

You can test without production keys by using these header values. Testing with your real keys also works, but the sandbox database is purged periodically, so treat it as a testing environment only.

```
--header 'Authorization: None'
--header 'Content-Type: application/json'
--header 'Data-Client-ID: test'
```

<Warning>
  **Sandbox testing notes**

  * The sandbox does **not save orders** — it only checks that your payload is valid.
  * A “pass” response confirms the request structure is correct, but it does **not** validate the actual numbers.

  **For full validation of values (totals, tax, discounts, etc.)**, send test data to the production endpoint. We can remove those test orders for you afterward if needed.
</Warning>

## Data diagnostics

Northbeam provides a diagnostics tool to help you monitor Orders API activity in production.

If there are any issues with your API upserts, errors will appear here with details to help you debug. Common causes include **malformed payloads** or **missing required fields**.

### Where to find it

In the Northbeam dashboard:

1. Go to **Settings**
2. Select **Data Diagnostics** (bottom of the left-hand column)

### Error table

Each error entry includes:

* **Request ID**
* **Error message**
* **Error type** (e.g., `payload_validation_error`)
* **Timestamp of error**
* **Link to request** for deeper inspection

<Warning>
  **Tip:** most errors are due to **missing required fields** or **invalid payload format**.
  Fix the payload and resend with the same `order_id` — the latest record will take priority.
</Warning>

<Frame caption="Dashboard: Settings > Data Diagnostics">
  <img src="https://mintcdn.com/northbeam/EpMPeQ8Ec2Yrg9EI/images/readme/0e0a9776-6d5501e4e4629e57eb5844f821aaab7f0c074c09c2e6331488cb3a5e4828e271-image.png?fit=max&auto=format&n=EpMPeQ8Ec2Yrg9EI&q=85&s=d633fa76cc2fc5fb00cbe7bcc132ba0c" alt="" width="900" height="481" data-path="images/readme/0e0a9776-6d5501e4e4629e57eb5844f821aaab7f0c074c09c2e6331488cb3a5e4828e271-image.png" />
</Frame>

### Error trends

* A chart shows API error counts over time (1–30 day ranges available).
  * Errors typically appear within **1–3 minutes** after they occur.
    * Use this view to identify spikes or recurring issues.

<Note>
  **Monitoring:** this view is most helpful for spotting systemic issues (e.g., a bad deploy or recurring field mismatch) rather than one-off errors.
</Note>

<Frame caption="Dashboard: Settings > Data Diagnostics">
  <img src="https://mintcdn.com/northbeam/EpMPeQ8Ec2Yrg9EI/images/readme/57af865f-7b3f71ed9fe095bf5526f43c59f1c72b73f17e92ffe9b8b980d804aedbc146d2-image.png?fit=max&auto=format&n=EpMPeQ8Ec2Yrg9EI&q=85&s=faf440e789edd3d97e98e9cf2f58713b" alt="" width="1224" height="543" data-path="images/readme/57af865f-7b3f71ed9fe095bf5526f43c59f1c72b73f17e92ffe9b8b980d804aedbc146d2-image.png" />
</Frame>
