Retries and schedule
An event is delivered when your endpoint answers 2xx within 15 seconds. Anything else — another status,
a timeout, a refused connection — is retried. Redirects are not followed.
Schedule
Section titled “Schedule”| Attempt | After the previous one |
|---|---|
| 2 | 10 seconds |
| 3 | 30 seconds |
| 4–7 | 1, 2, 5, 10 minutes |
| 8–10 | 15, 30 minutes, 1 hour |
| then | every hour, until 24 hours have passed since the first attempt |
A Retry-After longer than the next wait is honoured, up to an hour. After 24 hours the delivery is
failed. 410 Gone fails the delivery at once and turns the endpoint off.
Events, deliveries and attempts are kept 30 days.
Resend a delivery
Section titled “Resend a delivery”A delivered or failed delivery can be sent again — same event, same webhook-id, a fresh schedule — after
you fixed your endpoint:
#!/usr/bin/env bash# One delivery: the exact body sent and every attempt.set -euo pipefail. "$(dirname "$0")/../../signed-request.sh"
delivery_id=$(mka_required DELIVERY_ID)mka_request GET "/v1/webhook-deliveries/$delivery_id"// One delivery: the exact body sent and every attempt.import { print, request, required } from "../../signed-request.mjs";
const deliveryId = required("DELIVERY_ID");const answer = await request("GET", `/v1/webhook-deliveries/${deliveryId}`);print(answer);<?php// One delivery: the exact body sent and every attempt.
declare(strict_types=1);
require __DIR__ . '/../../signed_request.php';
$deliveryId = mka_required('DELIVERY_ID');mka_show(mka_request('GET', "/v1/webhook-deliveries/{$deliveryId}"));"""One delivery: the exact body sent and every attempt."""from signed_request import request, required, show
delivery_id = required("DELIVERY_ID")show(request("GET", f"/v1/webhook-deliveries/{delivery_id}"))//go:build ignore
// One delivery: the exact body sent and every attempt.package main
import ( "docs.processing.yolotech.cc/examples/signedrequest")
func main() { deliveryID := signedrequest.Required("DELIVERY_ID") signedrequest.Show(signedrequest.Request("GET", "/v1/webhook-deliveries/"+deliveryID, nil, ""))}#!/usr/bin/env bash# Send a delivered or failed event again, under the same event ID.set -euo pipefail. "$(dirname "$0")/../../signed-request.sh"
delivery_id=$(mka_required DELIVERY_ID)mka_request POST "/v1/webhook-deliveries/$delivery_id/retry"// Send a delivered or failed event again, under the same event ID.import { print, request, required } from "../../signed-request.mjs";
const deliveryId = required("DELIVERY_ID");const answer = await request("POST", `/v1/webhook-deliveries/${deliveryId}/retry`);print(answer);<?php// Send a delivered or failed event again, under the same event ID.
declare(strict_types=1);
require __DIR__ . '/../../signed_request.php';
$deliveryId = mka_required('DELIVERY_ID');mka_show(mka_request('POST', "/v1/webhook-deliveries/{$deliveryId}/retry"));"""Send a delivered or failed event again, under the same event ID."""from signed_request import request, required, show
delivery_id = required("DELIVERY_ID")show(request("POST", f"/v1/webhook-deliveries/{delivery_id}/retry"))//go:build ignore
// Send a delivered or failed event again, under the same event ID.package main
import ( "docs.processing.yolotech.cc/examples/signedrequest")
func main() { deliveryID := signedrequest.Required("DELIVERY_ID") signedrequest.Show(signedrequest.Request("POST", "/v1/webhook-deliveries/"+deliveryID+"/retry", nil, ""))}A delivery still on its schedule is 409 delivery_not_retryable.
Pause the endpoint
Section titled “Pause the endpoint”While the endpoint is off, events wait and go out once it is on again — nothing is lost.
#!/usr/bin/env bash# Turn the endpoint off (ENABLED=false) or on; events wait while it is off.set -euo pipefail. "$(dirname "$0")/../../signed-request.sh"
body=$(cat <<JSON{ "enabled": ${ENABLED:-true}}JSON)mka_request POST "/v1/webhook-endpoint/status" "$body"// Turn the endpoint off (ENABLED=false) or on; events wait while it is off.import { print, request } from "../../signed-request.mjs";
const answer = await request("POST", "/v1/webhook-endpoint/status", { body: { enabled: process.env.ENABLED !== "false", },});print(answer);<?php// Turn the endpoint off (ENABLED=false) or on; events wait while it is off.
declare(strict_types=1);
require __DIR__ . '/../../signed_request.php';
mka_show(mka_request( 'POST', '/v1/webhook-endpoint/status', [ 'enabled' => getenv('ENABLED') !== 'false', ],));"""Turn the endpoint off (ENABLED=false) or on; events wait while it is off."""import os
from signed_request import request, show
show(request( "POST", "/v1/webhook-endpoint/status", body={ "enabled": os.environ.get("ENABLED") != "false", },))//go:build ignore
// Turn the endpoint off (ENABLED=false) or on; events wait while it is off.package main
import ( "os"
"docs.processing.yolotech.cc/examples/signedrequest")
func main() { signedrequest.Show(signedrequest.Request("POST", "/v1/webhook-endpoint/status", map[string]any{ "enabled": os.Getenv("ENABLED") != "false", }, ""))}Rolling the secret
Section titled “Rolling the secret”#!/usr/bin/env bash# Replace the signing secret; the old one keeps signing for an hour.set -euo pipefail. "$(dirname "$0")/../../signed-request.sh"
body=$(cat <<JSON{ "expire_current_in": 3600}JSON)mka_request POST "/v1/webhook-endpoint/secret/roll" "$body"// Replace the signing secret; the old one keeps signing for an hour.import { print, request } from "../../signed-request.mjs";
const answer = await request("POST", "/v1/webhook-endpoint/secret/roll", { body: { expire_current_in: 3600, },});print(answer);<?php// Replace the signing secret; the old one keeps signing for an hour.
declare(strict_types=1);
require __DIR__ . '/../../signed_request.php';
mka_show(mka_request( 'POST', '/v1/webhook-endpoint/secret/roll', [ 'expire_current_in' => 3600, ],));"""Replace the signing secret; the old one keeps signing for an hour."""from signed_request import request, show
show(request( "POST", "/v1/webhook-endpoint/secret/roll", body={ "expire_current_in": 3600, },))//go:build ignore
// Replace the signing secret; the old one keeps signing for an hour.package main
import ( "docs.processing.yolotech.cc/examples/signedrequest")
func main() { signedrequest.Show(signedrequest.Request("POST", "/v1/webhook-endpoint/secret/roll", map[string]any{ "expire_current_in": 3600, }, ""))}The answer carries the new secret once. Until previous_secret_expires_at — expire_current_in seconds, a
day at most, 0 for at once — every event is signed with both secrets, so you switch your servers without
losing a delivery. Rolling again before then drops the older one.
Remove the endpoint
Section titled “Remove the endpoint”#!/usr/bin/env bash# Remove the endpoint; events stop going anywhere.set -euo pipefail. "$(dirname "$0")/../../signed-request.sh"
mka_request DELETE "/v1/webhook-endpoint"// Remove the endpoint; events stop going anywhere.import { print, request } from "../../signed-request.mjs";
const answer = await request("DELETE", "/v1/webhook-endpoint");print(answer);<?php// Remove the endpoint; events stop going anywhere.
declare(strict_types=1);
require __DIR__ . '/../../signed_request.php';
mka_show(mka_request('DELETE', '/v1/webhook-endpoint'));"""Remove the endpoint; events stop going anywhere."""from signed_request import request, show
show(request("DELETE", "/v1/webhook-endpoint"))//go:build ignore
// Remove the endpoint; events stop going anywhere.package main
import ( "docs.processing.yolotech.cc/examples/signedrequest")
func main() { signedrequest.Show(signedrequest.Request("DELETE", "/v1/webhook-endpoint", nil, ""))}Deliveries on their way fail. A new endpoint gets a new secret.