# SparkLayer API operations > All 90 operations of the SparkLayer APIs and the Ignite endpoints, one line each: method and path, summary (linking to the operation's full Markdown reference), operation ID, what it does and its inputs. `*` marks a required parameter or body field; `Site-Id` and `Authorization` headers are left out because every call needs them. Developer guides in full: https://docs.sparklayer.io/developers/llms.txt. Every page: https://docs.sparklayer.io/llms.txt. ## Facts for building integrations These apply to every call to the SparkLayer APIs. Use only what the docs and OpenAPI specs define. - **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 ` and `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 `409`s 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. Products are matched by SKU. Keep credentials in environment variables or a secrets manager, never in code. - **Ignite:** With Ignite, SparkLayer calls endpoints that your service implements (the Ignite spec), and your service calls the SparkLayer APIs above for everything else. - **Read the docs as Markdown:** Add `.md` to any page URL. Index of every page: https://docs.sparklayer.io/llms.txt. Every API operation, compactly: https://docs.sparklayer.io/llms-api.txt. The developer guides in full: https://docs.sparklayer.io/developers/llms.txt. - **OpenAPI specs:** `core`, `ordering`, `pricing`, `purchasing`, `stock`, `files`, `sync-log`: https://docs.sparklayer.io/openapi/.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. OpenAPI specs (index: https://docs.sparklayer.io/openapi/index.json; each is also published as `.json`): - Core API: https://docs.sparklayer.io/openapi/core.yaml - Ordering API: https://docs.sparklayer.io/openapi/ordering.yaml - Pricing API: https://docs.sparklayer.io/openapi/pricing.yaml - Purchasing API: https://docs.sparklayer.io/openapi/purchasing.yaml - Stock API: https://docs.sparklayer.io/openapi/stock.yaml - Files API: https://docs.sparklayer.io/openapi/files.yaml - Sync Logging API: https://docs.sparklayer.io/openapi/sync-log.yaml - Ignite endpoints: https://docs.sparklayer.io/openapi/ignite.yaml ## Core API Overview: https://docs.sparklayer.io/developers/api/core.md · OpenAPI spec: https://docs.sparklayer.io/openapi/core.yaml - `POST /api/auth/token` [Get an access token](https://docs.sparklayer.io/developers/api/core/get-an-access-token.md) (`getAccessToken`): Exchanges an API key's Client ID and Client Secret for an access token (the OAuth 2.0 client credentials grant). Send the credentials as JSON with `Content-Type: application/json`: the endpoint doesn't accept a form-encoded body, so standard OAuth 2.0 client libraries won't work. Send the token as `Authorization: Bearer `, with the same `Site-Id` header, on every other request. Body: `grant_type`*, `client_id`*, `client_secret`*. - `DELETE /api/v1/customers/{lookupBy}/{id}` [Delete a customer](https://docs.sparklayer.io/developers/api/core/delete-a-customer.md) (`deleteCustomer`): Permanently deletes a customer and returns `204`. Set `lookupBy` to `sparklayer` (a `cu_`-prefixed ID or the customer's UUID), `platform` (the ID from your eCommerce platform) or `email` (URL-encoded). Returns `404` if no customer matches, or `400` (`resource-id-invalid`) if the ID isn't in the expected format. Path: `lookupBy`*, `id`*. - `POST /api/v1/fetch-customer-pricing` [Get customer-specific pricing](https://docs.sparklayer.io/developers/api/core/get-customer-specific-pricing.md) (`getCustomerPricing`): Returns the net unit price, line total and quantity price breaks a customer would get for each SKU, based on their price lists and any customer discount percentage. If some SKUs can't be priced the response is `207`, and those line items have an `error` message instead of prices. Body: `customer_id`*, `customer_lookup_by`*, `line_items`*. - `GET /api/v1/customer-groups` [List customer groups](https://docs.sparklayer.io/developers/api/core/list-customer-groups.md) (`listCustomerGroups`): Returns every customer group with its `slug`, `name` and `parent_slug` as a single array. The list isn't paginated. - `POST /api/v1/customer-groups` [Create a customer group](https://docs.sparklayer.io/developers/api/core/new-customer-group.md) (`createCustomerGroup`): Creates a customer group and returns the full, updated list of groups. `parent_slug` defaults to `base` and must be an existing group. A `slug` that's already in use returns `400` (`resource-already-exists`), and an unknown parent returns `400` (`resource-id-not-found`). Body: `slug`*, `name`*, `parent_slug`. - `DELETE /api/v1/customer-groups/{slug}` [Delete a customer group](https://docs.sparklayer.io/developers/api/core/delete-customer-group.md) (`deleteCustomerGroup`): Deletes a customer group, along with any settings specific to it, and returns `204`. You can't delete a group that's still assigned to customers: this returns `400` (`resource-in-use`). An unknown slug returns `400` (`resource-id-not-found`). Path: `slug`*. - `PATCH /api/v1/customer-groups/{slug}` [Update a customer group](https://docs.sparklayer.io/developers/api/core/update-customer-group.md) (`updateCustomerGroup`): Sets the group's `name` and `parent_slug` and returns the full, updated list of groups. If you omit `parent_slug`, the parent is reset to `base`. An unknown slug returns `400` (`resource-id-not-found`) rather than `404`. Path: `slug`*. Body: `name`*, `parent_slug`. - `GET /api/v1/discounts` [List discounts](https://docs.sparklayer.io/developers/api/core/list-of-discounts.md) (`listOfDiscounts`): Returns every discount that hasn't been deleted, both active and inactive, as a single array ordered by calculation group and then priority (highest first). The list isn't paginated. - `POST /api/v1/discounts` [Create a discount](https://docs.sparklayer.io/developers/api/core/create-a-discount.md) (`createDiscount`): Creates a discount and returns it with its generated UUID. `currency_code` is required when a reward or other requirement is based on a monetary amount, and coupon codes may only contain letters, numbers, underscores and hyphens. A discount can have at most 10 requirements (with up to 10 items each) and 25 rewards; breaking any of these rules returns `400`. Body: `internal_name`*, `internal_slug`*, `calculation_group`*, `priority`*, `times_applicable_per_order`*, `groups`*, `requirement_selection_type`*, `reward_selection_type`*, `currency_code`*, `start_date`*, `end_date`*, `active`*, +12 more. - `PATCH /api/v1/set-discount-priorities` [Update discount priorities](https://docs.sparklayer.io/developers/api/core/update-discount-priorities.md) (`updateDiscountPriorities`): Sets the `priority` of several discounts in a single transaction and returns the full list of discounts. Every `id` and every `priority` in the request must be unique, otherwise you get a `400`. IDs that don't match a discount are ignored. Body: array of `id`*, `priority`*. - `GET /api/v1/discounts/{id}` [Get a discount](https://docs.sparklayer.io/developers/api/core/get-a-discount.md) (`getDiscount`): Returns a single discount by its UUID. Returns `404` if the discount doesn't exist or has been deleted. Path: `id`*. - `DELETE /api/v1/discounts/{id}` [Delete a discount](https://docs.sparklayer.io/developers/api/core/delete-a-discount.md) (`deleteDiscount`): Deletes a discount so it no longer applies to carts or appears in the API, and returns `204`. Returns `404` if the discount doesn't exist. Path: `id`*. - `PATCH /api/v1/discounts/{id}` [Update a discount](https://docs.sparklayer.io/developers/api/core/update-a-discount.md) (`updateDiscount`): Replaces the discount with the object you send, so include every required field, not just the ones you're changing. `internal_slug` can't be changed and must match the existing value, otherwise you get a `400`. The same currency, coupon code and size rules apply as when creating a discount, and an unknown ID returns `404`. Path: `id`*. Body: `internal_name`*, `internal_slug`*, `calculation_group`*, `priority`*, `times_applicable_per_order`*, `groups`*, `requirement_selection_type`*, `reward_selection_type`*, `currency_code`*, `start_date`*, `end_date`*, `active`*, +12 more. - `GET /api/v1/shipping-methods` [List shipping methods](https://docs.sparklayer.io/developers/api/core/list-of-shipping-methods.md) (`listOfShippingMethods`): Returns every shipping method configured for the store, including its bands, as a single array. Methods aren't filtered by country, customer group or cart contents, and the list isn't paginated. - `POST /api/v1/shipping-methods` [Create a shipping method](https://docs.sparklayer.io/developers/api/core/create-a-shipping-method.md) (`createShippingMethod`): Creates a shipping method, including its bands, and returns it with its `sm_`-prefixed ID. The `sku` must be unique across shipping methods; a duplicate returns `400` (`duplicate-sku`). Body: `sku`*, `title`*, `countries`*, `id`, `created_at`, `updated_at`, `priority`, `regions`, `groups`, `bands`. - `GET /api/v1/shipping-methods/{id}` [Get a shipping method](https://docs.sparklayer.io/developers/api/core/get-a-shipping-method.md) (`getShippingMethod`): Returns a single shipping method by its `sm_`-prefixed ID. Returns `404` if the shipping method doesn't exist. Path: `id`*. - `DELETE /api/v1/shipping-methods/{id}` [Delete a shipping method](https://docs.sparklayer.io/developers/api/core/delete-a-shipping-method.md) (`deleteShippingMethod`): Permanently deletes a shipping method along with its bands, costs and platform mappings, and returns `204`. Returns `404` if the shipping method doesn't exist. Path: `id`*. - `PATCH /api/v1/shipping-methods/{id}` [Update a shipping method](https://docs.sparklayer.io/developers/api/core/update-a-shipping-method.md) (`updateShippingMethod`): Updates a shipping method and returns it. Fields you omit keep their current values, but if you send `bands` the list replaces all existing bands. Returns `404` if the shipping method doesn't exist. Path: `id`*. Body: `id`, `created_at`, `updated_at`, `sku`, `title`, `priority`, `countries`, `regions`, `groups`, `bands`. - `GET /api/v1/settings` [List global settings](https://docs.sparklayer.io/developers/api/core/list-global-settings.md) (`listGlobalSettings`): Lists Global settings (minus settings which include authentication details) - `PATCH /api/v1/settings` [Update global settings](https://docs.sparklayer.io/developers/api/core/update-global-setting.md) (`patchGlobalSetting`): Updates one or more store-wide settings, sent as an array of `key`/`value` pairs, and returns `204`. Only a fixed set of setting keys can be updated. API keys created in the SparkLayer Dashboard can't update global settings: the request is rejected with the message "Global settings unavailable for updates, please contact support". Contact support if you need to change them. Body: array of `key`*, `value`*. - `GET /api/v1/settings/{slug}` [List customer group settings](https://docs.sparklayer.io/developers/api/core/list-customer-group-settings.md) (`listSettings`): Lists Customer Group settings by Customer Group Path: `slug`*. - `PATCH /api/v1/settings/{slug}` [Update customer group settings](https://docs.sparklayer.io/developers/api/core/update-customer-group-setting.md) (`patchCustomerGroupSetting`): Updates one or more settings for the customer group identified by `slug`, sent as an array of `key`/`value` pairs, and returns `204`. Only customer group settings can be set here, for example `allowCheckout`, `allowedPaymentMethods`, `paymentRules`, `priceListSelection` and `orderTotalsValidation`. Path: `slug`*. ## Ordering API Overview: https://docs.sparklayer.io/developers/api/ordering.md · OpenAPI spec: https://docs.sparklayer.io/openapi/ordering.yaml - `POST /api/v1/carts` [Create a cart](https://docs.sparklayer.io/developers/api/ordering/create-cart.md) (`createCart`): Creates an empty cart for a customer and returns its `cart_id` with a `201`. Identify the customer with `customer_id` and `customer_lookup_by`: `sparklayer` (the customer's UUID), `platform` (the ID from your eCommerce platform) or `email`. An unknown customer returns `400` (`resource-id-not-found`), and the `Accept-Language` header sets the cart's locale (default `en-US`). Body: `customer_id`, `customer_lookup_by`. - `GET /api/v1/carts/{id}` [Get a cart](https://docs.sparklayer.io/developers/api/ordering/get-cart.md) (`getCart`): Returns the cart's line items, addresses, totals and any `validation_errors` (such as minimum order or stock rules) that you need to resolve or ignore before completing it. Returns `404` if the cart doesn't exist, for example because it has already been completed. Path: `id`*. - `DELETE /api/v1/carts/{id}` [Delete a cart](https://docs.sparklayer.io/developers/api/ordering/delete-cart.md) (`deleteCart`): Deletes a cart and returns `204`. The request succeeds even if the cart doesn't exist, so it's safe to retry. Path: `id`*. - `PATCH /api/v1/carts/{id}` [Update a cart](https://docs.sparklayer.io/developers/api/ordering/update-cart.md) (`updateCart`): Updates the cart and returns it along with a result for each line item. Line items are always replaced: quantities are absolute, and omitting `line_items` or sending an empty array empties the cart. Path: `id`*. Body: `line_items`, `shipping_address_id`, `temporary_shipping_address`, `customer_reference`, `po_number`, `shipping_requested_date`, `custom_fields`. - `POST /api/v1/carts/{id}/complete` [Complete a cart](https://docs.sparklayer.io/developers/api/ordering/complete-cart.md) (`completeCart`): Places the order: checks the shipping rate and payment method, creates a purchase, deletes the cart and returns the new `purchase_id` with a `201`. If the cart has validation errors you haven't listed in `ignore_validation_errors` (use `"*"` to ignore all of them), you get a `422` (`cart-validation-errors`) and no order is created. Path: `id`*. Body: `shipping_rate_handle`*, `payment_method`*, `ignore_validation_errors`*. - `POST /api/v1/carts/{id}/calculate` [Calculate a cart](https://docs.sparklayer.io/developers/api/ordering/calculate-cart.md) (`calculateCart`): Calculates the cart's totals, tax, available shipping methods and allowed payment methods, optionally for the shipping rate given in `shipping_rate_handle`. Returns `422` with the error code `cart-empty` if the cart has no items, or `cart-shipping-rate-handle-unavailable` if the SparkLayer shipping rate you chose isn't available for this cart. Path: `id`*. Body: `shipping_rate_handle`. ## Pricing API Overview: https://docs.sparklayer.io/developers/api/pricing.md · OpenAPI spec: https://docs.sparklayer.io/openapi/pricing.yaml - `GET /api/v1/price-lists` [List price lists](https://docs.sparklayer.io/developers/api/pricing/get-price-lists.md) (`getPriceListsLegacy`): Returns every price list for the site as a single, unpaginated array (up to 25,000 price lists from all sources, ordered by name). This is the legacy version of this endpoint. For new integrations, use `GET /api/v2/price-lists`, which supports pagination, ordering and filtering by source. - `POST /api/v1/price-lists` [Create a price list](https://docs.sparklayer.io/developers/api/pricing/create-a-price-list.md) (`createPriceList`): `slug`, `name` and `currency_code` are required, and `currency_code` must be a valid ISO 4217 code. `source` defaults to `custom`. Returns `400` if a price list with the same slug already exists, or if a rule references a source price list that does not exist. Body: `slug`*, `name`*, `currency_code`*, `source`, `tax_inclusive_display`, `rules`. - `GET /api/v1/price-lists/{slug}` [Get a price list](https://docs.sparklayer.io/developers/api/pricing/get-price-list.md) (`getPriceList`): Returns a single price list, including its rules. Returns `404` if no price list exists with that slug. Path: `slug`*. - `DELETE /api/v1/price-lists/{slug}` [Delete a price list](https://docs.sparklayer.io/developers/api/pricing/delete-a-price-list.md) (`deletePriceList`): Deletes the price list together with its rules and all of its prices. Returns `400` if another price list has a rule that uses this list as its source, and `404` if the price list does not exist. Path: `slug`*. - `PATCH /api/v1/price-lists/{slug}` [Update a price list](https://docs.sparklayer.io/developers/api/pricing/update-a-price-list.md) (`updatePriceList`): Updates only the fields you send (`name`, `currency_code`, `rules` and `tax_inclusive_display`); the slug and source cannot be changed. Sending `rules` replaces all of the existing rules. Changing `currency_code` relabels the prices already on the list with the new currency without converting the amounts. Returns the updated price list, or `404` if it does not exist. Path: `slug`*. Body: `rules`, `name`, `currency_code`, `tax_inclusive_display`. - `GET /api/v2/price-lists` [List price lists (v2)](https://docs.sparklayer.io/developers/api/pricing/get-price-lists-v2.md) (`getPriceLists`): Returns price lists one page at a time. Use `page` (default `1`) and `page_size` (default `100`, maximum `250`) to page through the results, `order_by` to sort them (for example `name:asc` or `updated_at:desc`), and `source` to filter by a comma-separated list of sources. Results are returned in `data`, with a `pagination` object giving `total`, `per_page`, `current_page` and `total_pages`. Query: `page`, `page_size`, `order_by`, `source`. - `GET /api/v1/price-lists/{slug}/pricing` [List prices in a price list](https://docs.sparklayer.io/developers/api/pricing/get-pricing-by-price-list.md) (`getPriceListPricingData`): Returns every price stored on the price list, one entry per SKU and quantity break, ordered by SKU. Prices derived from the list's rules are not included. Send the request with a `Content-Type: text/csv` header to receive the same data as a CSV file. Returns `204` with no body if the price list has no prices, and `404` if the price list does not exist. Path: `slug`*. - `PATCH /api/v1/price-lists/{slug}/pricing` [Update prices in a price list](https://docs.sparklayer.io/developers/api/pricing/update-pricing-by-price-list.md) (`updatePriceListPricing`): Accepts a JSON array or a CSV file (`Content-Type: text/csv`). Only the SKUs you send are affected: each SKU's existing prices on this list are replaced with the ones supplied. Validation errors return `400`, usually as an array of `{line, field, message}` objects. Path: `slug`*. Body: array of `sku`*, `pricing`*, `display_tax_rate`. - `GET /api/v1/pricing/{sku}` [Get prices for a SKU](https://docs.sparklayer.io/developers/api/pricing/get-pricing-by-sku.md) (`getVariantPricing`): Returns the prices stored for the SKU on every price list, grouped by price list. URL-encode the SKU if it contains reserved characters such as `/`. Returns an empty array if the SKU has no prices. Path: `sku`*. - `PATCH /api/v1/pricing/{sku}` [Update prices for a SKU](https://docs.sparklayer.io/developers/api/pricing/update-pricing-by-sku.md) (`updateVariantPricing`): This patch endpoint will remove all pricing for the __price list slugs__ provided and apply provided pricing against the provided price lists. It is also important to note you can upload multiple price lists in one call. Path: `sku`*. Body: array of `price_list_slug`*, `pricing`*, `display_tax_rate`. - `PATCH /api/v1/batch-update-pricing` [Update prices across price lists](https://docs.sparklayer.io/developers/api/pricing/update-pricing-for-multiple-price-lists.md) (`updateMultiplePriceListPricing`): Accepts a JSON array or a CSV file (`Content-Type: text/csv`); each entry names a SKU, a `price_list_slug` and the prices for that combination. Only the SKU and price list combinations you send are affected, and their existing prices are replaced. Body: array of `sku`*, `price_list_slug`*, `pricing`*, `display_tax_rate`. - `POST /api/v1/calculate-pricing` [Calculate prices for SKUs](https://docs.sparklayer.io/developers/api/pricing/calculate-pricing.md) (`calculateVariantPricing`): Works out the price of each SKU in `skus` from the price lists in `price_list_slugs`, checked in the order given. The first list that has prices for the SKU wins, whether those prices are stored on the list or derived from one of its rules (with currency conversion and the percentage adjustment applied). Prices are always net and are returned as `{number, currency}` objects. Body: `skus`, `price_list_slugs`. - `GET /api/v2/price-lists-num-manual-prices` [List price lists with manual price counts](https://docs.sparklayer.io/developers/api/pricing/get-price-lists-with-manual-price-counts.md) (`getPriceListsNumManualPrices`): Works like `GET /api/v2/price-lists`, with the same pagination, ordering and `source` filter, but each price list also includes `num_manual_prices`: the number of SKUs with prices stored directly on that list. Query: `page`, `page_size`, `order_by`, `source`. ## Purchasing API Overview: https://docs.sparklayer.io/developers/api/purchasing.md · OpenAPI spec: https://docs.sparklayer.io/openapi/purchasing.yaml - `GET /api/v1/purchases/{lookupBy}/{identifier}` [Get a purchase](https://docs.sparklayer.io/developers/api/purchasing/get-purchase.md) (`getPurchase`): Returns a purchase: a cart, quote, purchase awaiting approval or confirmation, or placed order. Set `lookupBy` to the `purchase_identifiers` field to match on (`sparklayer`, `platform`, `internal` or `visible`) and pass its value in `identifier`; with `sparklayer`, `identifier` must be a UUID. Returns `404` if no purchase matches. Path: `lookupBy`*, `identifier`*. - `PUT /api/v1/purchases/{lookupBy}/{identifier}` [Create or update a purchase](https://docs.sparklayer.io/developers/api/purchasing/create-update-purchase.md) (`createUpdatePurchase`): 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. Path: `lookupBy`*, `identifier`*. Body: `type`*, `purchase_identifiers`*, `customer_identifiers`*, `dates`*, `packages`*, `accounting_files`*, `custom_fields`*, `company`, `payment_method`, `customer_reference`, `po_number`, `shipping_requested_date`, +15 more. - `DELETE /api/v1/purchases/{lookupBy}/{identifier}` [Delete a purchase](https://docs.sparklayer.io/developers/api/purchasing/delete-purchase.md) (`deletePurchase`): Deletes the purchase that matches `lookupBy` and `identifier`, and returns `204`. Returns `404` if no purchase matches. Path: `lookupBy`*, `identifier`*. - `GET /api/v1/purchases` [List purchases](https://docs.sparklayer.io/developers/api/purchasing/get-purchases.md) (`getPurchases`): 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. Query: `limit`, `offset`, `order_by`, `customer_identifiers[sparklayer]`, `customer_identifiers[sparklayer_impersonator]`, `customer_identifiers[sparklayer_sales_rep]`, `customer_identifiers[sparklayer_impersonator_assignee]`, `company[id]`, `company[section_id]`, `status`, `type`, `quote_status`, `search`, `dates[last_updated][lte]`, `dates[last_updated][gte]`, `dates[placed][lte]`, `dates[placed][gte]`, `dates[submitted][lte]`, `dates[submitted][gte]`, `dates[shipping_requested][lte]`, `dates[shipping_requested][gte]`. - `GET /api/v1/purchases/{lookupBy}/{identifier}/history` [List purchase history](https://docs.sparklayer.io/developers/api/purchasing/get-purchase-history.md) (`getPurchaseHistory`): Returns the history of the purchase that matches `lookupBy` and `identifier`: its message, note, email and update events. Returns `404` if no purchase matches. Path: `lookupBy`*, `identifier`*. - `POST /api/v1/purchases/{lookupBy}/{identifier}/history` [Create a purchase history entry](https://docs.sparklayer.io/developers/api/purchasing/create-a-purchase-history-entry.md) (`createPurchaseHistory`): Adds an event to the history of the purchase that matches `lookupBy` and `identifier`. Set `event_type` to `message` or `note` (with `created_by` and `body`), or to `email` (with `sent_by` and `body`). Returns `404` if no purchase matches. Path: `lookupBy`*, `identifier`*. - `GET /api/v1/purchases/{lookupBy}/{identifier}/transactions` [List purchase transactions](https://docs.sparklayer.io/developers/api/purchasing/get-purchase-transactions.md) (`getTransactions`): Returns the transactions, such as payments and refunds, recorded against the purchase that matches `lookupBy` and `identifier`, including those stored for information only. Returns `404` if no purchase matches. Path: `lookupBy`*, `identifier`*. - `PUT /api/v1/purchases/{lookupBy}/{identifier}/transactions` [Create or update a purchase transaction](https://docs.sparklayer.io/developers/api/purchasing/create-or-update-a-purchase-transaction.md) (`createTransaction`): Records a transaction, such as a payment or refund, against the purchase that matches `lookupBy` and `identifier`. A transaction is identified by its purchase and `platform_id` (the transaction's ID in the third-party system), so sending a `platform_id` again updates that transaction. `total` is positive for a payment and negative for a refund. Path: `lookupBy`*, `identifier`*. Body: `platform_id`*, `full_transaction`*, `type`*, `apply_to_balance`*, `currency_code`*, `total`*, `transaction_date`*, `id`, `purchase_spark_id`, `created_at`. - `GET /api/v1/store-currency` [Get the store currency](https://docs.sparklayer.io/developers/api/purchasing/get-store-currency.md) (`getStoreCurrency`): Returns the store's base currency as an ISO 4217 `currency_code`, such as `GBP`. Returns `404` if no base currency has been set. - `PUT /api/v1/store-currency` [Update the store currency](https://docs.sparklayer.io/developers/api/purchasing/update-store-currency.md) (`putStoreCurrency`): Sets the store's base currency to the ISO 4217 `currency_code` you send, such as `GBP`, and returns it. Returns `409` if the base currency is already set to a different value. Body: `currency_code`*. - `GET /api/v1/purchases/stats/order/sku` [Get a customer's SKU order stats](https://docs.sparklayer.io/developers/api/purchasing/get-order-stats-for-a-customer.md) (`getSKUSalesStats`): Returns how many units of each SKU a customer ordered between `start_date` and `end_date`, grouped by `week`, `month` or `quarter`. Give both dates as RFC 3339 date-times with a time zone offset, or `Z` for UTC. Each period is identified by its start date, returned in UTC. Query: `spark_customer_id`*, `start_date`*, `end_date`*, `date_period_type`*. ## Stock API Overview: https://docs.sparklayer.io/developers/api/stock.md · OpenAPI spec: https://docs.sparklayer.io/openapi/stock.yaml - `POST /api/v1/batch-fetch-stock` [Get stock levels for multiple SKUs](https://docs.sparklayer.io/developers/api/stock/get-stock-levels.md) (`getBatchStock`): Returns stock levels for the SKUs in `skus`, grouped by SKU. By default only the stock location with the external ID `default` is included: set `filter.all_stock_locations` to `true` to include every location, or pass `filter.stock_location_ids` to choose specific ones. SKUs with no matching stock levels are left out of the response. Body: `skus`, `filter`. - `POST /api/v1/batch-update-stock` [Update stock levels for multiple SKUs](https://docs.sparklayer.io/developers/api/stock/update-stock-levels.md) (`updateBatchStock`): Creates or updates the stock level for each SKU and stock location pair in the array. Identify the location with either `stock_location_id` or `stock_location_external_id`, not both. The stored values for each pair you send are overwritten; pairs you leave out are unchanged. - `POST /api/v1/batch-delete-stock` [Delete stock levels for multiple SKUs](https://docs.sparklayer.io/developers/api/stock/delete-stock-levels.md) (`deleteBatchStock`): Deletes the stock levels at every stock location for the SKUs in `skus`. SKUs that have no stock levels are ignored. Body: `skus`. - `GET /api/v1/stock-locations` [List stock locations](https://docs.sparklayer.io/developers/api/stock/list-stock-locations.md) (`getStockLocations`): Returns all stock locations for the site. The list is not paginated. - `POST /api/v1/stock-locations` [Create a stock location](https://docs.sparklayer.io/developers/api/stock/create-a-stock-location.md) (`createStockLocation`): `name` and `external_id` are required, and `external_id` must be unique for the site: a duplicate returns `409`. Returns the new location, including its SparkLayer `id`. Body: `name`*, `external_id`*, `id`, `created_at`, `updated_at`. - `GET /api/v1/stock-locations/{StockLocationID}` [Get a stock location](https://docs.sparklayer.io/developers/api/stock/get-a-stock-location.md) (`getStockLocation`): Looks up a stock location by its SparkLayer ID or its `external_id`. Returns `404` if no location matches. Path: `StockLocationID`*. - `DELETE /api/v1/stock-locations/{StockLocationID}` [Delete a stock location](https://docs.sparklayer.io/developers/api/stock/delete-a-stock-location.md) (`deleteStockLocation`): Deletes the stock location, identified by its SparkLayer ID or `external_id`, together with all stock levels held at it. Returns `204` even if no location matched. Path: `StockLocationID`*. - `PATCH /api/v1/stock-locations/{StockLocationID}` [Update a stock location](https://docs.sparklayer.io/developers/api/stock/update-a-stock-location.md) (`updateStockLocation`): Replaces the location's `name` and `external_id`, which are both required. Identify the location by its SparkLayer ID or its current `external_id`. Returns `404` if no location matches, and `409` if the new `external_id` is already used by another location. Path: `StockLocationID`*. Body: `name`*, `external_id`*, `id`, `created_at`, `updated_at`. ## Files API Overview: https://docs.sparklayer.io/developers/api/files.md · OpenAPI spec: https://docs.sparklayer.io/openapi/files.yaml - `GET /api/v1/files` [Get multiple files](https://docs.sparklayer.io/developers/api/files/get-bulk-files.md) (`getBulkFiles`): Returns the files whose IDs you pass in `ids`; repeat the parameter for each ID (`?ids=…&ids=…`). IDs that do not exist, or whose files have been deleted or have expired, are left out of the response. If any requested file failed its post-upload checks, the whole request returns `410`. Query: `ids`*. - `POST /api/v1/files` [Create a file](https://docs.sparklayer.io/developers/api/files/create-a-new-file.md) (`createFile`): Registers a file and returns a signed upload URL. Upload the contents with an HTTP `PUT` to `url`, sending the `required_headers`, within 15 minutes; files can be up to 20 MB. The file type comes from the extension in `file_path` and must be on the allowed list (including PDF, CSV, common image formats and Office documents). Body: `file_path`*, `expires_at`, `metadata`. - `DELETE /api/v1/files` [Delete all files](https://docs.sparklayer.io/developers/api/files/delete-all-files.md) (`deleteAllClientFiles`): Permanently deletes every file for the site in the current environment (live or test), including the stored contents. - `POST /api/v1/search-files` [Search files by metadata](https://docs.sparklayer.io/developers/api/files/query-files-by-metadata.md) (`fileSearch`): Returns every file whose `metadata` contains the JSON object you send (PostgreSQL JSON containment). Files that failed their post-upload checks are included and flagged with `rejected: true`. Deleted and expired files are excluded, and results are not paginated. Body: `metadata`*. - `GET /api/v1/files/{id}` [Get a file](https://docs.sparklayer.io/developers/api/files/get-a-file.md) (`getFile`): Returns the file. Once it is `ready`, the response includes a signed download URL that is valid for 15 minutes. Returns `404` if the file does not exist, has been deleted or has expired, and `410` if it failed its post-upload checks (for example, its contents did not match its extension). Pass `allowRejected=true` to receive the file details with the `410`. Path: `id`*. Query: `allowRejected`. - `DELETE /api/v1/files/{id}` [Delete a file](https://docs.sparklayer.io/developers/api/files/delete-a-file.md) (`deleteFile`): Deletes the file and its stored contents. Returns `404` if the file does not exist or has already been deleted. Path: `id`*. - `PATCH /api/v1/files/{id}` [Update a file](https://docs.sparklayer.io/developers/api/files/update-a-file.md) (`updateFile`): Returns a new signed upload URL for an existing file so you can replace its contents: upload with an HTTP `PUT` to `url`, sending the `required_headers`, within 15 minutes. No request body is needed and the file path cannot be changed. Returns `404` if the file does not exist. Path: `id`*. - `POST /api/v1/batch-delete-files` [Delete multiple files](https://docs.sparklayer.io/developers/api/files/delete-multiple-files.md) (`deleteBulkFiles`): Deletes the files whose IDs you send as a JSON array. IDs that do not exist are ignored. If some files could not be removed from storage, the response is a `500` whose `errors` give the affected file IDs in `property`, so you can retry just those. ## Sync Logging API Overview: https://docs.sparklayer.io/developers/api/sync-log.md · OpenAPI spec: https://docs.sparklayer.io/openapi/sync-log.yaml - `DELETE /api/v1/sync-log` [Delete all sync logs](https://docs.sparklayer.io/developers/api/sync-log/delete-a-stores-sync-logs.md) (`deleteAllLoggingStatus`): Deletes the sync status and logged errors for every integration and data type on the site, in the current environment (live or test). - `GET /api/v1/sync-log/{integration}/{data_type}` [Get a sync status](https://docs.sparklayer.io/developers/api/sync-log/get-sync-logging-status.md) (`getLoggingStatus`): Returns the sync timestamps and the number of logged errors for the integration and data type. Returns `404` if no full sync has been recorded for them yet. Path: `integration`*, `data_type`*. - `PUT /api/v1/sync-log/{integration}/{data_type}` [Record a full sync](https://docs.sparklayer.io/developers/api/sync-log/update-sync-logs-with-a-full-sync.md) (`updateFullLoggingStatus`): Sets `started_full_sync` and `last_full_sync` (a timestamp you omit is cleared) and replaces all previously logged errors for the integration and data type with the `errors` you send, up to 5,000. Each error's `external_id` must be unique within the request, otherwise you get a `400`. Path: `integration`*, `data_type`*. Body: `started_full_sync`*, `last_full_sync`, `last_full_sync_succeeded`, `errors`. - `PATCH /api/v1/sync-log/{integration}/{data_type}` [Record a partial sync](https://docs.sparklayer.io/developers/api/sync-log/update-sync-logs-with-a-partial-sync.md) (`updatePartialLoggingStatus`): Updates `last_partial_sync`, removes logged errors whose `external_id` is listed in `successfully_synced`, and adds or updates the `errors` you send, matched by `external_id`. Timestamps are only saved once a full sync has been recorded for the integration and data type. Each error's `external_id` must be unique within the request, otherwise you get a `400`. Path: `integration`*, `data_type`*. Body: `last_partial_sync`*, `last_full_sync`, `last_full_sync_succeeded`, `errors`, `successfully_synced`. - `GET /api/v1/sync-log/{integration}/{data_type}/errors` [List sync errors](https://docs.sparklayer.io/developers/api/sync-log/get-sync-logging-status-errors.md) (`getLoggingStatusErrors`): Returns the sync status for the integration and data type together with its logged errors (at most 5,000). Returns `404` if no full sync has been recorded for them yet. Path: `integration`*, `data_type`*. ## Ignite endpoints (your service implements these; SparkLayer calls them) Overview: https://docs.sparklayer.io/ignite/api.md · OpenAPI spec: https://docs.sparklayer.io/openapi/ignite.yaml - `POST /v1/{siteEnv}/{siteId}` [Connect a platform](https://docs.sparklayer.io/ignite/api/new-platform-connection.md) (`createPlatformConnection`): The SparkLayer Ignite platform will call this endpoint when the merchant connects SparkLayer on the specific platform. Please note that this endpoint must be idempotent as it may be called multiple times. Path: `siteEnv`*, `siteId`*. Body: `store_id`*, `spark_api_client_id`*, `spark_api_client_secret`*, `extra_config`, `magento_consumer_key`, `magento_consumer_secret`, `magento_access_token`, `magento_access_token_secret`. - `DELETE /v1/{siteEnv}/{siteId}` [Disconnect a platform](https://docs.sparklayer.io/ignite/api/remove-platform-connection.md) (`removePlatformConnection`): SparkLayer Ignite platform will call this endpoint when the merchant disconnects SparkLayer on the specific platform. Path: `siteEnv`*, `siteId`*. - `PUT /v1/{siteEnv}/{siteId}/customers` [Create or update a customer](https://docs.sparklayer.io/ignite/api/create-update-a-customer.md) (`createUpdateCustomer`): Create or update a "customer" on the eCommerce platform. The email address of the customer should be used as the unique identifier for finding the customer on the target platform. Path: `siteEnv`*, `siteId`*. Body: `email`*, `first_name`*, `last_name`*, `company_name`, `accounting_id`, `sales_agent_groups`, `price_lists`, `customer_discount_percentage`, `group`, `role`, `addresses`, `send_invite`, +4 more. - `POST /v1/{siteEnv}/{siteId}/sub-accounts` [Create a sub-account](https://docs.sparklayer.io/ignite/api/create-a-new-customer-sub-account.md) (`createSubAccount`): Create a new "customer" on the eCommerce platform and designates it as a sub-account with `parent_customer_id` as an attribute. The implementation should explicitly handle the possibility that a customer with the supplied email address already exists and return a 400 response as documented. Path: `siteEnv`*, `siteId`*. Body: `email`*, `first_name`*, `last_name`*, `parent_customer_external_id`*, `role`. - `DELETE /v1/{siteEnv}/{siteId}/sub-accounts/{customer_external_id}` [Delete a sub-account](https://docs.sparklayer.io/ignite/api/remove-a-customer-sub-account.md) (`deleteSubAccount`): Remove a customer sub-account from the specific platform, ensuring the account can no longer interact with the parent account. Platforms may prevent the deletion of customers which have orders, for this reason it is recommended that the `parent_customer_external_id` attribute is removed from the customer object rather than actual deletion. Path: `siteEnv`*, `siteId`*, `customer_external_id`*. - `PATCH /v1/{siteEnv}/{siteId}/sub-accounts/{customer_external_id}` [Update a sub-account](https://docs.sparklayer.io/ignite/api/update-an-existing-customer-sub-account.md) (`updateSubAccount`): Update the details of an existing customer sub-account. This allows changing the account's first name, last name and role. This does not allow for the email to be updated. Path: `siteEnv`*, `siteId`*, `customer_external_id`*. Body: `first_name`, `last_name`, `role`. - `POST /v1/{siteEnv}/{siteId}/customers/{customer_external_id}/addresses` [Create a customer address](https://docs.sparklayer.io/ignite/api/create-a-new-customer-address.md) (`createCustomerAddress`): Create a new "address" for a customer on the specific platform. Path: `siteEnv`*, `siteId`*, `customer_external_id`*. Body: `title`, `first_name`, `last_name`, `company`, `address_line1`, `address_line2`, `city`, `region_name`, `region_code`, `postal_code`, `country_code`, `phone`, +3 more. - `PUT /v1/{siteEnv}/{siteId}/customers/{customer_external_id}/addresses/{customer_address_external_id}` [Update a customer address](https://docs.sparklayer.io/ignite/api/update-a-customer-address.md) (`updateCustomerAddress`): Update a customer address on the specific platform. Path: `siteEnv`*, `siteId`*, `customer_external_id`*, `customer_address_external_id`*. Body: `title`, `first_name`, `last_name`, `company`, `address_line1`, `address_line2`, `city`, `region_name`, `region_code`, `postal_code`, `country_code`, `phone`, +3 more. - `DELETE /v1/{siteEnv}/{siteId}/customers/{customer_external_id}/addresses/{customer_address_external_id}` [Delete a customer address](https://docs.sparklayer.io/ignite/api/remove-a-customer-address.md) (`deleteCustomerAddress`): Remove a customer address from the specific platform. Path: `siteEnv`*, `siteId`*, `customer_external_id`*, `customer_address_external_id`*. - `POST /v1/{siteEnv}/{siteId}/checkout/calculate` [Calculate tax and shipping](https://docs.sparklayer.io/ignite/api/calculate-tax-and-shipping.md) (`calculateOrder`): This endpoint is called at the final step of the checkout process in order to show tax and shipping methods available to the customer. Path: `siteEnv`*, `siteId`*. Body: `cart_id`, `customer`, `currency_code`, `billing_address`, `shipping_address`, `shipping_line`, `internal_shipping_methods`, `shop`, `line_items`, `ignite_state`, `ignite_checkout_context`, `shipping_method_source`. - `POST /v1/{siteEnv}/{siteId}/checkout/complete` [Complete checkout](https://docs.sparklayer.io/ignite/api/complete-checkout.md) (`completeOrder`): This endpoint is called at the final step once the customer attempts to complete the order. If the payment type is `upfrontPayment` the customer should be directed to the checkout flow to complete payment. Alternatively, an order can be created there and then for other systems to manage payments. Path: `siteEnv`*, `siteId`*. Body: `cart_id`, `customer`, `currency_code`, `billing_address`, `shipping_address`, `shipping_line`, `internal_shipping_methods`, `shop`, `line_items`, `ignite_state`, `ignite_checkout_context`, `shipping_method_source`, +9 more. - `GET /v1/{siteEnv}/{siteId}/sync/{syncDataType}` [List entities for a sync](https://docs.sparklayer.io/ignite/api/list-entities.md) (`getPage`): SparkLayer calls this endpoint during a full sync to page through every entity of the given type. Return one page of entities and a `next_page` value; SparkLayer requests the next page with it in the `page` query parameter. Return an empty string or `null` for `next_page` to end the sync. Path: `siteEnv`*, `siteId`*, `syncDataType`*. Query: `page`. - `POST /v1/{siteEnv}/{siteId}/sync/{syncDataType}/{entityId}` [Fetch an entity](https://docs.sparklayer.io/ignite/api/fetch-entity.md) (`getEntity`): Fetch an entity from the platform. Path: `siteEnv`*, `siteId`*, `syncDataType`*, `entityId`*. Body: `payload`. - `POST /v1/{siteEnv}/{siteId}/status/{syncDataType}` [Trigger a data sync](https://docs.sparklayer.io/ignite/api/trigger-a-data-sync.md) (`triggerDataSync`): Allow internal users (e.g. support staff) to trigger a manual sync external to the standard process. Path: `siteEnv`*, `siteId`*, `syncDataType`*. - `GET /v1/{siteEnv}/{siteId}/metafield-configuration` [Get metafield configuration](https://docs.sparklayer.io/ignite/api/get-metafield-configuration.md) (`getMetafieldConfiguration`): Returns a list of all SparkLayer metafield schema keys supported by the platform and the current configuration state for each key Path: `siteEnv`*, `siteId`*. - `POST /v1/{siteEnv}/{siteId}/metafield-configuration/enable` [Enable a metafield](https://docs.sparklayer.io/ignite/api/enable-a-metafield.md) (`enableMetafield`): Enables the specified key within the platform Path: `siteEnv`*, `siteId`*. Body: `key`*, `name`*. - `POST /v1/{siteEnv}/{siteId}/authentication/verify` [Verify storefront authentication](https://docs.sparklayer.io/ignite/api/verify-authentication.md) (`authenticationVerify`): Verifies authentication data, such as a JWT, provided by the platform on the front end. Path: `siteEnv`*, `siteId`*. Body: `data`*.