Errors and limits
Errors
Section titled “Errors”Every error has the same JSON shape, whatever the endpoint:
{ "error": { "code": "invalid_request", "message": "Invalid request json.", "details": [ { "path": "participantRef", "message": "Required" } ] }}code is stable, so branch on it in your code. message is written for people
and may change. details is only present on some errors, such as validation
failures, where it lists each field that was wrong.
| Status | Code | What it means | What to do |
|---|---|---|---|
| 400 | invalid_request |
The request is malformed or a field is invalid. | Fix the request. details says which field. |
| 401 | unauthorized |
The API key is missing, wrong or revoked. | Check the Authorization header and the key. |
| 402 | upgrade_required |
Your plan does not include this feature, or you have reached a plan limit. | Ask your account manager. The message says what is missing. |
| 403 | forbidden |
The key does not have the permission this needs. | Give the key the permission, or use another key. |
| 404 | not_found |
Nothing with that id exists in your organisation. | Check the id. |
| 409 | conflict |
The request clashes with the current state, such as a player who has used all their plays, or two campaigns live at once on one channel. | Read the message. Retrying unchanged will fail again. |
| 429 | rate_limited |
Too many requests. | Wait for the number of seconds in Retry-After, then retry. |
| 500 | internal_error |
Something went wrong on our side. | Retry with backoff. Contact support if it continues. |
| 503 | service_unavailable |
A service is briefly unavailable. | Retry with backoff. |
Rate limits
Section titled “Rate limits”Limits are counted per API key over a fixed window. Responses from the endpoints below include:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Requests allowed in the window. |
X-RateLimit-Remaining |
Requests left in the current window. |
Retry-After |
On a 429 only: seconds until you can try again. |
| Endpoint | Limit |
|---|---|
POST /v1/auth/session-tokens |
600 a minute |
POST /v1/game-instances/{id}/winner-selection/trigger |
30 a minute |
POST /v1/game-instances/{id}/reward-grants |
60 a minute |
POST /v1/game-instances/{id}/reward-coupons |
10 a minute |
POST /v1/game-instances/{id}/reward-coupons/generate |
10 a minute |
POST /v1/tenant/assets/import |
10 a minute and 200 an hour |
If you expect more traffic than this, for example a large launch, tell your account manager beforehand.
Plan limits
Section titled “Plan limits”Separate from rate limits, your plan sets limits such as how many campaigns can be
live at once, how many plays a month your organisation can have, and how much
storage the media library can use. Going over one returns 402. See
Plans.
Pagination
Section titled “Pagination”Long lists are paged with limit and offset:
curl "https://api.keliplay.com/v1/game-instances/$CAMPAIGN_ID/reward-grants?limit=50&offset=100" \ -H "Authorization: Bearer $KELIPLAY_API_KEY"{ "total": 1284, "grants": [ ... ]}| Parameter | Description |
|---|---|
limit |
How many items to return, up to 200. The default depends on the list. |
offset |
How many items to skip. Starts at 0. |
total is the number of items across all pages. Keep requesting with a larger
offset until you have total items.
Ids and times
Section titled “Ids and times”- Ids are opaque strings. Store them as given and do not parse them.
- Times are ISO 8601 strings in UTC, such as
2026-10-05T09:32:11.204Z.