Platform

Webhooks

Three different POSTs. One inbound owner per connection — never both the gateway and your URL.

KindWho → whomYou see it?
Provisioning callbackDiscord/Slack → CaspianNo — flips connection to active
Platform webhookTelegram → Caspian or your URLOnly if self-host
Event deliveryCaspian → your appHosted: the only URL you expose

Self-host: platform → you

cx.handle(channel, body, headers) verifies signatures. A wrong secret is 401; ACK 200 before the model. Channel-specific extras live on the HTTP front, not in handle():

Repo helper: examples/serve.py.

Hosted: Caspian → you

Gateway registers the platform webhook at Caspian, ACKs in milliseconds, then POSTs a normalized core Event envelope signed with HMAC-SHA256 (X-Caspian-Signature). Execute goes to the Caspian outbox, not api.telegram.org.

cx = Caspian(api_key=KEY, webhook_secret=SECRET)
cx.handle("gateway", body, headers)
# or poll: cx.run()
const cx = new Caspian()
await cx.handle("gateway", body, headers)
// or poll: await cx.run({ apiKey: KEY })
// push URL: cx.webhooks.caspian(req) after bindHosted — X-Caspian-Signature