Webhooks
Create a webhook
Add a public HTTPS endpoint in the dashboard or through the REST API, and manage it afterwards.
Who can manage webhooks
Every team member can add, edit, enable, disable, delete, and rotate the secret of the team's webhooks, and can read the signing secret. Through the REST API the same operations need a full-access API key.
Endpoint requirements
- An
https://URL of at most 2048 characters, without a username or password in it. - A public hostname. IP addresses,
localhost, and names ending in.localhost,.local,.internal, or.arpaare refused when you save. Before every delivery Opensend resolves the hostname again and refuses any address on a private network. - Redirects are not followed. A
3xxanswer is a failed attempt. - At least one event type. A team can have up to 100 webhooks.
Add a webhook in the dashboard
- Open Webhooks and click Add webhook.
- Enter the Endpoint URL.
- Under Events, tick the event types to listen for. They are grouped as Email, Contact, and Domain; ticking a group name selects the whole group.
- Click Add.
The dashboard form does not list suppression.added and suppression.removed. Subscribe to those through the REST API.
The webhook's page opens. Its Signing secret section shows the secret; click the eye icon to reveal it and the copy button to copy it. Store it on your receiving server and use it to verify requests.
OPENSEND_WEBHOOK_SECRET=whsec_replace_meCreate a webhook through the API
Call create webhook with your installation's API base URL and a full-access key.
curl https://api.example.com/webhooks \
-H "Authorization: Bearer $OPENSEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"endpoint": "https://example.com/webhooks/opensend",
"events": ["email.delivered", "email.bounced", "suppression.added"]
}'{"object":"webhook","id":"YOUR_WEBHOOK_ID","signing_secret":"whsec_..."}Retrieve webhook also returns signing_secret. List webhooks does not.
Manage a webhook
In the dashboard, open the webhook's ... menu from the Webhooks list or from the webhook's page:
| Menu item | What it does |
|---|---|
| Edit webhook | Change the endpoint URL or the event types, then click Save. |
| Disable / Enable | Disabled webhooks reject replays. Automatic attempts that reach a disabled webhook stop without sending; already in-flight requests may finish. Re-enabling does not restart stopped retry chains. |
| Rotate secret | Only on the webhook's page. Confirms with Rotate. |
| Delete | Stops deliveries at once and removes the webhook's delivery history. |
The REST equivalents are update webhook (PATCH /webhooks/{webhook_id} with optional endpoint, events, and status of enabled or disabled), delete webhook, and rotate signing secret.
curl -X PATCH https://api.example.com/webhooks/YOUR_WEBHOOK_ID \
-H "Authorization: Bearer $OPENSEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"disabled"}'Rotate the signing secret
Rotating generates a new secret and keeps the previous one for 24 hours. During that window every delivery carries two signatures in svix-signature, separated by a space: the new secret's first, then the previous secret's. Update your receiver within the window. After it, only the new secret signs. Rotating again replaces the previous secret immediately.
curl -X POST https://api.example.com/webhooks/YOUR_WEBHOOK_ID/signing-secret/rotate \
-H "Authorization: Bearer $OPENSEND_API_KEY"{"object":"webhook","id":"YOUR_WEBHOOK_ID","signing_secret":"whsec_..."}Check a delivery
Trigger a subscribed event, then open the webhook's page. The Deliveries table lists each event with its HTTP status, attempt count, and send time. Through the API, list events and retrieve an event to see its status (pending, attempting, success, or failed), next_attempt_at, and payload. See retries and replays.