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

# Webhooks

> Receive signed, real-time event deliveries per agent.

# Webhooks

Each agent can have **one webhook URL** that receives all of that agent's
events as signed JSON POSTs. Delivered types are `call.received` (inbound
answer), `call.utterance`, `call.completed`, `call.owner_task`, `call.failed`,
`call.busy`, `call.no-answer`, `call.canceled`, `sms.received`, and
`webhook.test`. See [Events](/guides/events). For local agents without a public
URL, prefer the [persistent Agent Relay](/guides/relay).

JavaScript examples call `https://api.agentline.cloud` with `fetch` and a
Bearer `al_live_...` key. The Node package is not on npm. The signature check
below is local and does not call the API.

## Configure a webhook

<CodeGroup>
  ```python theme={null}
  wh = client.webhooks.set(
      agent_id=agent.id,
      url="https://yourapp.com/agentline-webhook",
  )
  print(wh.secret)  # full secret shown ONCE — save it
  ```

  ```javascript theme={null}
  const wh = await fetch("https://api.agentline.cloud/v1/webhooks", {
    method: "POST",
    headers: {
      Authorization: "Bearer al_live_...",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      agent_id: agent.id,
      url: "https://yourapp.com/agentline-webhook",
    }),
  }).then((res) => res.json());
  console.log(wh.secret); // full secret shown ONCE — save it
  ```
</CodeGroup>

The response returns the **full signing secret once**. On later reads it is
masked.

## Verify the signature

Each delivery includes an HMAC-SHA256 signature of the **raw request body** in
a header (default `X-Webhook-Signature`). Verify it before trusting the
payload:

<CodeGroup>
  ```python theme={null}
  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 theme={null}
  import crypto from "node:crypto";

  function verify(rawBody, signature, secret) {
    const expected = crypto
      .createHmac("sha256", secret)
      .update(rawBody)
      .digest("hex");
    return crypto.timingSafeEqual(
      Buffer.from(expected),
      Buffer.from(signature),
    );
  }
  ```
</CodeGroup>

<Note>
  You can set a custom signature header (e.g. `X-Hub-Signature-256` for
  GitHub-style verification) via the `signature_header` field when configuring
  the webhook.
</Note>

## Manage & test

<CodeGroup>
  ```python theme={null}
  client.webhooks.list()
  client.webhooks.delete(agent_id=agent.id)
  client.webhooks.test(agent_id=agent.id)   # sends a signed webhook.test event
  ```

  ```javascript theme={null}
  const headers = { Authorization: "Bearer al_live_..." };

  await fetch("https://api.agentline.cloud/v1/webhooks", { headers });
  await fetch(`https://api.agentline.cloud/v1/webhooks?agent_id=${agent.id}`, {
    method: "DELETE",
    headers,
  });
  await fetch(`https://api.agentline.cloud/v1/webhooks/test?agent_id=${agent.id}`, {
    method: "POST",
    headers,
  });
  ```
</CodeGroup>

`test` fires a `webhook.test` event through the exact same pipeline as real
events — a successful delivery confirms the whole chain is wired correctly.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.