> This page is also available as Markdown: append .md to its URL. The full index of Sikaru docs is at https://docs.sikaru.ai/llms.txt. Code examples use only operations from the public API reference at https://docs.sikaru.ai/api-reference.

# Receive run webhooks

Operations and contract on this page (Python SDK `sikaru_api`):

1. `client.run_webhooks.create_webhook(project, run_id=..., url=..., idempotency_key=...)["webhook"]` (needs `runs:create`). Destination must be an allowlisted public HTTPS host on port 443 with a configured signing secret, arranged with Sikaru first. The API returns no per-webhook signing secret.
2. `client.run_webhooks.list_webhooks(project)` (needs `runs:read`).
3. `client.run_webhooks.delete_webhook(project, webhook_id)` stops future delivery.
4. Body: `deliveryId`, `projectId`, `runId`, `event` (`id`, `sequence`, `type`). Headers: `Sikaru-Delivery-Id`, `Sikaru-Timestamp`, `Sikaru-Signature`.
5. Signature: `v1=` + hex HMAC-SHA256 of `<timestamp>.<raw body>` with the agreed receiver secret. Compare in constant time, check timestamp freshness, deduplicate on `deliveryId`, return 2xx only after durable acceptance.

CLI: `sikaru run-webhooks`. Redirects are not followed; delivery can repeat.

Register a webhook for a specific run to receive lifecycle notifications.

> **Warning**
>
> The current service requires a configured signing secret and an allowlisted public HTTPS destination on port 443. Arrange destination approval and receiver verification configuration with Sikaru before registering; the API does not return a per-webhook signing secret.

```mermaid
sequenceDiagram
    participant Sikaru
    participant Receiver as Your receiver
    participant App as Your application
    Sikaru->>Receiver: Signed lifecycle notification
    Receiver->>Receiver: Verify signature, freshness, deduplicate deliveryId
    Receiver-->>Sikaru: 2xx after durable acceptance
    Receiver->>App: Process asynchronously
    App->>Sikaru: Fetch run and events when more detail is needed
```

Sikaru sends a signed notification. Your receiver verifies it, stores it durably, returns 2xx, and processes the work later. Fetch the run through the SDK when you need more detail.

## Register a webhook

```python
webhook = client.run_webhooks.create_webhook(
    project,
    run_id=run_id,
    url="https://your-approved-host.example/sikaru/events",
    idempotency_key="case-42-webhook",
)["webhook"]
```

Replace the example URL with your approved receiver. Registration needs `runs:create`; listing uses `runs:read`.

## Receiver contract

Notifications contain `deliveryId`, `projectId`, `runId`, and an `event` with `id`, `sequence`, and `type`. They contain lifecycle metadata rather than arbitrary event payloads. Fetch the run and its events through the authenticated SDK when you need more detail.

| Header               | Content                                                                                           |
| -------------------- | ------------------------------------------------------------------------------------------------- |
| `Sikaru-Delivery-Id` | The delivery ID.                                                                                  |
| `Sikaru-Timestamp`   | The timestamp used in the signature.                                                              |
| `Sikaru-Signature`   | `v1=` followed by the hex HMAC-SHA256 of the timestamp, a period, and the exact raw request body. |

Use the receiver secret agreed with Sikaru; never use your API key as the signing secret.

Your receiver should:

1. Verify the signature using a constant-time comparison before parsing or acting on the body.
2. Enforce a timestamp freshness policy.
3. Durably deduplicate on `deliveryId`.
4. Return a 2xx response only after accepting the notification durably.
5. Process slower business work asynchronously.

> **Note**
>
> Delivery can repeat. The service makes bounded attempts, and redirects are not followed. Do not depend on webhooks as your only way to learn a run's final state: reconcile with run status and event polling after an outage.

## Manage registrations

```python
registrations = client.run_webhooks.list_webhooks(project)
client.run_webhooks.delete_webhook(project, webhook["id"])
```

Deleting a registration stops future delivery from it; it does not cancel the run or undo notifications already delivered. CLI equivalents are under `sikaru run-webhooks`.

## Next steps

#### [Runs and tool requests](/run/runs-and-tool-requests)

Poll run status and events to reconcile final state.

#### [Authentication](/get-started/authentication)

Set up the API key your SDK uses to fetch run details.