Docs menu
Webhooks
Flinkk Mail calls your endpoint when something happens to an email you sent. Each delivery is signed, retried on failure and listed in your delivery log.
Events
| Event | When |
|---|---|
email.sent | An email was accepted for sending. |
email.delivered | The recipient's mail server accepted it. |
email.bounced | It bounced. bounceType is Permanent, Transient or Undetermined. Permanent bounces are also added to the suppression list. |
email.complained | The recipient marked it as spam (also suppressed automatically). |
email.opened | The recipient opened it (each open is an event). |
email.clicked | The recipient clicked a link (link has the URL). |
The same endpoints can also receive agent events such as email.received and draft.pending_approval, see the agent inbox API.
Create an endpoint
curl -X POST https://mail.flinkk.io/api/v1/webhooks \
-H "Authorization: Bearer $FLINKK_API_KEY" -H "Content-Type: application/json" \
-d '{"url":"https://example.com/hooks/flinkk","events":["email.delivered","email.bounced","email.complained"]}'
# 201 { "id": "...", "secret": "whsec_..." } the secret is shown onceThe URL must be public https. You can also manage endpoints in the app under Agents, Webhooks. GET /api/v1/webhooks lists them, PATCH /api/v1/webhooks/{id} with {"enabled": false} pauses one, DELETE /api/v1/webhooks/{id} removes it, POST /api/v1/webhooks/{id}/test sends a signed ping, and GET /api/v1/webhooks/{id}/deliveries shows recent deliveries, attempts and errors.
What you receive
{
"id": "evt_Hq3...",
"type": "email.bounced",
"createdAt": "2026-11-02T10:15:02.114Z",
"data": {
"emailId": "ckx9...",
"from": "hello@yourdomain.com",
"to": "gone@example.com",
"subject": "Welcome aboard",
"occurredAt": "2026-11-02T10:15:01.000Z",
"bounceType": "Permanent",
"bounceSubType": "General"
}
}Payloads carry ids and metadata, never the message body. Use emailId with GET /api/v1/emails/{id} for the full record and timeline.
Verify the signature
Each request has Flinkk-Signature: t=<unix>,v1=<hex>, the hex HMAC-SHA256 of t + "." + the raw request body keyed with your endpoint secret, plus Flinkk-Event and Flinkk-Delivery. Verify against the raw body, compare in constant time and reject old timestamps.
import { verifyWebhook } from 'flinkk-mail';
const ok = await verifyWebhook(rawBody, req.headers['flinkk-signature'], process.env.FLINKK_WEBHOOK_SECRET!);
if (!ok) return res.status(401).end();Retries
Reply with any 2xx within 8 seconds. Otherwise Flinkk Mail retries after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 24 hours, then marks the delivery failed. Deliveries can arrive more than once, so de-duplicate on id. Redirects are not followed.
On this page: Events · Create an endpoint · What you receive · Verify the signature · Retries