---
title: Accounting Reference
path: reference/accounting
status: published
---

# Accounting Reference

Usage queries, budgets, and exports. For concepts, see [Accounting and Budgets](../03-core-concepts/04-accounting-and-budgets.md).

## GET /v1/accounting/usage

Get usage records. Requires `accounting:view_own` (your own usage), `accounting:view_tenant` (full tenant), or `accounting:view_partner` (across tenants).

Query params:

| Param | Description |
|-------|-------------|
| `start` | ISO 8601 timestamp |
| `end` | ISO 8601 timestamp |
| `period` | Shortcut — `hour`, `day`, `week`, `month` |
| `user_id` | Filter by user (requires `accounting:view_tenant`) |
| `tenant_id` | Filter by tenant (requires `accounting:view_partner`) |
| `model` | Filter by frontend model slug |
| `backend_id` | Filter by backend |
| `limit` | Page size (default 100, max 1000) |
| `cursor` | Pagination cursor |

Response:

```json
{
  "status": "ok",
  "data": {
    "items": [
      {
        "id": "usage_...",
        "model": "scailabs/poolnoodle-omni",
        "backend_id": "be_openai_gpt4o",
        "user_id": "user_alice",
        "tenant_id": "tenant_acme",
        "tokens_in": 1247,
        "tokens_out": 389,
        "cost": "0.007275",
        "latency_ms": 842,
        "created_at": "2026-04-22T14:30:01Z"
      }
    ]
  },
  "pagination": {"has_more": true, "next_cursor": "..."}
}
```

## GET /v1/accounting/usage/summary

Aggregated usage.

Query params: `period` (`hour`/`day`/`week`/`month`), `group_by` (`model`, `user`, `backend`, `tenant`), plus all filters from `/usage`.

Response:

```json
{
  "data": [
    {
      "group_key": "scailabs/poolnoodle-omni",
      "request_count": 12450,
      "input_tokens": 4823991,
      "output_tokens": 1287332,
      "total_tokens": 6111323,
      "total_cost": "62.47",
      "backend_cost": "61.93"
    }
  ]
}
```

## GET /v1/accounting/export

Export raw usage records as CSV, JSON, or NDJSON.

Query params: `start`, `end`, `format` (`csv` / `json` / `ndjson`), plus standard filters.

Returns a downloadable stream. For very large exports, consider querying in smaller windows.

## Budgets

### GET /v1/accounting/budgets

List budgets for the caller's scope.

### POST /v1/accounting/budgets

Create a budget. Requires `accounting:manage_budgets`.

```json
{
  "scope": "tenant",
  "scope_id": "tenant_acme",
  "model_slug": "openai/gpt-4o",
  "period": "monthly",
  "cost_limit": "500.00",
  "soft_limit_pct": 0.8,
  "hard_action": "block"
}
```

`scope` values: `partner`, `tenant`, `user`, `group`.

`period` values: `daily`, `weekly`, `monthly`, `total` (lifetime).

Budget limits — at least one required:

| Field | Purpose |
|-------|---------|
| `cost_limit` | Maximum spend (decimal) |
| `token_limit` | Maximum total tokens |
| `request_limit` | Maximum request count |

`hard_action` values: `block` (return 429), `notify` (webhook only), `throttle` (reduce rate limits without blocking).

`soft_limit_pct` (0.0–1.0) — at this fraction, fire a `budget.soft_limit_reached` event. Default 0.8.

### GET /v1/accounting/budgets/{budget_id}

Get budget details, current usage, and enforcement state.

### PUT /v1/accounting/budgets/{budget_id}

Update budget limits.

### DELETE /v1/accounting/budgets/{budget_id}

Remove a budget.

## Events

Budget events flow through the event bus. Subscribe via webhooks:

| Event type | When fired |
|------------|------------|
| `budget.soft_limit_reached` | Crossed `soft_limit_pct × hard_limit` |
| `budget.hard_limit_reached` | Hard limit reached, enforcement active |
| `budget.period_rolled` | New period started, counters reset |

See [Webhooks](./08-webhooks.md) to subscribe.

## Related

- [Accounting and Budgets](../03-core-concepts/04-accounting-and-budgets.md)
- [Rate Limiting](../07-advanced/05-rate-limiting.md) — complementary enforcement
- [Webhooks](./08-webhooks.md)
