مرجع المطوّرين

أحداث الويب‌هوك

كل حدث يبعته محرّك UTD Stream لباكندك — بحمولته الحقيقية وحقوله المضمونة.

رجوع لمنتجات المطوّرين

تحقّق من التوقيع أولاً

كل طلب بيحمل توقيعًا بسرّك. تحقّق منه قبل ما تثق في أي حقل — الحمولة جاية من الشبكة، مش من عندك.

التسليم مضمون بإعادة محاولة

فشل التسليم بيتعاد 3 مرات (2s · 4s · 8s). يعني تقدر تبني عليها حالة، مش تأكيدًا بس.

ردّك بـ4xx بيوقف كل شيء

أي رد 4xx بيلغي إعادة المحاولة فورًا ويروح الحدث للرسائل الميتة. لو باكندك مش جاهز، ردّ 5xx عشان تاخد إعادة محاولة.

الترويسات

على كل تسليم، من غير ما تفتح الحمولة.

الترويسةالمعنى
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_request

An audience member asks to come on stage.

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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" }
}

المقاعد

من قعد، من قام، وأي مقعد اتقفل.

seat_taken

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

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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_ended

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

الحقلالمعنى
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

بداية المعركة ونهايتها. تحديثات النقاط لحظية بلا ويب‌هوك — النتيجة المعتمدة بتيجي مع 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.

الحقلالمعنى
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.

الحقلالمعنى
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.

الحقلالمعنى
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" }
}

شكل الداعم في top_a و top_b

كل عنصر بيحمل المفردتين — الجديدة والقديمة — بنفس القيمة. الاسم والأفاتار بيبقوا null لما يكونوا مجهولين، والمعرّف عمره ما بيتحط مكان الاسم.

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؟

أنشئ حسابك، اشحن محفظتك الأم، وشغّل الخدمات التي تحتاجها.