Skip to content

Authentication

Steps for
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. 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: 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.

Every request to the SparkLayer APIs needs an access token. Getting one takes three steps:

  1. Create an API key in the SparkLayer Dashboard.
  2. Swap the key's client ID and secret for an access token, which lasts an hour.
  3. Send the token with every request.

This is the standard OAuth 2.0 client credentials flow.

For a step-by-step first call, see the quickstart.

Environments

Each SparkLayer account has a live environment and, on plans with Test mode, a test environment. The host you call selects the environment:

EnvironmentBase URL
Livehttps://app.sparklayer.io
Testhttps://test.app.sparklayer.io

The environments hold separate data and separate API keys. A key created while the Dashboard is in Test mode only works against the test base URL, and a key created in live mode only works against the live base URL.

Create an API key

Create a key

Select Create new API Key and give the key a name that identifies the integration using it.

Copy the credentials

Copy the Site ID, Client ID and Client Secret. The client secret is only shown once, so store it securely — for example in your integration's secrets manager.

Deleting a key in the Dashboard also revokes every access token issued for it.

Request an access token

Send a POST request to /api/auth/token with your Site ID in the Site-Id header and your credentials in a JSON body. The token endpoint only accepts Content-Type: application/json:

curl -X POST https://app.sparklayer.io/api/auth/token \
  -H "Site-Id: <SITE_ID>" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "<CLIENT_ID>",
    "client_secret": "<CLIENT_SECRET>"
  }'
FieldValue
grant_typeAlways client_credentials
client_idThe Client ID shown when you created the key
client_secretThe Client Secret shown when you created the key

If the credentials are valid, you receive an access token:

{
  "token_type": "Bearer",
  "expires_in": 3600,
  "access_token": "<ACCESS_TOKEN>"
}
FieldDescription
token_typeAlways Bearer
expires_inSeconds until the token expires: tokens are valid for 1 hour
access_tokenThe token to send in the Authorization header

A token only works with the Site ID and environment it was issued for. No refresh token is issued: when a token expires, request a new one with the same credentials.

Standard OAuth libraries won't work as they are

The token request is JSON with a Site-Id header, not the form-encoded body most OAuth 2.0 client libraries send. Request the token with a plain HTTP call, as below, or configure your library to send JSON and the extra header.

Call the API

Send the token in the Authorization header, together with the Site-Id header, on every request:

curl "https://app.sparklayer.io/api/v2/price-lists" \
  -H "Site-Id: <SITE_ID>" \
  -H "Authorization: Bearer <ACCESS_TOKEN>" \
  -H "User-Agent: acme-erp-sync/1.2"
HeaderValue
Site-IdYour Site ID
AuthorizationBearer <ACCESS_TOKEN>
Content-Typeapplication/json for requests with a body

Set a User-Agent

Set a User-Agent header that identifies your integration, such as acme-erp-sync/1.2. It helps our support team find your requests if you need help debugging an issue.

Reuse the access token

Request a token once and reuse it for every call until it's close to expiry, rather than requesting one per call. These small helpers do that, and fetch a new token when one is rejected:

sparklayer.mjs
const { SPARKLAYER_BASE_URL, SPARKLAYER_SITE_ID, SPARKLAYER_CLIENT_ID, SPARKLAYER_CLIENT_SECRET } =
  process.env;

let token = null; // { value, expiresAt }

async function getToken() {
  // reuse the token until a minute before it expires
  if (token && Date.now() < token.expiresAt - 60_000) return token.value;
  const response = await fetch(`${SPARKLAYER_BASE_URL}/api/auth/token`, {
    method: 'POST',
    headers: { 'Site-Id': SPARKLAYER_SITE_ID, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      grant_type: 'client_credentials',
      client_id: SPARKLAYER_CLIENT_ID,
      client_secret: SPARKLAYER_CLIENT_SECRET,
    }),
  });
  if (!response.ok) throw new Error(`Token request failed: ${response.status}`);
  const body = await response.json();
  token = { value: body.access_token, expiresAt: Date.now() + body.expires_in * 1000 };
  return token.value;
}

/** Calls a SparkLayer API path, e.g. sparklayer('/api/v2/price-lists'). */
export async function sparklayer(path, init = {}, retried = false) {
  const response = await fetch(`${SPARKLAYER_BASE_URL}${path}`, {
    ...init,
    headers: {
      'Site-Id': SPARKLAYER_SITE_ID,
      Authorization: `Bearer ${await getToken()}`,
      'User-Agent': 'acme-erp-sync/1.2',
      ...(init.body ? { 'Content-Type': 'application/json' } : {}),
      ...init.headers,
    },
  });
  if (response.status === 401 && !retried) {
    token = null; // the token was rejected: get a new one and try once more
    return sparklayer(path, init, true);
  }
  return response;
}

For retries on other errors, see Retrying requests.

Authentication errors

If authentication fails, the API responds with a JSON error body. See Errors for the format and every status code.

StatusWhen
400The token request is missing the Site-Id header, a required field or Content-Type: application/json
401The client ID or secret is wrong, or the access token is missing, invalid or expired
401 or 403The access token was issued for a different Site ID or environment. The Pricing and Purchasing APIs also return 403 when the Authorization header is missing
Was this page helpful?

Last updated