# Create or update a purchase

URL: https://docs.sparklayer.io/developers/api/purchasing/create-update-purchase
Operation: `PUT /api/v1/purchases/{lookupBy}/{identifier}` (operationId `createUpdatePurchase`)
OpenAPI spec: https://docs.sparklayer.io/openapi/purchasing.yaml

Creates the purchase if none matches `lookupBy` and `identifier`, otherwise replaces it, and returns the stored purchase. The request replaces all of the purchase's data, so always send the full purchase rather than only the fields that changed, and leave out calculated fields: the API calculates them. For an order placed through SparkLayer, look it up with `lookupBy=sparklayer` and the SparkLayer cart ID, so the order replaces the cart.

Purchases created here appear in My Account but aren't sent to your eCommerce platform. Returns `400` if a required value is missing or invalid, `403` if the request tries to change the purchase's SparkLayer ID, and `409` if it conflicts with the stored purchase.

`PUT /api/v1/purchases/{lookupBy}/{identifier}`

**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 -X PUT "https://app.sparklayer.io/api/v1/purchases/platform/123456789" \
  -H "Authorization: Bearer $SPARKLAYER_TOKEN" \
  -H "Site-Id: $SPARKLAYER_SITE_ID" \
  -H "Content-Type: application/json" \
  -d '{
  "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": {
    "placed_at": "2020-01-01T00:00:00+02:00",
    "to_be_placed_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",
  "currency_code_base": "GBP",
  "calculated_total": {
    "number": "15.99",
    "currency": "GBP"
  },
  "calculated_total_usd": {
    "number": "15.99",
    "currency": "GBP"
  },
  "calculated_total_base": {
    "number": "15.99",
    "currency": "GBP"
  },
  "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"
  },
  "revision_date": "2020-01-01T00:00:00+02:00",
  "tax_lines": [
    {
      "title": "HST",
      "amount": {
        "number": "15.99",
        "currency": "GBP"
      },
      "amount_base": {
        "number": "15.99",
        "currency": "GBP"
      },
      "rate": 20
    }
  ],
  "billing_address": {
    "name": "Tom Jones",
    "company": "Tom Jones Hardware Ltd",
    "address_line1": "7 Philosophy way",
    "address_line2": null,
    "city": "Willerby",
    "region_code": null,
    "postal_code": "BJ6 9MK",
    "country_code": "GB",
    "phone": "0123456789",
    "sparklayer_id": "63428136-658f-48a6-beb7-7f333dfd9686",
    "first_name": "Tom",
    "last_name": "Jones"
  },
  "packages": [
    {
      "identifiers": {
        "sparklayer_package_id": "63428136-658f-48a6-beb7-7f333dfd9686",
        "platform": "123456789",
        "internal": "<internal>",
        "visible": "<visible>"
      },
      "accounting_files": [
        {
          "identifiers": {
            "internal": "INV011",
            "visible": "INV011"
          },
          "data": {
            "uri": "https://example.com",
            "type": "uri"
          },
          "file_type": "invoice"
        }
      ],
      "line_items": [
        {
          "type": "custom",
          "identifiers": {
            "sparklayer_item_key": "<sparklayer_item_key>",
            "sparklayer_variant_id": "45552423353839",
            "sku": "CAT-MUG",
            "platform": "123456789",
            "internal": "<internal>",
            "visible": "<visible>"
          },
          "name_parent": "T-Shirt",
          "name_child": "Red",
          "quantity": 4,
          "custom_attributes": [
            {
              "key": "mug text",
              "value": "best company ever"
            }
          ],
          "line_total": {
            "total_net": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_net_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_tax": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_tax_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_gross": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_gross_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "discount_net": {
              "number": "15.99",
              "currency": "GBP"
            },
            "discount_net_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "tax_rate": 20
          },
          "tax_lines": [
            {
              "title": "HST",
              "amount": {
                "number": "15.99",
                "currency": "GBP"
              },
              "amount_base": {
                "number": "15.99",
                "currency": "GBP"
              },
              "rate": 20
            }
          ]
        }
      ],
      "shipping_method": {
        "sku": "SHIP-ECO",
        "name": "Standard Shipping",
        "line_total": {
          "total_net": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_net_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_tax": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_tax_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_gross": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_gross_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "discount_net": {
            "number": "15.99",
            "currency": "GBP"
          },
          "discount_net_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "tax_rate": 20
        },
        "tax_lines": [
          {
            "title": "HST",
            "amount": {
              "number": "15.99",
              "currency": "GBP"
            },
            "amount_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "rate": 20
          }
        ]
      },
      "shipping_address": {
        "name": "Tom Jones",
        "company": "Tom Jones Hardware Ltd",
        "address_line1": "7 Philosophy way",
        "address_line2": null,
        "city": "Willerby",
        "region_code": null,
        "postal_code": "BJ6 9MK",
        "country_code": "GB",
        "phone": "0123456789",
        "sparklayer_id": "63428136-658f-48a6-beb7-7f333dfd9686",
        "first_name": "Tom",
        "last_name": "Jones"
      },
      "shipments": [
        {
          "carrier": "Carrier Company Ltd",
          "carrier_id": "<carrier_id>",
          "tracking_url": "https://example.com"
        }
      ],
      "type": "incoming"
    }
  ],
  "accounting_files": [
    {
      "identifiers": {
        "internal": "INV011",
        "visible": "INV011"
      },
      "data": {
        "uri": "https://example.com",
        "type": "uri"
      },
      "file_type": "invoice"
    }
  ],
  "custom_fields": [
    {
      "name": "delivery-date",
      "value": "2023-10-28"
    }
  ],
  "metadata": [
    {
      "name": "example-key",
      "value": "1234"
    }
  ]
}'
```

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`.

### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `lookupBy` | "sparklayer" \| "platform" \| "internal" \| "visible" | Yes | Which of the purchase's `purchase_identifiers` `identifier` is: `sparklayer`, `platform`, `internal` or `visible`. Example: `platform` |
| `identifier` | string \| string (uuid) | Yes | The purchase identifier, of the kind set by `lookupBy`. With `lookupBy=sparklayer` it must be a UUID. Example: `123456789` |

### 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` |

### Request body (`application/json`) (required)

SparkLayer purchase object.

| 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.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.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. |
| `currency_code_base` | string \| null | | The 3 letter currency code of the store's base currency. Length: min 3, max 3. |
| `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. |
| `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. |
| `revision_date` | string (date-time) \| null | | The date at which the purchase was last modified - include user timezone or Z for UTC (RFC-3339) |
| `tax_lines` | object[] | | Tax lines for the purchase. |
| `tax_lines[].title` | string | Yes | The title of the tax line |
| `tax_lines[].amount` | object | Yes | The amount of tax of the tax line |
| `tax_lines[].amount.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `tax_lines[].amount.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `tax_lines[].amount_base` | object | | The amount of tax of the tax line in the store's base currency |
| `tax_lines[].amount_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `tax_lines[].amount_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `tax_lines[].rate` | number (double) \| null | Yes | The rate of the tax. The value represents a percentage e.g. 20 means 20%. Min 0. |
| `billing_address` | object \| null | | |
| `billing_address.name` | string \| null | | |
| `billing_address.company` | string \| null | | |
| `billing_address.address_line1` | string | Yes | |
| `billing_address.address_line2` | string \| null | | |
| `billing_address.city` | string | Yes | |
| `billing_address.region_code` | string \| null | | Length: min 1. |
| `billing_address.postal_code` | string \| null | | |
| `billing_address.country_code` | string | Yes | |
| `billing_address.phone` | string \| null | | |
| `billing_address.sparklayer_id` | string \| null | | |
| `billing_address.first_name` | string \| null | | |
| `billing_address.last_name` | string \| null | | |
| `packages` | (Incoming \| Processing \| Shipment \| Cancelled \| Return)[] | Yes | Packages contained within this purchase |
| `packages[].identifiers` | object | | |
| `packages[].identifiers.sparklayer_package_id` | string (uuid) | Yes | A UUID for the package that must be unique within the purchase. You must generate this yourself |
| `packages[].identifiers.platform` | string \| null | | The identifier for the package on the e-commerce platform. Length: min 1. |
| `packages[].identifiers.internal` | string \| null | | The identifier for the package on your system. Length: min 1. |
| `packages[].identifiers.visible` | string \| null | | The identifier that will be shown to the customer in their recent orders |
| `packages[].accounting_files` | object[] | | |
| `packages[].accounting_files[].identifiers` | object | Yes | |
| `packages[].accounting_files[].identifiers.internal` | string \| null | | The identifier of the purchase file that is used by your system. Length: min 1. |
| `packages[].accounting_files[].identifiers.visible` | string \| null | | The identifier of the purchase file that should be shown to the customer. Default: `INV011`. |
| `packages[].accounting_files[].data` | object | Yes | |
| `packages[].accounting_files[].data.uri` | string (uri) \| null | | |
| `packages[].accounting_files[].data.type` | "uri" | Yes | Default: `uri`. |
| `packages[].accounting_files[].file_type` | "credit" \| "invoice" \| "payment" | Yes | |
| `packages[].line_items` | object[] | | |
| `packages[].line_items[].type` | "custom" \| "product" | | |
| `packages[].line_items[].identifiers` | object | Yes | |
| `packages[].line_items[].identifiers.sparklayer_item_key` | string \| null | | Internally used for tracking line items. For orders, can be set to null. Length: min 1. |
| `packages[].line_items[].identifiers.sparklayer_variant_id` | string \| null | | The ID of the variant on your e-commerce platform. Length: min 1. |
| `packages[].line_items[].identifiers.sku` | string \| null | | Length: max 128. |
| `packages[].line_items[].identifiers.platform` | string \| null | | The identifier for the product on the e-commerce platform. Length: min 1. |
| `packages[].line_items[].identifiers.internal` | string \| null | | The identifier for the product on your system. Length: min 1. |
| `packages[].line_items[].identifiers.visible` | string \| null | | A human-readable identifier for the product |
| `packages[].line_items[].name_parent` | string | Yes | Name of the product |
| `packages[].line_items[].name_child` | string \| null | | Name of the product variant/type |
| `packages[].line_items[].quantity` | number | Yes | |
| `packages[].line_items[].custom_attributes` | object[] | | |
| `packages[].line_items[].custom_attributes[].key` | string | Yes | Key or name of the attribute. |
| `packages[].line_items[].custom_attributes[].value` | string | Yes | Value of the attribute. |
| `packages[].line_items[].line_total` | object \| null | Yes | The total cost of this line. This is nullable only for quotes. |
| `packages[].line_items[].line_total.total_net` | object | Yes | The net cost of the line item. This should be the price after any discounts are applied |
| `packages[].line_items[].line_total.total_net.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.total_net.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.total_net_base` | object | | The net cost of the line item in the store's base currency. |
| `packages[].line_items[].line_total.total_net_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.total_net_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.total_tax` | object | | The tax on the line item. |
| `packages[].line_items[].line_total.total_tax.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.total_tax.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.total_tax_base` | object | | The tax on the line item in the store's base currency. |
| `packages[].line_items[].line_total.total_tax_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.total_tax_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.total_gross` | object | | The gross cost of the line item. |
| `packages[].line_items[].line_total.total_gross.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.total_gross.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.total_gross_base` | object | | The gross cost of the line item in the store's base currency. |
| `packages[].line_items[].line_total.total_gross_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.total_gross_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.discount_net` | object | Yes | The net discount that has already been applied to the total. This is just to show to the end user |
| `packages[].line_items[].line_total.discount_net.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.discount_net.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.discount_net_base` | object | | The net discount in the store's base currency. |
| `packages[].line_items[].line_total.discount_net_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].line_total.discount_net_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].line_total.tax_rate` | number (double) \| null | | **Deprecated.** The tax rate to apply to the net total. The value represents a percentage e.g. 20 means 20%. Default: `0`. Min 0. |
| `packages[].line_items[].tax_lines` | object[] | | |
| `packages[].line_items[].tax_lines[].title` | string | Yes | The title of the tax line |
| `packages[].line_items[].tax_lines[].amount` | object | Yes | The amount of tax of the tax line |
| `packages[].line_items[].tax_lines[].amount.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].tax_lines[].amount.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].tax_lines[].amount_base` | object | | The amount of tax of the tax line in the store's base currency |
| `packages[].line_items[].tax_lines[].amount_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].line_items[].tax_lines[].amount_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].line_items[].tax_lines[].rate` | number (double) \| null | Yes | The rate of the tax. The value represents a percentage e.g. 20 means 20%. Min 0. |
| `packages[].shipping_method` | object \| null | | Details of how the package was/will be shipped |
| `packages[].shipping_method.sku` | string \| null | | SKU that identifies the shipping method used. Length: min 1. |
| `packages[].shipping_method.name` | string | Yes | The friendly/human-readable name for the shipping method |
| `packages[].shipping_method.line_total` | object | Yes | Cost of the shipment |
| `packages[].shipping_method.line_total.total_net` | object | Yes | The net cost of the line item. This should be the price after any discounts are applied |
| `packages[].shipping_method.line_total.total_net.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.total_net.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.total_net_base` | object | | The net cost of the line item in the store's base currency. |
| `packages[].shipping_method.line_total.total_net_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.total_net_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.total_tax` | object | | The tax on the line item. |
| `packages[].shipping_method.line_total.total_tax.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.total_tax.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.total_tax_base` | object | | The tax on the line item in the store's base currency. |
| `packages[].shipping_method.line_total.total_tax_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.total_tax_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.total_gross` | object | | The gross cost of the line item. |
| `packages[].shipping_method.line_total.total_gross.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.total_gross.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.total_gross_base` | object | | The gross cost of the line item in the store's base currency. |
| `packages[].shipping_method.line_total.total_gross_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.total_gross_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.discount_net` | object | Yes | The net discount that has already been applied to the total. This is just to show to the end user |
| `packages[].shipping_method.line_total.discount_net.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.discount_net.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.discount_net_base` | object | | The net discount in the store's base currency. |
| `packages[].shipping_method.line_total.discount_net_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.line_total.discount_net_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.line_total.tax_rate` | number (double) \| null | | **Deprecated.** The tax rate to apply to the net total. The value represents a percentage e.g. 20 means 20%. Default: `0`. Min 0. |
| `packages[].shipping_method.tax_lines` | object[] | | |
| `packages[].shipping_method.tax_lines[].title` | string | Yes | The title of the tax line |
| `packages[].shipping_method.tax_lines[].amount` | object | Yes | The amount of tax of the tax line |
| `packages[].shipping_method.tax_lines[].amount.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.tax_lines[].amount.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.tax_lines[].amount_base` | object | | The amount of tax of the tax line in the store's base currency |
| `packages[].shipping_method.tax_lines[].amount_base.number` | string | Yes | The amount of currency in this currency, represented as a string. Length: min 1. |
| `packages[].shipping_method.tax_lines[].amount_base.currency` | string | Yes | The 3 letter currency code used for the prices in the purchase. Length: min 3, max 3. |
| `packages[].shipping_method.tax_lines[].rate` | number (double) \| null | Yes | The rate of the tax. The value represents a percentage e.g. 20 means 20%. Min 0. |
| `packages[].shipping_address` | object \| null | | |
| `packages[].shipping_address.name` | string \| null | | |
| `packages[].shipping_address.company` | string \| null | | |
| `packages[].shipping_address.address_line1` | string | Yes | |
| `packages[].shipping_address.address_line2` | string \| null | | |
| `packages[].shipping_address.city` | string | Yes | |
| `packages[].shipping_address.region_code` | string \| null | | Length: min 1. |
| `packages[].shipping_address.postal_code` | string \| null | | |
| `packages[].shipping_address.country_code` | string | Yes | |
| `packages[].shipping_address.phone` | string \| null | | |
| `packages[].shipping_address.sparklayer_id` | string \| null | | |
| `packages[].shipping_address.first_name` | string \| null | | |
| `packages[].shipping_address.last_name` | string \| null | | |
| `packages[].shipments` | object[] | | Carrier and tracking details for the shipment |
| `packages[].shipments[].carrier` | string | Yes | |
| `packages[].shipments[].carrier_id` | string | Yes | The tracking number/ID used by the carrier |
| `packages[].shipments[].tracking_url` | string (uri) \| null | | The URL the customer can use to track their shipment |
| `packages[].type` | "incoming" | | |
| `packages[].dates` | object | | |
| `packages[].dates.shipped_at` | string (date-time) | Yes | The date at which the package was shipped - include user timezone or Z for UTC (RFC-3339) |
| `accounting_files` | object[] | Yes | Any accounting files associated with this package e.g. invoices |
| `accounting_files[].identifiers` | object | Yes | |
| `accounting_files[].identifiers.internal` | string \| null | | The identifier of the purchase file that is used by your system. Length: min 1. |
| `accounting_files[].identifiers.visible` | string \| null | | The identifier of the purchase file that should be shown to the customer. Default: `INV011`. |
| `accounting_files[].data` | object | Yes | |
| `accounting_files[].data.uri` | string (uri) \| null | | |
| `accounting_files[].data.type` | "uri" | Yes | Default: `uri`. |
| `accounting_files[].file_type` | "credit" \| "invoice" \| "payment" | Yes | |
| `custom_fields` | object[] | Yes | Extra information for the purchase. This will be shown to the customer in their recent orders |
| `custom_fields[].name` | string | Yes | Name/identifier for the custom field. Length: min 1. |
| `custom_fields[].value` | string \| null | | Data for the custom field |
| `metadata` | object[] | | Extra information for the purchase. This not will be shown to the customer |
| `metadata[].name` | string | Yes | Name/identifier for the metadata. Length: min 1. |
| `metadata[].value` | string | Yes | Data for the metadata |

```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": {
    "placed_at": "2020-01-01T00:00:00+02:00",
    "to_be_placed_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",
  "currency_code_base": "GBP",
  "calculated_total": {
    "number": "15.99",
    "currency": "GBP"
  },
  "calculated_total_usd": {
    "number": "15.99",
    "currency": "GBP"
  },
  "calculated_total_base": {
    "number": "15.99",
    "currency": "GBP"
  },
  "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"
  },
  "revision_date": "2020-01-01T00:00:00+02:00",
  "tax_lines": [
    {
      "title": "HST",
      "amount": {
        "number": "15.99",
        "currency": "GBP"
      },
      "amount_base": {
        "number": "15.99",
        "currency": "GBP"
      },
      "rate": 20
    }
  ],
  "billing_address": {
    "name": "Tom Jones",
    "company": "Tom Jones Hardware Ltd",
    "address_line1": "7 Philosophy way",
    "address_line2": null,
    "city": "Willerby",
    "region_code": null,
    "postal_code": "BJ6 9MK",
    "country_code": "GB",
    "phone": "0123456789",
    "sparklayer_id": "63428136-658f-48a6-beb7-7f333dfd9686",
    "first_name": "Tom",
    "last_name": "Jones"
  },
  "packages": [
    {
      "identifiers": {
        "sparklayer_package_id": "63428136-658f-48a6-beb7-7f333dfd9686",
        "platform": "123456789",
        "internal": "<internal>",
        "visible": "<visible>"
      },
      "accounting_files": [
        {
          "identifiers": {
            "internal": "INV011",
            "visible": "INV011"
          },
          "data": {
            "uri": "https://example.com",
            "type": "uri"
          },
          "file_type": "invoice"
        }
      ],
      "line_items": [
        {
          "type": "custom",
          "identifiers": {
            "sparklayer_item_key": "<sparklayer_item_key>",
            "sparklayer_variant_id": "45552423353839",
            "sku": "CAT-MUG",
            "platform": "123456789",
            "internal": "<internal>",
            "visible": "<visible>"
          },
          "name_parent": "T-Shirt",
          "name_child": "Red",
          "quantity": 4,
          "custom_attributes": [
            {
              "key": "mug text",
              "value": "best company ever"
            }
          ],
          "line_total": {
            "total_net": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_net_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_tax": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_tax_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_gross": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_gross_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "discount_net": {
              "number": "15.99",
              "currency": "GBP"
            },
            "discount_net_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "tax_rate": 20
          },
          "tax_lines": [
            {
              "title": "HST",
              "amount": {
                "number": "15.99",
                "currency": "GBP"
              },
              "amount_base": {
                "number": "15.99",
                "currency": "GBP"
              },
              "rate": 20
            }
          ]
        }
      ],
      "shipping_method": {
        "sku": "SHIP-ECO",
        "name": "Standard Shipping",
        "line_total": {
          "total_net": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_net_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_tax": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_tax_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_gross": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_gross_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "discount_net": {
            "number": "15.99",
            "currency": "GBP"
          },
          "discount_net_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "tax_rate": 20
        },
        "tax_lines": [
          {
            "title": "HST",
            "amount": {
              "number": "15.99",
              "currency": "GBP"
            },
            "amount_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "rate": 20
          }
        ]
      },
      "shipping_address": {
        "name": "Tom Jones",
        "company": "Tom Jones Hardware Ltd",
        "address_line1": "7 Philosophy way",
        "address_line2": null,
        "city": "Willerby",
        "region_code": null,
        "postal_code": "BJ6 9MK",
        "country_code": "GB",
        "phone": "0123456789",
        "sparklayer_id": "63428136-658f-48a6-beb7-7f333dfd9686",
        "first_name": "Tom",
        "last_name": "Jones"
      },
      "shipments": [
        {
          "carrier": "Carrier Company Ltd",
          "carrier_id": "<carrier_id>",
          "tracking_url": "https://example.com"
        }
      ],
      "type": "incoming"
    }
  ],
  "accounting_files": [
    {
      "identifiers": {
        "internal": "INV011",
        "visible": "INV011"
      },
      "data": {
        "uri": "https://example.com",
        "type": "uri"
      },
      "file_type": "invoice"
    }
  ],
  "custom_fields": [
    {
      "name": "delivery-date",
      "value": "2023-10-28"
    }
  ],
  "metadata": [
    {
      "name": "example-key",
      "value": "1234"
    }
  ]
}
```

### Responses

#### 200: The created or updated purchase.

The `Purchase` object: the request body's fields, plus:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `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.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 |
| `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_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 |

```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"
  },
  "revision_date": "2020-01-01T00:00:00+02:00",
  "tax_lines": [
    {
      "title": "HST",
      "amount": {
        "number": "15.99",
        "currency": "GBP"
      },
      "amount_base": {
        "number": "15.99",
        "currency": "GBP"
      },
      "rate": 20
    }
  ],
  "billing_address": {
    "name": "Tom Jones",
    "company": "Tom Jones Hardware Ltd",
    "address_line1": "7 Philosophy way",
    "address_line2": null,
    "city": "Willerby",
    "region_code": null,
    "postal_code": "BJ6 9MK",
    "country_code": "GB",
    "phone": "0123456789",
    "sparklayer_id": "63428136-658f-48a6-beb7-7f333dfd9686",
    "first_name": "Tom",
    "last_name": "Jones"
  },
  "packages": [
    {
      "identifiers": {
        "sparklayer_package_id": "63428136-658f-48a6-beb7-7f333dfd9686",
        "platform": "123456789",
        "internal": "<internal>",
        "visible": "<visible>"
      },
      "accounting_files": [
        {
          "identifiers": {
            "internal": "INV011",
            "visible": "INV011"
          },
          "data": {
            "uri": "https://example.com",
            "type": "uri"
          },
          "file_type": "invoice"
        }
      ],
      "line_items": [
        {
          "type": "custom",
          "identifiers": {
            "sparklayer_item_key": "<sparklayer_item_key>",
            "sparklayer_variant_id": "45552423353839",
            "sku": "CAT-MUG",
            "platform": "123456789",
            "internal": "<internal>",
            "visible": "<visible>"
          },
          "name_parent": "T-Shirt",
          "name_child": "Red",
          "quantity": 4,
          "custom_attributes": [
            {
              "key": "mug text",
              "value": "best company ever"
            }
          ],
          "line_total": {
            "total_net": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_net_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_tax": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_tax_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_gross": {
              "number": "15.99",
              "currency": "GBP"
            },
            "total_gross_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "discount_net": {
              "number": "15.99",
              "currency": "GBP"
            },
            "discount_net_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "tax_rate": 20
          },
          "tax_lines": [
            {
              "title": "HST",
              "amount": {
                "number": "15.99",
                "currency": "GBP"
              },
              "amount_base": {
                "number": "15.99",
                "currency": "GBP"
              },
              "rate": 20
            }
          ]
        }
      ],
      "shipping_method": {
        "sku": "SHIP-ECO",
        "name": "Standard Shipping",
        "line_total": {
          "total_net": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_net_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_tax": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_tax_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_gross": {
            "number": "15.99",
            "currency": "GBP"
          },
          "total_gross_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "discount_net": {
            "number": "15.99",
            "currency": "GBP"
          },
          "discount_net_base": {
            "number": "15.99",
            "currency": "GBP"
          },
          "tax_rate": 20
        },
        "tax_lines": [
          {
            "title": "HST",
            "amount": {
              "number": "15.99",
              "currency": "GBP"
            },
            "amount_base": {
              "number": "15.99",
              "currency": "GBP"
            },
            "rate": 20
          }
        ]
      },
      "shipping_address": {
        "name": "Tom Jones",
        "company": "Tom Jones Hardware Ltd",
        "address_line1": "7 Philosophy way",
        "address_line2": null,
        "city": "Willerby",
        "region_code": null,
        "postal_code": "BJ6 9MK",
        "country_code": "GB",
        "phone": "0123456789",
        "sparklayer_id": "63428136-658f-48a6-beb7-7f333dfd9686",
        "first_name": "Tom",
        "last_name": "Jones"
      },
      "shipments": [
        {
          "carrier": "Carrier Company Ltd",
          "carrier_id": "<carrier_id>",
          "tracking_url": "https://example.com"
        }
      ],
      "type": "incoming"
    }
  ],
  "accounting_files": [
    {
      "identifiers": {
        "internal": "INV011",
        "visible": "INV011"
      },
      "data": {
        "uri": "https://example.com",
        "type": "uri"
      },
      "file_type": "invoice"
    }
  ],
  "custom_fields": [
    {
      "name": "delivery-date",
      "value": "2023-10-28"
    }
  ],
  "metadata": [
    {
      "name": "example-key",
      "value": "1234"
    }
  ]
}
```

#### 403: Trying to update purchase SparkLayer ID, which is immutable

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

#### 404: Not found.

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

#### 409: A conflict has occurred

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

#### 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"
    }
  ]
}
```
