Catalog authoring
Register the events you send, author missions against them, have a second key approve them, and configure the level curve and membership-tier settings.
Your catalog is the set of events and missions that drive progression for your players. You build it in three steps:
- Register an event in the event registry and publish it (
gamification-config:mutate). - Author a mission that reacts to that event (
gamification-catalog:author). - Approve the mission with a different key (
gamification-catalog:approve). Approval is the only way a mission is published to players.
Administrators can do the same from the dashboard; see Missions in the dashboard.
The event registry
An event declares a key, a display name, and the payload fields a mission may test.
| Route | Scope | What it does |
|---|---|---|
POST /v1/gamification/event-registry | gamification-config:mutate | Register an event, or replace an existing one with the same eventKey |
GET /v1/gamification/event-registry | gamification-catalog:author | List your events, sorted by eventKey (no pagination) |
GET /v1/gamification/event-registry/:eventKey | gamification-catalog:author | Read one event |
POST /v1/gamification/event-registry/:eventKey/archive | gamification-config:mutate | Archive an event |
DELETE /v1/gamification/event-registry/:eventKey | gamification-config:mutate | Delete an event |
curl -X POST "$GAMIFICATION_API_URL/v1/gamification/event-registry" \
-H "Authorization: Bearer $TANITAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"eventKey": "match:won",
"displayName": "Match won",
"status": "published",
"fields": [
{ "field": "mode", "primitiveType": "string", "allowedOperators": ["eq", "in"], "required": true },
{ "field": "kills", "primitiveType": "number", "allowedOperators": ["gte", "gt"] }
]
}'| Field | Rules |
|---|---|
eventKey | namespace:name, lowercase letters, digits and hyphens on each side of the colon. The namespaces tanitar, defendr, platform, player, tournament, reward, game and gamification are reserved (409 GAMIFICATION_EVENT_NAMESPACE_RESERVED). |
status | draft or published. Only a published event can be referenced by a mission or ingested. |
fields[].field | Starts with a lowercase letter, then letters and digits. A name owned by the platform vocabulary (below) is refused with 409 GAMIFICATION_FIELD_RESERVED. |
fields[].primitiveType | string, number or boolean. |
fields[].allowedOperators | Any of eq, neq, gt, gte, lt, lte, in. |
fields[].required | Whether every occurrence must carry the field. |
An event that an active mission references cannot be archived, deleted, moved back to draft, or
re-registered without one of its fields: each answers 409 GAMIFICATION_EVENT_IN_USE. Disable the
missions first.
Platform fields and built-in events
Every event may also carry these platform fields, which you do not declare:
| Field | Type | Operators | Meaning |
|---|---|---|---|
source | string | eq, neq, in, notIn | The cause of the activity, from Tanitar's closed provenance list |
streakCount | number | eq, gt, gte, lt, lte | A streak length |
levelKey | string | eq, in | A membership tier key you have published |
currencyKey | string | eq, in | A currency key you have published |
gameSlug | string | eq, in | A game from the Tanitar game registry |
teamId | string | eq, in | The team the activity is attributed to; feeds the team leaderboard |
A condition on levelKey, currencyKey or gameSlug is checked against the owning registry when
the mission is written. A reference that does not exist is refused with
422 GAMIFICATION_REGISTRY_REFERENCE_INVALID; if the registry cannot be reached the write answers
503 GAMIFICATION_REGISTRY_UNAVAILABLE, which you can retry.
Tanitar also defines built-in events that missions can use without registering them:
player:game-won and tournament:completed (field gameSlug), gamification:chest-opened
(field chestType) and reward:granted (field currencyKey).
Missions
| Route | Scope | What it does |
|---|---|---|
POST /v1/gamification/catalog/missions | gamification-catalog:author | Create a mission, or replace the one with the same missionKey |
PATCH /v1/gamification/catalog/missions/:missionKey | gamification-catalog:author | Replace a mission; send the full definition |
GET /v1/gamification/catalog/missions | gamification-catalog:author | List every mission, sorted by missionKey (no pagination) |
GET /v1/gamification/catalog/missions/:missionKey | gamification-catalog:author | Read one mission |
POST /v1/gamification/catalog/missions/:missionKey/disable | gamification-catalog:author | Unpublish and deactivate a mission, keeping player progress |
POST /v1/gamification/catalog/approvals | gamification-catalog:approve | Approve and publish a mission |
curl -X POST "$GAMIFICATION_API_URL/v1/gamification/catalog/missions" \
-H "Authorization: Bearer $TANITAR_AUTHOR_KEY" \
-H "Content-Type: application/json" \
-d '{
"missionKey": "win-three-ranked",
"displayName": "Win three ranked matches",
"eventKey": "match:won",
"conditions": [{ "field": "mode", "operator": "eq", "value": "ranked" }],
"rewards": [
{ "rewardType": "xp", "amount": 150 },
{ "rewardType": "currency", "amount": 25, "key": "gems" },
{ "rewardType": "chest", "key": "rare" }
],
"cadence": "daily",
"targetCount": 3,
"authorType": "human"
}'| Field | Rules |
|---|---|
missionKey | Lowercase letters, digits and hyphens. |
eventKey | A published event from your registry, or a built-in event (422 GAMIFICATION_EVENT_NOT_ADMISSIBLE otherwise). |
conditions[] | field, operator (eq, neq, gt, gte, lt, lte, in, notIn) and value. The field must be declared by the event or be a platform field, the operator must be one the field allows, and in/notIn take a list (422 GAMIFICATION_FIELD_INVALID). All conditions must hold. |
rewards[] | At least one (422 GAMIFICATION_REWARD_REQUIRED). rewardType is xp, battlePassXP, chest, currency or badge; nft and token are refused (422 GAMIFICATION_REWARD_TYPE_DISABLED). A chest names its tier in key. A currency or badge names a key you have published in Rewards. |
cadence | one-time (once ever), daily (once per UTC day), weekly (once per UTC week, starting Monday) or special (up to maxOccurrences times, no period). |
targetCount | How many matching events complete the mission; at least 1. |
maxOccurrences | Required for special, refused for every other cadence (422 GAMIFICATION_CADENCE_INVALID). |
startsAt, endsAt | Optional ISO 8601 window; endsAt must be after startsAt. |
allowedLevelKeys | Optional, up to 20 membership tier keys. Only players holding one of these tiers advance the mission; empty means everyone. See Membership tiers. |
authorType | human or ai-generated, with an optional generatedAt timestamp. |
The approval state, the publication flag and the author are never taken from the body. Every
create or update stores the mission as pending and unpublished, so an approval never carries over
to terms nobody approved. A write that fails a rule is refused whole with a 422; nothing is stored.
The response is the stored mission, including approvalState, active, published and a
revision that increases on every change.
Your catalog starts with one mission provided by Tanitar, core-win-valorant, which reacts to
player:game-won for the valorant game. It appears the first time you read your catalog or send
an event; you can disable it like any other mission.
Approval
curl -X POST "$GAMIFICATION_API_URL/v1/gamification/catalog/approvals" -d '{ "missionKey": "win-three-ranked" }' \
-H "Authorization: Bearer $TANITAR_APPROVER_KEY" \
-H "Content-Type: application/json"Approval sets the mission to approved and publishes it in one step. It is refused when:
| Status | errorCode | Why |
|---|---|---|
404 | GAMIFICATION_MISSION_NOT_FOUND | No mission has this key |
409 | GAMIFICATION_AUTHOR_CANNOT_APPROVE | The approving principal is the one that last wrote the mission. With API keys, the principal is the key, so use a second key. |
409 | GAMIFICATION_MISSION_DISABLED | The mission is disabled |
Editing an approved mission returns it to pending and unpublishes it until it is approved again.
Progress players have already made is kept.
Level curve
The level curve sets how much XP each level costs. Until you author one, a default curve applies
(revision 0). Every change appends a new revision; earlier revisions stay readable because a
player's stored level records the revision it was earned under.
| Route | Scope | What it does |
|---|---|---|
GET /v1/gamification/levels/curve | gamification-catalog:author | The curve in effect, with revision, source (pinned or tenant), configured, levelCap and levels |
GET /v1/gamification/levels/curve/:revision | gamification-catalog:author | A past revision; 0 is the default curve |
PUT /v1/gamification/levels/curve | gamification-catalog:author | Replace the whole curve |
curl -X PUT "$GAMIFICATION_API_URL/v1/gamification/levels/curve" \
-H "Authorization: Bearer $TANITAR_API_KEY" \
-H "If-Match: \"3\"" \
-H "Content-Type: application/json" \
-d '{
"levels": [
{ "level": 1, "xpRequired": 100 },
{ "level": 2, "xpRequired": 250 },
{ "level": 3, "xpRequired": 500 }
],
"levelCap": null
}'xpRequiredis the XP a player must earn to leave that level.- Levels start at 1 and increase by one with no gaps; each costs more than the one before; at most
200 levels and 1,000,000 XP per level.
levelCapis optional, between 2 and the highest level the table reaches;nullremoves a cap. A breach is422 GAMIFICATION_LEVEL_CURVE_INVALID. - Once you have stored a curve,
If-Matchmust carry its current revision. A missing header is400 GAMIFICATION_PRECONDITION_REQUIRED; a stale one is409 GAMIFICATION_LEVEL_CURVE_REVISION_MISMATCH: read the curve again and retry. - A change applies forward only: levels players already hold stand, and the new curve prices their next level.
Membership-tier settings
Tier settings decide which of your membership tiers unlock the premium battle-pass track.
| Route | Scope | What it does |
|---|---|---|
GET /v1/gamification/tiers/settings | gamification-catalog:author | Read the settings |
PUT /v1/gamification/tiers/settings | gamification-catalog:author | Replace them |
The body is premiumLevelKeys: up to 20 tier keys you have published. An empty list means no tier
is premium. If you never store settings, the tiers premium and pro unlock the premium track.
Chest drop tables and the chest currency are configured with the same scope; see Seasons and chests.