Mint a client token
const url = 'https://api.keliplay.com/v1/auth/session-tokens';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"channelId":"0192f3a1-0000-7000-8000-00000000c001","participantRef":"user_48213","origin":"https://www.example.com","ttlSeconds":900}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.keliplay.com/v1/auth/session-tokens \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "channelId": "0192f3a1-0000-7000-8000-00000000c001", "participantRef": "user_48213", "origin": "https://www.example.com", "ttlSeconds": 900 }'Mints a client token for one player on one channel. Call this from your backend each time a player opens the page, and pass the token to the embed.
The token is for whichever campaign is live on the channel right now.
When nothing is live, the response is 200 with clientToken: null and
the channel’s between-campaigns message. Pass the null token to the embed
anyway: it shows that message.
origin must be one of your allowed origins. If the player has used all
their plays, the response is 409 with a message you can show them.
Permission: tokens.mint. Rate limit: 600 requests per minute.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
The channel the player is about to play.
Your own id for the player. Winners and rewards are reported against it.
Where the game will be shown: a site’s origin, such as
https://www.example.com, or an app as android:<application id>
or ios:<bundle id>, such as android:com.example.app. Must be
registered under allowed origins.
How long the token lasts, in seconds. Defaults to 900.
Example
{ "channelId": "0192f3a1-0000-7000-8000-00000000c001", "participantRef": "user_48213", "origin": "https://www.example.com", "ttlSeconds": 900}Responses
Section titled “Responses”Nothing is live on the channel. No token is issued.
object
Example
{ "clientToken": null, "betweenCampaigns": { "title": "Back soon", "body": "Our next game starts on Monday." }}Headers
Section titled “Headers”Requests allowed in the current window.
Requests left in the current window.
A token for the live campaign.
object
Pass this to the embed as clientToken.
A unique id for this token, useful in your own logs.
Example
{ "clientToken": "eyJhbGciOiJIUzI1NiJ9.eyJleGFtcGxlIjp0cnVlfQ.c2lnbmF0dXJl", "expiresAt": "2026-10-05T12:15:00.000Z", "jti": "0192f3a1-0000-7000-8000-0000000000a1"}Headers
Section titled “Headers”Requests allowed in the current window.
Requests left in the current window.
The request is not valid. details lists each field that failed, where there is one.
object
object
Stable and safe to branch on.
invalid_request(400): the request is not valid.unauthorized(401): missing, malformed or revoked API key.upgrade_required(402): not in your plan, or a plan limit is reached.forbidden(403): the key lacks a permission, or the action is not allowed.not_found(404): nothing with that id in your account.conflict(409): clashes with the current state.confirmation_required(409): repeat withconfirm=true. Folder deletion only.rate_limited(429): wait forRetry-Afterseconds.internal_error(500) andservice_unavailable(503): try again later.
Written for a person. May change; do not parse it.
object
The failing field, dot separated, such as prize.label.
object
Example
{ "error": { "code": "invalid_request", "message": "Invalid request json.", "details": [ { "path": "name", "message": "Too small, expected string to have >=1 characters" } ] }}The API key is missing, malformed or revoked.
object
object
Stable and safe to branch on.
invalid_request(400): the request is not valid.unauthorized(401): missing, malformed or revoked API key.upgrade_required(402): not in your plan, or a plan limit is reached.forbidden(403): the key lacks a permission, or the action is not allowed.not_found(404): nothing with that id in your account.conflict(409): clashes with the current state.confirmation_required(409): repeat withconfirm=true. Folder deletion only.rate_limited(429): wait forRetry-Afterseconds.internal_error(500) andservice_unavailable(503): try again later.
Written for a person. May change; do not parse it.
object
The failing field, dot separated, such as prize.label.
object
Example
{ "error": { "code": "unauthorized", "message": "Invalid or revoked API key." }}The API key does not carry the permission this needs, or the request is not allowed.
object
object
Stable and safe to branch on.
invalid_request(400): the request is not valid.unauthorized(401): missing, malformed or revoked API key.upgrade_required(402): not in your plan, or a plan limit is reached.forbidden(403): the key lacks a permission, or the action is not allowed.not_found(404): nothing with that id in your account.conflict(409): clashes with the current state.confirmation_required(409): repeat withconfirm=true. Folder deletion only.rate_limited(429): wait forRetry-Afterseconds.internal_error(500) andservice_unavailable(503): try again later.
Written for a person. May change; do not parse it.
object
The failing field, dot separated, such as prize.label.
object
Example
{ "error": { "code": "forbidden", "message": "Your role does not allow this (draws.run)." }}Nothing with that id exists in your account.
object
object
Stable and safe to branch on.
invalid_request(400): the request is not valid.unauthorized(401): missing, malformed or revoked API key.upgrade_required(402): not in your plan, or a plan limit is reached.forbidden(403): the key lacks a permission, or the action is not allowed.not_found(404): nothing with that id in your account.conflict(409): clashes with the current state.confirmation_required(409): repeat withconfirm=true. Folder deletion only.rate_limited(429): wait forRetry-Afterseconds.internal_error(500) andservice_unavailable(503): try again later.
Written for a person. May change; do not parse it.
object
The failing field, dot separated, such as prize.label.
object
Example
{ "error": { "code": "not_found", "message": "Channel 0192f3a1-0000-7000-8000-00000000c009 not found." }}The request clashes with the current state. The message says what to change.
object
object
Stable and safe to branch on.
invalid_request(400): the request is not valid.unauthorized(401): missing, malformed or revoked API key.upgrade_required(402): not in your plan, or a plan limit is reached.forbidden(403): the key lacks a permission, or the action is not allowed.not_found(404): nothing with that id in your account.conflict(409): clashes with the current state.confirmation_required(409): repeat withconfirm=true. Folder deletion only.rate_limited(429): wait forRetry-Afterseconds.internal_error(500) andservice_unavailable(503): try again later.
Written for a person. May change; do not parse it.
object
The failing field, dot separated, such as prize.label.
object
Example
{ "error": { "code": "conflict", "message": "An archived campaign cannot be edited. Restore it first, then make the change." }}Rate limit exceeded. Wait for Retry-After seconds.
object
object
Stable and safe to branch on.
invalid_request(400): the request is not valid.unauthorized(401): missing, malformed or revoked API key.upgrade_required(402): not in your plan, or a plan limit is reached.forbidden(403): the key lacks a permission, or the action is not allowed.not_found(404): nothing with that id in your account.conflict(409): clashes with the current state.confirmation_required(409): repeat withconfirm=true. Folder deletion only.rate_limited(429): wait forRetry-Afterseconds.internal_error(500) andservice_unavailable(503): try again later.
Written for a person. May change; do not parse it.
object
The failing field, dot separated, such as prize.label.
object
Example
{ "error": { "code": "rate_limited", "message": "Rate limit exceeded: 30 requests per 60s." }}Headers
Section titled “Headers”Seconds to wait before trying again.