# Usage for one API key over a date range

`GET /v1/usage` (operation id `getUsage`)

Returns usage buckets for the calling key, or for another key of the same account when `key_id` is given.
Dates are UTC; `end` is exclusive. Day granularity allows up to 93 days, hour granularity up to 7 days.

Authentication: API key as `authorization: Bearer <key>`, scope `usage:read`.

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `start` | query | string | yes | First UTC date included. (format date) |
| `end` | query | string | yes | First UTC date not included. (format date) |
| `granularity` | query | string | no | (one of "day", "hour"; default "day") |
| `key_id` | query | KeyId | no | Another key of the same account. Defaults to the calling key. (pattern ^key_[0-9A-HJKMNP-TV-Z]{26}$) |
| `x-client-request-id` | header | string | no | Your own correlation id, accepted on every public operation. Logged with the request metadata and echoed in the response. A malformed value answers 400 `invalid_header`. (1 to 128 characters; pattern ^[\x21-\x7E]+$) |

## Responses

### 200

Usage buckets and totals.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `object` | string | yes | (always "usage_report") |
| `key_id` | KeyId | yes | (pattern ^key_[0-9A-HJKMNP-TV-Z]{26}$) |
| `start` | string | yes | (format date) |
| `end` | string | yes | (format date) |
| `granularity` | string | yes | (one of "day", "hour") |
| `buckets` | array of UsageBucket | yes |  |
| `buckets[].start` | string | yes | (format date-time) |
| `buckets[].end` | string | yes | (format date-time) |
| `buckets[].requests` | integer | yes | Successful (billed or test) decide calls. |
| `buckets[].input_tokens` | integer | yes | (format int64) |
| `buckets[].charge_micro_cents` | integer | yes | (format int64) |
| `buckets[].gpu_requests` | integer | yes |  |
| `buckets[].fallback_requests` | integer | yes |  |
| `buckets[].error_requests` | integer | yes | Calls that ended in an error. Never charged. |
| `totals` | object | yes |  |
| `totals.requests` | integer | yes |  |
| `totals.input_tokens` | integer | yes | (format int64) |
| `totals.charge_micro_cents` | integer | yes | (format int64) |

### 400

The request could not be read. Codes: `invalid_json` (not JSON, not UTF-8, or a `\u` escape that is half of a
surrogate pair, such as `"\ud800"` without its low half), `duplicate_key` (a JSON object
repeats a key; `param` is the JSON pointer of the repeated member, such as `/questions/q1/options/a`),
`unsupported_media_type` (not `application/json`) and `invalid_header` (a malformed `idempotency-key` or
`x-client-request-id`; `param` names the header).


### 401

Missing, unknown, revoked or expired credentials.

### 403

The credentials are valid but not allowed to do this (missing scope, suspended account or failed CSRF check).

### 404

The model, key or route does not exist, or the model version is retired.

### 422

The request is well-formed JSON but breaks a validation rule. `param` names the field as a dotted path.
Codes: `unknown_field`, `missing_field`, `invalid_type` (wrong JSON type), `invalid_value` (right type, value
out of range: an empty or over-long string, a state, `instructions`, `criteria` string or option description
of only whitespace, an empty `questions` or `options` object, an empty state object or array, a pattern or
allowed-value mismatch such as a label or level with outer whitespace, a state nested deeper than 32 levels, a
bad date or date range), `field_not_allowed` (`options` or `levels` on the wrong question type),
`invalid_question_id`, `too_many_questions`, `too_many_options`, `invalid_levels` (including two levels equal
after Unicode NFC normalisation and lower-casing), `invalid_min_confidence`, `duplicate_label` (two option
labels equal after Unicode NFC normalisation and lower-casing, such as `Billing` and `billing`),
`state_path_not_found`, `state_not_json` and, on the console, `top_up_limit_exceeded`.


### 429

A rate limit or quota is exhausted. Retry after the given number of seconds. For `test_daily_quota` that is
the time until 00:00 UTC; clients should not retry it automatically.


### 500

An unexpected error. Any charge was refunded. Retry with the same idempotency key.

### 503

No serving path could answer in time, or a dependency is down. Any charge was refunded.

## Example request

```bash
curl "https://api.thinqit.ai/v1/usage?start=2026-10-19&end=2026-10-21&key_id=key_01M54VQCG06CQ643DZVMXXQKFB" \
  -H "authorization: Bearer $DEX_API_KEY"
```

## Examples

Illustrative values. Examples show the shape of requests and responses; the numbers in them are not measured results.

Response: Two days of usage for one key

```json
{
  "object": "usage_report",
  "key_id": "key_01M54VQCG06CQ643DZVMXXQKFB",
  "start": "2026-10-19",
  "end": "2026-10-21",
  "granularity": "day",
  "buckets": [
    {
      "start": "2026-10-19T00:00:00Z",
      "end": "2026-10-20T00:00:00Z",
      "requests": 18422,
      "input_tokens": 6120334,
      "charge_micro_cents": 30601670,
      "gpu_requests": 18390,
      "fallback_requests": 32,
      "error_requests": 41
    },
    {
      "start": "2026-10-20T00:00:00Z",
      "end": "2026-10-21T00:00:00Z",
      "requests": 20107,
      "input_tokens": 6874812,
      "charge_micro_cents": 34374060,
      "gpu_requests": 19650,
      "fallback_requests": 457,
      "error_requests": 12
    }
  ],
  "totals": {
    "requests": 38529,
    "input_tokens": 12995146,
    "charge_micro_cents": 64975730
  }
}
```
