Skip to content

Rewards and coupons

A reward gives a player a coupon code when they qualify, for example everyone who scores 500 or more, or whoever the wheel lands on “Free coffee” for. The player sees the code in the game frame at the end of their play. This page covers doing it with the API. To set rewards up in the dashboard, see Rewards.

Rewards need the Rewards feature on your plan.

A campaign’s reward is a list of up to eight prizes. When a play ends, Keliplay checks the prizes in order and gives the first one the player qualifies for. Each prize has:

  • a match: who qualifies,
  • a display: the title, description and terms link the player sees,
  • a code strategy: where its codes come from.
when Extra field Qualifies when
everyone Every finished play.
won The wheel stopped on a winning segment. Only for Spin the Wheel: on any other game the request is refused with 400, because those games end on a score. Use score_at_least instead.
score_at_least score The score is at least this number.
outcome outcomeIds The result is one of these, for example these wheel segments. Up to 24 ids.
rank_at_most rank A draw ranks the player at this place or better. Given out when the draw runs, not at the end of a play.
Strategy Use it when
pool You have a list of codes from your own shop or till system.
shared Everyone gets the same code, and your system limits how often it can be used.
generated You want Keliplay to create unique, hard-to-guess codes, and your system can accept them.

PUT replaces the campaign’s whole reward. Send null to turn rewards off.

Terminal window
curl -X PUT https://api.keliplay.com/v1/game-instances/$CAMPAIGN_ID/reward \
-H "Authorization: Bearer $KELIPLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tiers": [
{
"match": { "when": "score_at_least", "score": 500 },
"display": {
"title": "10% off your next order",
"description": "Use the code at checkout.",
"termsUrl": "https://www.example.com/terms"
},
"codeStrategy": "pool"
}
],
"grantOncePerParticipant": true,
"validForSeconds": 2592000
}'
Field Description
tiers The prizes, in order, from 1 to 8. Include a prize’s id to keep it and its codes; leave id out to add a new one. A prize you leave out is removed, which is refused while it still has codes.
grantOncePerParticipant When true (the default), each player can get at most one coupon from this campaign.
validForSeconds How long a coupon stays valid after it is given, up to one year. Leave it out or send null for no expiry.
page The layout of the reward page the player sees. Easiest to arrange in the dashboard; leave it out to keep the current page, or get a starting page on the first save.

The response is the saved reward with an id for each prize. GET on the same path returns it with stock counts for each prize: how many codes it has, how many are left, and how many have been given out.

Upload up to 5,000 codes per request. Send tierId to choose the prize; leave it out for the first prize.

Terminal window
curl -X POST https://api.keliplay.com/v1/game-instances/$CAMPAIGN_ID/reward-coupons \
-H "Authorization: Bearer $KELIPLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"codes": ["SPRING-4KQ2", "SPRING-8HT7", "SPRING-2MW9"],
"issueLimit": 1
}'
{ "submitted": 3, "accepted": 3, "duplicates": 0 }

issueLimit is how many players can be given each code. Set it to 1 for single-use codes. Leave it out for a code anyone may get, which is what a shared prize wants. Codes already in the campaign are counted as duplicates and skipped, so it is safe to retry an upload.

To match each coupon to a record in your own system, send coupons instead of codes. Each coupon can carry a ref (your own ID for it) and a name. Both are optional, up to 200 characters.

Terminal window
curl -X POST https://api.keliplay.com/v1/game-instances/$CAMPAIGN_ID/reward-coupons \
-H "Authorization: Bearer $KELIPLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"coupons": [
{ "code": "SPRING-4KQ2", "ref": "CRM-00417", "name": "Spring 10%" },
{ "code": "SPRING-8HT7", "ref": "CRM-00418", "name": "Spring 10%" }
],
"issueLimit": 1
}'

The response is the same as for codes. Send one of codes or coupons, not both.

  • A ref names one coupon in a campaign. A ref the campaign already has is refused with 409, and the same ref twice in one request with 400.
  • When a player is given the coupon, the reward_granted webhook carries its ref and name, so you know which coupon they got. The code itself is sent only to an endpoint that opts in.
  • Players never see the ref. They see the name only if the reward page’s coupon block is set to show it (show: "name" or "both").
  • A request can be up to 3 MB, enough for 5,000 coupons with long refs and names.

For a generated prize, ask Keliplay to create codes:

Terminal window
curl -X POST https://api.keliplay.com/v1/game-instances/$CAMPAIGN_ID/reward-coupons/generate \
-H "Authorization: Bearer $KELIPLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "quantity": 500, "prefix": "SPRING-" }'
{ "generated": 500, "codes": ["SPRING-7Q4KX9M2TB", "..."] }

Up to 1,000 per request. prefix may use A to Z, 0 to 9 and -, up to 12 characters. Generated codes are single use unless you set issueLimit.

GET .../reward-coupons lists codes, newest first, with all but the last four characters hidden. Each code’s ref and name are shown in full. Add reveal=true to see them in full; this needs the Add, generate and withdraw coupon codes permission.

To stop a code being given out, withdraw it:

Terminal window
curl -X DELETE https://api.keliplay.com/v1/game-instances/$CAMPAIGN_ID/reward-coupons/$COUPON_ID \
-H "Authorization: Bearer $KELIPLAY_API_KEY"

A withdrawn code stays on record, and players who already have it keep it.

Use this for goodwill gestures or prizes decided outside Keliplay. It takes a code from the prize’s stock and records it against the player.

Terminal window
curl -X POST https://api.keliplay.com/v1/game-instances/$CAMPAIGN_ID/reward-grants \
-H "Authorization: Bearer $KELIPLAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"participantRef": "user_8412",
"idempotencyKey": "support-ticket-55210"
}'
{
"grantId": "0199f0d1-3a4b-7c5d-8e6f-7a8b9c0d1e2f",
"participantRef": "user_8412",
"code": "SPRING-8HT7",
"expiresAt": "2026-11-04T10:20:00.000Z"
}

idempotencyKey is required, 8 to 200 characters. Sending the same key again does not give out a second code, so you can safely retry after a timeout.

The player is not shown anything: they are no longer in the game. Send them the code yourself, for example by email or in your app. A reward_granted webhook with source: "manual" is also sent.

If no code is available, because the prize has run out or the player already has a coupon from this campaign, the request is refused with 409.

GET .../reward-grants lists every coupon given out, newest first, with the player, the prize (tierId), how it was given (rule, draw or manual), the coupon’s couponRef and couponName, and when it expires. Codes are partly hidden. The list is paged; see pagination.