Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.botdog.co/llms.txt

Use this file to discover all available pages before exploring further.

Successful delivery

A delivery is considered successful when your endpoint returns any 2xx HTTP status code within the request timeout. Botdog records the status code and response body and stops retrying. Aim to acknowledge with 200 OK as quickly as possible — your handler should hand the work off to a background job and reply, rather than do the work inline. Long-running handlers risk being treated as failures and retried.

Failure and retry schedule

If your endpoint returns a non-2xx status code, times out, or is unreachable, the delivery is marked as RETRYING and Botdog tries again with exponential backoff.
AttemptWaits before this attempt
1(initial delivery)
21 minute
32 minutes
44 minutes
58 minutes
616 minutes
After 6 attempts, the delivery is marked FAILED and Botdog gives up on that event. The webhook itself stays active and continues to receive future events. The backoff is capped at 24 hours per wait, so this schedule won’t grow further even if limits change.

Delivery statuses

Each delivery moves through one of these statuses:
StatusMeaning
PENDINGQueued for first delivery.
RETRYINGAt least one attempt failed; another is scheduled.
SUCCESSEndpoint responded 2xx. No further attempts.
FAILEDAll 6 attempts failed. No further attempts.
You can see counts and recent deliveries — including status code, response body, attempt number, and next-attempt time — on the webhook’s detail page in the dashboard.

At-least-once delivery and idempotency

Because Botdog retries on failure, your endpoint may receive the same event more than once — for example if your handler succeeds but the response is lost in transit. Design handlers to be idempotent:
  • Use the top-level id field on each payload as a deduplication key.
  • Persist id after processing, and ignore deliveries you’ve already seen.
const seen = new Set(); // in real systems, persist this in a database

async function handle(event) {
  if (seen.has(event.id)) return; // already processed
  await doWork(event);
  seen.add(event.id);
}

Pausing, resuming, and deleting

From the Webhooks dashboard you can:
  • Pause a webhook to stop new deliveries without losing the configuration. Events that fire while paused are not queued for later.
  • Resume to start receiving events again.
  • Delete a webhook to remove it entirely. In-flight retries for that webhook stop on the next attempt.

Testing your endpoint

Use Send test event on the webhook’s detail page to dispatch a sample payload for any event type you’ve subscribed to. Test events use the same shape and signature scheme as production deliveries, with stub contact data. They count as real deliveries in the history view so you can verify the full flow end to end.