Skip to content

Retry & Delivery

Synapse delivers webhooks reliably using automatic retries with exponential backoff and a circuit breaker to protect your server from being overwhelmed.


Delivery Flow

When an email event occurs, Synapse fans out the event to all active webhook endpoints that subscribe to that event type. Each endpoint receives its own independent delivery with its own retry cycle.

Email event occurs
-> Find all active endpoints subscribed to this event type
-> For each endpoint (concurrently):
-> Sign payload with endpoint's secret
-> POST to endpoint URL
-> If 2xx: success, reset failure counter
-> If 4xx: permanent failure, no retry
-> If 5xx or timeout: retry with backoff

Retry Policy

Failed deliveries are retried up to 3 times with exponential backoff:

AttemptDelay before attempt
1Immediate
210 seconds
330 seconds
4 (final)120 seconds

What counts as a failure?

ResponseBehavior
2xxSuccess. Delivery complete. Failure counter reset.
4xx (client error)Permanent failure. No retries -- your server explicitly rejected the request.
5xx (server error)Retried with backoff.
Timeout (>10 seconds)Retried with backoff.
Connection errorRetried with backoff.
Tip

Return 200 OK quickly from your webhook handler. Acknowledge receipt immediately, then process the event asynchronously. If your handler takes longer than 10 seconds, the delivery will be marked as timed out.


Circuit Breaker

If an endpoint accumulates 10 consecutive failures (across multiple event deliveries), Synapse automatically suspends the endpoint:

  • is_active is set to false
  • suspended_at is set to the current timestamp
  • No further deliveries are attempted until the endpoint is re-enabled

Re-enabling a Suspended Endpoint

Update the endpoint and set is_active: true:

bash
curl -X PATCH https://synapse-api.pyrx.tech/v1/workspace/webhook-endpoints/<endpoint_id> \
-H "Authorization: Bearer <jwt>" \
-H "Content-Type: application/json" \
-d '{"is_active": true}'

This resets the consecutive failure counter to 0. Use the test endpoint to verify your server is reachable before re-enabling.


Delivery Logs

Every delivery attempt is logged. You can inspect delivery history for any endpoint:

bash
curl "https://synapse-api.pyrx.tech/v1/workspace/webhook-endpoints/<endpoint_id>/deliveries?limit=20&offset=0" \
-H "Authorization: Bearer <jwt>"

Auth: JWT (dashboard). Requires webhooks:read permission.

Query Parameters

ParameterTypeDefaultDescription
status_filterstring(all)Filter by success or failed
limitinteger20Max items per page (capped at 100)
offsetinteger0Pagination offset

Response

json
{
"items": [
{
"id": "d1e2f3a4-b5c6-7890-abcd-ef1234567890",
"endpoint_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event_type": "email_delivered",
"status": "success",
"http_status_code": 200,
"response_body": "{\"received\": true}",
"attempt_number": 1,
"duration_ms": 142,
"error_message": null,
"created_at": "2026-04-25T10:15:45Z"
},
{
"id": "e2f3a4b5-c6d7-8901-bcde-f12345678901",
"endpoint_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event_type": "email_bounced",
"status": "failed",
"http_status_code": 500,
"response_body": "Internal Server Error",
"attempt_number": 3,
"duration_ms": 2340,
"error_message": "HTTP 500",
"created_at": "2026-04-25T10:20:30Z"
}
],
"total": 47
}

Delivery Record Fields

FieldTypeDescription
idUUIDUnique delivery attempt ID
endpoint_idUUIDThe webhook endpoint
event_typestringThe event that triggered this delivery
statusstringsuccess or failed
http_status_codeinteger or nullHTTP response status (null on timeout/connection error)
response_bodystring or nullFirst 1,000 characters of the response body
attempt_numberinteger1-based attempt number (0 = test delivery)
duration_msinteger or nullRound-trip time in milliseconds
error_messagestring or nullError description on failure
created_atstring (ISO 8601)When the attempt was made

Best Practices

  1. Return 200 quickly. Acknowledge receipt, enqueue work, return. Do not perform slow processing in the handler.
  2. Handle duplicates. Network retries may deliver the same event more than once. Use id from the payload to deduplicate.
  3. Verify signatures. Always verify X-Synapse-Signature before processing. See Signature Verification.
  4. Monitor the circuit breaker. If consecutive_failures is climbing, check your server logs. Suspension at 10 failures means you're missing events.
  5. Use test deliveries. After deploying handler changes, send a test event before relying on real traffic.