Developer reference

Webhook events

Every event the UTD Stream engine sends to your backend — real payloads and guaranteed fields.

Back to developer products

Verify the signature first

Every request carries a signature keyed with your secret. Verify it before trusting any field — the payload arrives over the network, not from you.

Delivery is retried

A failed delivery is retried 3 times (2s · 4s · 8s). You can build state on these, not just confirm it.

A 4xx reply stops everything

Any 4xx cancels the retries immediately and dead-letters the event. If your backend is not ready, answer 5xx so you still get retried.

Headers

On every delivery, before you parse the body.

HeaderMeaning
X-UTD-Stream-Signaturestringsha256=<hmac> over the raw body, keyed with your callback secret. Verify it before trusting anything.
X-UTD-Stream-EventstringThe event name, so you can route without parsing the body first.
X-UTD-Stream-Attemptstring1 on the first delivery, 2..4 on retries. Use it to tell a retry from a duplicate event.
X-UTD-Stream-App-IdstringYour app id, when the project has one.

Stage and roles

Requests to come up, invitations, and who changed whose role.

stage_request

An audience member asks to come on stage.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho asked.
stage_request.json
{
  "event": "stage_request",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "48" }
}
stage_joined

A participant is put on stage — by a host, or by accepting an invitation.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho joined the stage.
participant.added_bystringWho put them there.
stage_joined.json
{
  "event": "stage_joined",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "48", "added_by": "148" }
}
stage_left

A participant leaves the stage, or a host removes them.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho left the stage.
participant.removed_bystringWho removed them. Equals identity when they left on their own.
stage_left.json
{
  "event": "stage_left",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "48", "removed_by": "148" }
}
stage_invitation_sent

A host invites someone to the stage.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho was invited.
invitation.idstringInvitation id — carried by the accept / decline / expire events.
invitation.inviter_identitystringWho sent it.
invitation.resentbooleantrue when this re-sends an invitation that was still open.
stage_invitation_sent.json
{
  "event": "stage_invitation_sent",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "48" },
  "invitation": { "id": "inv_3f2a…", "inviter_identity": "148", "resent": false }
}
stage_invitation_accepted

The invited participant accepts. A stage_joined follows.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho accepted.
invitation.idstringThe invitation this answers.
stage_invitation_accepted.json
{
  "event": "stage_invitation_accepted",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "48" },
  "invitation": { "id": "inv_3f2a…" }
}
stage_invitation_declined

The invited participant declines.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho declined.
invitation.idstringThe invitation this answers.
stage_invitation_declined.json
{
  "event": "stage_invitation_declined",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "48" },
  "invitation": { "id": "inv_3f2a…" }
}
participant_role_changed

A room owner or admin changes someone's role.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWhose role changed.
role.previousstringRole before the change.
role.currentstringRole after the change.
role.changed_bystringWho made the change.
role.reasonstringWhy. `owner` means an authorised person did it deliberately.
participant_role_changed.json
{
  "event": "participant_role_changed",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "48" },
  "role": { "previous": "audience", "current": "admin", "changed_by": "148", "reason": "owner" }
}

Seats

Who sat, who left, and which seat was locked.

seat_taken

A participant takes a seat, or is placed on one.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho is on the seat.
seat.indexnumberZero-based seat position.
seat_taken.json
{
  "event": "seat_taken",
  "room": { "name": "402", "sid": "RM_5QnMVtk5tgAs" },
  "participant": { "identity": "48" },
  "seat": { "index": 3 }
}
seat_left

A seat is vacated.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringWho left the seat.
seat.indexnumberThe seat that is now free.
seat_left.json
{
  "event": "seat_left",
  "room": { "name": "402", "sid": "RM_5QnMVtk5tgAs" },
  "participant": { "identity": "48" },
  "seat": { "index": 3 }
}
seat_locked

A host locks a seat so nobody can take it.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
seat.indexnumberThe locked seat.
seat.locked_bystringWho locked it.
seat_locked.json
{
  "event": "seat_locked",
  "room": { "name": "402", "sid": "RM_5QnMVtk5tgAs" },
  "seat": { "index": 3, "locked_by": "148" }
}
seat_unlocked

A host unlocks a seat.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
seat.indexnumberThe unlocked seat.
seat.unlocked_bystringWho unlocked it.
seat_unlocked.json
{
  "event": "seat_unlocked",
  "room": { "name": "402", "sid": "RM_5QnMVtk5tgAs" },
  "seat": { "index": 3, "unlocked_by": "148" }
}

Live broadcast

When a broadcast ends, and why.

live_ended

A live broadcast ends. `reason` says why — `host_left` means the host disconnected rather than closing it.

FieldMeaning
room.namestringYour room id, exactly as you created it.
room.sidstringThe media server's own room id. Changes if the room is recreated.
participant.identitystringThe host the broadcast belonged to.
participant.reasonstringWhy it ended. `host_left` when the host's connection dropped.
live_ended.json
{
  "event": "live_ended",
  "room": { "name": "114", "sid": "RM_Lfzv9uoLpyMs" },
  "participant": { "identity": "148", "reason": "host_left" }
}

PK battles

Battle start and end. Score updates are realtime only — the settled result arrives with pk_ended.

pk_started

A PK battle begins. Score updates are realtime only — there is no webhook per point; the settled tally arrives with pk_ended.

FieldMeaning
battle.battle_idstringBattle id. Use it to correlate with pk_ended.
battle.statusstring`active` while it runs.
battle.room_a / room_bstringThe two room ids. There is no `side_a` / `team_1` / `a` — the sides are a and b, spelled as these fields.
battle.host_a / host_bstringEach side's host identity. Never null.
battle.host_a_name / host_b_namestring | nullDisplay name, or null when unknown — never the identity substituted in.
battle.host_a_avatar / host_b_avatarstring | nullAvatar url, or null.
battle.score_a / score_bnumberPoints per side. 0 at the start.
battle.top_a / top_barrayTop three supporters per side, highest first. Always an array — [] when nobody has sent a gift, never null.
battle.duration_secondsnumberPlanned length.
battle.winnerstring | nullnull while active.
battle.end_reasonstring | nullnull while active.
battle.started_at / ends_at / ended_atstring | nullISO-8601 UTC. ended_at is null while active.
battle.metadataobject | nullWhatever you attached when creating the battle.
pk_started.json
{
  "event": "pk_started",
  "battle": {
    "battle_id": "pk_70b45421a5b7380d5b35e9a6",
    "status": "active",
    "room_a": "91",
    "host_a": "46",
    "host_a_name": "UP TO DATE",
    "host_a_avatar": null,
    "room_b": "42",
    "host_b": "48",
    "host_b_name": "RECHIL STERK",
    "host_b_avatar": null,
    "score_a": 0,
    "score_b": 0,
    "top_a": [],
    "top_b": [],
    "duration_seconds": 300,
    "winner": null,
    "end_reason": null,
    "started_at": "2026-09-22T18:35:53.000Z",
    "ends_at": "2026-09-22T18:40:53.000Z",
    "ended_at": null,
    "metadata": null
  }
}
pk_ended

The battle finishes. Same shape as pk_started, with the settled result filled in.

FieldMeaning
battle.statusstringNo longer `active`.
battle.winnerstring | nullThe winning side, or null on a draw.
battle.end_reasonstringWhy it ended — e.g. `ended_by_host`, `host_left`.
battle.ended_atstringISO-8601 UTC.
battle.score_a / score_bnumberFinal tally. This is the authoritative result.
pk_ended.json
{
  "event": "pk_ended",
  "battle": {
    "battle_id": "pk_a6dae4bb78791c0803f4724c",
    "status": "ended",
    "room_a": "91",
    "host_a": "46",
    "room_b": "42",
    "host_b": "48",
    "score_a": 0,
    "score_b": 0,
    "top_a": [],
    "top_b": [],
    "winner": null,
    "end_reason": "ended_by_host",
    "ended_at": "2026-09-22T18:35:46.000Z"
  }
}
pk_invited

One host invites another to a battle, before it starts.

FieldMeaning
battleobjectSame battle object as pk_started, with status not yet active.
pk_invited.json
{
  "event": "pk_invited",
  "battle": { "battle_id": "pk_70b4…", "status": "pending", "room_a": "91", "room_b": "42" }
}

Contributor shape in top_a and top_b

Each entry carries both vocabularies — new and legacy — with the same value. Name and avatar are null when unknown; the identity is never substituted for the name.

contributor.json
{
  "user_id": "48",
  "identity": "48",
  "user_name": "RECHIL STERK",
  "name": "RECHIL STERK",
  "user_avatar": null,
  "avatar_url": null,
  "points": 1200,
  "rank": 1
}

UTD के साथ बनाने के लिए तैयार हैं?

अपना अकाउंट बनाएँ, अपने मास्टर वॉलेट को फंड करें, और अपनी ज़रूरत की सेवाएँ चालू करें।