Skip to main content

Available Events

EventDescription
email.sentEmail was sent to the recipient
email.deliveredEmail was delivered to inbox
email.openedRecipient opened the email
email.clickedRecipient clicked a link
email.bouncedEmail bounced (hard or soft)
email.complainedRecipient marked as spam
email.failedEmail failed to send

Create a Webhook

POST/v1/webhooks

Request Body

url
string
required
HTTPS endpoint URL
events
string[]
required
Events to subscribe to (min: 1)
cURL
curl -X POST https://www.unosend.co/api/v1/webhooks \
  -H "Authorization: Bearer un_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourdomain.com/webhooks/unosend",
    "events": ["email.delivered", "email.opened", "email.clicked", "email.bounced"]
  }'

Response

201 Created
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://yourdomain.com/webhooks/unosend",
  "events": ["email.delivered", "email.opened", "email.clicked", "email.bounced"],
  "secret": "whsec_xxxxxxxxxxxxxxxxxxxx",
  "enabled": true,
  "created_at": "2024-01-15T10:30:00.000Z"
}
Important: The signing secret is only returned once during creation. Store it securely to verify webhook signatures.

List Webhooks

GET/v1/webhooks
cURL
curl https://www.unosend.co/api/v1/webhooks \
  -H "Authorization: Bearer un_your_api_key"

Response

200 OK
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "url": "https://yourdomain.com/webhooks/unosend",
      "events": ["email.delivered", "email.opened", "email.clicked", "email.bounced"],
      "enabled": true,
      "created_at": "2024-01-15T10:30:00.000Z"
    }
  ]
}

Webhook Payload

Webhooks are sent as HTTP POST requests with a JSON payload:
Webhook Payload
{
  "id": "evt_xxxxxxxxxxxxxxxx",
  "type": "email.delivered",
  "created_at": "2024-01-15T10:30:00.000Z",
  "data": {
    "email_id": "550e8400-e29b-41d4-a716-446655440000",
    "from": "[email protected]",
    "to": "[email protected]",
    "subject": "Welcome to Unosend",
    "timestamp": "2024-01-15T10:30:00.000Z"
  }
}

Verify Webhook Signature

Verify the webhook signature to ensure it came from Unosend. The signature is in the X-Unosend-Signature header.
Node.js
import crypto from 'crypto';

function verifyWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
app.post('/webhooks/unosend', (req, res) => {
  const signature = req.headers['x-unosend-signature'];
  const isValid = verifyWebhook(
    JSON.stringify(req.body),
    signature,
    process.env.WEBHOOK_SECRET
  );
  
  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process the webhook
  const { type, data } = req.body;
  console.log('Received:', type, data);
  
  res.status(200).send('OK');
});

Delete Webhook

DELETE/v1/webhooks/:id
cURL
curl -X DELETE https://www.unosend.co/api/v1/webhooks/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer un_your_api_key"