Skip to main content
Reliable webhook delivery requires cooperation between ByDoctor and your server. ByDoctor guarantees at-least-once delivery by retrying failed attempts automatically, but your endpoint needs to be designed to handle those retries gracefully. This page explains the full retry lifecycle and how to build an endpoint that stays healthy under real-world conditions.

Delivery Expectations

When ByDoctor sends a webhook, your endpoint must return a 2xx HTTP status code within 30 seconds. Any response in the 200–299 range counts as a successful acknowledgement — 200 OK and 204 No Content are both fine. What ByDoctor considers a failed delivery:
  • A non-2xx response code (e.g., 400, 404, 500, 503)
  • No response within 30 seconds (connection timeout)
  • A network-level error (DNS failure, TLS handshake error, connection refused)
What ByDoctor does not consider a failure:
  • A 2xx response with an error message in the body — the body is ignored; only the status code matters
  • A 2xx response that arrives after you have already begun processing the event

Retry Schedule

When a delivery attempt fails, ByDoctor retries with exponential backoff. You have up to five total attempts to successfully acknowledge the event: After the fifth attempt fails, the event is marked as permanently failed and no further retries occur. You can still view the event in your delivery logs to inspect the payload and replay it manually if needed.
Retry delays are approximate. ByDoctor adds a small amount of jitter to avoid thundering-herd problems when many webhooks fail at the same time.

Handling Idempotency

Because ByDoctor retries failed deliveries, your endpoint may receive the same event more than once. Your handler must be idempotent — processing the same event twice should produce the same outcome as processing it once. Use the top-level id field on every event as your idempotency key:
Node.js
Store processed event IDs in a fast, durable store (Redis with TTL or a database table). A TTL of 24 hours is sufficient since all retries complete within ~3 hours of the initial attempt.

Automatic Webhook Deactivation

If your endpoint fails consistently, ByDoctor will automatically mark it as inactive after 100 consecutive failed delivery attempts. Once inactive, ByDoctor stops sending events to that endpoint entirely. You will receive an email notification when your webhook is deactivated. To reactivate it, fix the underlying issue with your endpoint and then re-enable it:
cURL
Events that fired while your webhook was inactive are not replayed automatically. Use the delivery log in the dashboard to identify missed events and reconcile your system if needed.

Best Practices

Respond immediately, process asynchronously. The single most effective thing you can do to avoid failed deliveries is to decouple acknowledgement from processing. When a request arrives, push the raw payload onto a message queue (e.g., RabbitMQ, SQS, BullMQ) or a background job, return 200 OK instantly, and let a worker process the event at its own pace. This keeps your response time well under the 30-second limit even if your database is slow or a downstream API is unavailable.
Node.js — queue-first pattern
Additional best practices:
  • Set a generous server-side timeout on your route. Ensure your framework’s request timeout is longer than 30 seconds so ByDoctor’s retry does not race against your own timeout.
  • Return meaningful non-2xx codes during maintenance. If you know your endpoint is temporarily down, return 503 Service Unavailable so the retry logs are clearly distinguishable from unexpected errors.
  • Monitor your error rate. A spike in failed deliveries usually indicates a deployment issue or a change in your server configuration, not a ByDoctor problem.
  • Do not block on third-party APIs. Calling a slow external service (e.g., a payment gateway or email provider) synchronously inside your webhook handler is the most common cause of timeouts.

Monitoring Delivery Logs

You can inspect the full history of webhook deliveries — including request headers, response codes, response bodies, and timestamps for each attempt — in the ByDoctor dashboard: Settings → Webhooks → [select your webhook] → Delivery Logs Each log entry shows: Use the Resend button next to any failed event to manually trigger a new delivery attempt at any time.