Webhooks

Receive real-time HTTP notifications about email delivery events. Configure webhook endpoints per message stream to track deliveries, bounces, opens, and more.


Event Types

When creating a webhook, specify which events you want to receive. Use * to subscribe to all events.

EventDescription
sentThe SMTP relay accepted the message for delivery
deliveredRecipient mail server accepted the message
bouncedHard or soft bounce from recipient server
complainedRecipient marked the email as spam
rejectedRejected by the SMTP relay or suppressed before sending
failedSend attempt failed after all retries exhausted
openedRecipient opened the email
clickedRecipient clicked a link in the email
*Wildcard - receive all event types

Create a Webhook

POSThttps://api.postject.com/v1/webhooks/:streamId

Register a webhook URL to receive events for a specific message stream. Requires JWT Bearer authentication.

Request Body

urlstring (required)

The HTTPS endpoint URL that will receive webhook payloads.

eventsstring[] (required)

Array of event types to subscribe to. Use ["*"] for all events.

json
{
  "url": "https://yourapp.com/webhooks/postject",
  "events": ["delivered", "bounced", "complained"]
}

Webhook Payload

When an event occurs, Postject sends a POST request to your webhook URL with the following JSON body:

json
{
  "id": "msg_01hy4z9k2m...",
  "type": "delivered",
  "to": "user@example.com",
  "subject": "Welcome aboard!",
  "metadata": {},
  "timestamp": "2024-01-15T10:30:00.000Z"
}

Signature Verification

All webhook requests include an HMAC-SHA256 signature in the X-Postject-Signature header to verify authenticity and prevent tampering.

Getting Your Webhook Secret

When you create a webhook, the response includes a unique secret. Store this securely . you'll need it to verify webhook signatures.

json
{
  "id": "wh_abc123",
  "url": "https://yourapp.com/webhooks/postject",
  "events": ["delivered", "bounced"],
  "secret": "whsec_a3f7d9e2c1b8a4f6e8d3c9b7a5f1e3d2",
  "createdAt": "2025-07-15T10:30:00.000Z"
}

Verifying Signatures

Compute an HMAC-SHA256 digest of the raw request body using your webhook secret, then compare it to the signature header:

javascript
import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(JSON.stringify(payload));
  const expectedSignature = `sha256=${hmac.digest('hex')}`;

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler:
app.post('/webhooks/postject', (req, res) => {
  const signature = req.headers['x-postject-signature'];
  const isValid = verifyWebhookSignature(
    req.body,
    signature,
    'whsec_your_secret_here'
  );

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  // Process webhook event
  console.log('Event:', req.body.type);
  res.status(200).send('OK');
});

Security Note

Always verify webhook signatures before processing events. This prevents attackers from sending forged webhook requests to your endpoint.


Retry Policy

If your webhook endpoint returns a non-2xx HTTP status or times out, Postject automatically retries delivery with exponential backoff up to 8 times over 30 days.

Retry Schedule

AttemptDelayTotal Time Since First Attempt
1Immediate.
21 minute1 min
35 minutes6 min
430 minutes36 min
52 hours~3 hours
612 hours~15 hours
71 day~2 days
83 days~5 days

After 8 failed attempts, the webhook delivery is marked as permanently failed and logged. You can view failed deliveries in the webhook logs.

Request Timeout

Each webhook request has a 10 second timeout. If your endpoint doesn't respond within this window, the delivery is considered failed and will be retried according to the schedule above.


Delivery Logs

View detailed logs of all webhook delivery attempts, including successful deliveries, failures, and retry history.

GEThttps://api.postject.com/v1/webhooks/:webhookId/logs

Query Parameters

limitnumber (optional)

Number of logs to return (max 1000, default 100)

offsetnumber (optional)

Pagination offset

json
{
  "logs": [
    {
      "id": "log_xyz789",
      "webhookId": "wh_abc123",
      "eventType": "delivered",
      "status": "success",
      "statusCode": 200,
      "attempt": 1,
      "response": "OK",
      "duration": 145,
      "createdAt": "2025-07-15T10:30:00.000Z",
      "nextRetry": null
    },
    {
      "id": "log_def456",
      "webhookId": "wh_abc123",
      "eventType": "bounced",
      "status": "failed",
      "statusCode": 500,
      "attempt": 3,
      "response": "Internal Server Error",
      "duration": 10000,
      "createdAt": "2025-07-15T09:15:00.000Z",
      "nextRetry": "2025-07-15T09:45:00.000Z"
    }
  ],
  "total": 1234
}

Test a Webhook

Send a test event to verify your webhook endpoint is working correctly.

POSThttps://api.postject.com/v1/webhooks/:webhookId/test

This sends a test delivered event to your webhook URL with sample data. The response includes the HTTP status code and response body from your endpoint.

json
{
  "success": true,
  "statusCode": 200,
  "response": "OK",
  "duration": 123
}

List Webhooks

GEThttps://api.postject.com/v1/webhooks/:streamId

Returns all registered webhooks for a given stream. Requires JWT Bearer authentication.


Delete a Webhook

DELETEhttps://api.postject.com/v1/webhooks/:streamId/:id

Permanently removes a webhook. Events will no longer be sent to the registered URL. Requires JWT Bearer authentication.