Authenticate the raw body before parsing it, deduplicate on the event ID before taking a side effect, and return a successful response only after the receiver has safely accepted the event.
1. Register a public HTTPS endpoint
Create the endpoint through POST /api/v1/webhook-endpoints using a workspace key with webhooks:manage. Choose only the event families the receiver needs. The signing secret is returned once. Store it in a secret manager and keep it out of source code and workflow JSON.
Targets are checked against public-host rules, including redirects. Private, loopback, and metadata destinations are rejected to reduce server-side request-forgery risk.
2. Subscribe to emitted events
| Event | Use |
|---|---|
message.sent | Update an outbound activity record. |
email.replied | Start reply routing or CRM handoff. |
email.bounced | Record the delivery failure and investigate patterns. |
contact.created | Synchronize a newly created contact. |
enrollment.completed | Trigger a post-sequence workflow. |
Open and click event names are reserved in the catalog but do not have production emitters. Do not build an automation that expects them to fire.
3. Preserve the raw body and headers
X-MailSequence-Signature: sha256=<hex digest>
X-MailSequence-Event-Id: <uuid>
X-MailSequence-Event: email.replied
Content-Type: application/json
The JSON envelope contains id, version, event, occurred_at, and event-specific data. Use the version before assuming a payload shape.
4. Verify before parsing
- Read the exact request bytes without re-serializing the JSON.
- Compute HMAC-SHA256 over those bytes with the endpoint signing secret.
- Prefix the hexadecimal digest with
sha256=. - Compare the expected and supplied values in constant time.
- Reject the delivery before any side effect when verification fails.
expected = "sha256=" + HMAC_SHA256(signing_secret, raw_body)
valid = constant_time_compare(expected, signature_header)
5. Deduplicate before side effects
Delivery is at least once. Persist X-MailSequence-Event-Id with a unique constraint or equivalent atomic claim before updating a CRM, sending a notification, or starting another workflow. A duplicate should return the same successful acknowledgement without repeating the side effect.
6. Design for retries and disablement
A 2xx response records success. Timeouts, blocked redirects, oversized responses, and non-2xx responses count as failures. MailSequence retries with exponential backoff, marks a delivery failed after five attempts, and automatically disables an endpoint after five consecutive failed attempts across deliveries.
Keep the receiver fast: verify, durably enqueue or record, then acknowledge. Monitor endpoint state and repair the receiver before re-enabling or recreating a disabled endpoint.
Sources and product basis
- RFC 2104: HMAC
Keyed-hash message-authentication construction used for payload integrity. - MailSequence public API reference
Webhook endpoint creation, event subscription, and response schemas. - MailSequence developer platform
Every-plan access, workspace scope, retries, and product boundaries.