Webhooks
Webhooks send workspace events to an HTTPS endpoint you host, as they happen. Workspace owners manage endpoints in the app under Settings → Webhooks: add a URL, copy the signing secret (it’s shown once), and events start arriving.
Managing endpoints through the API
Section titled “Managing endpoints through the API”Software can manage endpoints too, with a credential that has the
workspace.webhooks:write scope. Reading them needs
workspace.webhooks:read, and a personal access token must also belong
to a workspace owner.
curl -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/hooks" }' \ https://api.reminix.com/v1/workspace/webhook-endpointsThe response includes the endpoint’s signing secret, once. The API can also list endpoints, re-enable one that we switched off after repeated failures, send a test event, and list and redeliver deliveries. See the API reference.
AI agents connected to the workspace can read endpoints and delivery history, send test events and redeliver. They can’t add, remove or re-enable endpoints, because that changes where your workspace’s data goes, so a person does it.
A delivery
Section titled “A delivery”Each delivery is an HTTP POST with a JSON body:
{ "id": "evt_5f0c…", "type": "workspace.member.joined", "createdAt": "2026-08-20T12:00:00.000Z", "data": { "userId": "…", "email": "casey@example.com" }}and three signature headers:
webhook-id: del_9a1b…webhook-timestamp: 1755691200webhook-signature: v1,MEQCIB…webhook-id identifies the delivery, and stays the same when it’s
retried, so use it to ignore duplicates. The id in the body identifies
the event. If you have several endpoints, each gets its own delivery of
the same event; to process an event once across endpoints, deduplicate
by its id. An event can occasionally reach you more than once as
separate deliveries, for example when we resend it after an outage. It
keeps the same id each time, so deduplicating by id covers that too.
Verifying signatures
Section titled “Verifying signatures”We sign deliveries with your endpoint’s secret (whsec_…) in the same way as Svix,
so any standard Svix library can verify them:
import { Webhook } from "svix";
const wh = new Webhook(process.env.WEBHOOK_SECRET);
// Express-style handler; `payload` must be the RAW request body string.app.post("/webhooks", (req, res) => { let event; try { event = wh.verify(req.body, req.headers); } catch { return res.status(400).send("bad signature"); } // handle event… res.status(200).send("ok");});To verify by hand: the signature is v1, followed by a Base64
HMAC-SHA256 of `${webhookId}.${timestamp}.${body}`, keyed with the
secret after its whsec_ prefix, Base64-decoded. Always verify the
raw body, because re-serialising the JSON changes it and breaks the
signature. Reject timestamps more than a few minutes old, so nobody can replay an old delivery.
Respond quickly, process later
Section titled “Respond quickly, process later”Answer with a 2xx within 10 seconds. If processing takes longer,
acknowledge first and do the work afterwards, because a timeout counts
as a failed delivery.
Retries and failures
Section titled “Retries and failures”We retry a failed delivery (anything but a 2xx, or a timeout) automatically, with backoff, up to 6 attempts, with the same
webhook-id. If an endpoint fails 20 deliveries in a row, we switch it off. Once your endpoint is working again, delete it and add it back,
which gives it a new secret.
Under Settings → Webhooks → Deliveries you can see each delivery’s
status and attempts, send a test event (type: "ping"), and redeliver
any recorded delivery. A redelivery has a new webhook-id but the same
event id, so deduplicating by event still works.
Events
Section titled “Events”| Type | Sent when | data |
|---|---|---|
workspace.member.joined |
Someone accepts an invitation. | userId, email |
ping |
You send a test from Settings. | a test message |
Event payloads only ever gain fields, so write parsers that ignore
fields they don’t know. GET /v1/workspace/event-types lists every
event type and what it means.
Choosing events
Section titled “Choosing events”An endpoint receives every event unless you choose otherwise. In
Settings → Webhooks, pick “Only these” when you add it, or pass
eventTypes when you create it through the API:
curl -X POST https://api.reminix.com/v1/workspace/webhook-endpoints \ -H "Authorization: Bearer YOUR_API_KEY" -H "content-type: application/json" \ -d '{"url":"https://example.com/hooks","eventTypes":["workspace.member.joined"]}'A test event (ping) always reaches the endpoint you’re testing.