Skip to content

Quick Start

Five calls against a test project: read config, register a customer, credit points, read the balance, send an event. Every response uses the envelope { "success": true, "data": … }.

In the Storelayer dashboard, open (or create) a test project and create an API key under the project’s API keys. You need two values:

  • Project ID, e.g. prj_ab12cd34ef56
  • API key, e.g. sk_… (keep it on your backend — see authentication)
Terminal window
export SL_API=https://api.storelayer.io
export SL_PROJECT=prj_ab12cd34ef56
export SL_KEY=sk_your_key_here

The key only works for the project that issued it. Any /projects/{projectId}/… path with another project ID returns 403 (code 1003).

Terminal window
curl -s "$SL_API/projects/$SL_PROJECT/config" \
-H "Authorization: Bearer $SL_KEY"
{ "success": true, "data": { "currency": "USD", "timezone": "UTC", "settings": {} } }

A 401 with code 1002 means the key is missing, wrong, or expired.

userId is your stable customer ID. firstName and lastName are required.

Terminal window
curl -s -X POST "$SL_API/projects/$SL_PROJECT/users" \
-H "Authorization: Bearer $SL_KEY" \
-H "Content-Type: application/json" \
-d '{ "userId": "cus_1001", "firstName": "Ada", "lastName": "Lovelace", "email": "ada@example.com" }'

Returns 201 with the stored profile (data.id is cus_1001). Registering the same userId again returns 409 with code 2500.

Terminal window
curl -s -X POST "$SL_API/projects/$SL_PROJECT/users/cus_1001/wallet/earn" \
-H "Authorization: Bearer $SL_KEY" \
-H "Content-Type: application/json" \
-d '{ "assetType": "points", "amount": 100, "referenceId": "welcome_cus_1001", "referenceType": "manual", "description": "Welcome bonus" }'

data contains transaction, asset, and the updated wallet. Earn is not idempotent: referenceId is stored for traceability but a retried request credits again. Only retry after confirming the first call did not land (check GET …/wallet/transactions).

Terminal window
curl -s "$SL_API/projects/$SL_PROJECT/users/cus_1001/wallet" \
-H "Authorization: Bearer $SL_KEY"
{
"success": true,
"data": {
"assets": {
"points": {
"assetType": "points",
"balance": 100,
"lifetimeEarned": 100,
"lifetimeSpent": 0,
"lifetimeExpired": 0,
"nextExpiration": null
}
}
}
}

The balance is at data.assets.<assetType>.balance — here data.assets.points.balance.

Events go to /ingest/events. The project comes from the key, so there is no project ID in the path.

Terminal window
curl -s -X POST "$SL_API/ingest/events" \
-H "Authorization: Bearer $SL_KEY" \
-H "Content-Type: application/json" \
-d '{ "type": "purchase", "userId": "cus_1001", "payload": { "orderId": "ord_5001", "amount": 5000, "currency": "USD" } }'
{ "success": true, "data": { "id": "evt_k3j9x0q2m1ab", "status": "accepted" } }

accepted means queued, not rewarded. Nothing changes in the wallet until an active rule matches purchase events. Build that rule in the loyalty program guide, then check the run under workflows. Pick one unit for money in payloads (integer cents above) and use it in every event and rule.

  • payload is required on events, even if empty ({}).
  • Wallet calls do not check that the customer is registered; a typo in userId silently creates a separate wallet.
  • Use a test project for experiments — wallet transactions are a ledger, and there is no “undo” besides another transaction (spend or modify).