WebhooksEvent catalogTournaments
tournament.tournament.placements-finalized
Version 1 of the tournament.tournament.placements-finalized webhook event.
A tournament completed and its final stage's placements are settled. Each placement carries the enrollment's entrant identity so an award consumer can resolve recipients without reading tournament storage: an opaque entrant's externalId is the tenant's own player identifier, while a saas principal is a customer-plane identity that the consumer must resolve explicitly rather than assume.
| Event type | tournament.tournament.placements-finalized |
| Schema version | 1 |
| Routing key | event.tournament.tournament.placements-finalized.v1 |
| Produced by | Tournament Management |
| Schema | urn:defendr:contract:tournament:tournament-placements-finalized:1 |
data fields
| Field | Type | Required | Description |
|---|---|---|---|
tournamentId | string | yes | |
organizationId | string | yes | |
revision | integer | yes | |
stageId | string or null | yes | |
completedAt | string (date-time) | yes | |
placements | array of object | yes | |
placements[].rankFrom | integer | yes | |
placements[].rankTo | integer | yes | |
placements[].rank | integer or null | yes | |
placements[].status | "provisional", "final" | yes | |
placements[].reason | "champion", "runner_up", "consolation_winner", "consolation_loser", "eliminated", "standing" | yes | |
placements[].enrollmentId | string | yes | |
placements[].entrantKey | string | yes | |
placements[].entrantType | "solo", "team" | yes | |
placements[].teamId | string or null | yes | |
placements[].entrant | object | yes | |
placements[].entrant.identityKey | string | yes | |
placements[].entrant.mode | "saas", "opaque" | yes | |
placements[].entrant.principalId | string or null | yes | |
placements[].entrant.externalId | string or null | yes | |
placements[].roster | array of values | yes | |
placements[].roster[].identityKey | string | yes | |
placements[].roster[].mode | "saas", "opaque" | yes | |
placements[].roster[].principalId | string or null | yes | |
placements[].roster[].externalId | string or null | yes | |
placements[].roster[].playerType | "main", "substitute" | yes |
Some fields are required only in particular states. The JSON Schema below is authoritative.
Example delivery
Signed with the example secret whsec_placeholder_example_webhooks_signing_secret, so you can check your verifier against it. See Verifying signatures.
POST /your/webhook/endpoint HTTP/1.1
content-type: application/json
webhook-id: whd_00000000-0000-4000-8000-000000000080
webhook-timestamp: 1800000000
webhook-signature: v1,XvONMyH1FzH6+W7sEt+RfIo1vMru+JlrEVIv0l4O15g=
tanitar-event-type: tournament.tournament.placements-finalized
tanitar-schema-version: 1
tanitar-delivery-attempt: 1
{"messageId":"evt_00000000-0000-4000-8000-000000000080","kind":"event","type":"tournament.tournament.placements-finalized","schemaVersion":1,"occurredAt":"2027-01-15T10:00:00.000Z","producer":"tournament-management-service","accountId":"acc_11111111-1111-4111-8111-111111111111","correlationId":"corr_00000000-0000-4000-8000-000000000080","data":{"tournamentId":"trn_example","organizationId":"org_example","revision":9,"stageId":"stg_final","completedAt":"2026-09-10T18:00:00.000Z","placements":[{"rankFrom":1,"rankTo":1,"rank":1,"status":"final","reason":"champion","enrollmentId":"enr_one","entrantKey":"opaque:player-one","entrantType":"solo","teamId":null,"entrant":{"identityKey":"opaque:player-one","mode":"opaque","principalId":null,"externalId":"player-one"},"roster":[]},{"rankFrom":2,"rankTo":2,"rank":2,"status":"final","reason":"runner_up","enrollmentId":"enr_two","entrantKey":"saas:prn_two","entrantType":"team","teamId":"team_two","entrant":{"identityKey":"saas:prn_two","mode":"saas","principalId":"prn_two","externalId":null},"roster":[{"identityKey":"opaque:player-three","mode":"opaque","principalId":null,"externalId":"player-three","playerType":"main"}]}]}}The same body, formatted:
{
"messageId": "evt_00000000-0000-4000-8000-000000000080",
"kind": "event",
"type": "tournament.tournament.placements-finalized",
"schemaVersion": 1,
"occurredAt": "2027-01-15T10:00:00.000Z",
"producer": "tournament-management-service",
"accountId": "acc_11111111-1111-4111-8111-111111111111",
"correlationId": "corr_00000000-0000-4000-8000-000000000080",
"data": {
"tournamentId": "trn_example",
"organizationId": "org_example",
"revision": 9,
"stageId": "stg_final",
"completedAt": "2026-09-10T18:00:00.000Z",
"placements": [
{
"rankFrom": 1,
"rankTo": 1,
"rank": 1,
"status": "final",
"reason": "champion",
"enrollmentId": "enr_one",
"entrantKey": "opaque:player-one",
"entrantType": "solo",
"teamId": null,
"entrant": {
"identityKey": "opaque:player-one",
"mode": "opaque",
"principalId": null,
"externalId": "player-one"
},
"roster": []
},
{
"rankFrom": 2,
"rankTo": 2,
"rank": 2,
"status": "final",
"reason": "runner_up",
"enrollmentId": "enr_two",
"entrantKey": "saas:prn_two",
"entrantType": "team",
"teamId": "team_two",
"entrant": {
"identityKey": "saas:prn_two",
"mode": "saas",
"principalId": "prn_two",
"externalId": null
},
"roster": [
{
"identityKey": "opaque:player-three",
"mode": "opaque",
"principalId": null,
"externalId": "player-three",
"playerType": "main"
}
]
}
]
}
}JSON Schema
urn:defendr:contract:tournament:tournament-placements-finalized:1
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "urn:defendr:contract:tournament:tournament-placements-finalized:1",
"title": "Tournament placements finalized event payload",
"description": "A tournament completed and its final stage's placements are settled. Each placement carries the enrollment's entrant identity so an award consumer can resolve recipients without reading tournament storage: an `opaque` entrant's externalId is the tenant's own player identifier, while a `saas` principal is a customer-plane identity that the consumer must resolve explicitly rather than assume.",
"type": "object",
"additionalProperties": false,
"required": [
"tournamentId",
"organizationId",
"revision",
"stageId",
"completedAt",
"placements"
],
"properties": {
"tournamentId": {
"type": "string",
"minLength": 1
},
"organizationId": {
"type": "string",
"minLength": 1
},
"revision": {
"type": "integer",
"minimum": 1
},
"stageId": {
"type": [
"string",
"null"
]
},
"completedAt": {
"type": "string",
"format": "date-time"
},
"placements": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"rankFrom",
"rankTo",
"rank",
"status",
"reason",
"enrollmentId",
"entrantKey",
"entrantType",
"teamId",
"entrant",
"roster"
],
"properties": {
"rankFrom": {
"type": "integer",
"minimum": 1
},
"rankTo": {
"type": "integer",
"minimum": 1
},
"rank": {
"type": [
"integer",
"null"
],
"minimum": 1
},
"status": {
"enum": [
"provisional",
"final"
]
},
"reason": {
"enum": [
"champion",
"runner_up",
"consolation_winner",
"consolation_loser",
"eliminated",
"standing"
]
},
"enrollmentId": {
"type": "string",
"minLength": 1
},
"entrantKey": {
"type": "string",
"minLength": 1
},
"entrantType": {
"enum": [
"solo",
"team"
]
},
"teamId": {
"type": [
"string",
"null"
]
},
"entrant": {
"$ref": "#/$defs/identity"
},
"roster": {
"type": "array",
"items": {
"$ref": "#/$defs/rosterMember"
}
}
}
}
}
},
"$defs": {
"identity": {
"type": "object",
"additionalProperties": false,
"required": [
"identityKey",
"mode",
"principalId",
"externalId"
],
"properties": {
"identityKey": {
"type": "string",
"minLength": 1
},
"mode": {
"enum": [
"saas",
"opaque"
]
},
"principalId": {
"type": [
"string",
"null"
]
},
"externalId": {
"type": [
"string",
"null"
]
}
}
},
"rosterMember": {
"type": "object",
"additionalProperties": false,
"required": [
"identityKey",
"mode",
"principalId",
"externalId",
"playerType"
],
"properties": {
"identityKey": {
"type": "string",
"minLength": 1
},
"mode": {
"enum": [
"saas",
"opaque"
]
},
"principalId": {
"type": [
"string",
"null"
]
},
"externalId": {
"type": [
"string",
"null"
]
},
"playerType": {
"enum": [
"main",
"substitute"
]
}
}
}
}
}