Webhook delivery retry schedule
Five exponential retries from a base of 1000 wait 1000, 2000, 4000, 8000 and 16000, a total of 31000: choose the number of retries, the base delay and the strategy to get the full schedule with cumulative waits. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Max retries
- 5
- Base delay
- 1,000
- Strategy
- Exponential
- Delays
- 1,000, 2,000, 4,000, 8,000, 16,000
- Total wait
- 31,000
- Attempt count
- 5
fixed, linear, exponential backoff delays
Why a retry plan should be written down
When an event notification fails, the system that sends it waits and tries again. The services that deliver those notifications and the ones that receive them need an explicit list of wait times before each retry, not a vague promise that backoff happens somewhere. Without a published schedule, operators cannot reason about the worst-case delivery delay, and load simulations cannot reproduce the exact gaps that production will insert between attempts. This builder takes a maximum number of retries, a base delay greater than zero and a strategy, and returns each attempt's delay, the cumulative wait and a short formula you can keep next to a dashboard or in your runbook.
Fixed, linear or exponential, and the usual mistake
Fixed backoff keeps the same base delay on every attempt: easy to reason about and gentle on receivers that only need a short cooling-off period. Linear backoff multiplies the base by the attempt number, counting from one, so later retries wait proportionally longer without growing as fast as exponential. Exponential backoff doubles each time: five retries from 1000 give 1000, 2000, 4000, 8000 and 16000, for a total of 31000. The usual mistake is a zero or negative base delay, which would make a queue spin in a busy loop; it is rejected straight away. Keep every delay in one unit, typically milliseconds.
FAQ
Does the schedule include random jitter?
Apply your own jitter on top if you need scatter between workers.
How long is the total wait for five exponential retries?
With a base delay of 1000, the waits are 1000, 2000, 4000, 8000 and 16000, and the cumulative wait reaches 31000 before the fifth attempt fires. The result uses the same unit you chose, typically milliseconds.
What is the difference between fixed, linear and exponential backoff?
Fixed waits the same base delay before every attempt. Linear multiplies the base by the attempt number, counting from one. Exponential doubles the wait each time: the base times two raised to the attempt number minus one.
What unit should the base delay use?
Any unit you like, as long as every delay shares it; milliseconds are the usual choice. The base must be greater than zero, because a zero or negative wait would make a queue retry in a tight loop, so such values are rejected.
How many retries can I plan?
From 1 to 100. Each attempt gets exactly one delay before it fires, and the schedule lists the attempt number, its own delay and the cumulative wait so far, which makes the worst-case delivery time easy to read.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev/webhook-retry-schedule-build \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"max_retries":5,"base_delay":1000,"strategy":"exponential"}'const res = await fetch("https://api.kit.forhosting.com/dev/webhook-retry-schedule-build", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"max_retries": 5,
"base_delay": 1000,
"strategy": "exponential"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev/webhook-retry-schedule-build",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"max_retries": 5,
"base_delay": 1000,
"strategy": "exponential"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev/webhook-retry-schedule-build", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"max_retries":5,"base_delay":1000,"strategy":"exponential"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"max_retries":5,"base_delay":1000,"strategy":"exponential"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev/webhook-retry-schedule-build", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"max_retries": 5,
"base_delay": 1000,
"strategy": "exponential"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev.webhook_retry_schedule_build",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Webhook receivers and delivery workers need an explicit list of wait times before each retry, not a vague promise that backoff will be applied somewhere in the stack. This webhook delivery retry schedule builder takes a maximum retry count, a strictly positive base delay, and a strategy of fixed, linear, or exponential, then returns the per-attempt delays, cumulative waits, and a short formula string you can pin in tests or show next to a dashboard. The same pure logic runs free in the browser and over the API, so planning a five-retry exponential ladder offline matches what your edge worker will use when configuring notify paths or custom delivery loops. Invalid base delays fail fast with invalid_input instead of inventing zero or negative waits that would busy-loop a queue.
What a webhook retry schedule is and how the three strategies differ
Without a published schedule, operators cannot reason about worst-case delivery latency, and load tests cannot reproduce the exact gaps a production worker will insert between retries. Fixed backoff keeps the same base delay on every attempt: simple to reason about and kind to downstreams that only need a short cooling-off period. Linear backoff multiplies the base delay by the one-based attempt index, so later retries wait proportionally longer without exploding as fast as pure exponential growth. A webhook delivery retry schedule is the ordered list of delays you wait before attempt one, attempt two, and so on after a failed POST to a subscriber URL. This capability encodes three common backoff families used across message buses and HTTP clients. Exponential backoff doubles the previous delay each time using base_delay times two to the power of attempt minus one, which is the classic pattern for transient network faults and rate limits. You supply max_retries as how many retry slots to materialize, base_delay as the positive seed in your chosen unit (usually milliseconds), and strategy as one of fixed, linear, or exponential. The response echoes those inputs, lists delays in order, sums them as total_wait, and expands a schedule array with attempt number, delay, and cumulative wait so UI charts and config generators need no extra arithmetic.
Input contract, response shape, and when validation fails
POST a JSON body with three required fields. max_retries is an integer from one through one hundred naming how many retry attempts to schedule. base_delay is a finite number strictly greater than zero in any consistent unit; zero and negative values are rejected because a non-positive wait either busy-spins or is meaningless for scheduling. strategy must be the string fixed, linear, or exponential (case-insensitive after trim). Alias keys such as retries, base_ms, and backoff are accepted so existing config shapes map cleanly. Missing fields, non-integers for max_retries, non-finite base_delay, and unknown strategies all raise invalid_input and are not billed. On success the body includes max_retries, base_delay, strategy, delays as a flat array, total_wait as the sum of delays, attempt_count equal to max_retries, schedule as objects with attempt, delay, and cumulative fields, and formula restating the closed form for the chosen strategy. Example: max_retries five, base_delay one thousand, strategy exponential yields delays one thousand, two thousand, four thousand, eight thousand, and sixteen thousand with total_wait thirty-one thousand. Pair the schedule with your own jitter policy if you need random scatter; this endpoint intentionally omits jitter and wall-clock timestamps so results stay deterministic across browser and API paths. Cap max_retries at one hundred so a typo cannot expand into an enormous payload or overflow intermediate products for large exponential ladders.
Where building a retry schedule earns its keep in real systems
Load-test harnesses inject the same delay array the production worker uses, eliminating the classic gap where staging retries faster than production and masks rate-limit bugs. Delivery platforms that expose webhook reliability settings can call this builder when an operator picks max retries and a backoff mode, then store the resulting delays next to the endpoint secret and signing key. Incident runbooks benefit from a printable total_wait so on-call staff know how long a flaky subscriber may lag before the last attempt. OpenAPI and SDK generators can document concrete example ladders without hand-maintaining tables that drift from runtime code. Keep base_delay and total_wait in the same unit as your sleep primitives so you never convert milliseconds to seconds by accident when wiring the schedule into a worker loop.
Integration use cases
Configure webhook delivery backoff in a dashboard
Let operators choose max retries and fixed, linear, or exponential strategy, then persist the computed delay list next to each subscriber endpoint.
Document worst-case delivery latency
Show total_wait and per-attempt cumulative delays in runbooks so on-call knows how long retries may take before dead-lettering.
Pin golden schedules in CI
Assert that config files expand to the same delay arrays as production workers, catching accidental strategy or base_delay regressions.
Technical questions
How do I build a webhook delivery retry schedule?
Send max_retries (1–100), a positive base_delay, and strategy fixed, linear, or exponential. The API returns ordered delays, total_wait, and a schedule with cumulative waits for each attempt.
What is the difference between fixed, linear, and exponential backoff?
Fixed repeats base_delay every attempt. Linear uses base_delay times the attempt number. Exponential uses base_delay times two to the power of attempt minus one.
Why must base_delay be positive?
Zero or negative delays cannot define a meaningful wait before a retry and would risk busy-looping a delivery worker. Non-positive base_delay fails with invalid_input and is not billed.
What does building a webhook retry schedule cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.