# AgentLine Webhooks

Use a webhook when a public HTTPS server should receive an agent's events. For a
local agent without a public URL, use the relay
(https://agentline.md/relay.md). Webhooks are a separate resource: do not set them with `PATCH /v1/agents`.

Each agent has at most one webhook. It receives all of that agent's events. See
https://agentline.md/events.md

## Set

```bash
curl -s -X POST https://api.agentline.cloud/v1/webhooks \
  -H "Authorization: Bearer $AGENTLINE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id":"agt_xxx","url":"https://your-app.example.com/agentline"}'
```

| Field | Notes |
|---|---|
| `agent_id` | Required. |
| `url` | Required. HTTPS. Posting again replaces the existing webhook. |
| `secret` | HMAC signing secret. Auto-generated if omitted. |
| `signature_header` | Default `X-Webhook-Signature`. Use `X-Hub-Signature-256` for GitHub-style. |
| `protocol` | `agentline-relay/1` (default) or `agentline-relay/2`. |

Store the returned `secret` immediately. It is shown once and masked after.

## Handle

Headers: the signature header (default `X-Webhook-Signature`) and
`X-AgentLine-Event`.

1. Verify the HMAC-SHA256 of the raw, unparsed body with the secret.
2. Dedupe by `event_id`.
3. Return `2xx` quickly.
4. Process asynchronously. For `call.utterance`, push context to the event's
   `push_context_url` as described in https://agentline.md/relay.md

```python
import hmac, hashlib

def verify(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
```

```javascript
import crypto from "node:crypto";

function verify(rawBody, signature, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
```

## Manage

```bash
# List (secrets masked); add ?agent_id= for one agent
curl -s https://api.agentline.cloud/v1/webhooks \
  -H "Authorization: Bearer $AGENTLINE_API_KEY"

# Send a signed webhook.test through the real event pipeline
curl -s -X POST "https://api.agentline.cloud/v1/webhooks/test?agent_id=agt_xxx" \
  -H "Authorization: Bearer $AGENTLINE_API_KEY"

# Delete; events then stay in the mailbox (GET /v1/events)
curl -s -X DELETE "https://api.agentline.cloud/v1/webhooks?agent_id=agt_xxx" \
  -H "Authorization: Bearer $AGENTLINE_API_KEY"
```

`test` returns `404` when the agent has no webhook.

## Relay Protocol v2

Set `"protocol":"agentline-relay/2"` and optional `capabilities`
(`supports_amend`, `supports_cancel`, `briefing`, `streams_progress`) to receive
typed POSTs: `call.session.start`, `call.task.open`, `call.task.amend`,
`call.task.cancel`, `call.session.end`. Return `202` quickly and answer only via
`POST /v1/calls/{call_id}/context`.

AgentLine: https://agentline.cloud | API: https://api.agentline.cloud | All guides: https://agentline.md
