Webhook Delivery and Failure Handling
Use this guide when you need to answer a practical webhook question quickly:
- Was the webhook only accepted for dispatch, or actually delivered?
- Which failures are retried automatically?
- Which responses are treated as terminal failures?
- What evidence should you collect before escalating to support?
Delivery model
- 10x sends webhooks as HTTPS
POSTrequests to your configured endpoint. - Webhook dispatch is asynchronous. Creating a subscription or triggering a test accepts work for delivery; it does not wait for your endpoint to finish processing.
- Deliveries are at-least-once, not exactly-once. Your receiver must handle duplicate deliveries safely.
- If ordering matters to your system, compare
id,occurredAt, and your own idempotency state instead of assuming strict in-order arrival.
What a webhook test does and does not prove
POST /v2/handles/{handle}/webhooks/{subscriptionId}/test queues a webhook.test delivery and returns 202 with an eventId.
What it proves:
- the subscription exists
- 10x accepted the dispatch request
- your endpoint can be exercised at that moment
What it does not prove:
- that future live deliveries will succeed
- that your production endpoint will stay healthy
- that your live event filters are broad enough for the business events you care about
Delivery request format
Each delivery includes these headers:
x-arjun-signature: HMAC-SHA256 signature in the formatsha256=<hex>x-arjun-event-type: event type such aslink.clickedx-arjun-attempt: delivery attempt number
Typical payload shape:
{
"id": "evt_...",
"type": "link.clicked",
"handle": "acme",
"occurredAt": "2026-02-25T12:00:00Z",
"payload": {}
}
Retry and terminal-failure policy
10x currently performs up to 5 total delivery attempts. Retryable failures are retried after 5s, 10s, 20s, and 40s.
| Receiver outcome | 10x behavior | What you should do |
|---|---|---|
| timeout / connection failure / no HTTP response | Retry automatically | Keep the endpoint reachable and return a response quickly |
5xx | Retry automatically | Treat as receiver instability and restore service |
408, 409, 425, 429 | Retry automatically | Stabilize the receiver, then let retries succeed |
most other 4xx such as 400, 401, 403, 404, 410, 422 | Classify as terminal immediately | Fix route, auth, secret validation, or payload expectations |
| repeated retryable failure through attempt 5 | Classify as terminal on the final attempt | Investigate receiver stability before replaying |
What happens on terminal failure
When a delivery is classified as terminal:
- the failed delivery is written to the webhook DLQ for operator triage
- a
webhook.delivery.terminal_failureevent can be emitted for downstream notification flows - handle-owner alerting paths may notify operators or owners about the failed subscription
Current operational note: 10x does not automatically disable your subscription for you. If your endpoint is invalid or no longer wanted, you should update or remove it.
Troubleshooting by status code
| Symptom | Typical cause | Next step |
|---|---|---|
401 or 403 | Secret/auth verification mismatch | Re-check signature verification, auth middleware, and any IP or header gating |
404 | Wrong path, inactive route, or deleted workflow | Confirm the exact production URL and make sure the route is deployed |
410 | Endpoint intentionally retired | Update the subscription to a live endpoint |
422 | Payload rejected by business validation | Relax the receiver schema or update the integration contract |
429 | Receiver is throttling | Queue internally on your side or raise receiver capacity |
5xx | Receiver outage or unhandled exception | Fix the receiver and inspect application logs before replay |
| no request seen | DNS, TLS, firewall, egress, or host mismatch | Verify hostname, certificate, network rules, and request logs |
Evidence to capture before escalating
If you need help from support, capture:
handlesubscriptionIdeventId- receiver URL hostname and path
- approximate failure timestamp in UTC
- receiver logs showing the returned status code
- whether the failure happened on
webhook.test, live traffic, or both - any recent deployment or config change on the receiver
Integration best practices
- Return a
2xxquickly, then process asynchronously in your own worker if needed. - Verify the HMAC signature before trusting the payload.
- Make your receiver idempotent so duplicate deliveries are safe.
- Keep production webhook URLs stable; avoid temporary tunnels for long-lived subscriptions.
- Use separate test and production endpoints if your downstream system has different validation rules.
- Subscribe only to the event types you actually need.
Triggering Context Store refreshes
Webhooks are outbound delivery events, not direct Context Store ingestion. Use a receiver or automation worker as the bridge:
- Receive and verify the 10x webhook, or receive and verify a provider webhook in your own system.
- Decide which Context Store
sourceIdneeds refresh. - Call the Context Store MCP sync route using a PAT with
mcp.connectandcontext_store.manage. - Let the async worker refresh the source; use
context_store_statusto confirm readiness.
curl -sS -X POST "https://ai.10x.in/v2/mcp/{handle}/context-store/sources/{sourceId}/sync" \
-H "authorization: Bearer patv1_<tokenId>.<secret>" \
-H "content-type: application/json" \
-d '{}'
Do not store provider webhook secrets in Context Store source config. Keep provider verification in your receiver and Context Store as the replicated search layer.
Related
Updated Jun 19, 2026
