TANITARDevelopers
GuidesGamification

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:

  1. Register an event in the event registry and publish it (gamification-config:mutate).
  2. Author a mission that reacts to that event (gamification-catalog:author).
  3. 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.

RouteScopeWhat it does
POST /v1/gamification/event-registrygamification-config:mutateRegister an event, or replace an existing one with the same eventKey
GET /v1/gamification/event-registrygamification-catalog:authorList your events, sorted by eventKey (no pagination)
GET /v1/gamification/event-registry/:eventKeygamification-catalog:authorRead one event
POST /v1/gamification/event-registry/:eventKey/archivegamification-config:mutateArchive an event
DELETE /v1/gamification/event-registry/:eventKeygamification-config:mutateDelete 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"] }
    ]
  }'
FieldRules
eventKeynamespace: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).
statusdraft or published. Only a published event can be referenced by a mission or ingested.
fields[].fieldStarts with a lowercase letter, then letters and digits. A name owned by the platform vocabulary (below) is refused with 409 GAMIFICATION_FIELD_RESERVED.
fields[].primitiveTypestring, number or boolean.
fields[].allowedOperatorsAny of eq, neq, gt, gte, lt, lte, in.
fields[].requiredWhether 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:

FieldTypeOperatorsMeaning
sourcestringeq, neq, in, notInThe cause of the activity, from Tanitar's closed provenance list
streakCountnumbereq, gt, gte, lt, lteA streak length
levelKeystringeq, inA membership tier key you have published
currencyKeystringeq, inA currency key you have published
gameSlugstringeq, inA game from the Tanitar game registry
teamIdstringeq, inThe 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

RouteScopeWhat it does
POST /v1/gamification/catalog/missionsgamification-catalog:authorCreate a mission, or replace the one with the same missionKey
PATCH /v1/gamification/catalog/missions/:missionKeygamification-catalog:authorReplace a mission; send the full definition
GET /v1/gamification/catalog/missionsgamification-catalog:authorList every mission, sorted by missionKey (no pagination)
GET /v1/gamification/catalog/missions/:missionKeygamification-catalog:authorRead one mission
POST /v1/gamification/catalog/missions/:missionKey/disablegamification-catalog:authorUnpublish and deactivate a mission, keeping player progress
POST /v1/gamification/catalog/approvalsgamification-catalog:approveApprove 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"
  }'
FieldRules
missionKeyLowercase letters, digits and hyphens.
eventKeyA 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.
cadenceone-time (once ever), daily (once per UTC day), weekly (once per UTC week, starting Monday) or special (up to maxOccurrences times, no period).
targetCountHow many matching events complete the mission; at least 1.
maxOccurrencesRequired for special, refused for every other cadence (422 GAMIFICATION_CADENCE_INVALID).
startsAt, endsAtOptional ISO 8601 window; endsAt must be after startsAt.
allowedLevelKeysOptional, up to 20 membership tier keys. Only players holding one of these tiers advance the mission; empty means everyone. See Membership tiers.
authorTypehuman 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:

StatuserrorCodeWhy
404GAMIFICATION_MISSION_NOT_FOUNDNo mission has this key
409GAMIFICATION_AUTHOR_CANNOT_APPROVEThe approving principal is the one that last wrote the mission. With API keys, the principal is the key, so use a second key.
409GAMIFICATION_MISSION_DISABLEDThe 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.

RouteScopeWhat it does
GET /v1/gamification/levels/curvegamification-catalog:authorThe curve in effect, with revision, source (pinned or tenant), configured, levelCap and levels
GET /v1/gamification/levels/curve/:revisiongamification-catalog:authorA past revision; 0 is the default curve
PUT /v1/gamification/levels/curvegamification-catalog:authorReplace 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
  }'
  • xpRequired is 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. levelCap is optional, between 2 and the highest level the table reaches; null removes a cap. A breach is 422 GAMIFICATION_LEVEL_CURVE_INVALID.
  • Once you have stored a curve, If-Match must carry its current revision. A missing header is 400 GAMIFICATION_PRECONDITION_REQUIRED; a stale one is 409 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.

RouteScopeWhat it does
GET /v1/gamification/tiers/settingsgamification-catalog:authorRead the settings
PUT /v1/gamification/tiers/settingsgamification-catalog:authorReplace 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.

On this page