Built for agents · MCP · CLI · OpenAPI

The control plane for your webhook agents

See and run every skillhook machine in one place: webhooks, agent jobs, the questions agents are waiting on, health and stats, with replay, remote runs and hosted webhook URLs that hold deliveries while a machine sleeps.

One command on a machine with skillhook installed; the dashboard shows the code.

Machines pull

The cloud never calls a machine.

72 h

A hosted delivery waits for a sleeping machine.

43 tools

The same operations over MCP, REST and the CLI.

RFC 9457

Every error has a code and a request id.

How it works

One package on the machine, one link out

skillhook makes a machine a webhook endpoint that runs Agent Skills. Skillhook Cloud is where every one of those machines reports.

01
Install skillhook and pair
npm install -g @meterapp/skillhook, then the pairing command the dashboard shows. The machine holds an outbound long-poll to the cloud and opens no port. Observe mode reports; control mode lets the cloud queue commands, and the machine's own allow and deny lists have the last word.
02
Webhook in, agent out
A sender posts to the machine's own URL or to a hosted one. The machine checks the signature, runs the skill's SKILL.md with Claude Code, Codex or a shell command, and reports the job: status, outcome, cost, output, and the question it stopped on, if any.
03
See and act: dashboard, API, MCP, CLI
Every machine of the organisation in one place. Answer the agent, replay a delivery, run or test a skill, read a failing health check and its fix. Each action is a command the machine picks up on its next sync; it waits up to 10 minutes for a machine that is offline.

What you see

The overview, as the dashboard shows it

The last 24 hours across every machine, then what needs a person first.

Sample data
Machines online
3/3
Every machine is polling
Needs input
1
Agents are waiting for a person
Jobs
42
39 succeeded · 2 failed · $4.12
Deliveries
118
116 accepted · 2 rejected
Jobs
Newest first, every machine.
triagemac-mini

Webhook from GitHub · waiting 4 min · “Close the two duplicate issues as well?”

Needs input
deploybuild-box

Webhook from CI · 2 min 14 s · $0.31

SucceededCompleted
nightly-reportbuild-box

Schedule · running for 38 s

Running

Hosted webhook URLs

A URL for a machine that is not always awake

A machine on a laptop, behind a NAT or asleep at night has no address a sender can reach. A hosted webhook URL on this service accepts the webhook on its behalf.

The delivery is sealed with AES-256-GCM the moment it arrives and waits up to 72 hours for the machine's next sync. The machine verifies the sender's signature with its own secret: the cloud never holds webhook secrets, and a delivery is deleted once the machine has acknowledged it.

Slack's URL verification is answered at once, so a Slack app can point at a machine that is not awake yet.

Three steps
From the dashboard to the first delivery.
Turn it on

Hosted URLs, the skill, on. The dashboard shows the URL; turning it on again makes a new one, and the old one stops working.

Paste the URL in the sender

GitHub, Sentry, Slack, Zapier, anything that posts JSON. The sender's secret stays on the machine, as it does for a direct URL.

Deliveries wait while the machine sleeps

Each one is sealed as it arrives and held for up to 72 hours. On its next sync the machine collects it, checks the signature and runs the skill.

Webhook history and replay

Every webhook, kept and replayable

Every request a machine received is on record: accepted, rejected with the reason and the HTTP status, skipped by a filter, deduplicated. The record stays as long as the organisation does; the body, the part a replay needs, stays for the plan's window: 7 days on Free, up to 365 days on Enterprise.

Search by the sender's delivery id, the reason, the path, the address or a time window. Replay from the dashboard, the API, the MCP server or the CLI: through the skill as it is now, past the checks it failed, past its filters.

Or somewhere else: the same body on another machine or through another skill, as a fresh run. And from the CLI, send a stored webhook to any URL: a staging server, a rewritten skill, a test.

Four steps
From a failed webhook to a fixed skill.
Find it

Deliveries, then the id the sender shows or the reason the machine gave; a time window narrows it. list_deliveries {q, since, until} does the same for an agent.

Read why

The outcome, the HTTP status, the reason, the redacted headers and the body, shown as text and never rendered.

Replay it

Through the skill as it is now; force past a check it failed, skip_filters past the when-filters. One button on the dashboard, one call on the API or MCP, one command in the terminal.

Or run it elsewhere

On another machine or through another skill, from the delivery's page or replay_delivery {machine, skill}; or skillhook send the stored body to any URL from the terminal.

What people run on it

A webhook in, a job out, a person only where one is needed

Our own self-heal loop and six worked playbooks, each with the prompt that sets it up with your agent and the SKILL.md it runs. Labelled honestly: no testimonials, no invented numbers.

Our own use
A Sentry alert posts to a hosted URL. The machine collects it, the skill finds the cause, lands a small tested fix through a pull request, checks it in production, and asks a person only for what is theirs.
Trigger: A Sentry alert, and a sweep every three hoursLands alone: A small fix with a test that failed before itAsks a person for: Migrations, environment, billing, the loop itself
A worked playbook
When Granola finishes a note, one skill emails it to the people who were in the meeting, the other turns the action items into tasks for their owners, researches the ones that need it, and asks when an owner or a date is unclear.
Trigger: Granola's note.generated webhookEmails go to: Addresses in the note's attendee list onlyAsks a person when: An owner or a due date is unclear
A worked playbook
Every new issue gets a run. A small, well-specified one gets a fix on a branch and a pull request; the rest get a triage comment with findings and questions. Design questions go to a person, and nothing merges without one.
Trigger: GitHub's issues webhook, action openedMerges: Nothing without a personAsks a person for: Design questions, with the options as buttons
A worked playbook
A customer writes in. The skill looks at the logs, Sentry and the database before it drafts an answer; it replies through Intercom when the answer is certain, and otherwise leaves an internal note and asks a person in the inbox: send the draft, edit it, or escalate.
Trigger: Intercom's conversation webhooksReplies alone when: The answer is certain from what it foundOtherwise: An internal note, and the draft as a choice in the inbox
A worked playbook
A dispute arrives with a deadline. The skill collects the customer, the invoices, the access and usage logs, the correspondence and the delivery records, writes the evidence up, submits it through the API when it is complete, and asks a person first when it is thin or the amount is large.
Trigger: Stripe's charge.dispute.created eventSubmits alone when: The evidence is complete and the amount smallAsks a person when: The evidence is thin or the amount is large
A worked playbook
A new lead gets a first reply with real context about what they asked. Every later message in the thread gets an answer, deduplicated by message id, the CRM is updated, and a person is asked before any pricing exception, promise or legal question. It stops when a person says so.
Trigger: A form, CRM or inbound-email webhookDeduplicated by: The message id, in skillhook and in the CRMAsks a person before: Pricing exceptions, promises and legal questions
A worked playbook
Every webhook a machine received is on record in the cloud, with the reason when it did not run. Filter them, replay one through the skill as it is now, run its body on another machine or skill, send it to any other location from the CLI, and test a SKILL.md before it is saved.
On record: Every delivery, with its outcome and reasonBody kept: 7 to 365 days, by planReplay: As the skill is now; force and skip_filters when needed

Agents are the first-class client

Everything the dashboard does, as operations an agent can call

One catalogue serves the hosted MCP server, the REST API and the CLI, so an agent sees what a person sees and acts the same way: through commands the machine still checks.

The hosted server at /api/mcp: Streamable HTTP, stateless, one bearer key. A key is offered the tools its scope allows, and describe_cloud tells an agent where to start.
POST https://skillhook.dev/api/mcp
skillhook 0.7.0 runs the whole catalogue from a terminal: machines, jobs, answers, replays, stats. Log in once; the key stays in ~/.skillhook/.env and is never printed.
skillhook cloud answer_job <job> "yes" --option yes
Every REST route and every operation of the catalogue, with their schemas, in one document. Generate a client, or import it into Postman or an agent framework.
GET https://skillhook.dev/openapi.json
What the service is and how to use it, written for models; llms-full.txt is the long version. agents.md is the operating guide for an agent that holds a key.
curl https://skillhook.dev/llms.txt
The skillhook repository is the plugin. It registers two MCP servers, this machine and the organisation, and a skill that teaches the agent to triage and operate the fleet.
/plugin install skillhook@meterapp-skillhook
A custom GPT imports openapi.json with Bearer authentication and gets every operation as an action. Chat connectors with sign-in, for claude.ai and ChatGPT, are coming.
Import https://skillhook.dev/openapi.json

What needs a person

Agents ask; the cloud makes sure someone hears

Agents stop and ask. A skill that needs a decision ends its run with a question; the dashboard's inbox lists it with its choices as buttons, an alert goes out, and the answer is delivered to the waiting run or resumes the agent's session with it.

Answer from the dashboard, the API, the MCP server or the CLI. Each alert opens once for its cause; dismiss it by hand from the dashboard or with dismiss_alert.

Four alerts
Each one names the machine, the job or the check it is about.
An agent needs a personneeds_human

A skill ended its run on a question. The job waits in the inbox until a person, or an agent with a key, answers it.

A machine went offlinemachine_offline

A machine stopped polling. Commands queued for it wait 10 minutes; hosted deliveries wait 72 hours.

A job failedjob_failed

A job failed. Its failure kind, output and artifacts are on the job; replay it once the cause is fixed.

A health check is failinghealth_failing

A health check on a machine fails. The check names the fix.

ChannelsSlackSigned webhooks (Standard Webhooks)Email

Pricing

Free for a couple of machines, a plan when the fleet grows

Every plan has the whole product: dashboard, API, MCP server and CLI. They differ in how many machines, people, hosted URLs and deliveries they hold.

Free
One person, a couple of machines

$0

  • 2 machines, 3 people
  • 3 hosted webhook URLs, 1,000 hosted deliveries a month
  • Replay, remote runs and answers to agents
Pro
A team and its fleet

$29 / month

  • 10 machines, 10 people
  • 25 hosted webhook URLs, 50,000 hosted deliveries a month
  • Everything in Free
Business
Many machines, many senders

$99 / month

  • 50 machines, 50 people
  • 250 hosted webhook URLs, 500,000 hosted deliveries a month
  • Everything in Pro

FAQ

Questions people ask first

Pair a machine, see its first webhook

Free for 2 machines; a plan when the fleet grows. Nothing to install on the cloud side.