Webhook history and replay
Every delivery kept and searchable; replay it through its skill, on another machine or skill, or send it anywhere from the CLI.
What is recorded
Every request to a skill's URL, the machine's own or its hosted URL, becomes a delivery on the machine and reaches the cloud on its next sync: the skill, when it arrived, the outcome, the HTTP status the sender got, the code and the reason when it did not run, the sender's own delivery id, the address, the method, the path, the user agent, the content type and size, the request headers (signatures and credentials are replaced on the machine before anything is uploaded) and the job it started. The record stays as long as the organisation does; nothing prunes it.
The body is uploaded with the record while the organisation keeps webhook bodies (Settings → keep webhook bodies, or update_settings {store_payloads}), the machine's cloud.upload_payloads is on and the body is at most 262,144 bytes. The cloud keeps it for the plan's retention window (Plans and limits), then deletes the body and keeps the record. A replay on the delivery's own machine reads the machine's own delivery log, not the cloud's copy; a replay on another machine or through another skill, and sending a stored webhook anywhere, need the copy.
Search and filters
Deliveries on the dashboard filters by machine, outcome and how the webhook came (straight to the machine, or through a hosted URL), and searches: the box looks, case-insensitively, anywhere in the sender's delivery id, the machine's delivery id, the reason, the code, the path, the address and the user agent, and Since and Until bound the day it was received (UTC). Paste the id Stripe, GitHub or Sentry shows for an event, or the words of a reason, and the matching deliveries are there, whatever became of them.
list_deliveries takes the same filters, plus two exact ones: the sender's delivery id and the job it started. Free text is at most 200 characters; since and until are ISO 8601 times, and a date alone means its start or its whole day.
Replay
replay_delivery {delivery} has the machine run the stored request again through the skill as it is now: a new job with trigger replay, linked from the delivery. A delivery that was rejected or ended in error needs force, which skips the checks it failed (the signature, the authentication); skip_filters ignores the skill's when filters, for a delivery that was skipped. On the delivery's page these are the Replay, Replay anyway and Replay, skip filters buttons. The machine must accept the command: control mode, or delivery.replay in its cloud.allow_commands; a fleet:run key or the member role on this side.
On another machine or through another skill
With machine or skill, replay_delivery takes the stored body and the redacted headers and runs them on that target as a fresh run, exactly as run_skill does: no signature check, no when filters, no deduplication, so force and skip_filters do not apply. A webhook that hit production runs on the staging machine; an event that the old skill mishandled runs through the rewritten one. The target machine must accept skill.run (control mode, or its allow list). This needs the cloud's copy of the whole body: without one the answer is 409 no_body, and the replay where it arrived still works. The audit log's entry for the run names the delivery it replays.
On the delivery's page, Replay elsewhere is a machine, one of the skills it last reported, and a button.
Send a stored webhook anywhere from the CLI
For a URL that is not a paired machine (a staging deployment of your own service, a skillhook that is not connected, a colleague's laptop), take the body out with get_delivery and send it yourself. skillhook send signs it the way the sender would, with the skill's secret as it is on the machine you run it on, and POSTs it to <url>/hooks/<skill>; the target has to have the skill with the same secret (or auth: none). Any other endpoint takes the body with curl. --header "Name: value" adds a header the skill's filters or the agent read (the originals are in the delivery's headers); a body stored as base64 is binary (| base64 -d), and one marked truncated is not the whole request.
Test a SKILL.md with a real webhook before saving it
test_skill {machine, skill_md, payload} runs a SKILL.md once on a machine without installing it (a job with trigger test). With a stored body as the payload, a rewritten skill is tried against the event that broke the old one, and save_skill installs it once it does what you want. On the dashboard, the Playground does the same with a text box.
The routes and the tools
Everything above is the same catalogue on the hosted MCP server, over REST and in the terminal (API reference); the resource routes below name the same things.