Award kinds and awards
The six system award kinds, your own award-kind registry, award definitions, and how awards are granted, read, resolved and optionally minted on a testnet.
An award is a durable record that a player (or an organization) earned something: a badge, a medal, a trophy. Every award is an instance of an award definition you author, and every definition has a kind.
Kinds
The six system kinds
These always exist, cannot be renamed or redefined, and each carries its own rules:
| Kind | Rules |
|---|---|
achievement | Earned automatically when a condition is met (see Achievement conditions) |
badge | A player badge, usually paid by a mission or granted by you |
medal | Bound to a tournament and a finishing rank; awarded when the tournament completes |
trophy | Bound to a tournament and a finishing rank |
prize | Bound to a tournament and a finishing rank; the only kind that may declare a cash payout |
organization-badge | Awarded to an organization rather than a player; carries no wallet value |
Your own kinds
You can add kinds to your tenant's award-kind registry, such as season-champion or
community-hero. A custom kind is a label for your own vocabulary: it carries none of the system
rules (no condition, no tournament binding, no payout) and it is off-chain only.
| Route | Scope | Does |
|---|---|---|
GET /v1/award-kinds | rewards:read | Your custom kinds with the registry revision; system kinds are not listed |
POST /v1/award-kinds | rewards:mutate | Create a kind in draft: awardKindKey (lowercase slug, up to 64 characters) and displayName (up to 120) |
PATCH /v1/award-kinds/:awardKindKey | rewards:mutate | Change displayName; the key never changes |
POST /v1/award-kinds/:awardKindKey/publish | rewards:mutate | draft to published |
POST /v1/award-kinds/:awardKindKey/archive | rewards:mutate | published to archived |
curl -X POST "$REWARD_API_URL/v1/award-kinds" \
-H "Authorization: Bearer $TANITAR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"awardKindKey":"season-champion","displayName":"Season champion"}'A definition can name a custom kind only while it is published. Archiving a kind blocks new
definitions from naming it; definitions and awards that already use it are unaffected. Every write
raises the registry revision, so you can cache the list against it.
| Status | errorCode | Cause |
|---|---|---|
422 | AWARD_KIND_INVALID | The key is not a canonical lowercase slug |
422 | AWARD_KIND_RESERVED | The key is one of the six system kinds |
422 | AWARD_KIND_UNAVAILABLE | The key does not exist, or a definition names a kind that is not published |
409 | AWARD_KIND_EXISTS | The key already exists |
409 | AWARD_KIND_TRANSITION_INVALID | Publishing a non-draft or archiving a non-published kind |
409 | AWARD_KIND_REVISION_CONFLICT | The entry changed concurrently; read and retry |
Award definitions
A definition says what an award is and what it carries. Definitions move from draft to
published to retired; only a published definition can be awarded, and a retired one can no
longer change.
| Route | Scope |
|---|---|
GET /v1/awards/definitions (filters kind, status, tournamentId) | rewards:read |
GET /v1/awards/definitions/:awardKey | rewards:read |
POST /v1/awards/definitions | rewards:mutate |
PATCH /v1/awards/definitions/:awardKey | rewards:mutate |
POST /v1/awards/definitions/:awardKey/publish | rewards:mutate |
POST /v1/awards/definitions/:awardKey/retire | rewards:mutate |
| Field | Rule |
|---|---|
awardKey | Lowercase slug, up to 64 characters, unique in your tenant |
kind | A system kind or one of your published kinds |
name, description | Up to 120 and 2000 characters |
media | Optional image and artwork URLs |
value | Optional, up to 8 entries of currencyKey and a positive integer amount; every currency must be published |
walletScope, gameSlug | Where value is credited; gameSlug is required for game |
condition | Required for, and only allowed on, achievement |
tournamentId, rank | Required for, and only allowed on, medal, trophy and prize |
payout | Only on prize: ISO currency currency (three lowercase letters) and amountMinor |
curl -X POST "$REWARD_API_URL/v1/awards/definitions" \
-H "Authorization: Bearer $TANITAR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"awardKey":"autumn-cup-gold","kind":"medal","name":"Autumn Cup gold","description":"First place, Autumn Cup","value":[{"currencyKey":"red","amount":1000}],"walletScope":"platform","tournamentId":"autumn-cup","rank":1}'A definition bound to a tournament can only be created or changed by a caller that owns the
tournament's organization. Shape violations are refused with 422 and a specific code such as
AWARD_CONDITION_REQUIRED, AWARD_BINDING_REQUIRED, AWARD_CURRENCY_UNPUBLISHED or
AWARD_VALUE_INVALID.
Achievement conditions
An achievement definition names one condition from a closed set, each observed on an event the
Gamification service publishes:
condition.kind | Met when | Extra field |
|---|---|---|
mission-completed | The named mission has been completed threshold times | missionKey |
streak-days | The player's streak reaches threshold days | none |
level-reached | The player reaches level threshold | none |
total-xp | The player's total XP reaches threshold | none |
GET /v1/awards/trigger-policy returns this table as data: each condition, the event that produces
it and whether it is producible.
Awards
Awards are created in three ways:
- Automatically on tournament completion, for every published
medal,trophyandprizedefinition bound to that tournament and a finishing rank. - Automatically when an achievement condition is met.
- By your integration with
POST /v1/awards/grants.
Each trigger produces exactly one award record. If the definition has a value, the currency is
credited through the grant spine in the same transaction, and a value
that cannot settle makes the award rejected as a whole.
Award status | Meaning |
|---|---|
applied | The award is held, and its value (if any) is in the wallet |
rejected | Settled as refused, with rejection.code and rejection.reason; for example AWARD_ALREADY_HELD or AWARD_DEFINITION_MISSING |
unresolved | A tournament placement could not be attributed to a player; the award waits for you to name the recipient |
Grant an award
POST /v1/awards/grants with scope rewards:mutate. This is the route behind the product term
"operator grant", and awards created this way carry the provenance operator-grant.
| Field | Rule |
|---|---|
awardKey | A published definition |
subjectType | player or organization |
playerId or organizationId | The recipient, matching subjectType |
reason | Optional, up to 500 characters |
curl -X POST "$REWARD_API_URL/v1/awards/grants" \
-H "Authorization: Bearer $TANITAR_API_KEY" \
-H "Idempotency-Key: 6c1d0f4e-2b8a-4f0e-9d51-8a0f3b7c2e11" \
-H "Content-Type: application/json" \
-d '{"awardKey":"community-hero","subjectType":"player","playerId":"player-7f3a","reason":"Moderated the September finals"}'The award's identity is derived from your Idempotency-Key, so repeating the request with the same
key returns the same award rather than a second one. Granting an organization badge, or a definition
bound to a tournament, requires that you own the organization concerned.
Read and resolve awards
GET /v1/awardslists awards, newest first. It requires one ofplayerId,organizationIdortournamentId, unless you ask forstatus=unresolved. Other filters:awardKey,kind,status, andlimit(1 to 100, default 50). No cursor. Invalid filters are refused with400 AWARD_QUERY_INVALID.GET /v1/awards/:awardIdreads one award, or404 AWARD_NOT_FOUND.POST /v1/awards/:awardId/recipientwith{ "playerId": "…" }settles anunresolvedaward to the player you name.POST /v1/awards/tournaments/:tournamentId/settlere-runs award settlement for a completed tournament from its stored placements. Use it after publishing a definition that should have applied: it only adds awards that are missing and never duplicates one.
Players see their own awards through the Player surface and may equip one of their applied awards
as a displayed title. Every settled award publishes reward.award-granted (see the
event catalog).
On-chain fulfillment (testnets)
When your deployment has Web3 enabled, an applied award of a system kind that has a collection on the chain can be minted as a token on a testnet: Ethereum Sepolia, Hedera testnet or Solana. Mainnets are refused.
GET /v1/web3/capabilitieslists the chains your tenant can use now. A chain that is absent is disabled.POST /v1/awards/:awardId/fulfillmentswithchain, the player'sdestinationaddress and an optionalmetadataUri(at most 200 characters) mints the award. There is one fulfillment per award and chain: a repeated request reaches the existing record, and answers409 FULFILLMENT_PENDINGwhile its transaction is still unconfirmed rather than broadcasting again.GET /v1/awards/:awardId/fulfillmentsreads its status:claimed,submitted,confirmed,failedorunresolved.GET /v1/awards/:awardId/mint-recordsandPOST /v1/awards/:awardId/mint-recordsread and record the resulting token identity (chain, contract, token id, wallet, transaction).
A custom kind has no collection on any chain, so a fulfillment request for one is refused with
FULFILLMENT_KIND_UNSUPPORTED before any chain is contacted. To check what the chains are running,
see Web3 verification.
Grants
How earned value reaches a player's wallet exactly once, why a rejected grant is a settled outcome, and how to read a player's grants.
Exchanges
How players convert Red into Blue or into a testnet token and back, what each exchange status means, and how you read, reconcile and release exchanges.