Skip to main content
Version: 1.0

Webhook Retry

Fix the receiver before retrying a failed delivery. Retry is for eligible Error logs, not for re-running events already acknowledged successfully. Inspect canRetry / canRetryBulk from logs; they are eligibility hints, not a reservation against concurrent retries.

Single retry​

curl -X POST 'https://app.chatt2.me/v1/organization/webhook/WEBHOOK_UUID/webhook-log/LOG_UUID/retry' \
-H 'x-api-key: YOUR_APPLICATION_API_KEY'
{"success": true, "newLogId": "d4e5f6a7-b8c9-4123-def0-456789012345"}

success reports the new delivery result. A failed new delivery can still have newLogId: inspect that log. Each retry creates a child log; the original remains Error and becomes resolved when a descendant succeeds. Once an attempt has a child, retry the latest eligible attempt instead.

A validation log can be retried individually even to recover an inactive webhook. This issues a fresh empty-body token challenge; success activates/verifies the webhook. Ordinary event delivery requires the webhook to be active and its current access/delivery conditions to permit a send.

HTTP / stable codeMeaning and recovery
400 CANNOT_RETRY_SUCCESSFUL_WEBHOOK_LOGAlready successful; recover failures from your own durable worker queue
409 WEBHOOK_LOG_RETRY_IN_PROGRESSAnother attempt owns the retry/delivery lock; wait and refresh logs
400 WEBHOOK_LOG_ALREADY_RETRIEDUse the latest eligible child
400 WEBHOOK_LOG_PAYLOAD_UNAVAILABLENo complete replayable stored payload; inspect logs/source data
400 WEBHOOK_DELIVERY_NOT_STARTEDNo HTTP attempt began; fix current access/delivery conditions and refresh eligibility
401 / 404Invalid key or webhook/log outside this application's scope

Bulk retry​

Send 1–100 IDs with canRetryBulk: true. Validation logs do not support bulk retry.

curl -X POST 'https://app.chatt2.me/v1/organization/webhook/WEBHOOK_UUID/webhook-log/retry' \
-H 'x-api-key: YOUR_APPLICATION_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"webhookLogIds": ["b2c3d4e5-f6a7-4901-bcde-f23456789012"]}'
{
"results": [
{"webhookLogId": "b2c3d4e5-f6a7-4901-bcde-f23456789012", "success": true, "newLogId": "e5f6a7b8-c9d0-4234-ef01-567890123456"},
{"webhookLogId": "c3d4e5f6-a7b8-4012-cdef-345678901234", "success": false, "errorCode": "WEBHOOK_INACTIVE"}
]
}

A rejected item may have neither errorCode nor newLogId; inspect each result and current eligibility. Inactive webhook rejection can return WEBHOOK_INACTIVE. Bulk processing also respects per-log locks; it does not override an in-progress single/history retry.

Recovering a failure period​

  1. Page through status=Error&limit=50&offset=0, then offset=1, etc., using pagination.totalPages.
  2. Collect and deduplicate IDs with canRetryBulk: true into a snapshot before starting retries. New retry logs change offset-based pages.
  3. If the snapshot is empty, skip the POST. Split remaining IDs into batches of at most 100.
  4. Submit each batch and inspect every result/new log. Concurrent incoming failures can still move listing pages; rescan and deduplicate if completeness matters.
  5. Handle validation recovery separately using single retry. Refresh the binding and webhook's active state before replaying events.

What replay preserves​

Event replay uses the stored body/envelope with its original event timestamp and expiry, including recorded delivery identity where available. It uses the webhook's current endpoint, headers, authorization and signing configuration, and generates a fresh HMAC timestamp/signature. Old payload time is not an old signing time. Updating a destination or credentials therefore affects subsequent retries. Receivers must deduplicate messages/provider events/delivery IDs where available; expiry may already be past when replay occurs.

No general automatic retry policy is promised for ordinary live events. WhatsApp Coexistence history delivery has a separate durable policy: at most eight HTTP attempts for transient failures (no HTTP response, 408, 429 or 5xx), with backoff and Retry-After respected; non-transient failures stop earlier. This history policy does not apply to every live event or create unlimited replay. History and manual retries share delivery coordination to avoid overlapping attempts.