> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.conductorquantum.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.conductorquantum.com/_mcp/server.

# Usage callbacks

Enterprise team owners can configure a signed webhook instead of polling. Under **Settings → Teams → (team) → Keys → Usage callback**, an owner sets an `https://` callback URL, enables it, and receives a signing secret once (it can be rotated, or a test event sent, from the same panel). Key minting on that tab is covered on [Teams and team wallets](/coda/usage/teams-and-team-wallets#keys).

![Settings → Teams keys tab with a usage callback URL enabled](/_fern-img/cc582233c6d0855d13ba5654c5245c6f81800099250fad7d2656b0ee40af25c5.webp)

The callback host must resolve to a public IP address. Deliveries to private or loopback addresses are not attempted.

Whenever an AI run billed to that team (`billed_team_id` on the charge) reaches a terminal billing state, Coda POSTs a JSON event to the URL:

* `usage.settled`: the charge settled, including `debt` (partial payment).
* `usage.released`: the authorisation hold was refunded.
* `usage.test`: a test event sent from the settings panel.

Example payload (field names mirror `GET /usage/runs/{run_id}`):

```json
{
  "event": "usage.settled",
  "event_id": "8f3d2c10-4f5a-4b1e-9c6d-2e7a1b0f3a11",
  "job_id": "11111111-1111-4111-8111-111111111111",
  "run_id": "11111111-1111-4111-8111-111111111111",
  "thread_id": "22222222-2222-4222-8222-222222222222",
  "team_id": "33333333-3333-4333-8333-333333333333",
  "billed_team_id": "33333333-3333-4333-8333-333333333333",
  "user_id": "44444444-4444-4444-8444-444444444444",
  "source": "public_agents_api",
  "budget": "high",
  "status": "settled",
  "requested_credits": 0.25,
  "charged_credits": 0.184321,
  "tokens": {"prompt": 1200, "completion": 340},
  "team_remaining": {"free_remaining": 0.0, "paid_remaining": 997.358889, "remaining": 997.358889},
  "settled_at": "2026-08-20T15:04:12+00:00",
  "created_at": "2026-08-20T15:04:00+00:00"
}
```

Each request carries `X-Coda-Signature: t=<unix>,v1=<hmac-sha256-hex>`, `X-Coda-Event`, and `X-Coda-Delivery-Id`. Verify before trusting:

```python
import hashlib, hmac, time

sig = dict(part.split("=", 1) for part in request.headers["X-Coda-Signature"].split(","))
signed = f"{sig['t']}.".encode() + request.body  # raw request bytes, not re-serialized JSON
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
if abs(time.time() - int(sig["t"])) > 300:
    raise ValueError("Stale callback timestamp")
if not hmac.compare_digest(expected, sig["v1"]):
    raise ValueError("Invalid callback signature")
```

Deliveries retry up to 20 attempts with exponential backoff starting at 30 seconds and capped at 1 hour (roughly 13 hours total). Deduplicate on `event_id`. Retries replay the same delivery. A `debt` event may be followed by a second `usage.settled` for the same `run_id` once the debt is collected; use the latest `settled_at` / `charged_credits`. `status` and `charged_credits` are snapshotted when the event is enqueued. `team_remaining` reflects the wallet at delivery time.

> **Warning**
>
> The [usage pull API](/coda/usage/usage-and-credits) remains the source of truth. Callbacks are a notification, not the ledger.

`user_id` on the payload is the actor. API-token identity is not stored.