Skip to documentation

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 .arpa are 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 3xx answer is a failed attempt.
  • At least one event type. A team can have up to 100 webhooks.

Add a webhook in the dashboard

  1. Open Webhooks and click Add webhook.
  2. Enter the Endpoint URL.
  3. 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.
  4. 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.

dotenv
OPENSEND_WEBHOOK_SECRET=whsec_replace_me

Create a webhook through the API

Call create webhook with your installation's API base URL and a full-access key.

bash
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"]
  }'
json
{"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 itemWhat it does
Edit webhookChange the endpoint URL or the event types, then click Save.
Disable / EnableDisabled 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 secretOnly on the webhook's page. Confirms with Rotate.
DeleteStops 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.

bash
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.

bash
curl -X POST https://api.example.com/webhooks/YOUR_WEBHOOK_ID/signing-secret/rotate \
  -H "Authorization: Bearer $OPENSEND_API_KEY"
json
{"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.