Balance
3 endpoints. Every path below is relative to the API base URL and already includes the /api/v1 prefix — see conventions for authentication, pagination, errors and idempotency.
| Endpoint | ||
|---|---|---|
| GET | /billing/balance | Return the credit balance with reserved funds, burn rate, projected runway and estimated minutes left |
| GET | /billing/ledger | List credit ledger entries for a period with the balance after each, filterable by entry type |
| GET | /billing/ledger/reconcile | Recompute the balance from the ledger and report drift |
Endpoints
Return the credit balance with reserved funds, burn rate, projected runway and estimated minutes left
GET/billing/balance
- Requires
billing.read. - Provisions a billing account on first read if one does not yet exist, so a GET can create a row
bash
curl -X GET "$CALLAGENT_API_URL/billing/balance" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/balance`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/balance');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/billing/balance",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | Neither the API key scope nor the session user's permission allows billing.read |
Example response, generated from the schema:
json
{
"data": {
"currency": "string",
"balance": "string",
"available_balance": "string",
"reserved": "string",
"billing_mode": "string",
"status": "string",
"outbound_frozen": true,
"credit_limit": "string",
"dunning_stage": 1,
"burn_rate_per_day": "string",
"projected_runway_hours": "string",
"estimated_minutes_remaining": "string",
"daily_spend_cap": "string"
}
}List credit ledger entries for a period with the balance after each, filterable by entry type
GET/billing/ledger
- Requires
billing.read. - Defaults to the last 30 days.
from/togo straight to Carbon::parse with no validation, so a malformed date is a 500 rather than a 422.
bash
curl -X GET "$CALLAGENT_API_URL/billing/ledger" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/ledger`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/ledger');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/billing/ledger",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Errors
| Status | When it happens |
|---|---|
403 | Neither the API key scope nor the session user's permission allows billing.read |
Example response, generated from the schema:
json
{
"data": [
{
"id": null,
"type": "string",
"amount": "string",
"currency": "string",
"balance_after": "string",
"description": "string",
"source_type": "string",
"source_id": "01JQ0000000000000000000000",
"call_id": "01JQ0000000000000000000000",
"created_at": "2026-01-01T12:00:00+00:00"
}
],
"meta": {
"current_page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}Recompute the balance from the ledger and report drift
GET/billing/ledger/reconcile
Exposed on purpose: a customer who thinks their balance is wrong should be able to make us prove it against the ledger rather than trust a cache.
- Requires
billing.read. - Read-only from the API: the service's
repairmode is never enabled here, sorepairedis always false
bash
curl -X GET "$CALLAGENT_API_URL/billing/ledger/reconcile" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/ledger/reconcile`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/ledger/reconcile');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/billing/ledger/reconcile",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | Neither the API key scope nor the session user's permission allows billing.read |
Example response, generated from the schema:
json
{
"data": {
"organization_id": "01JQ0000000000000000000000",
"ledger_settled": "string",
"ledger_reserved": "string",
"cached_settled": "string",
"cached_reserved": "string",
"settled_drift": "string",
"reserved_drift": "string",
"ledger_entry_count": 1,
"cached_entry_count": 1,
"has_drift": true,
"repaired": true
}
}