Event ingestion
Send player activity to Tanitar as events, idempotently, and read what each event advanced.
Your backend reports player activity by sending one event per occurrence. Each event names one player and carries a payload that matches the event's declaration in your event registry.
| Route | Scope | Idempotency |
|---|---|---|
POST /v1/gamification/events | gamification-events:ingest | Idempotency-Key required |
Send an event
With match-won.json holding the event:
{
"eventKey": "match:won",
"playerId": "player-2231",
"payload": { "mode": "ranked", "kills": 14, "teamId": "team-orange" }
}curl -X POST "$GAMIFICATION_API_URL/v1/gamification/events" --data @match-won.json \
-H "Authorization: Bearer $TANITAR_API_KEY" \
-H "Idempotency-Key: match-8841-player-2231" \
-H "Content-Type: application/json"| Field | Rules |
|---|---|
eventKey | A published event in your registry, or a built-in event such as player:game-won. An unknown, draft or archived event is 422 GAMIFICATION_EVENT_NOT_ADMISSIBLE. |
playerId | Your identifier for the player, 1 to 200 characters. Tanitar does not look the player up; it advances progress for exactly the player you name, within your tenant. |
payload | An object. Every key must be a field the event declares or a platform field, with the declared type, and every required field must be present. Otherwise 422 GAMIFICATION_EVENT_PAYLOAD_INVALID and nothing is recorded. |
Include teamId in the payload when the activity belongs to a team; it is what places the
player's mission XP on the team leaderboard.
Idempotency
Use an Idempotency-Key that identifies the real-world occurrence, such as a match id plus a player
id, rather than a random value per attempt. The key is 1 to 256 characters from letters, digits,
., _, : and -.
Two layers protect you from double counting:
- The request layer. A retry with the same key and the same body returns the original
response. The same key with a different body is
409 ACCESS_REPLAYED; a retry while the first request is still running is409 ACCESS_IDEMPOTENCY_IN_PROGRESS. See Idempotency. - The event record. Tanitar stores each event durably under (
eventKey,playerId,Idempotency-Key). Sending that event again later, whether after the request layer has forgotten the key or from your own queue's redelivery, answers with the outcome already recorded and"duplicate": true, and advances nothing twice.
The response
{
"admitted": true,
"eventKey": "match:won",
"duplicate": false,
"outcomes": [
{
"missionKey": "win-three-ranked",
"missionRevision": 2,
"currentCount": 3,
"requiredCount": 3,
"status": "completed",
"completed": true
}
],
"ineligible": [
{ "missionKey": "gold-weekly-grind", "missionRevision": 1, "reason": "MISSION_TIER_NOT_ELIGIBLE" }
]
}outcomeslists every mission the event advanced, with the player's count after this event.completed: truemeans this event completed the mission.ineligiblelists missions whose conditions matched but that the player may not advance because the mission is restricted to membership tiers:MISSION_TIER_NOT_ELIGIBLEwhen the player does not hold one of them,MISSION_ELIGIBILITY_UNRESOLVEDwhen the tier registry could not be read (unknown is treated as not eligible). A duplicate answers with the stored outcomes and an emptyineligiblelist.- A mission whose conditions do not hold, that is disabled or unpublished, outside its
startsAt/endsAtwindow, or already completed for the current period, does not appear.
What happens after ingestion
Everything below happens in one transaction with the ingestion itself. If any step fails, nothing is recorded, and you can resend the same event with the same key.
- The event is stored against the player for 90 days, so it can be replayed later.
- Each matching mission's progress for the current period is advanced by one. A
gamification.progress.updatedevent is published per mission. - A mission that reaches
targetCountcompletes exactly once, however many events race for it. Its rewards are paid as described in How mission rewards settle. XP may raise the player's level (gamification.xp.granted), and the first completion of a UTC day advances the streak (gamification.streak.advanced). - If the active battle-pass season awards flat battle-pass XP for this event, it is added once per event.
Periods are UTC. When a daily or weekly period ends, unfinished progress for it becomes expired
and the next event starts a fresh count.
Subscribe to these events with a webhook endpoint; the payloads are in the event catalog.
Errors
| Status | errorCode | Meaning |
|---|---|---|
400 | (validation) | The body does not have the shape above |
400 | ACCESS_IDEMPOTENCY_REQUIRED / ACCESS_IDEMPOTENCY_INVALID | Idempotency-Key is missing or malformed |
409 | ACCESS_REPLAYED / ACCESS_IDEMPOTENCY_IN_PROGRESS | The key was used with a different body, or the first request is still running |
422 | GAMIFICATION_EVENT_NOT_ADMISSIBLE | The event is not published and not built in |
422 | GAMIFICATION_EVENT_PAYLOAD_INVALID | A payload field is undeclared, has the wrong type, or a required field is missing |
All errors use the shared envelope; see Errors. Ingestion is in the
mutation rate class; see Rate limits.
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.
Progress, XP and levels
Read a player's level, XP, streak and mission progress, and replay retained history after publishing a mission.