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

# Orders API: Place, Track, and Manage Orders

> Place orders via Direct Fulfillment in a single idempotent call, retrieve orders with full line item and fulfillment tracking, list and filter orders, and cancel unfulfilled orders.

An **Order** represents the physical fulfillment event - the point at which a gift becomes a shipment. The Order is the **primary integration object for Direct Fulfillment**: you create it via a single call to `POST /v3/orders` with the recipient and variant details, then track its progress through the lifecycle.

Orders are also generated automatically by Snappy when a recipient claims their gift in the **Triggered Gifting** model - those orders are retrievable, listable, and cancellable through the same V3 Orders API.

<Tip>
  Want to understand how **Orders** fit into the bigger picture? Check out the [Core Concepts & Data Models](/pages/snappy-core-concepts-and-data-models) page.
</Tip>

<Note>
  The V3 Orders API exposes Orders as first-class resources with their own lifecycle, line items, fulfillments, and tracking - independent of the Gift entity. You no longer need to retrieve orders through their parent Gift.
</Note>

***

## The Order Object

| Field                 | Type         | Description                                                                                                                |
| :-------------------- | :----------- | :------------------------------------------------------------------------------------------------------------------------- |
| `id`                  | string       | Unique identifier of the Order (e.g. `G7nR4bD9mK`)                                                                         |
| `status`              | enum         | Order lifecycle status. One of: `active`, `completed`, `cancelled`, `refunded`                                             |
| `fulfillmentStatus`   | enum         | Aggregated fulfillment status across all line items. One of: `unfulfilled`, `fulfilled`, `cancelled`                       |
| `idempotencyKey`      | string       | Caller-supplied idempotency key from order creation                                                                        |
| `tags`                | string array | Caller-supplied tags for grouping and filtering orders in reports                                                          |
| `lineItems`           | array        | Products included in this Order. See [Line items](#line-items) below.                                                      |
| `fulfillments`        | array        | Fulfillment records - shipments with carrier, tracking info, and delivery status. See [Fulfillments](#fulfillments) below. |
| `recipient`           | object       | Recipient contact details. See [Recipient](#recipient) below.                                                              |
| `shippingAddress`     | object       | Physical shipping address. See [Shipping address](#shipping-address) below.                                                |
| `metadata`            | object       | Caller-supplied key-value pairs. `null` when no metadata was supplied.                                                     |
| `cancellationDetails` | object       | Populated only when `status` is `cancelled`. See [Cancellation details](#cancellation-details) below.                      |

***

### Order status

| Status      | Description                          |
| :---------- | :----------------------------------- |
| `active`    | Being processed or in fulfillment    |
| `completed` | Fulfilled and finalized              |
| `cancelled` | Cancelled before fulfillment         |
| `refunded`  | Returned and refunded after delivery |

### Fulfillment status

Aggregated across all line items.

| Status        | Description                                        |
| :------------ | :------------------------------------------------- |
| `unfulfilled` | No fulfillments exist yet                          |
| `fulfilled`   | Every line item is covered by a fulfillment record |
| `cancelled`   | Order fulfillment was cancelled                    |

***

### Line items

| Field       | Type    | Description                                 |
| :---------- | :------ | :------------------------------------------ |
| `variantId` | string  | Variant ID of the ordered product           |
| `title`     | string  | Product title captured at the time of order |
| `quantity`  | integer | Number of units of this variant ordered     |

### Fulfillments

A Fulfillment represents a shipment containing one or more line items. An Order can have multiple Fulfillments (e.g. split shipments), and a Fulfillment can cover multiple line items (e.g. consolidated shipping). This is a many-to-many relationship between line items and fulfillments.

| Field                  | Type   | Description                                                                 |
| :--------------------- | :----- | :-------------------------------------------------------------------------- |
| `id`                   | string | Unique identifier of the fulfillment record                                 |
| `status`               | enum   | Carrier delivery status. See [Delivery statuses](#delivery-statuses) below. |
| `trackingCompany`      | string | Carrier name (e.g. `UPS`, `USPS`, `FedEx`)                                  |
| `trackingInfo.number`  | string | Carrier tracking number                                                     |
| `trackingInfo.url`     | string | Carrier tracking page URL                                                   |
| `fulfillmentLineItems` | array  | Line items included in this fulfillment                                     |

#### Delivery statuses

| Status             | Description                  |
| :----------------- | :--------------------------- |
| `confirmed`        | Order received by the vendor |
| `processing`       | Being prepared for shipment  |
| `in_transit`       | Shipped and in transit       |
| `out_for_delivery` | Out for delivery             |
| `delivered`        | Delivered to the recipient   |

<Tip>
  Use Webhooks to track delivery status changes in real time rather than polling. See [Webhook Event Types](/pages/webhook-event-types).
</Tip>

### Recipient

| Field       | Type   | Description             |
| :---------- | :----- | :---------------------- |
| `firstName` | string | Recipient first name    |
| `lastName`  | string | Recipient last name     |
| `email`     | string | Recipient email address |
| `phone`     | string | E.164 phone number      |

### Shipping address

| Field          | Type   | Description                                    |
| :------------- | :----- | :--------------------------------------------- |
| `address1`     | string | Street address (max 35 chars)                  |
| `address2`     | string | Apartment, suite, floor (max 35 chars)         |
| `city`         | string | City name                                      |
| `provinceCode` | string | State or province code (2-3 uppercase letters) |
| `postalCode`   | string | Postal/ZIP code (alphanumeric, 3-10 chars)     |
| `countryCode`  | string | ISO 3166-1 alpha-2 country code (uppercase)    |

### Cancellation details

| Field                | Type              | Description                                                   |
| :------------------- | :---------------- | :------------------------------------------------------------ |
| `cancelledAt`        | string (ISO 8601) | Timestamp when the Order was cancelled                        |
| `cancellationReason` | enum              | Reason for cancellation. Currently only: `customer_requested` |

***

## Key Concepts & Business Rules

#### Idempotency on order placement

Every `POST /v3/orders` request must include an `idempotencyKey` (1-120 characters). If a request with the same key has already succeeded for this Company, the original order is returned - no duplicate is created. Use stable, caller-generated keys (e.g. your internal order ID).

See [Duplicate Detection](/pages/duplicate-gifts-detection) for the full idempotency reference.

#### Variants are required - not Products

When placing an order, you must always specify the `variantId`, not the `productId`. Every Product has at least one Variant, even if it has no variations. See [Products & Variants Overview](/modules/api/v2/products/overview).

#### Tags vs metadata

Two separate fields with different purposes:

* **`tags`** - array of strings for grouping and filtering orders in reports (e.g. `["q4-campaign", "vip"]`).
* **`metadata`** - key-value object for arbitrary passthrough data (e.g. `{"externalRecipientId": "crm-user-987"}`). Up to 50 pairs, keys up to 40 chars, values up to 500 chars.

Use `tags` for categorization; use `metadata` for data you want to round-trip.

#### Status vs fulfillment status

The Order has two distinct status fields that capture different concerns:

* **`status`** tracks the **commercial** lifecycle: `active` → `completed`, or `active` → `cancelled` / `refunded`
* **`fulfillmentStatus`** tracks the **physical** lifecycle aggregated across line items: `unfulfilled` → `fulfilled` (or `cancelled`)

Per-shipment carrier progress lives inside `fulfillments[].status`.

#### Cancellation rules

Orders can only be cancelled before they are picked up by the fulfillment partner. Once an Order is in transit, cancellation returns `422`. The `cancellationReason` enum currently only supports `customer_requested`; additional reasons may be added in future releases.

#### Address validation reduces fulfillment failures

Invalid or incomplete shipping addresses are a common cause of fulfillment failures. We recommend validating the recipient's address via `POST /orders/addresses/validate` before calling `POST /v3/orders`, especially when addresses are entered by end users in your platform UI.

#### Billing is triggered at order creation

The Billing Method (referenced via `billingMethodId`) is debited when an Order is successfully placed. If the Billing Method has insufficient funds at the time of the request, the order will not be processed. See [Billing Methods Overview](/modules/api/v3/billing-methods/overview) to check remaining balance before placing high-value orders.

#### Pagination

The V3 list endpoint uses **page-number pagination** (`page[number]` and `page[size]`, max 300, default 100). Responses include a top-level `links` object with `first`, `next`, and `prev` URLs.

See [Request & Response Standards](/pages/request-response-standards) for the full V3 pagination contract.

#### Account scoping

Pass the optional `Snappy-Account-Id` header to scope queries to a specific Account. For `POST /v3/orders`, `accountId` may alternatively be supplied in the request body - the header takes precedence when both are provided.

#### Permissions

The V3 Orders endpoints require different scopes depending on the operation:

| Endpoint                           | Required scope                                 |
| :--------------------------------- | :--------------------------------------------- |
| `POST /v3/orders`                  | `orders:create`                                |
| `GET /v3/orders`                   | `orders:read:masked` or `orders:read:unmasked` |
| `GET /v3/orders/{orderId}`         | `orders:read:masked` or `orders:read:unmasked` |
| `POST /v3/orders/{orderId}/cancel` | `orders:cancel`                                |

PII fields (recipient name, tracking info) are masked under `orders:read:masked` and returned in full under `orders:read:unmasked`.

***

## How to Work with Orders

**Place an order** *(Direct Fulfillment)*

```text theme={null} theme={null}
POST /v3/orders
```

Creates a new Order for a single variant on behalf of a recipient. Returns a minimal create result with the Order ID, initial status (`active`), and a tracking link. Required: `billingMethodId`, `variantId`, `recipient`, `shippingAddress`, `idempotencyKey`. Optional: `accountId`, `tags`, `metadata`.

**List orders**

```text theme={null} theme={null}
GET /v3/orders
```

Returns a paginated list of Orders matching the supplied filters. Filter by `status` (`active`, `cancelled`), `idempotencyKey` (comma-separated array), or `createdAt` range. Sort by `createdAt` (newest first by default).

**Get an order by ID**

```text theme={null} theme={null}
GET /v3/orders/{orderId}
```

Retrieves a single Order with full detail - line items, recipient, shipping address, fulfillments, and tracking info.

**Cancel an order**

```text theme={null} theme={null}
POST /v3/orders/{orderId}/cancel
```

Cancels an Order that has not yet been fulfilled. Returns the Order in its post-cancellation state with `status: "cancelled"` and a populated `cancellationDetails` object. Returns `422` if the Order has already been picked up by the fulfillment partner.

***
