Skip to content
Guides

Webhooks & signatures

Signed delivery, bounce and incoming events.

Register

An owner/admin can register five active endpoints per workspace. Public HTTPS port 443 is required; private destinations and redirects are blocked. Store the returned secret immediately.

Example
inboxit webhooks create --url https://yourbrand.com/hooks/inboxit --events email.delivered,email.bounced,email.received

Payloads

Envelope: id, type, created_at, workspace_id, data. Native delivery/bounce data: email_id, message_id, from, to, provider_status. Incoming data: inbox_id, uid, uid_validity, address, message_id. Fetch message bodies separately.

Example
{"id":"EVENT_UUID","type":"email.received","created_at":"2026-10-23T12:00:00Z","workspace_id":"WORKSPACE_UUID","data":{"inbox_id":"INBOX_UUID","uid":"42","uid_validity":"123456","address":"hello@mail.yourbrand.com","message_id":"<reply@example.com>"}}

Verify signatures

Use the unmodified raw request Buffer before parsing JSON. Headers: webhook-id, webhook-timestamp, webhook-signature. Sign id.timestamp.rawBody with HMAC-SHA256 using the secret as a UTF-8 string. Enforce a five-minute window, then persist/deduplicate event IDs.

Example
import {createHmac, timingSafeEqual} from 'node:crypto';



export function verify(rawBody, headers, secret) {



  const id = headers['webhook-id'];



  const time = headers['webhook-timestamp'];



  const signature = headers['webhook-signature'];



  if (!id || !/^\d+$/.test(time || '') || !signature) return false;



  if (Math.abs(Date.now() / 1000 - Number(time)) > 300) return false;



  const hex = createHmac('sha256', secret)



    .update(id + '.' + time + '.').update(rawBody).digest('hex');



  const expected = Buffer.from('v1=' + hex);



  const actual = Buffer.from(signature);



  return actual.length === expected.length && timingSafeEqual(actual, expected);



}



// After verification: persist/deduplicate event.id, enqueue work, return 2xx.

Retries

At-least-once delivery: non-2xx/network failures retry up to eight total attempts, exponential delays from 30 seconds capped at one hour. IDs stay stable; ordering is not guaranteed. Acknowledge only after durable acceptance. GET /webhooks includes the latest 100 delivery records.

Example
inboxit webhooks list
inboxit webhooks retry --id DELIVERY_UUID

Disable and rotate

DELETE disables an endpoint and cancels queued deliveries; an in-flight request may arrive. No update/rotation endpoint exists. Create a replacement, configure its secret, then disable the old endpoint. Deduplicate during overlap.