# Report drift between billed usage and the request log for one day

> Compares billed usage for one UTC day with usage re-derived from the Postgres request log.

Source: https://docs.spicrawl.com/api-reference/usage/usage-reconciliation

## GET /v1/usage/reconciliation

Operation ID: `usageReconciliation`. API key scope: `read`.

Compares billed usage for one UTC day with usage re-derived from the Postgres request log. Report only;
nothing is repaired (`repairable` is always false).

Pitfalls:
- Read `interpretation` before `drift`. In the current deployment the Postgres request log is usually
  empty (`request_log_rows: 0`), so every billed row shows as `absent_from_request_log`. That is not
  evidence of overbilling.
- Defaults to yesterday (UTC); today is still accumulating.

### Example

```bash
curl "https://api.spicrawl.com/v1/usage/reconciliation" \
  -H "Authorization: Bearer $SPICRAWL_API_KEY"
```

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `day` | query | string (date) | no | UTC day to reconcile, `YYYY-MM-DD`. Defaults to yesterday. |

### Responses

#### 200

The drift report.

`application/json`.

| Field | Type | Required | Description |
|---|---|---|---|
| `day` | string (date) | yes | UTC day reconciled. |
| `drift` | array of object (`UsageDriftItem`) | yes | Disagreements. Empty means no drift. |
| `request_log_rows` | integer (int64) | yes | Rows the Postgres request log holds for the day. 0 means there was nothing to reconcile against. |
| `interpretation` | string | yes | What the drift can and cannot prove. Read this before acting on `drift`. |
| `repairable` | boolean | yes | Always false; the API never repairs billing data. Contact support to dispute. |
| `warnings` | array of string | no | Extra caveats. Omitted when empty. |

Example `emptyLog`

```json
{
  "day": "2026-09-21",
  "drift": [
    {
      "project_id": "01J9Y0000000000000000PROJ1",
      "metric": "credits",
      "stored_qty": 3100000000,
      "observed_qty": 0,
      "delta": -3100000000,
      "action": "absent_from_request_log"
    }
  ],
  "request_log_rows": 0,
  "interpretation": "The Postgres request log holds no rows for this day, so there is nothing to re-derive usage from and every billed row is reported as `absent_from_request_log`. ...",
  "repairable": false
}
```

#### 400

The request is invalid. Not retryable; fix the request using `code` and `diagnostics.hint`.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

#### 401

Missing, invalid, revoked or expired key. Not retryable with the same key.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

#### 403

The key lacks the scope this route requires (`ERR::AUTH::INSUFFICIENT_SCOPE`), or the action is not permitted.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

#### 500

Internal error. Retryable when `retryable` is true.

Headers: `X-Request-Id`.

`application/problem+json` (`Problem` schema).

Full OpenAPI spec: https://docs.spicrawl.com/openapi.yaml
