Room webhooks
Rooms speak both directions: an incoming webhook lets another system post into a room, and an outgoing one forwards what is said to a URL you control.
Incoming webhooks
Section titled “Incoming webhooks”An incoming webhook lets a script post a message into a room — CI results, deploy notifications, alerts.
Create one on the room’s Settings → Webhooks tab: give the key a name (that’s the name messages will display under) and it’s created immediately. Each key gets its own page with the full key (masked until you press Reveal), the ingest URL, a ready-made curl example, and buttons to rotate, disable, or delete it.
curl -X POST \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: my-unique-id-001' \ -d '{"body": "hello from a script", "sender": "my-bot"}' \ https://vroxy.ai/wh/in/YOUR_KEYRequest fields:
| Field | Meaning |
|---|---|
body |
The message text — markdown and @-mentions work. Required. Slack-style text is accepted as an alias; body wins if you send both. |
sender |
Per-request display-name override, up to 120 characters (aliases: name, username). Falls back to the key’s name, then the key creator’s account name. |
room |
Post into a different room by its id (aliases: room_hashid, channel). Only rooms the key’s creator has joined and can see — never a DM. |
idempotency_key |
Retry-safe deduplication, up to 255 characters. A replay answers 200 with the original message id instead of posting a duplicate. The Idempotency-Key header wins over the field. |
Responses: 201 with {"message_id": "…"} on success, 404 for an unknown, disabled, or deleted key (all three answer identically, so the key’s existence never leaks), 422 for a missing or over-long body, and 429 when rate-limited — 60 posts per minute per key by default.
Things to know:
- The path token is the authentication. There are no headers to set and no CSRF token. Treat the URL like a password: anyone holding it can post into that room.
- Permissions resolve against the seat of the person who created the key, so if they leave the room (or the workspace) their keys stop working.
- Webhook messages display under the key’s name with a 🔗 badge, and notify everyone in the room — including the key’s creator.
- Rotate mints a fresh key and the old one stops working immediately.
Outgoing webhooks
Section titled “Outgoing webhooks”An outgoing webhook POSTs every member-posted message in the room to a URL of yours. Add one on the same Settings → Webhooks tab.
The body is JSON:
{ "event": "message_created", "room": { … }, "message": { … } }and it carries a signature header computed over the raw request body with the hook’s signing secret:
X-Vroxy-Signature: sha256=<HMAC-SHA256 of the body>Verify it before trusting the payload. The webhook’s page shows the secret (masked until revealed), the payload shape, and a Ruby verification snippet.
Two behaviors to plan around:
- Loop guard. Messages that arrived via an incoming webhook are never fanned out to outgoing webhooks. Without that, an incoming hook feeding an outgoing hook that posts back is a message storm.
- Auto-disable. A hook that fails 20 times in a row disables itself, so a dead endpoint doesn’t burn a delivery attempt per message forever. The room’s webhook list shows the consecutive-failure count; fix the endpoint and re-enable it.