Webhooks
Register an endpoint and SendByte POSTs every email lifecycle event to it, signed so you can prove it came from us.
Register an endpoint
curl -X POST https://api.sendbyte.africa/v1/webhooks \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{"url": "https://yourapp.ng/hooks/sendbyte", "events": ["email.delivered", "email.bounced"]}'Omit events to receive everything. The response contains your signing secret (whsec_...), shown exactly once.
Payload shape
{ "type": "email.delivered", "created_at": "2026-06-13T09:14:07Z", "data": { "email_id": "em_8f2a91c4", "smtp_response": "250 2.0.0 OK" }}Verify signatures (always)
Every request carries a sendbyte-signature header: t=<unix seconds>,v1=<hex hmac-sha256> over "<t>.<raw body>". The timestamp blocks replay attacks; verification uses a constant-time comparison. All SDKs ship a verifier:
import { verifyWebhookSignature } from '@sendbyte/node';
app.post('/hooks/sendbyte', (req, res) => { if (!verifyWebhookSignature(secret, req.headers['sendbyte-signature'], req.rawBody)) { return res.status(401).end(); } // handle the event});from sendbyte import verify_webhook_signature
if not verify_webhook_signature(secret, request.headers.get("sendbyte-signature"), request.body): return Response(status=401)use SendByte\SendByte;
if (!SendByte::verifyWebhookSignature($secret, $_SERVER['HTTP_SENDBYTE_SIGNATURE'] ?? null, $rawBody)) { http_response_code(401); exit;}Retries
Failed deliveries (non-2xx or timeout) retry with exponential backoff for roughly 72 hours. Every attempt (status code, latency, error) is visible in the dashboard, and any delivery can be replayed with one click or via POST /v1/webhooks/deliveries/{id}/replay.
Event types
email.sent · email.delivered · email.opened · email.clicked · email.bounced · email.complained · email.unsubscribed · domain.verified · domain.degraded