# List purchases

URL: https://docs.sparklayer.io/developers/api/purchasing/get-purchases
Operation: `GET /api/v1/purchases` (operationId `getPurchases`)
OpenAPI spec: https://docs.sparklayer.io/openapi/purchasing.yaml

Lists purchases, filtered by customer, company, status, type, quote status, search term and date ranges. Results are sorted by `order_by`, newest first when you don't set it. Page through them with `limit` (up to 500) and `offset`, and stop when a page has fewer than `limit` results.

`GET /api/v1/purchases`

**Base URLs:** `https://app.sparklayer.io` (Live), `https://test.app.sparklayer.io` (Test)

**Authentication:** send `Authorization: Bearer <access_token>` and `Site-Id: <site id>` with every request. Get the token from [Get an access token](https://docs.sparklayer.io/developers/api/core/get-an-access-token.md); see [Authentication](https://docs.sparklayer.io/developers/authentication.md).

### Example request

```bash
curl "https://app.sparklayer.io/api/v1/purchases" \
  -H "Authorization: Bearer $SPARKLAYER_TOKEN" \
  -H "Site-Id: $SPARKLAYER_SITE_ID"
```

Set `SPARKLAYER_TOKEN` to an access token and `SPARKLAYER_SITE_ID` to your Site ID. For the test environment, use `https://test.app.sparklayer.io`.

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | | Limit the number of results returned. Min 1, max 500. |
| `offset` | integer | | Skip this many results, for paging. Sorted by order_by, newest first when none is given. Min 0. |
| `order_by` | "created_at" \| "updated_at" \| "placed_at" \| "calculated_submitted_at" \| "shipping_requested_date" | | The date field to sort by, in descending order (newest first). Without it, results are newest first. |
| `customer_identifiers[sparklayer]` | string | | Filter by customer_identifiers[sparklayer]. Accepts comma-separated values. Maximum total length of all values is 2000 characters. Length: min 1, max 2000. |
| `customer_identifiers[sparklayer_impersonator]` | string | | Filter by customer_identifiers[sparklayer_impersonator]. Accepts comma-separated values. Maximum total length of all values is 2000 characters. Length: min 1, max 2000. |
| `customer_identifiers[sparklayer_sales_rep]` | string | | Filter by customer_identifiers[sparklayer_sales_rep]. Accepts comma-separated values. Maximum total length of all values is 2000 characters. Length: min 1, max 2000. |
| `customer_identifiers[sparklayer_impersonator_assignee]` | string | | Filter by customer_identifiers[sparklayer_impersonator_assignee]. Accepts comma-separated values. Maximum total length of all values is 2000 characters. To get purchases that have no assignee, include a string value of 'NULL'. Length: min 1, max 2000. |
| `company[id]` | string | | Filter by company[id]. Accepts comma-separated values. Maximum total length of all values is 2000 characters. Use this rather than listing every section id to report on a whole company. Length: min 1, max 2000. |
| `company[section_id]` | string | | Filter by company[section_id]. Accepts comma-separated values. Maximum total length of all values is 2000 characters. Length: min 1, max 2000. |
| `status` | "incoming" \| "processing" \| "shipped" \| "part_shipped" \| "cancelled" \| "returned" \| "part_returned" \| "varied" | | Only purchases with this status. Example: `shipped` |
| `type` | "order" \| "quote" \| "cart" \| "awaiting_approval" \| "awaiting_merchant" \| "archived" \| "platform_archived" \| "pending_recurring_order" | | Only purchases of this type. Example: `order` |
| `quote_status` | string | | Only quotes with this quote status slug. Example: `quote-requested` |
| `search` | string | | Only purchases that match this search term. Example: `PO-12345` |
| `dates[last_updated][lte]` | string | | Only purchases last updated on or before this date. Length: min 1. |
| `dates[last_updated][gte]` | string | | Only purchases last updated on or after this date. Length: min 1. |
| `dates[placed][lte]` | string | | Only purchases placed on or before this date. Length: min 1. |
| `dates[placed][gte]` | string | | Only purchases placed on or after this date. Length: min 1. |
| `dates[submitted][lte]` | string | | Only purchases submitted on or before this date. Length: min 1. |
| `dates[submitted][gte]` | string | | Only purchases submitted on or after this date. Length: min 1. |
| `dates[shipping_requested][lte]` | string | | Only purchases with a requested shipping date on or before this date. Length: min 1. |
| `dates[shipping_requested][gte]` | string | | Only purchases with a requested shipping date on or after this date. Length: min 1. |

### Header parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Site-Id` | string | Yes | Your SparkLayer Site ID, from Settings > API in the SparkLayer Dashboard. Length: min 1. Example: `jones-climbing` |

### Responses

#### 200: The matching purchases.

An array. Each item:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `[].type` | "quote" \| "cart" \| "awaiting_approval" \| "order" \| "awaiting_merchant" \| "archived" \| "platform_archived" \| "pending_recurring_order" | Yes | |
| `[].purchase_identifiers` | object | Yes | |
| `[].purchase_identifiers.sparklayer` | string (uuid) \| null | | The identifier SparkLayer uses for the purchase. You will need to generate this if the purchase does not exist. Length: min 1. |
| `[].purchase_identifiers.platform` | string \| null | | The identifier for the purchase on the e-commerce platform. Length: min 1. |
| `[].purchase_identifiers.internal` | string \| null | | The identifier for the purchase on your system. Length: min 1. |
| `[].purchase_identifiers.visible` | string \| null | | The identifier that will be shown to the customer in their recent orders |
| `[].customer_identifiers` | object | Yes | |
| `[].customer_identifiers.sparklayer` | string | Yes | The ID of the customer that that order is for. |
| `[].customer_identifiers.sparklayer_impersonator` | string \| null | | The ID of the sales agent placing the order. |
| `[].customer_identifiers.sparklayer_impersonator_assignee` | string \| null | | The ID of the sales agent assigned to be responsible for the order. |
| `[].customer_identifiers.sparklayer_child` | string \| null | | The ID of the company user that placed the order. |
| `[].company` | object \| null | | Company sections are opt-in; omit this entirely for merchants that do not use them. |
| `[].company.id` | string (uuid) \| null | | The ID of the company the purchase was placed for. |
| `[].company.section_id` | string (uuid) \| null | | The ID of the company section the purchase was placed for. |
| `[].company.section_name` | string \| null | | The section name at the time of purchase, kept so historical purchases stay readable after a section is renamed or deleted. Not filterable. Length: max 128. |
| `[].payment_method` | "quote" \| "upfrontPayment" \| "paymentOnAccount" \| "paymentByInvoice" \| null | | How the purchase was/will be paid for |
| `[].dates` | object | Yes | |
| `[].dates.created_at` | string (date-time) | | The date the purchase was created in SparkLayer (RFC-3339). This is read only - it should not be sent to the API, but will be returned form it |
| `[].dates.updated_at` | string (date-time) | | The date the purchase was last updated in SparkLayer (RFC-3339). This is read only - it should not be sent to the API, but will be returned form it |
| `[].dates.placed_at` | string (date-time) \| null | | The date at which the purchase was placed - include user timezone or Z for UTC (RFC-3339) |
| `[].dates.to_be_placed_at` | string (date-time) \| null | | The date at which the purchase is due to be placed, for a purchase that is scheduled rather than placed immediately (RFC-3339). It can be changed while the purchase is still pending |
| `[].dates.calculated_submitted_at` | string (date-time) | | The date the purchase was submitted (RFC-3339). This is when the cart is converted into another purchase type. This is read only - it should not be sent to the API, but will be returned form it |
| `[].dates.expires_at` | string (date-time) | | the date at which the purchase will expire and become archived (RFC-3339). This is read only - it should not be sent to the API, but will be returned form it |
| `[].dates.payment_due_at` | string (date-time) | | The date at which payment for the purchase is expected |
| `[].customer_reference` | string \| null | | Additional information that a customer adds to the order |
| `[].po_number` | string \| null | | PO number for the purchase |
| `[].shipping_requested_date` | string (date-time) \| null | | The date requested for the delivery to arrive |
| `[].recurring_purchase` | object \| null | | Present only for a purchase created from a recurring purchase template. Both properties are stored when the purchase is created and ignored on any later update |
| `[].recurring_purchase.template_id` | string (uuid) \| null | | The recurring purchase template this purchase was created from. Set on creation and ignored on update |
| `[].recurring_purchase.cancelled_at` | string (date-time) \| null | | The date the customer cancelled the purchase, after which it will not be placed (RFC-3339). Cancelling does not free the date - the template has already had its turn for it |
| `[].recurring_purchase.to_be_placed_at_initial` | string (date-time) \| null | | The date to_be_placed_at was first set to (RFC-3339). Set on creation and ignored on update, so that rescheduling cannot let the same template produce a second purchase for the same date |
| `[].currency_code` | string \| null | | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `[].calculated_shipping_address` | string \| null | | A single string containing all the details of the shipping address. This is read only - it should not be sent to the API, but will be returned form it |
| `[].calculated_total` | object | | Gross total price of the purchase, calculated by SparkLayer based on package and shipment costs. This is read only - it should not be sent to the API, but will be returned form it |
| `[].calculated_total.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `[].calculated_total.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `[].calculated_total_usd` | object | | Gross total price in USD of the purchase, calculated by SparkLayer based on package and shipment costs. This is read only - it should not be sent to the API, but will be returned form it |
| `[].calculated_total_usd.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `[].calculated_total_usd.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `[].calculated_total_base` | object | | Gross total price in the store's base currency, calculated by SparkLayer. This is read only - it should not be sent to the API, but will be returned from it |
| `[].calculated_total_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `[].calculated_total_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `[].calculated_fulfilment_status` | "incoming" \| "processing" \| "shipped" \| "part_shipped" \| "cancelled" \| "returned" \| "part_returned" \| "varied" \| null | | The status of the order, calculated from the statuses of the individual packages. This is read only - it should not be sent to the API, but will be returned form it |
| `[].quote` | object \| null | | Quote data |
| `[].quote.status_slug` | string | | The slug of the quote status applied to this quote |
| `[].quote.status` | object \| null | | |
| `[].quote.status.id` | string | | |
| `[].quote.status.name` | string | | Length: max 45. |
| `[].quote.status.slug` | string | | Length: max 45. Pattern: `^[a-z0-9-]+$`. |
| `[].quote.status.default` | boolean | | |
| `[].quote.status.next` | string \| null | | Length: max 45. Pattern: `^[a-z0-9-]+$`. |
| `[].quote.status.actions` | ("edit_quote" \| "complete_quote" \| "expiry_date" \| "download_pdf")[] | | |
| `[].quote.status.created_at` | string (date-time) | | |
| `[].quote.status.updated_at` | string (date-time) | | |
| `[].quote.status.deleted_at` | string (date-time) \| null | | |
| `[].quote.expiry` | string (date-time) \| null | | The date at which the quote is considered expired and no longer valid (RFC-3339) |
| `[].payment_status` | "unpaid" \| "part_paid" \| "paid" | | That payment status of the order |
| `[].total_paid` | object | | |
| `[].total_paid.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `[].total_paid.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |

```json
[
  {
    "type": "order",
    "purchase_identifiers": {
      "sparklayer": "63428136-658f-48a6-beb7-7f333dfd9686",
      "platform": "123456789",
      "internal": "<internal>",
      "visible": "B2B01123"
    },
    "customer_identifiers": {
      "sparklayer": "4217ba4f-7618-4e3b-b1af-9055639b18d1",
      "sparklayer_impersonator": "4217ba4f-7618-4e3b-b1af-9055639b18d1",
      "sparklayer_impersonator_assignee": "4217ba4f-7618-4e3b-b1af-9055639b18d1",
      "sparklayer_child": "4217ba4f-7618-4e3b-b1af-9055639b18d1"
    },
    "company": {
      "id": "4217ba4f-7618-4e3b-b1af-9055639b18d1",
      "section_id": "4217ba4f-7618-4e3b-b1af-9055639b18d1",
      "section_name": "Bristol"
    },
    "payment_method": "quote",
    "dates": {
      "created_at": "2020-01-01T00:00:00+02:00",
      "updated_at": "2020-01-01T00:00:00+02:00",
      "placed_at": "2020-01-01T00:00:00+02:00",
      "to_be_placed_at": "2020-01-01T00:00:00+02:00",
      "calculated_submitted_at": "2020-01-01T00:00:00+02:00",
      "expires_at": "2020-01-01T00:00:00+02:00",
      "payment_due_at": "2020-01-01T00:00:00+02:00"
    },
    "customer_reference": "Please deliver to the back of the store",
    "po_number": "PO-001",
    "shipping_requested_date": "2020-01-01T00:00:00+02:00",
    "recurring_purchase": {
      "template_id": "0f8fad5b-d9cb-469f-a165-70867728950e",
      "cancelled_at": "2020-01-01T00:00:00+02:00",
      "to_be_placed_at_initial": "2020-01-01T00:00:00+02:00"
    },
    "currency_code": "GBP",
    "calculated_shipping_address": "John Spark, SparkLayer, SparkLayer HQ, Example City, 12345",
    "calculated_total": {
      "number": "15.99",
      "currency": "GBP"
    },
    "calculated_total_usd": {
      "number": "15.99",
      "currency": "GBP"
    },
    "calculated_total_base": {
      "number": "15.99",
      "currency": "GBP"
    },
    "calculated_fulfilment_status": "processing",
    "quote": {
      "status_slug": "<status_slug>",
      "status": {
        "id": "<id>",
        "name": "<name>",
        "slug": "<slug>",
        "default": true,
        "next": "<next>",
        "actions": [
          "edit_quote"
        ],
        "created_at": "2026-01-31T09:00:00Z",
        "updated_at": "2026-01-31T09:00:00Z",
        "deleted_at": "2026-01-31T09:00:00Z"
      },
      "expiry": "2020-01-01T00:00:00+02:00"
    },
    "payment_status": "unpaid",
    "total_paid": {
      "number": "15.99",
      "currency": "GBP"
    }
  }
]
```

#### 500: An unexpected error.

`application/problem+json`: the standard error body (below).

### Error body

Error responses with a body use this RFC 7807 problem details object. See [Errors](https://docs.sparklayer.io/developers/errors.md) for every status code and which errors to retry.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `detail` | string | | Human-readable summary of the error |
| `status` | integer | | HTTP Status code returned from API |
| `title` | string | | Machine-readable error code |
| `type` | string | | |
| `errors` | object[] | | |
| `errors[].code` | string | | A machine-readable error message |
| `errors[].property` | string | | The offending property |
| `errors[].message` | string | | A human-readable summary of the error |

```json
{
  "detail": "Data Validation Failed",
  "status": 400,
  "title": "invalid-api-request-contents",
  "type": "https://hub.sparklayer.io/tech-docs",
  "errors": [
    {
      "code": "unique-constraint-violation",
      "property": "purchase_identifiers.sparklayer",
      "message": "Each stock level must have a unique stock location and sku combination"
    }
  ]
}
```
