Dashboard

Webhooks

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

EventSent when
email.sentThe email leaves Inboxjot.
email.deliveredThe receiving server accepts the email.
email.delivery_delayedDelivery is delayed and will retry.
email.openedThe recipient opens the email.
email.clickedThe recipient clicks a link.
email.bouncedThe email bounces.
email.complainedThe recipient marks the email as spam.
email.rejectedThe email is rejected before delivery.
email.failedThe email cannot be sent.
email.unsubscribedThe recipient unsubscribes.
contact.createdA contact is created.
contact.updatedA contact changes.
contact.deletedA 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.