Platform
Webhooks
Three different POSTs. One inbound owner per connection — never both the gateway and your URL.
| Kind | Who → whom | You see it? |
|---|---|---|
| Provisioning callback | Discord/Slack → Caspian | No — flips connection to active |
| Platform webhook | Telegram → Caspian or your URL | Only if self-host |
| Event delivery | Caspian → your app | Hosted: 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():
- Meta (WhatsApp, Messenger): GET subscribe challenge
- X: GET
crc_token - Voice: TwiML
text/xmlresponse
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