Dashboard
DocsTarget Live Updates for Your Subscription Bot | BotSubscription

Target Live Updates

Subscribe to the targets channel to mirror the lifecycle of your subscription bot targets — Telegram groups, Discord servers, channels, and roles — live in an admin UI. The channel emits events when targets are added, removed, renamed, enabled, or disabled.


Subscribing

No identifier is required. Subscribing returns every target event for the project the connection is authenticated against.

{ "action": "subscribe", "channel": "targets" }

The server replies with subscribed. Use action: "unsubscribe" with the same channel to stop the feed.


Events

All events arrive as named Socket.IO events with snake_case field names and the standard broadcast envelope (event_id, emitted_at).

Common fields

Every event on this channel carries these top-level fields:

FieldTypeNotes
channelstringAlways "targets".
project_idstringThe owning project.
platformstring"discord" or "telegram".

Events that carry a target object include the full snapshot below. Treat it as a complete state replacement, not a diff:

target fieldTypeNotes
target_idUUIDBotSubscription identifier.
target_namestringHuman-readable name (e.g. server or group name).
platformstring"discord" or "telegram".
kindstringguild, group, channel, or role.
external_idstringThe platform's own ID (Discord guild ID, Telegram chat ID, etc.).
is_enabledbooleanWhether the target is currently active.
parent_target_idUUID | nullFor nested targets (e.g. a channel under a guild).
plan_countinteger (optional)Number of plans attached. May be absent for some events.
participant_countinteger (optional)Number of active members. May be absent for some events.

target.added

A new target was created. Only fires for newly persisted targets — not cache rehydration.

{
  "event_id": "9b724ac8-f0e1-4b56-8d7a-2c9c0d11b2f1",
  "emitted_at": 1779836400000,
  "channel": "targets",
  "project_id": "93425026-6bb8-4f81-a75d-63f538e1a123",
  "platform": "discord",
  "target": {
    "target_id": "1f2e3d4c-5b6a-7e8f-9a0b-1c2d3e4f5a6b",
    "target_name": "My Server",
    "platform": "discord",
    "kind": "guild",
    "external_id": "123456789012345678",
    "is_enabled": true,
    "parent_target_id": null,
    "plan_count": 0,
    "participant_count": 0
  }
}

target.removed

A target was deleted. The payload identifies the target without resending the full record.

{
  "event_id": "5e2a1b0d-7c61-4d83-9f10-aa00b2c3d4e5",
  "emitted_at": 1779836400000,
  "channel": "targets",
  "project_id": "93425026-6bb8-4f81-a75d-63f538e1a123",
  "platform": "telegram",
  "target_id": "1f2e3d4c-5b6a-7e8f-9a0b-1c2d3e4f5a6b",
  "kind": "channel",
  "external_id": "-1001234567890"
}

target.enabled / target.disabled

Fires when is_enabled changes value. Both events carry the full updated target snapshot.

{
  "event_id": "uuid",
  "emitted_at": 1779836400000,
  "channel": "targets",
  "project_id": "93425026-6bb8-4f81-a75d-63f538e1a123",
  "platform": "discord",
  "target": {
    "target_id": "1f2e3d4c-5b6a-7e8f-9a0b-1c2d3e4f5a6b",
    "target_name": "My Server",
    "platform": "discord",
    "kind": "guild",
    "external_id": "123456789012345678",
    "is_enabled": false,
    "parent_target_id": null
  }
}
Note

No-op updates are suppressed. Setting is_enabled: true on an already-enabled target produces no event. Only real false → true and true → false transitions fire.

target.updated

Fires when target metadata changes without an is_enabled transition. Triggered by changes to target_name, kind, external_id, parent_target_id, plan_count, or participant_count.

{
  "event_id": "uuid",
  "emitted_at": 1779836400000,
  "channel": "targets",
  "project_id": "93425026-6bb8-4f81-a75d-63f538e1a123",
  "platform": "discord",
  "target": {
    "target_id": "1f2e3d4c-5b6a-7e8f-9a0b-1c2d3e4f5a6b",
    "target_name": "My Server (renamed)",
    "platform": "discord",
    "kind": "guild",
    "external_id": "123456789012345678",
    "is_enabled": true,
    "parent_target_id": null,
    "plan_count": 3,
    "participant_count": 142
  }
}

The target field carries the full new state — overwrite your local record from it instead of computing a diff.

Tip

Combined updates. When a single backend update changes is_enabled and other metadata in the same call, only target.enabled or target.disabled fires (with the new metadata already reflected in the target snapshot). target.updated is not emitted alongside. A client that overwrites local state from the target field on every event handles all three cases uniformly.


  1. On ready, subscribe to targets.
  2. Keep a local map keyed by target_id.
  3. On target.added, target.enabled, target.disabled, and target.updated, overwrite the entry from the target payload.
  4. On target.removed, delete the entry using target_id.
  5. After a reconnect, resubscribe and reconcile with a fresh REST fetch if you need authoritative counts.

Next steps

Last updated: