Register a webhook
curl -X POST https://api.torpedo.co.mz/api/v1/webhooks \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://myapp.com/webhooks/torpedo",
"events": ["email.delivered", "email.bounced", "email.complained", "email.failed"]
}'
The response includes a signingSecret — save it immediately, it is returned once only.
Available events
| Event | When it fires |
|---|
email.delivered | AWS SES confirmed delivery to the recipient’s inbox |
email.bounced | Email bounced — hard bounces are suppressed automatically |
email.complained | Recipient marked the email as spam |
email.failed | Delivery failed after retries |
domain.verified | Domain DNS records verified successfully |
domain.failed | Domain verification failed |
Event payload shape
All events share this envelope:
{
"event": "email.delivered",
"data": {
"id": "01960000-0000-0000-0000-000000000000",
"workspaceId": "...",
"to": "user@example.com",
"from": "hello@myapp.com",
"subject": "Welcome",
"status": "delivered",
"deliveredAt": "2026-04-15T10:00:00.000Z"
}
}
Verifying the signature
Every request from Torpedo includes an X-Signature header:
X-Signature: sha256=a3f2c1d8...
Verify it to confirm the request is genuine:
import { createHmac, timingSafeEqual } from 'crypto'
function verifySignature(rawBody, signature, secret) {
const expected = 'sha256=' + createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}
// Express example
app.post('/webhooks/torpedo', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-signature']
if (!verifySignature(req.body, sig, process.env.TORPEDO_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
const { event, data } = JSON.parse(req.body)
res.status(200).send('ok')
})
Always verify the signature before processing webhook payloads. Use timing-safe comparison
(timingSafeEqual, hmac.Equal, CryptographicOperations.FixedTimeEquals) to prevent timing
attacks — never use plain string equality.
Delivery retries
Torpedo retries failed webhook deliveries with exponential backoff. Your endpoint should:
- Return
2xx within 5 seconds
- Be idempotent — the same event may be delivered more than once
View delivery history via GET /api/v1/webhooks/{id}/deliveries.