# Account balance

Read your prepaid balance, how much of it is held by requests that are still running, and how much a new request can use. Call it from a script or an agent before a long job. The endpoint is specific to kenari and has no OpenAI or Anthropic equivalent.

`GET /v1/account/balance`

## Request

The endpoint takes no query parameters and no body. It needs an API key in the `Authorization` header.

| Header | Required | Description |
| --- | --- | --- |
| `Authorization` | yes | `Bearer kn-...`. Only an unrestricted key of your own account works. A shared API key and a restricted key are refused. See [Who can call it](#who-can-call-it). |

## Response

All amounts are integers in micro-Rupiah, where Rp 1 is 1,000,000 micro-Rupiah. See [How billing works](/en/docs/billing).

| Field | Type | Description |
| --- | --- | --- |
| `object` | string | Always `account.balance`. |
| `balance_micro_idr` | integer | Your balance. |
| `reserved_micro_idr` | integer | The amount held by requests that are still running. |
| `available_micro_idr` | integer | `balance_micro_idr` minus `reserved_micro_idr`, never below 0. This is what a new request can reserve against. |
| `currency` | string | Always `IDR`. |

Before a request runs, kenari holds its worst-case cost. When the request finishes, the hold is released and only the real cost is charged. So `reserved_micro_idr` goes up while requests run and returns to 0 when they are done. Use `available_micro_idr` to decide whether a new request fits. `balance_micro_idr` can be negative if a finished request cost more than its hold, while `available_micro_idr` stays at 0 in that case.

```json
{
  "object": "account.balance",
  "balance_micro_idr": 25000000000,
  "reserved_micro_idr": 1500000,
  "available_micro_idr": 24998500000,
  "currency": "IDR"
}
```

This balance is Rp 25,000, with Rp 1.5 held by a request in flight.

## Who can call it

Any API key of your account can call it, except:

- A shared API key gets `403` and `shared_key_not_allowed`.
- A restricted key gets `403` and `restricted_key_not_allowed`. A key is restricted when it has a model restriction, a spend cap or a token cap. The key's own usage is still readable from [`GET /v1/usage`](/en/docs/usage).

Use an unrestricted key from the account itself. See [Authentication and API keys](/en/docs/authentication).

## Examples

### curl

```bash
curl https://kenari.id/v1/account/balance \
  -H "Authorization: Bearer $KENARI_API_KEY"
```

### Python

```python
import os
import requests

response = requests.get(
    "https://kenari.id/v1/account/balance",
    headers={"Authorization": f"Bearer {os.environ['KENARI_API_KEY']}"},
)
response.raise_for_status()
balance = response.json()

print(balance["available_micro_idr"] / 1_000_000)
```

### JavaScript

```javascript
const response = await fetch("https://kenari.id/v1/account/balance", {
  headers: { Authorization: `Bearer ${process.env.KENARI_API_KEY}` },
});
if (!response.ok) throw new Error(await response.text());
const balance = await response.json();

console.log(balance.available_micro_idr / 1_000_000);
```

### Check before a batch

This script stops when the available balance is below what the batch needs. The estimate is yours to choose.

```python
import os
import requests

NEEDED_IDR = 50_000

response = requests.get(
    "https://kenari.id/v1/account/balance",
    headers={"Authorization": f"Bearer {os.environ['KENARI_API_KEY']}"},
)
response.raise_for_status()
available_idr = response.json()["available_micro_idr"] / 1_000_000

if available_idr < NEEDED_IDR:
    raise SystemExit(f"Only Rp {available_idr:,.0f} available. Top up first.")

# Start the batch here.
```

## MCP

The MCP tool `kenari_balance` returns your balance as plain text, in whole Rupiah. See [MCP server](/en/docs/mcp).

## Billing

Reading your balance is free and has no rate limit of its own. See [How billing works](/en/docs/billing).

## Errors

| Status | Code | When |
| --- | --- | --- |
| 401 | None | The key is missing, invalid or expired. The body is a short plain-text message, not JSON. |
| 403 | `shared_key_not_allowed` | The key is a shared API key. |
| 403 | `restricted_key_not_allowed` | The key has a model restriction, a spend cap or a token cap. The key's own usage is still readable from [`GET /v1/usage`](/en/docs/usage). |
| 500 | `internal_error` | Reading the balance failed in kenari. Retry once. |

See [Errors](/en/docs/errors) for the error format and the remaining codes.

## See also

- [Account overview](/en/docs/account)
- [Account quota](/en/docs/account-quota)
- [How billing works](/en/docs/billing)
- [MCP server](/en/docs/mcp)
