Webhooks
Register an endpoint, read the delivery log, replay, send a test event.
Delivery of post.sent and post.failed events to your own https endpoint.
Register a webhook
POST/webhooks
Registers an https endpoint of yours to receive post.sent and post.failed events.
The URL must be https and must point at a public host: private, loopback, link-local and metadata addresses are rejected. Deliveries do not follow redirects, so register the final URL.
The signing secret is returned exactly once, in this response. Store it somewhere safe; there is no way to read it again, only to delete the webhook and register a new one.
Rate limit: 60 requests per minute per API key, shared with GET /webhooks.
curl -X POST "https://api.yeetpost.com/api/v2/webhooks" \ -H "x-api-key: $YEETPOST_API_KEY" \ -H "content-type: application/json" \ -d '{ "url": "https://example.com/hooks/yeetpost", "events": [ "post.sent", "post.failed" ]}'{ "webhook": { "id": "2c9a4f3b-77d1-4b0e-9f2a-8c3e1a5b7d90", "url": "https://example.com/hooks/yeetpost", "events": [ "post.sent", "post.failed" ], "secret": "yp_whsec_3f1a...", "createdAt": "2026-08-26T09:24:11.412Z" }}request body (application/json)
Where to POST events. Must be https and must point at a public host.
Events to subscribe to. Defaults to all of them.
post.sent | post.failed | post.deleted | post.metrics | post.rescheduled | connection.created | connection.removed | connection.reconnect_required
response 200
The webhook was registered. This is the only response that contains the secret.
headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset
response body
post.sent | post.failed | post.deleted | post.metrics | post.rescheduled | connection.created | connection.removed | connection.reconnect_required
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
The signing secret, yp_whsec_…. Shown only here, only once.
errors
Missing url, a non-https url, a url pointing at a non-public host, or an unknown event name. A body that is not valid JSON is rejected before the rate limit is checked, so that one response carries x-request-id and no rate limit headers.
Missing or invalid API key.
More than 60 requests in a minute for this API key. Back off and retry.
Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.
What each code means and the fix: errors.
List your webhooks
GET/webhooks
Your webhooks, newest first. Secrets are never included.
Rate limit: 60 requests per minute per API key, shared with POST /webhooks.
curl "https://api.yeetpost.com/api/v2/webhooks" \ -H "x-api-key: $YEETPOST_API_KEY"{ "webhooks": [ { "id": "2c9a4f3b-77d1-4b0e-9f2a-8c3e1a5b7d90", "url": "https://example.com/hooks/yeetpost", "events": [ "post.sent", "post.failed" ], "createdAt": "2026-08-26T09:24:11.412Z" } ]}response 200
Your webhooks.
headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset
response body
post.sent | post.failed | post.deleted | post.metrics | post.rescheduled | connection.created | connection.removed | connection.reconnect_required
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
errors
Missing or invalid API key.
More than 60 requests in a minute for this API key. Back off and retry.
Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.
What each code means and the fix: errors.
Delete a webhook
DELETE/webhooks/{webhookId}
Stops delivering events to this webhook. Deliveries that are still queued for it are marked failed.
Rate limit: 60 requests per minute per API key.
curl -X DELETE "https://api.yeetpost.com/api/v2/webhooks/2c9a4f3b-77d1-4b0e-9f2a-8c3e1a5b7d90" \ -H "x-api-key: $YEETPOST_API_KEY"{ "id": "2c9a4f3b-77d1-4b0e-9f2a-8c3e1a5b7d90", "deleted": true}path parameters
Id of the webhook, as returned by POST /webhooks or GET /webhooks.
response 200
The webhook is deleted.
headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset
response body
true
errors
Malformed webhook id.
Missing or invalid API key.
No webhook of yours with that id.
More than 60 requests in a minute for this API key. Back off and retry.
Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.
What each code means and the fix: errors.
List a webhook's deliveries
GET/webhooks/{webhookId}/deliveries
The delivery log for one webhook of yours, newest first: what was sent, how it went, and the last error when it did not. Use it to see why a receiver is not getting events.
Deliveries are kept for 30 days. A dead letter's 30 days run from when it died rather than from when it was queued, so a delivery that spent its last day retrying is still there to replay.
Rate limit: 60 requests per minute per API key.
curl "https://api.yeetpost.com/api/v2/webhooks/2c9a4f3b-77d1-4b0e-9f2a-8c3e1a5b7d90/deliveries" \ -H "x-api-key: $YEETPOST_API_KEY"{ "deliveries": [ { "id": "8d3f2b7c-4e1a-4c6d-9b0f-1a2b3c4d5e6f", "eventId": "8d3f2b7c-4e1a-4c6d-9b0f-1a2b3c4d5e6f", "event": "post.sent", "status": "delivered", "attempts": 1, "createdAt": "2026-08-26T09:24:11.412Z", "nextAttemptAt": "2026-08-26T09:24:11.412Z", "deliveredAt": "2026-08-26T09:24:12.004Z", "deadAt": null, "lastStatusCode": 200, "lastError": null }, { "id": "1c4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f60", "eventId": "1c4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f60", "event": "post.failed", "status": "dead", "attempts": 7, "createdAt": "2026-08-25T18:02:44.118Z", "nextAttemptAt": "2026-08-26T14:39:12.882Z", "deliveredAt": null, "deadAt": "2026-08-26T14:39:13.204Z", "lastStatusCode": 500, "lastError": "response status 500" } ], "limit": 25, "hasMore": false}path parameters
Id of the webhook, as returned by POST /webhooks or GET /webhooks.
query parameters
How many deliveries to return.
Only deliveries in this state.
pending | delivered | failed | dead
Id of the last delivery of the previous page. New deliveries land at the top of this list while you page it, so the next page is the deliveries older than that one rather than the ones past an offset.
response 200
The webhook's deliveries, newest first.
headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset
response body
The same id the delivery carries in its x-yeetpost-delivery header.
Id of the event, the same value as id. It is what the delivery carries in x-yeetpost-event-id and in the eventId field of its body, on every attempt and every replay. Deduplicate on it.
post.sent | post.failed | post.deleted | post.metrics | post.rescheduled | connection.created | connection.removed | connection.reconnect_required
pending is waiting for its next attempt, processing is being sent right now, failed means the webhook was deleted under it, dead ran out of attempts and is only sent again by a replay.
pending | processing | delivered | failed | dead
How many times it has been sent. Up to 7, and back to 0 after a replay.
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
Same format as Timestamp, or null.
Same format as Timestamp, or null.
The status your receiver answered the last attempt with, or null when the request never got a response.
Our own one-line summary of why the last attempt did not land, or null. Never your receiver's response body.
Whether there is another page. Ask for it with startingAfter set to the id of the last delivery here.
errors
Malformed webhook id, a limit outside 1 to 100, an unknown status, or a startingAfter that is not a delivery of this webhook.
Missing or invalid API key.
No webhook of yours with that id.
More than 60 requests in a minute for this API key. Back off and retry.
Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.
What each code means and the fix: errors.
Replay a delivery
POST/webhooks/{webhookId}/deliveries/{deliveryId}/replay
Sends one delivery again. It is a new attempt chain on the same event: the same eventId, the same body, the same signature rules, so a receiver that deduplicates on the event id sees the event it missed rather than a new one.
A dead, failed or delivered delivery can be replayed. One that is still pending or processing is refused: it is already on its way.
Rate limit: 60 requests per minute per API key.
curl -X POST "https://api.yeetpost.com/api/v2/webhooks/2c9a4f3b-77d1-4b0e-9f2a-8c3e1a5b7d90/deliveries/1c4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f60/replay" \ -H "x-api-key: $YEETPOST_API_KEY"{ "delivery": { "id": "1c4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f60", "eventId": "1c4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f60", "event": "post.failed", "status": "pending", "attempts": 0, "createdAt": "2026-08-25T18:02:44.118Z", "nextAttemptAt": "2026-08-27T08:11:02.551Z", "deliveredAt": null, "deadAt": null, "lastStatusCode": null, "lastError": null }}path parameters
Id of the webhook, as returned by POST /webhooks or GET /webhooks.
Id of the delivery, as returned by GET /webhooks/{webhookId}/deliveries.
response 200
The delivery is queued for a fresh attempt chain.
headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset
response body
One attempt series at delivering one event to one webhook.
The same id the delivery carries in its x-yeetpost-delivery header.
Id of the event, the same value as id. It is what the delivery carries in x-yeetpost-event-id and in the eventId field of its body, on every attempt and every replay. Deduplicate on it.
post.sent | post.failed | post.deleted | post.metrics | post.rescheduled | connection.created | connection.removed | connection.reconnect_required
pending is waiting for its next attempt, processing is being sent right now, failed means the webhook was deleted under it, dead ran out of attempts and is only sent again by a replay.
pending | processing | delivered | failed | dead
How many times it has been sent. Up to 7, and back to 0 after a replay.
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
Same format as Timestamp, or null.
Same format as Timestamp, or null.
The status your receiver answered the last attempt with, or null when the request never got a response.
Our own one-line summary of why the last attempt did not land, or null. Never your receiver's response body.
errors
Malformed ids, or a delivery that is already queued for another attempt.
Missing or invalid API key.
No webhook of yours with that id, or no delivery of that webhook with that id.
More than 60 requests in a minute for this API key. Back off and retry.
Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.
What each code means and the fix: errors.
Send a test event
POST/webhooks/{webhookId}/test
Queues a post.sent delivery with a fixed, obviously fake post in it and "test": true at the top level of the body, so you can check a receiver and its signature check without posting anything.
It goes out through the normal worker, signed and retried like any other delivery, and it shows up in the delivery log. The webhook gets it whatever it is subscribed to, because you asked for it by id.
Rate limit: 60 requests per minute per API key.
curl -X POST "https://api.yeetpost.com/api/v2/webhooks/2c9a4f3b-77d1-4b0e-9f2a-8c3e1a5b7d90/test" \ -H "x-api-key: $YEETPOST_API_KEY"{ "delivery": { "id": "3a1d9c02-5b6e-4f7a-8c1d-9e0f1a2b3c4d", "eventId": "3a1d9c02-5b6e-4f7a-8c1d-9e0f1a2b3c4d", "event": "post.sent", "status": "pending", "attempts": 0, "createdAt": "2026-08-27T08:11:02.551Z", "nextAttemptAt": "2026-08-27T08:11:02.551Z", "deliveredAt": null, "deadAt": null, "lastStatusCode": null, "lastError": null }}path parameters
Id of the webhook, as returned by POST /webhooks or GET /webhooks.
response 200
The test delivery is queued.
headers: x-request-id, x-ratelimit-limit, x-ratelimit-remaining, x-ratelimit-reset
response body
One attempt series at delivering one event to one webhook.
The same id the delivery carries in its x-yeetpost-delivery header.
Id of the event, the same value as id. It is what the delivery carries in x-yeetpost-event-id and in the eventId field of its body, on every attempt and every replay. Deduplicate on it.
post.sent | post.failed | post.deleted | post.metrics | post.rescheduled | connection.created | connection.removed | connection.reconnect_required
pending is waiting for its next attempt, processing is being sent right now, failed means the webhook was deleted under it, dead ran out of attempts and is only sent again by a replay.
pending | processing | delivered | failed | dead
How many times it has been sent. Up to 7, and back to 0 after a replay.
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
An ISO 8601 timestamp in UTC, in the same format as the timestamps you send in: 2026-08-26T09:24:11.412Z.
Same format as Timestamp, or null.
Same format as Timestamp, or null.
The status your receiver answered the last attempt with, or null when the request never got a response.
Our own one-line summary of why the last attempt did not land, or null. Never your receiver's response body.
errors
Malformed webhook id.
Missing or invalid API key.
No webhook of yours with that id.
More than 60 requests in a minute for this API key. Back off and retry.
Something went wrong on our side. Quote the x-request-id when you report it. A failure can happen before the rate limit is checked, so this response carries the request id and nothing else.
What each code means and the fix: errors.