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

# Agent callbacks

> The only push we ship — HTTPS callback_url on agent jobs, HMAC-signed when you send a secret

There is no `POST /v1/webhooks` registry. Knowledge resolve and PA checks are synchronous. The only outbound POST is when an **agent job** finishes, if you set `callback_url` on submit.

You can still poll `GET /v1/agents/jobs/{job_id}`. Use a callback when an EHR or worker cannot poll.

## Submit with a callback

```bash theme={null}
curl -X POST https://api-dev.rcintell.com/v1/agents/code-research \
  -H "X-API-Key: kp_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "query": "CPT for total knee arthroplasty?",
    "ccn": "170001",
    "callback_url": "https://your-app.com/webhooks/rci-agent",
    "callback_secret": "whsec_your_shared_secret"
  }'
```

`callback_url` must be HTTPS (localhost HTTP is allowed in non-prod). Optional host allowlist: `CALLBACK_URL_ALLOWED_HOSTS`.

## Payload

```json theme={null}
{
  "id": "evt_550e8400e29b41d4a716446655440000",
  "type": "agent.job.completed",
  "created_at": "2026-08-27T18:00:00Z",
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "agent_type": "code_research",
  "result": {},
  "error": null,
  "latency_ms": 4120.5
}
```

| Field                                    | Notes                                                        |
| ---------------------------------------- | ------------------------------------------------------------ |
| `id`                                     | Stable per job (`evt_` + job UUID hex). Deduplicate on this. |
| `type`                                   | `agent.job.completed` or `agent.job.failed`                  |
| `job_id` / `status` / `result` / `error` | Same as poll                                                 |

## Signature

When `callback_secret` is set (8–128 characters), we send `X-RCI-Signature: sha256=<hex>` over the **raw JSON body**.

```python theme={null}
import hmac, hashlib

def verify(payload: bytes, signature: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
```

Without a secret we still POST (useful on localhost). Production should always set `callback_secret`. The secret is never returned on `GET /v1/agents/jobs/{id}`.

## Retries

Three attempts, in-process: immediate, then \~2s, then \~8s. We retry on timeouts, connection errors, 5xx, and 429. We do not retry other 4xx. After three failures we log and stop — poll the job.

Return `2xx` within 10 seconds. Do the work asynchronously.

## What is not a webhook

| Topic                         | How to get it                                                          |
| ----------------------------- | ---------------------------------------------------------------------- |
| Knowledge resolve             | `POST /v1/knowledge/resolve` (sync)                                    |
| Prior auth                    | `GET /v1/prior-auth/check` (sync)                                      |
| 340B policy changes           | `GET /v1/340b/changes` or `POST /v1/340b/watches` (live key)           |
| Dataset versions (MPFS CY)    | `GET /v1/data/changes`                                                 |
| CMS / commercial policy diffs | `GET /v1/policies/changes` (pull; empty until document versions exist) |
