API Overview
The Storelayer API is JSON over HTTPS at https://api.storelayer.io. Almost every route is project-scoped (/projects/{projectId}/…) and authenticated with a project API key. The API reference is generated from the live OpenAPI document and owns the full endpoint contracts; this page covers the conventions they share.
Conventions
Section titled “Conventions”| Topic | Convention |
|---|---|
| Base URL | https://api.storelayer.io |
| Auth | Authorization: Bearer <api key> — see authentication |
| Bodies | JSON with Content-Type: application/json; field names are camelCase |
| Success | { "success": true, "data": … } |
| Errors | { "success": false, "error": { "code": <number>, "message": "…" } } |
| IDs | Your customer IDs are yours (userId); Storelayer-generated IDs are prefixed strings such as prj_…, evt_… |
| Timestamps | ISO 8601 UTC strings, e.g. 2026-10-11T13:26:04.619Z; send the same format for fields like expiresAt |
| Money in carts | Integer minor units: $25.00 → 2500. Promotion cart prices are rejected if not integers |
| Wallet amounts | Asset units (points, stamps), not money |
Use integer minor units for money everywhere, including your own event payloads and catalog prices — only cart fields enforce it, so mixed units in events and rules fail silently.
Errors
Section titled “Errors”Error codes are numeric and stable; check error.code, not the message.
| Status | Code | Meaning |
|---|---|---|
| 400 | 1001 | Bad request (e.g. missing project ID) |
| 401 | 1002 | Missing, invalid, or expired credential |
| 403 | 1003 | Credential cannot access this project |
| 403 | 1004 | API key missing a required scope |
| 404 | 1000 | Route or resource not found |
| 409 | 1004 | Resource already exists (generic conflict) |
| 400 / 500 | 1005 | Operation failed; message carries the reason (400) or Internal server error (500) |
Domains add their own codes in the same envelope — for example 2500 user already exists, 2502 user not found, 2600 invalid wallet input, 2601 insufficient balance.
Request validation failures have a different shape. When a body, query, or path parameter fails schema validation, the response is 400 with error as an array of issues and the rejected input echoed back:
{ "success": false, "error": [ { "code": "too_small", "path": ["firstName"], "message": "Too small: expected string to have >=1 characters" } ], "data": { "userId": "cus_1001", "firstName": "" }}Handle both: Array.isArray(body.error) means validation issues; otherwise read body.error.code. Promotion cart evaluation can also return error.code as the string "VALIDATION_ERROR", so don’t assume codes are always numbers.
Pagination
Section titled “Pagination”Two styles exist; check the endpoint in the reference.
| Style | Query params | Defaults | Used by (examples) |
|---|---|---|---|
| Offset | limit, offset | limit=50, max 100, offset=0 | Customers, wallet transactions/assets, promotions list, referrals, catalog |
| Page | page (from 1), pageSize | pageSize max 100 | Promotion coupons and usage |
List responses commonly return { "items": [...], "total": <number> } inside data. Page until you have total items.
Asynchronous work
Section titled “Asynchronous work”POST /ingest/events returns 201 with { "id": "evt_…", "status": "accepted" } before rules run. Effects (wallet credits, referral completion, integrations) happen afterwards; inspect them through Workflows. Synchronous endpoints (wallet earn/spend/modify, promotion evaluation) return their result directly.
Where things live in the reference
Section titled “Where things live in the reference”| Tag | Use it for |
|---|---|
| Projects, Project Config | Project metadata; currency, timezone, settings |
| API Keys | Create, list, rename, revoke project keys |
| Team | Project members, roles, invitations |
| External Users | Register and manage customers by your userId |
| Wallet | Balances, earn, spend, modify, assets, transactions |
| Events | POST /ingest/events |
| Rules | Rule CRUD, testing conditions, evaluating, cloning to another project |
| Resources, Resources v2 | Data sources rules and promotions can read (/resources is current) |
| Workflows | Runs produced by events — what matched, what executed |
| Promotions, Promotions - Coupons, Promotions - Usage, Promotions - Stats | Discount definitions, coupon codes, redemptions, reporting, cart evaluation |
| Referrals | Referral config, codes, attribution, leaderboard |
| Integrations | Outbound HTTP/Slack/Telegram/etc. connections used by rule actions |
| Storage | Project custom tables |
| Catalog, Stores | Products/categories; stores and facilities |
| Internal Tools | The tool catalog used by agents and the MCP server |
| Support, Surveys | Tickets and surveys, including public submission routes |
To read one contract without loading the whole spec:
curl -s https://api.storelayer.io/openapi.json | jq '.paths["/projects/{projectId}/promotions/evaluate"].post'Pitfalls
Section titled “Pitfalls”- If a guide and the reference disagree on a request shape, trust the reference and report the discrepancy.
- Retries: wallet
earn/spendare not idempotent. After a timeout, check transactions before retrying.