A webhook sends a POST request to your server when something happens to an email or a contact. Use it to update your own records without polling the API.
Add an Endpoint
Open Webhooks and click Add Endpoint. Enter a name, an HTTPS URL and the events to send. Your server must answer with a 2xx status within 10 seconds. Send Test Event on the endpoint page checks your setup.
Event Types
| Event | Sent when |
|---|---|
| email.sent | The email leaves Inboxjot. |
| email.delivered | The receiving server accepts the email. |
| email.delivery_delayed | Delivery is delayed and will retry. |
| email.opened | The recipient opens the email. |
| email.clicked | The recipient clicks a link. |
| email.bounced | The email bounces. |
| email.complained | The recipient marks the email as spam. |
| email.rejected | The email is rejected before delivery. |
| email.failed | The email cannot be sent. |
| email.unsubscribed | The recipient unsubscribes. |
| contact.created | A contact is created. |
| contact.updated | A contact changes. |
| contact.deleted | A contact is deleted. |
Payload
Every request has a JSON body with the event id, type, time and data. Email events can also carry tags, the clicked link and bounce or complaint details.
{ "id": "evt_…", "type": "email.delivered", "created_at": "2026-10-17T09:30:00.000Z", "data": { "email_id": "eml_…", "to": ["riti@example.com"], "from": "Acme <hello@send.acme.dev>", "subject": "Your receipt from Acme" } }
Verify Signatures
Requests follow the Standard Webhooks spec. Each one has the webhook-id, webhook-timestamp and webhook-signature headers. Sign id.timestamp.body with HMAC-SHA256 and the signing secret, then compare the result with the signature.
import { verifyWebhook } from 'inboxjot'; export async function POST(request) { const event = await verifyWebhook({ payload: await request.text(), headers: request.headers, secret: process.env.INBOXJOT_WEBHOOK_SECRET, }); if (event.type === 'email.bounced') { console.log(event.data.email_id, event.data.bounce.type); } return new Response(null, { status: 204 }); }
Use the raw request body. Parsing and encoding the JSON again changes the bytes and breaks the signature.
Retries
A failed delivery retries 5 times, after 1 minute, 10 minutes, 1 hour, 6 hours and 16 hours. The webhook-id stays the same, so you can skip events you already handled.
If the last retry fails and the endpoint had no successful delivery in the last 24 hours, Inboxjot turns the endpoint off. The Event Log lists every delivery, and Replay Event sends one again.