> ## Documentation Index
> Fetch the complete documentation index at: https://docs.webhook.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Wake an agent on a webhook

> Register a webhook-to-agent trigger, then have your agent call triggers.wait to be woken when a matching event arrives — an event-driven primitive, not polling.

Most webhook-over-MCP tooling is read-only *pull*: an agent asks "what happened?" and gets a snapshot. webhook.co adds the missing half — an **event-driven** primitive. An inbound webhook can wake an agent that's waiting on it.

Two steps: register a webhook-to-agent trigger for an endpoint, then have the agent consume events from it.

## The model

```mermaid theme={null}
flowchart LR
  P[provider] -->|POST| I[ingest URL<br/>wbhk.my/token]
  I --> E[endpoint<br/>captures event]
  E --> T[agent trigger]
  T -->|triggers.wait| A[your agent]
```

A trigger is a durable webhook-to-agent subscription over an endpoint you can already read. Once it exists, an agent drains events from it with `triggers.wait` and acts on each one.

## Register the trigger

`triggers.create` needs the `triggers:write` scope and an endpoint id:

```json theme={null}
{
  "name": "triggers.create",
  "arguments": {
    "endpointId": "9f2c8b1e-0d3a-4c5e-8f7a-1b2c3d4e5f60",
    "name": "deploy-on-push"
  }
}
```

It returns a trigger record with an `id`. That id is durable — the subscription outlives any single agent process. Register once; consume from anywhere.

## The agent loop

The agent calls `triggers.wait`, acts on what comes back, and passes `nextCursor` forward. The cursor *is* the acknowledgement — persist it only after the work is done, and a crash re-reads rather than drops.

```ts theme={null}
let cursor: string | null = null; // null = start from the oldest retained event

while (true) {
  const { events, nextCursor, caughtUp } = await mcp.call("triggers.wait", {
    triggerId: "…",
    cursor,
    limit: 50,
  });

  for (const event of events) {
    await handle(event); // dedup on event.id — delivery is at-least-once
  }

  cursor = nextCursor; // ack only after the work above succeeded
  if (caughtUp) await sleep(1000); // drained; idle until the next event
}
```

While `caughtUp` is false you're draining a backlog — re-invoke promptly. Once it's true, you've reached the head; wait on your own cadence. `triggers.wait` returns immediately with whatever is past the cursor, so this is a short-poll consume, not a blocking push. The exact contract — cursors, ordering, at-least-once, body inlining — is on [trigger semantics](/mcp/trigger-semantics).

## Why this is safe to hand an agent

`triggers.wait` creates **no outbound egress**. It's read-consumption of events the caller can already read — the same data as `events.list`, delivered event-first instead of asked-for. That's exactly why triggers are exposed over MCP when [`subscriptions.*` and `replayDestinations.*` are not](/mcp/overview): those redirect where an org's events *go*, an egress decision an agent must never make. Being woken by your own events steers nothing.

<Card title="Trigger semantics" icon="book" href="/mcp/trigger-semantics">
  Cursors, at-least-once, ordering, body limits, and the API mirror.
</Card>
