Credits API
Updated
| Connection | Value |
|---|---|
| API base | https://api.runinfra.ai/v1 |
| Workspace key | rp_... |
| Process variable | RUNINFRA_GATEWAY_KEY |
| Billing | The existing funding rules of your open-model account. |
This endpoint reads the workspace credit balance and budget for pay-as-you-go work on the open-models service. An existing coding plan can fund covered requests without spending that balance. Use GET /v1/usage for coding plan windows and policy; /v1/credits does not include a coding_plan field.
It is read-only and charges nothing.
Request
The chat API SDKs have no credits method, so call the endpoint with your HTTP client. The same key you use for inference works here, as long as it is a workspace key (see Who can read it).
Response
| Field | Type | Value |
|---|---|---|
object | string | credits. |
workspace_id | string | The key's workspace. A UUID. |
balance_cents | integer | The stored ledger balance of the workspace, in US cents. Holds for requests in flight are already taken out of it. Can be negative when the workspace owes for usage that settled after the balance ran out. The same number a 402 reports as error.. |
held_cents | integer | Cents reserved by requests currently in flight. Informational: they are already inside balance_cents, so do not subtract them again. Each hold is refunded or recognised as spend when its request settles. |
available_cents | integer | balance_cents floored at zero. The amount a new request can be settled against right now. |
currency | string | Always usd. |
period.start | string | ISO 8601 start of the current billing period: your subscription period while the subscription is active or trialing, otherwise the calendar month in UTC. |
period.spent_cents | integer | Settled spend in the current period. Only settled charges count; an open hold is not spend yet. |
spend_cap.limit_cents | integer or null | The legacy workspace spend cap, or null when none is set. null means no cap, never zero. |
spend_cap.hard | boolean | true when the legacy cap refuses the work it covers, false when it only sends alerts. Always false when there is no cap. |
spend_cap.used_cents | integer or null | What the cap is measured against: settled spend plus holds for other authorised work. null when there is no cap. |
spend_cap.remaining_cents | integer or null | limit_cents minus used_cents, floored at zero, or null when there is no cap. |
spend_cap.gates_inference | boolean | Always false. This workspace cap never refuses an inference request. |
plan_tier | string | The entitled workspace tier, free, core or enterprise, the same value the X-RateLimit-Tier header carries. This is not the coding plan tier; read that from /v1/usage. |
as_of | string | ISO 8601 time the numbers were read. |
Every amount is an integer in US cents.
What decides whether a request runs
A credit-funded inference request is admitted against available_cents. Holds for requests already in flight are already taken out of that number, so a long request on a thin balance can show a small available_cents and a positive held_cents at the same time; when the request settles, the unused part of its hold returns to the balance.
The legacy workspace spend cap does not enter this decision, which is why gates_inference is always false. A per-key spending limit is separate and can refuse requests on that key.
A request refused for insufficient credits answers 402 with code: "insufficient_credits" and error., the same balance this endpoint reports, plus a topup_url. See Errors.
The credit amounts above appear directly in error on chat-compatible refusals. The Messages error envelope preserves only the error type and message text.
Who can read it
Use a workspace API key created in Settings. A key that can spend the balance can read it, because the number is already disclosed to that key inside every 402 it earns.
Adding funds, changing the plan and reading invoices stay with the account owner in the dashboard; there is no write surface here.
Freshness and limits
The response carries Cache-Control: no-store and is read from the ledger on every call. Use as_of rather than your own clock when you compare two reads.
On top of your workspace's per-key rate limit this endpoint has its own allowance of 60 reads a minute per key. Poll it when you need a decision, not on a timer. The x-ratelimit-* headers on the response describe the per-key request window, so a boot-time read here also tells you your remaining request quota.
Errors
| Status | error.code | Meaning |
|---|---|---|
401 | invalid_api_key | The key is missing, malformed, unknown or expired. |
403 | auth_error | The key is deactivated. Replace it with an active workspace key. |
403 | credits_scope_violation | A legacy key is limited to part of the workspace. Use a workspace key. |
405 | method_not_allowed | Only GET is served. The Allow header says so. |
429 | rate_limit_exceeded | The per-key request window or the 60-a-minute endpoint bucket. Honour Retry-After. |
503 | limiter_unavailable | The rate-limit store is not configured, or the connection gate could not evaluate the request. Retry shortly; nothing was charged. |
503 | datastore_unavailable | The ledger could not be read. Retry with backoff; the balance was not changed. |