Skip to content

HTTP Integration

Any language with an HTTP client can integrate Storelayer: send JSON with a Bearer API key to https://api.storelayer.io, read data on success, read error on failure. This page covers the delivery concerns that apply in every language; the JavaScript page has a complete typed client you can port.

POST /projects/prj_ab12cd34ef56/users/cus_1001/wallet/spend HTTP/1.1
Host: api.storelayer.io
Authorization: Bearer sk_your_key_here
Content-Type: application/json
{ "assetType": "points", "amount": 250, "referenceId": "ord_5002", "referenceType": "order" }

Every response body is one of:

{ "success": true, "data": { "...": "..." } }
{ "success": false, "error": { "code": 2601, "message": "Insufficient balance" } }
{ "success": false, "error": [ { "path": ["amount"], "message": "..." } ], "data": { "...": "..." } }

The third shape is a schema-validation failure (400). Branch on whether error is an array. Promotion evaluation can also report cart validation as { "success": false, "error": { "code": "VALIDATION_ERROR", "message": "…" } } — a string code — so don’t assume code is always a number. Codes are listed in the API overview.

Writes that move value are not idempotent. wallet/earn and wallet/spend record a new transaction on every call; referenceId is stored but not used to deduplicate. Retry them only after confirming the first attempt did not land:

  1. Set a client timeout (for example 10 s).
  2. On timeout or 5xx, list GET /projects/{projectId}/users/{userId}/wallet/transactions and look for your referenceId.
  3. Retry only if it is absent.

For balance targets that must be exact (imports, corrections), use POST …/wallet/modify with targetAmount; repeating it with the same target produces no further change. See wallets.

Call typeSafe to retry blindly?
GET readsYes, with backoff
POST …/promotions/evaluate (preview)Yes — computes discounts without recording usage
POST …/promotions/evaluate with dryRun: falseYes, with the same transactionId — a repeat returns the saved result marked duplicate: true instead of redeeming twice
POST …/wallet/modify (same targetAmount)Yes
POST …/wallet/earn, …/wallet/spendNo — check transactions first
POST /ingest/eventsNo — a duplicate event runs your rules again; deduplicate on your side (for example keep orderId in the payload and check before sending)
POST …/usersYes — a repeat returns 409 code 2500, treat as success

POST /ingest/events answers 201 { "id": "evt_…", "status": "accepted" } immediately. Rules run afterwards. Store the event ID, then inspect the run under Workflows in the API reference or poll the affected balance with a deadline. See workflows and debugging.

The OpenAPI document (OpenAPI 3, bearerAuth security) can feed any generator, e.g.:

Terminal window
npx @openapitools/openapi-generator-cli generate \
-i https://api.storelayer.io/openapi.json -g python -o ./storelayer-client

Expect to add response types yourself: most endpoints document only the { success, data } envelope with an untyped data. Request bodies and parameters are typed. The spec declares Bearer auth only; /ingest/events additionally accepts X-API-Key, which you don’t need.

Log the method, path, status, error.code, Storelayer IDs (evt_…, transaction IDs), and your referenceId. Never log the API key or full customer PII.