Skip to content

Send orders to SparkLayer

For AI assistants: the facts every SparkLayer API call needs
  • Base URLs: Live https://app.sparklayer.io, test https://test.app.sparklayer.io. Each environment has its own data and its own API keys.
  • Access: API access needs the Pro or Enterprise plan. Create credentials (Site ID, Client ID, Client Secret) in the SparkLayer Dashboard at Settings > API.
  • Access token: POST {base}/api/auth/token with a Site-Id header and a JSON body (not form-encoded): {"grant_type":"client_credentials","client_id":"…","client_secret":"…"}. It returns access_token, valid for 3,600 seconds. There is no refresh token: cache the token and request a new one shortly before it expires.
  • Every request: Authorization: Bearer <access_token> and Site-Id: <site id>, plus Content-Type: application/json when there is a body. Set a User-Agent that names your integration.
  • Errors: RFC 7807 problem details: title, status, detail and an optional errors[] of { code, message, property }. Some error responses have no body. Retry 5xx, 429 (honouring Retry-After) and concurrent-update 409s with exponential backoff; on 401, get a new token once and retry; don't retry other 4xx without changing the request.
  • Pagination: Most list endpoints return everything. GET /api/v2/price-lists pages with page and page_size (up to 250) until pagination.current_page equals total_pages. GET /api/v1/purchases uses limit (up to 500) and offset: stop when a page has fewer than limit results.
  • Ground rules: Use only endpoints, fields and SDK methods that the docs or OpenAPI specs define. Prefer GET /api/v2/price-lists over the deprecated v1, and the Customers API (/api/v2/customers) over the legacy DELETE /api/v1/customers in the Core API. Products are matched by SKU. Keep credentials in environment variables or a secrets manager, never in code.
  • Read the docs as Markdown: Add .md to any page URL. Index of every page: docs.sparklayer.io/llms.txt. Every API operation, compactly: docs.sparklayer.io/llms-api.txt. The developer guides in full: docs.sparklayer.io/developers/llms.txt.
  • OpenAPI specs: customers, core, ordering, pricing, purchasing, stock, files, sync-log: https://docs.sparklayer.io/openapi/<api>.yaml (also .json). Ignite: https://docs.sparklayer.io/openapi/ignite.yaml.
  • MCP: Search and read these docs from your assistant with the docs MCP server at https://docs.sparklayer.io/mcp.

This guide explains how to build an order for Create or update a purchase (PUT /api/v1/purchases/{lookupBy}/{identifier}), so that it shows correctly in My Account and in Pulse. It covers orders taken outside SparkLayer, such as phone orders keyed into your ERP, and one-off imports of past orders. The rules come from how SparkLayer's own Shopify, BigCommerce and Wix integrations send orders, and how the Purchasing API stores them.

Orders you send here aren't sent to your eCommerce platform, and nothing syncs them afterwards: SparkLayer shows them as you last sent them.

How an order is put together

An order is a purchase of type order. Its line items live in packages: each package is one thing that happened to some of the items, such as a shipment, a cancellation or a return. SparkLayer works out the order's status and total from its packages.

An order and its packages

Order

Identifiers, customer, dates, currency and addresses
(this flows forward)

Packages

One per shipment, cancellation or return, plus a processing package for anything still to ship
(this flows forward)

Line items

The SKUs and quantities in each package, with their amounts
PartWhat it holds
The ordertype, purchase_identifiers, customer_identifiers, dates, currency_code, billing_address, payment_method, po_number, custom_fields, accounting_files
Each packagetype, identifiers, dates, line_items, shipping_method, shipping_address, shipments (carrier and tracking), accounting_files
Each line itemtype, identifiers (such as sku), name_parent, name_child, quantity, line_total, custom_attributes

packages, accounting_files and custom_fields are required on the order, and accounting_files and shipments on each package. Send an empty array ([]) when there's nothing to put in them.

Identify the order

purchase_identifiers holds the order's ID in each system. The lookupBy in the URL says which one identifier is.

IdentifierUse it for
internalYour ID for the order, such as the sales order number in your ERP. Use this as lookupBy for orders from your own systems.
visibleThe order number customers see in My Account. Often the same as internal.
platformThe order's ID on your eCommerce platform, if it has one.
sparklayerSparkLayer's ID (a UUID). Leave it out for orders from your own systems: SparkLayer generates one when it creates the order. Only send it for an order placed through SparkLayer, as the SparkLayer cart ID, so the order replaces the cart.
  • The body must contain the ID in the URL. For PUT /api/v1/purchases/internal/SO-10452, the body needs "purchase_identifiers": { "internal": "SO-10452" }. A missing or different value is rejected with a 400.
  • Lookups are exact and case-sensitive. so-10452 doesn't find SO-10452.
  • Keep IDs to 64 characters, and the po_number too.
  • SparkLayer doesn't stop two orders sharing an ID. If 2 orders have the same internal ID, a lookup by it finds either of them. Give every order its own ID.
  • Never generate a new sparklayer ID each time you send an order. A lookup by a new ID never finds the existing order, so every request creates another copy.

Orders that are already in SparkLayer

Orders placed through SparkLayer, and orders your eCommerce platform syncs to SparkLayer (such as Shopify orders marked for import), are already there. If you send the same order from your ERP as well, it shows twice. Before importing an order you also have on your platform, check with Get a purchase, with lookupBy=platform and the platform's order ID, and skip it if it's found.

Choose the customer

customer_identifiers says who the order belongs to.

IdentifierWho
sparklayerRequired. The SparkLayer ID of the customer account the order belongs to. For company users, this is the main account, not the person who ordered.
sparklayer_childThe company user who placed the order, if it wasn't the main account.
sparklayer_impersonatorThe sales rep who placed the order for the customer, if one did.

My Account lists an order for the account in customer_identifiers.sparklayer, and its company users see it too.

To find a customer's SparkLayer ID, look them up with Get a customer in the Customers API, by their ID on your eCommerce platform or by their email address. Use the id in the response:

Find a customer's SparkLayer ID
GET /api/v2/customers/platform/{platform-customer-id}
GET /api/v2/customers/email/{url-encoded-email}

The Purchasing API doesn't check that the customer exists. An order for an ID SparkLayer doesn't know is stored, but no customer sees it in My Account and it drops out of sales reps' figures in Pulse. Make sure every customer is in SparkLayer before you send their orders, including customers who no longer buy from you. On Shopify, a customer syncs once they have the b2b tag: see Tag existing customers in Shopify. For a past customer who shouldn't be able to sign in, create them with Create or update a customer and status set to inactive: their orders count in Pulse, and you can make them active later.

Packages

Each package has a type, and the dates that go with it. SparkLayer works out a package's status from its dates, not its type, so always set the date that matches the type. A cancelled package with no cancelled_at, for example, counts as still processing, and its items count towards the total.

Package typeDates to setCounts as
processingNoneProcessing: ordered, not yet shipped
shipmentshipped_atShipped
cancelledcancelled_atCancelled. Left out of the total
returnreturn_started_at, and return_completed_at once the return is completeReturned. Taken off the total
incomingNoneOnly for purchases with no placed_at. Orders always have one, so never send incoming for an order

Give dates in RFC 3339 format, with a time zone offset or Z for UTC: 2024-03-18T14:00:00Z.

Rules for packages

  1. Every unit ordered is in exactly one processing, shipment or cancelled package. Add up those packages and you get the quantities ordered.
  2. Returned units stay in their shipment. List them again in a return package. SparkLayer subtracts returns from what was shipped, so a return package with no shipment package is rejected.
  3. Send one package for each real event: each shipment, each cancellation and each return, with its own date.
  4. Put the shipping method on one package only. Use the first shipment, or the processing package if nothing has shipped. Set shipping_method to null on every other package: each package with a shipping method adds its shipping cost to the total. Shipping on a cancelled or returned package is ignored.
  5. Amounts are for the package's quantity, not the whole order line. If 6 of 10 units ship, the shipment's line_total is for 6 units: see Line items and amounts.
  6. Give each package a sparklayer_package_id that never changes. It's a UUID you generate, unique within the order. Send the same ID for the same package every time, for example a version 5 UUID made from your order number and shipment number. SparkLayer treats a package with a new ID as a new package.

identifiers.internal and identifiers.visible on a package are your references for it, such as a delivery note number. shipments holds the carrier and tracking details: carrier, carrier_id (the tracking number) and tracking_url.

A part-shipped order

10 units of HB-200 were ordered. 6 have shipped and 4 are still to ship, so the order has a shipment package for 6 and a processing package for 4. The order's status is part_shipped. Amounts are left out to keep the example short.

packages (excerpt)
[
  {
    "type": "shipment",
    "identifiers": { "sparklayer_package_id": "0b7c1f4e-5a2d-5c8e-9f31-6d2a7e4b8c10", "internal": "SO-10452-1" },
    "dates": { "shipped_at": "2024-03-18T14:00:00Z" },
    "line_items": [{ "identifiers": { "sku": "HB-200" }, "name_parent": "Handlebar grip", "quantity": 6, "line_total": { "…": "…" } }],
    "shipping_method": { "name": "Standard delivery", "line_total": { "…": "…" } },
    "shipments": [{ "carrier": "DPD", "carrier_id": "15501234567890", "tracking_url": null }],
    "accounting_files": []
  },
  {
    "type": "processing",
    "identifiers": { "sparklayer_package_id": "6f1d2c3b-8e4a-5b7c-a1d2-3e4f5a6b7c8d" },
    "line_items": [{ "identifiers": { "sku": "HB-200" }, "name_parent": "Handlebar grip", "quantity": 4, "line_total": { "…": "…" } }],
    "shipping_method": null,
    "shipments": [],
    "accounting_files": []
  }
]

When the other 4 ship, send the whole order again with a second shipment package for 4 and no processing package. The status becomes shipped.

Cancellations

  • Whole order cancelled before anything shipped: one cancelled package with every unit, dated when it was cancelled. The status is cancelled and the total is zero.
  • Some units cancelled: take them out of the processing package and put them in a cancelled package with its cancelled_at. If the rest is still to ship, the status stays processing. If the rest has shipped, it's varied: see Order status.

Returns and refunds

  • Whole order returned: keep the shipment packages, and add a return package with every unit that shipped. When the units returned equal the units shipped, the status is returned.
  • Some units returned: keep the shipment packages, and add a return package with the units that came back. The status is part_returned.
  • A refund with no items returned or cancelled, such as a goodwill credit, isn't a package. Record the money with a transaction.

SparkLayer compares the total quantity shipped with the total quantity returned across the whole order, not SKU by SKU.

Order status

SparkLayer calculates the order's status, calculated_fulfilment_status, from the statuses of its packages every time you send the order. It's read-only, so don't send it. There are no rules about which status can follow which: send the packages as they are now, and the status follows.

The order's packages areStatus
All processingprocessing
All shippedshipped
Shipped and processingpart_shipped
All cancelledcancelled
Processing and cancelledprocessing
Shipped and returned, every shipped unit returnedreturned
Shipped and returned, some shipped units returnedpart_returned
Any other mix, such as shipped and cancelledvaried
No placed_at on the purchaseincoming

Line items and amounts

Each line item needs identifiers, name_parent, quantity and line_total.

  • type: product for a product in your catalogue, or custom for anything else, such as a service or a fee.
  • identifiers.sku: the SKU, up to 128 characters. SparkLayer matches order lines to your products by SKU, for example in Pulse's product figures.
  • identifiers.sparklayer_variant_id: the variant's ID on your eCommerce platform, if you know it.
  • name_parent and name_child: the product and variant names. They're kept as sent, so the order still reads correctly if the product is renamed or deleted later.
  • custom_attributes: extra details for the line, as key and value pairs, such as engraving text.

Every amount is a money object: a number as a string and a 3-letter currency, such as { "number": "72.00", "currency": "EUR" }.

line_total fieldWhat to send
total_netRequired. The line's price before tax, after discounts, for the package's quantity.
discount_netRequired. The discount already taken off total_net, for the customer's information. Use "0.00" for no discount.
total_taxThe tax on the line.
total_grosstotal_net plus total_tax.
total_net_base, discount_net_base, total_tax_base, total_gross_baseThe same amounts in your store's base currency: see Currencies.
  • Every line_total needs a value on an order. Only quotes can have a null line total.
  • total_net, discount_net and tax-line amounts must be in the order's currency_code. A different currency is rejected.
  • Split amounts across packages by quantity. For a line of 10 at 120.00 net, a shipment of 6 has total_net 72.00 and a processing package of 4 has 48.00.
  • Leave out tax_rate. It's deprecated: send the tax amount in total_tax, or as tax_lines.

The shipping method has the same line_total fields, plus a name and an optional sku.

How SparkLayer adds up the total

calculated_total is the order's gross total. SparkLayer calculates it, so don't send it. It adds up:

  • The net and tax of every line in processing and shipment packages.
  • Minus the net and tax of every line in return packages.
  • The net and tax of the shipping method on every package that isn't cancelled or returned.
  • Lines in cancelled packages count for nothing.

If you send tax_lines on the order itself, SparkLayer uses their sum for the tax instead of the line-by-line tax, minus the tax on cancelled and returned lines. Leave them out unless your system gives you order-level tax lines (for example several tax rates) that you want customers to see.

Currencies

Send the order's currency in currency_code. It's required.

Pulse reports in your store's base currency. Set it once, before your first order, with Update the store currency, or send it with every order in currency_code_base.

  • Orders in the base currency: you don't need to send any _base amounts. SparkLayer copies them from the order's amounts.
  • Orders in another currency: send every _base amount yourself, converted at the rate on the order's date: total_net_base, discount_net_base, total_tax_base and total_gross_base on every line item and shipping method, and amount_base on every tax line.

If an order in another currency is missing a _base amount, SparkLayer converts its total at today's exchange rate instead, and Pulse leaves the order out of its revenue figures. calculated_total_usd always uses today's rate.

SparkLayer recalculates totals every time you send an order. If you set the store currency after sending orders, send them again to fill in their base totals.

Dates

FieldWhat to send
dates.placed_atRequired for orders: when the order was placed. Pulse and order statistics use this date, so imported orders appear on their real dates.
dates.payment_due_atWhen payment is due, if you have it.
shipping_requested_dateThe delivery date the customer asked for, if any.
revision_dateWhen the order last changed in your system. SparkLayer rejects an update with an older revision_date than the one it holds (409), so a delayed or repeated request can't overwrite newer data.

dates.created_at and dates.updated_at are set by SparkLayer and can't be sent: they're the dates the order was stored. Sending a read-only field, such as created_at or calculated_fulfilment_status, is rejected with a 400.

Payments and the account balance

The account balance

Each customer has an account balance: what they owe you, shown in the Financials section of My Account when you use credit limits and pay on account.

  • Creating an order adds its total to the customer's balance, dated placed_at. Updating it later adjusts the balance by the change in total.
  • A transaction with apply_to_balance: true takes its amount off the balance, dated transaction_date.

Without an opening balance, the balance is every order and payment added together, however old. When a customer has an opening balance with a balance date, only orders and payments dated on or after that date count.

Before you import past orders for a customer who pays on account, give them an opening balance dated after the newest order you'll import, so old orders don't change what they owe. On any platform, set it with Adjust a customer's account balance and type set to opening_balance:

POST /api/v2/customers/platform/{platform-customer-id}/credit
{
  "type": "opening_balance",
  "amount": 1250.00,
  "date": "2026-11-01T00:00:00Z"
}

Payment status

SparkLayer calculates payment_status (unpaid, part_paid or paid) and total_paid from transactions, for orders placed on or after 6 March 2026. For earlier orders, it doesn't: send payment_status and total_paid yourself if you want them shown, and SparkLayer keeps them as sent. Pulse only counts orders placed on or after 6 March 2026 as amounts owed.

Transactions

Record payments and refunds with Create or update a purchase transaction, after the order exists. Send:

FieldWhat to send
platform_idThe transaction's ID in your payment or accounting system. Sending the same platform_id again for the order updates that transaction.
typeWhat it is, such as payment or refund. SparkLayer stores it as text.
amountThe amount as a string: positive for a payment, negative for a refund.
currency_codeThe 3-letter currency code.
transaction_dateWhen the payment was made.
apply_to_balancetrue to count it towards the payment status and the account balance, false to store it for information only.
full_transactionThe transaction as your system holds it, as a JSON string. Remove card numbers and other sensitive data first.

See Purchase transactions for what apply_to_balance does.

Send an order again

Sending an order with the same lookupBy and identifier updates it rather than creating a copy, so an import can be run as often as you like.

  • Send the whole order every time. The request replaces everything stored: a package you leave out is removed.
  • A few values are kept if you leave them out: the sparklayer ID, payment_status, total_paid and dates.created_at.
  • Keep every ID the same: the identifier you look up by and each sparklayer_package_id.
  • Send revision_date, so an older version can't replace a newer one.

Delete a purchase removes an order from My Account and Pulse. Sending it again with the same identifier brings it back.

Errors

StatusCauseFix
400A required field is missing or invalid. The error names the field.Correct the field and send the order again.
400The ID in the URL isn't in purchase_identifiers, or doesn't match.Put the same ID in the body.
400"Line item total cannot be null for orders".Give every line item a line_total.
400"Invalid package status".Use processing, shipment, cancelled or return packages, and set dates.placed_at.
400A read-only field was sent, such as created_at.Leave out read-only and calculated fields.
400The order's total is over 99,999,999.9999.Check the amounts.
400 or 500A return package with no shipment package.Keep returned units in their shipment package too.
403The order was found, but the sparklayer ID in the body is different.Leave sparklayer out, or send the stored one.
409"A newer revision already exists": revision_date is older than the stored one.Nothing to do: SparkLayer already has a newer version.
409"Duplicate SparkLayer ID": the sparklayer ID belongs to another order.Leave sparklayer out for orders from your own systems.
500An ID or po_number over 64 characters.Shorten it.

See Errors for the error format and when to retry.

A complete order

Order SO-10452 was placed on 14 March 2024, in euros, by a customer of a store whose base currency is pounds (1 EUR = 0.85 GBP on the order date). The customer ordered 10 handlebar grips and 4 seats, with 15.00 shipping, all with 20% VAT:

  • On 18 March, 6 grips and the 4 seats shipped.
  • On 25 March, the other 4 grips shipped.
  • On 2 April, the customer started a return of 1 seat, which was completed on 9 April.

That's 2 shipment packages and a return package. 14 units shipped and 1 came back, so the status is part_returned. The total is 402.00 ordered, less the 60.00 seat returned: 342.00 EUR, or 290.70 GBP.

Request
PUT /api/v1/purchases/internal/SO-10452
Body
{
  "type": "order",
  "purchase_identifiers": {
    "internal": "SO-10452",
    "visible": "SO-10452"
  },
  "customer_identifiers": {
    "sparklayer": "4217ba4f-7618-4e3b-b1af-9055639b18d1"
  },
  "dates": {
    "placed_at": "2024-03-14T09:30:00Z",
    "payment_due_at": "2024-04-13T00:00:00Z"
  },
  "revision_date": "2024-04-09T16:00:00Z",
  "currency_code": "EUR",
  "currency_code_base": "GBP",
  "payment_method": "paymentByInvoice",
  "po_number": "PO-7781",
  "customer_reference": null,
  "billing_address": {
    "company": "Harbour Cycles Ltd",
    "address_line1": "12 Quay Street",
    "city": "Cork",
    "postal_code": "T12 X2Y3",
    "country_code": "IE"
  },
  "custom_fields": [],
  "accounting_files": [],
  "packages": [
    {
      "type": "shipment",
      "identifiers": {
        "sparklayer_package_id": "0b7c1f4e-5a2d-5c8e-9f31-6d2a7e4b8c10",
        "internal": "SO-10452-1",
        "visible": "SO-10452-1"
      },
      "dates": { "shipped_at": "2024-03-18T14:00:00Z" },
      "shipping_address": {
        "company": "Harbour Cycles Ltd",
        "address_line1": "12 Quay Street",
        "city": "Cork",
        "postal_code": "T12 X2Y3",
        "country_code": "IE"
      },
      "shipping_method": {
        "name": "Standard delivery",
        "line_total": {
          "total_net": { "number": "15.00", "currency": "EUR" },
          "discount_net": { "number": "0.00", "currency": "EUR" },
          "total_tax": { "number": "3.00", "currency": "EUR" },
          "total_gross": { "number": "18.00", "currency": "EUR" },
          "total_net_base": { "number": "12.75", "currency": "GBP" },
          "discount_net_base": { "number": "0.00", "currency": "GBP" },
          "total_tax_base": { "number": "2.55", "currency": "GBP" },
          "total_gross_base": { "number": "15.30", "currency": "GBP" }
        }
      },
      "shipments": [
        { "carrier": "DPD", "carrier_id": "15501234567890", "tracking_url": null }
      ],
      "accounting_files": [],
      "line_items": [
        {
          "type": "product",
          "identifiers": { "sku": "HB-200" },
          "name_parent": "Handlebar grip",
          "name_child": "Black",
          "quantity": 6,
          "line_total": {
            "total_net": { "number": "72.00", "currency": "EUR" },
            "discount_net": { "number": "18.00", "currency": "EUR" },
            "total_tax": { "number": "14.40", "currency": "EUR" },
            "total_gross": { "number": "86.40", "currency": "EUR" },
            "total_net_base": { "number": "61.20", "currency": "GBP" },
            "discount_net_base": { "number": "15.30", "currency": "GBP" },
            "total_tax_base": { "number": "12.24", "currency": "GBP" },
            "total_gross_base": { "number": "73.44", "currency": "GBP" }
          }
        },
        {
          "type": "product",
          "identifiers": { "sku": "SD-110" },
          "name_parent": "Comfort seat",
          "name_child": null,
          "quantity": 4,
          "line_total": {
            "total_net": { "number": "200.00", "currency": "EUR" },
            "discount_net": { "number": "0.00", "currency": "EUR" },
            "total_tax": { "number": "40.00", "currency": "EUR" },
            "total_gross": { "number": "240.00", "currency": "EUR" },
            "total_net_base": { "number": "170.00", "currency": "GBP" },
            "discount_net_base": { "number": "0.00", "currency": "GBP" },
            "total_tax_base": { "number": "34.00", "currency": "GBP" },
            "total_gross_base": { "number": "204.00", "currency": "GBP" }
          }
        }
      ]
    },
    {
      "type": "shipment",
      "identifiers": {
        "sparklayer_package_id": "9a4e8c2d-1b3f-5d6e-8a7b-2c4d6e8f0a1b",
        "internal": "SO-10452-2",
        "visible": "SO-10452-2"
      },
      "dates": { "shipped_at": "2024-03-25T11:15:00Z" },
      "shipping_address": {
        "company": "Harbour Cycles Ltd",
        "address_line1": "12 Quay Street",
        "city": "Cork",
        "postal_code": "T12 X2Y3",
        "country_code": "IE"
      },
      "shipping_method": null,
      "shipments": [
        { "carrier": "DPD", "carrier_id": "15501234567999", "tracking_url": null }
      ],
      "accounting_files": [],
      "line_items": [
        {
          "type": "product",
          "identifiers": { "sku": "HB-200" },
          "name_parent": "Handlebar grip",
          "name_child": "Black",
          "quantity": 4,
          "line_total": {
            "total_net": { "number": "48.00", "currency": "EUR" },
            "discount_net": { "number": "12.00", "currency": "EUR" },
            "total_tax": { "number": "9.60", "currency": "EUR" },
            "total_gross": { "number": "57.60", "currency": "EUR" },
            "total_net_base": { "number": "40.80", "currency": "GBP" },
            "discount_net_base": { "number": "10.20", "currency": "GBP" },
            "total_tax_base": { "number": "8.16", "currency": "GBP" },
            "total_gross_base": { "number": "48.96", "currency": "GBP" }
          }
        }
      ]
    },
    {
      "type": "return",
      "identifiers": {
        "sparklayer_package_id": "3c5e7a9b-2d4f-5a6c-9e8d-7f1a3b5c7d9e",
        "internal": "RMA-2231",
        "visible": "RMA-2231"
      },
      "dates": {
        "return_started_at": "2024-04-02T10:00:00Z",
        "return_completed_at": "2024-04-09T16:00:00Z"
      },
      "shipping_address": null,
      "shipping_method": null,
      "shipments": [],
      "accounting_files": [],
      "line_items": [
        {
          "type": "product",
          "identifiers": { "sku": "SD-110" },
          "name_parent": "Comfort seat",
          "name_child": null,
          "quantity": 1,
          "line_total": {
            "total_net": { "number": "50.00", "currency": "EUR" },
            "discount_net": { "number": "0.00", "currency": "EUR" },
            "total_tax": { "number": "10.00", "currency": "EUR" },
            "total_gross": { "number": "60.00", "currency": "EUR" },
            "total_net_base": { "number": "42.50", "currency": "GBP" },
            "discount_net_base": { "number": "0.00", "currency": "GBP" },
            "total_tax_base": { "number": "8.50", "currency": "GBP" },
            "total_gross_base": { "number": "51.00", "currency": "GBP" }
          }
        }
      ]
    }
  ]
}

The response is the stored order, with calculated_fulfilment_status of part_returned, calculated_total of 342.00 EUR and calculated_total_base of 290.70 GBP.

Import order history

To load past orders once, so customers see them in My Account and your team sees them in Pulse:

  1. Start in the test environment. Create an API key in Test mode, and import a few orders there first.
  2. Set the store base currency with Update the store currency, if it isn't set.
  3. Make sure every customer is in SparkLayer, and map each customer in your export to their SparkLayer ID: see Choose the customer.
  4. Set opening balances for customers who pay on account, dated after the newest order you'll import: see The account balance.
  5. Leave out orders that are already in SparkLayer: see Orders that are already in SparkLayer.
  6. Build each order from your order, shipment, return and credit note records, with the rules above. Send them one at a time, looked up by internal ID, and log every failure with its error.
  7. Run it again for the orders that failed, once you've fixed them. Orders that went through are updated, not copied.
  8. Check the results in My Account, signed in as a customer, and in Pulse. Pulse picks up new orders within about 4 hours.

There's a ready-made prompt for this in Build with AI, and a guide for merchants in Import order history.

Next steps

Was this page helpful?

Last updated