Skip to content

Webhooks

Receive real-time notifications for email, contact, and domain events via HTTP webhooks. PostStack sends POST requests to your endpoint when events occur. Includes delivery tracking and replay for failed deliveries.

POST
/webhooks

Create a new webhook endpoint. Subscribe to specific events.

json
{
  "url": "https://yourdomain.com/webhooks/poststack",
  "events": [
    "email.delivered",
    "email.bounced",
    "email.complained",
    "email.opened",
    "email.clicked"
  ]
}
GET
/webhooks

List all webhook endpoints for your account.

json
{
  "webhooks": [
    {
      "id": "wh_abc123def456ghi789",
      "url": "https://yourdomain.com/webhooks/poststack",
      "events": ["email.delivered", "email.bounced"],
      "active": true,
      "created_at": "2026-03-23T10:00:00.000Z"
    }
  ]
}
GET
/webhooks/:id

Retrieve a single webhook endpoint with its configuration.

json
{
  "id": "wh_abc123def456ghi789",
  "url": "https://yourdomain.com/webhooks/poststack",
  "events": ["email.delivered", "email.bounced", "email.opened"],
  "active": true,
  "created_at": "2026-03-23T10:00:00.000Z"
}
PATCH
/webhooks/:id

Update a webhook's URL, events, or enabled status.

json
{
  "url": "https://yourdomain.com/webhooks/v2",
  "events": ["email.delivered", "email.bounced", "email.opened"],
  "enabled": true
}
DELETE
/webhooks/:id

Delete a webhook endpoint. No further events will be delivered.

json
{
  "deleted": true
}
POST
/webhooks/:id/test

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

json
{
  "success": true,
  "status_code": 200,
  "response_time_ms": 142
}
GET
/webhooks/:id/deliveries

List recent webhook delivery attempts with status, response codes, and timestamps.

json
{
  "deliveries": [
    {
      "id": 1,
      "webhook_id": 1,
      "event": "email.delivered",
      "status_code": 200,
      "success": true,
      "attempts": 1,
      "created_at": "2026-03-23T10:00:02.000Z",
      "next_attempt_at": null
    },
    {
      "id": 2,
      "webhook_id": 1,
      "event": "email.bounced",
      "status_code": 500,
      "success": false,
      "attempts": 3,
      "created_at": "2026-03-23T10:05:00.000Z",
      "next_attempt_at": "2026-03-23T11:05:00.000Z"
    }
  ],
  "pagination": {
    "total": 156,
    "page": 1,
    "per_page": 20,
    "total_pages": 8
  }
}
POST
/webhooks/:id/deliveries/:did/replay

Replay a failed webhook delivery. Sends the original event payload to your endpoint again.

json
{
  "success": true
}

Webhook Events

Subscribe to any combination of the following events:

Email Events

EventDescription
email.sentEmail has been sent to the recipient mail server
email.deliveredEmail was successfully delivered
email.bouncedEmail hard bounced (permanent failure)
email.soft_bouncedEmail soft bounced (temporary failure)
email.openedRecipient opened the email (if tracking enabled)
email.clickedRecipient clicked a link (if tracking enabled)
email.complainedRecipient marked the email as spam
email.unsubscribedRecipient clicked the unsubscribe link
email.failedEmail delivery failed
email.delivery_delayedEmail delivery was delayed
email.scheduledEmail was scheduled for future delivery
email.suppressedEmail was suppressed (recipient on suppression list)
email.inboundInbound email received on your domain

Contact Events

EventDescription
contact.createdA new contact was created
contact.updatedA contact was updated
contact.deletedA contact was deleted
contact.unsubscribedA contact unsubscribed

Domain Events

EventDescription
domain.createdA new domain was added
domain.updatedDomain settings were updated
domain.deletedA domain was removed
domain.verifiedDomain DNS verification succeeded
domain.failedDomain DNS verification failed

Webhook Payload

Each webhook delivery includes the event type, timestamp, and relevant data:

json
{
  "id": "evt_abc123def456",
  "type": "email.delivered",
  "timestamp": "2026-03-23T10:00:02.000Z",
  "data": {
    "email_id": "em_abc123def456ghi789",
    "from": "you@yourdomain.com",
    "to": "user@example.com",
    "subject": "Welcome to PostStack"
  }
}

Signature Verification

Every webhook request includes an X-PostStack-Signature header. Verify it to ensure the request came from PostStack:

typescript
import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string,
): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  const expectedSignature = `sha256=${expected}`;
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature),
  );
}

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

  if (!verifyWebhookSignature(body, signature, 'whsec_abc123...')) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the event
  const event = req.body;
  switch (event.type) {
    case 'email.delivered':
      // Handle delivery
      break;
    case 'email.bounced':
      // Handle bounce
      break;
  }

  res.status(200).json({ received: true });
});