GET /v1/usage¶
Balance and usage for the current period
The credits available to the key's account and the scans made in the current usage period, counted by status. Every settled scan is counted, whether or not its result was stored, so the figures do not decay as retention windows pass. A key with no account behind it (the public sandbox key) reports a null balance and zero counters.
Reports the balance in credits and the counters for the current period. One credit is one US cent, and one recognized document draws one, so the balance is also the number of documents left.
A sandbox key reads its own account's real figures. Its own scans are never charged, so they move the counters and not the balance.
Request¶
| Method | GET |
| Path | /v1/usage |
| Authentication | Authorization: Bearer <api key> |
Responses¶
200¶
Balance and counters.
Body: Usage.
| Field | Type | Description |
|---|---|---|
balance_credits |
integer | null | Credits currently available to the account; null for keys without a balance. |
period |
object | Bounds of the current usage period (UTC calendar month). |
scans |
object | |
credits_spent |
integer | Credits charged within the period. |
{
"balance_credits": 11,
"period": {
"start": "2026-09-01T00:00:00Z",
"end": "2026-10-01T00:00:00Z"
},
"scans": {
"total": 12,
"billed": 9,
"by_status": {
"recognized": 9,
"no_document_found": 1,
"unreadable": 1,
"unsupported_document": 1,
"rejected": 0
}
},
"credits_spent": 9
}401¶
Missing or malformed Authorization: Bearer <api key> header, or an unknown key.
Body: ErrorResponse.
{
"error": {
"code": "unauthorized",
"message": "Send your API key as `Authorization: Bearer <key>`.",
"docs_url": "https://doc.cheap/docs/errors/unauthorized",
"request_id": "req_9e6b1f7c-2d4a-4b83-9c51-7f0ad3e8b642",
"event_id": null
}
}429¶
Rate limit exceeded for this key or IP.
Body: ErrorResponse.
{
"error": {
"code": "rate_limited",
"message": "Sandbox limit of 10 requests per hour per IP reached.",
"docs_url": "https://doc.cheap/docs/errors/rate_limited",
"request_id": "req_9e6b1f7c-2d4a-4b83-9c51-7f0ad3e8b642",
"event_id": null
}
}500¶
Unexpected failure on the server; the scan was not charged.
Body: ErrorResponse.
{
"error": {
"code": "internal_error",
"message": "Unexpected error.",
"docs_url": "https://doc.cheap/docs/errors/internal_error",
"request_id": "req_9e6b1f7c-2d4a-4b83-9c51-7f0ad3e8b642",
"event_id": null
}
}503¶
Temporarily unable to serve the request: a store this service depends on is unreachable. Nothing was charged and it may be retried, after the Retry-After seconds where that header is present.
Body: ErrorResponse.
{
"error": {
"code": "service_unavailable",
"message": "The service is temporarily unable to handle this request; nothing was charged. Retry shortly.",
"docs_url": "https://doc.cheap/docs/errors/service_unavailable",
"request_id": "req_9e6b1f7c-2d4a-4b83-9c51-7f0ad3e8b642",
"event_id": null
}
}Error codes reachable here¶
| Code | When | Page |
|---|---|---|
internal_error |
The service failed in a way it does not model. | internal_error |
rate_limited |
The caller is over the rate limit for its key kind. | rate_limited |
service_unavailable |
A store this endpoint reads from is unreachable, so the answer could not be produced. Nothing was charged; retry after the Retry-After seconds. |
service_unavailable |
unauthorized |
The Authorization header is missing, malformed or names an unknown key. |
unauthorized |
Every error body carries the same shape; the full list is on Errors.