Webhook Toolkit API
Everything the inspector does, over HTTP: create capture URLs, wait for webhooks, read them, replay them. JSON in, JSON out, CORS enabled. The CLI and the MCP server are built on it.
https://webhook-toolkit.com/api/v1
Authentication
Optional. Without a key, you can create anonymous URLs (7-day lifetime, 30 per IP per day) and read any URL whose token you know. Send Authorization: Bearer whk_… (create keys in your dashboard) to create permanent URLs and use your plan's quotas.
Quick start
# 1. create a URL
curl -s -X POST https://webhook-toolkit.com/api/v1/endpoints -H 'content-type: application/json' -d '{"name":"demo"}'
# → { "endpoint": { "token": "Qx7pL2mN9aZk", "url": "https://webhook-toolkit.com/r/Qx7pL2mN9aZk", ... } }
# 2. wait for the next request (in another terminal: curl -d hello https://webhook-toolkit.com/r/Qx7pL2mN9aZk)
curl -s "https://webhook-toolkit.com/api/v1/endpoints/Qx7pL2mN9aZk/wait?timeout=50"
# → { "request": { "method": "POST", "body": "hello", "provider": null, ... } }Routes
| POST | /endpoints | Create a capture URL. Body: { name? }. Anonymous URLs expire after 7 days. |
| GET | /endpoints | List your URLs (API key required). |
| GET | /endpoints/:token | One URL, with its configured response. |
| PATCH | /endpoints/:token | Rename it or change what it answers: { name?, response: { status?, body?, contentType? } }. |
| DELETE | /endpoints/:token | Delete the URL and its requests. |
| POST | /endpoints/:token/claim | Make an anonymous URL permanent on your account (API key). |
| GET | /endpoints/:token/requests?limit=&after= | Captured requests, newest first. after = ISO timestamp. |
| DELETE | /endpoints/:token/requests | Clear the history. |
| GET | /endpoints/:token/requests/:id | One request in full. |
| GET | /endpoints/:token/wait?timeout=&after= | Long-poll: returns the next request (max 50 s), or { request: null, timedOut: true }. |
| GET | /endpoints/:token/stream | Server-Sent Events: one `request` event per captured request. |
| POST | /endpoints/:token/requests/:id/replay | Re-send the request to a public URL: { url }. |
| POST | /endpoints/:token/requests/:id/explain | AI: { mode: "explain" | "handler", language?, locale? }. |
| GET | /me | Your plan and limits (API key required). |
| GET · POST | /relays | List or create Relay tunnels (paid plans). |
Objects
{
"id": "clx…", "token": "Qx7pL2mN9aZk", "name": "demo",
"url": "https://webhook-toolkit.com/r/Qx7pL2mN9aZk",
"inspectUrl": "https://webhook-toolkit.com/e/Qx7pL2mN9aZk",
"expiresAt": "2026-09-25T10:00:00.000Z", // null = permanent
"owned": false, "locked": false, "requestCount": 0,
"createdAt": "2026-09-18T10:00:00.000Z",
"response": { "status": 200, "body": "{\"ok\":true}", "contentType": "application/json" }
}{
"id": "clx…", "method": "POST", "path": "/stripe", "query": "",
"headers": { "stripe-signature": "t=…,v1=…", "content-type": "application/json" },
"body": "{\"id\":\"evt_…\",\"type\":\"invoice.paid\"…}",
"contentType": "application/json", "size": 2143,
"ip": "54.187.174.169", "country": "US",
"createdAt": "2026-09-18T10:01:02.000Z",
"provider": "stripe", "event": "invoice.paid"
}Errors
Errors are JSON: { "error": "plan_limit", "message": "…", "upgradeUrl": "…" }. Codes: bad_request (400), unauthorized (401), upgrade_required and plan_limit (402), forbidden (403), not_found (404), expired (410), rate_limited (429). A capture URL whose owner's plan lapsed answers 402; an expired anonymous URL answers 410.
Streaming
curl -N https://webhook-toolkit.com/api/v1/endpoints/Qx7pL2mN9aZk/stream
event: hello
data: {"endpointId":"clx…","token":"Qx7pL2mN9aZk"}
event: request
data: {"id":"clx…","method":"POST","path":"/","body":"hello",…}Prefer the official client in Node.js: npm i webhook-toolkit — createEndpoint(), waitForRequest(), stream(), typed errors. See the CLI page.