Billing Reconciliation & Automated Usage Sync
If you want to feed AIone spend data into your own finance / monitoring system (daily reconciliation, balance alerts, per-model cost allocation), there is no need to log into the console and export by hand. The platform offers two programmatic query channels — combine them as needed for fully automated reconciliation:
| Channel | Credential | Best for |
|---|---|---|
① API-token direct query (/v1/dashboard/billing/*) |
Your sk-nex- API token |
Balance monitoring, quota alerts, month-to-date spend. Zero login; works out of the box with one-api / new-api ecosystem balance-checker tools |
② Account login for details (/api/v1/obs/*, /api/v1/billing/*) |
Console account (email + password) | Line-item reconciliation: aggregation by day / model / key, CSV / XLSX export, ledger and invoices |
Reconciliation basis: both channels read the same billing facts (the per-request
usage_ledger). All amounts are in USD, and month boundaries follow your organization's configured timezone. The sum of per-requestcost_usdin the detail export equals the invoice amount — there is no second set of books.
1. API-token direct query (recommended for daily monitoring)
Base URL: https://api.portal.aiin1.ai. Authentication is identical to model calls (Authorization: Bearer sk-nex-..., subject to the API key's IP allowlist). Responses use the OpenAI-compatible format.
1.1 Credit summary: GET /v1/dashboard/billing/credit_grants
curl https://api.portal.aiin1.ai/v1/dashboard/billing/credit_grants \
-H "Authorization: Bearer sk-nex-your-key-here"{
"object": "credit_summary",
"total_granted": 1000.0,
"total_used": 137.42,
"total_available": 862.58,
"grants": { "object": "list", "data": [] }
}Field semantics depend on your billing mode:
| Billing mode | total_available |
total_used |
total_granted |
|---|---|---|---|
| prepaid | real-time available balance | month-to-date spend | balance + month-to-date spend |
| postpaid / hybrid | credit limit − current exposure | current exposure (= month cost − confirmed payments this month) | credit limit |
1.2 Subscription / quota: GET /v1/dashboard/billing/subscription
curl https://api.portal.aiin1.ai/v1/dashboard/billing/subscription \
-H "Authorization: Bearer sk-nex-your-key-here"{
"object": "billing_subscription",
"has_payment_method": true,
"soft_limit_usd": 862.58,
"hard_limit_usd": 862.58,
"system_hard_limit_usd": 862.58,
"plan": { "title": "prepaid", "id": "prepaid" }
}hard_limit_usd is your current spending cap: the credit limit for postpaid / hybrid, or the current available balance for prepaid.
These endpoints mirror OpenAI's legacy billing API, so any tool that can "check an OpenAI balance" (browser extensions, new-api / one-api channel balance monitors, etc.) works by pointing its base URL at
https://api.portal.aiin1.ai.
2. Account login for line-item details (reconciliation / export)
Detail data lives under the console backend API, base URL https://portal.aiin1.ai/api/v1. Auth is a short-lived session token: log in once with a console account, receive an access_token valid for 15 minutes, and complete all pulls within that window — no token-refresh logic needed.
Recommendation: create a dedicated regular-member account for reconciliation (Console → Team members → Invite) and leave two-factor auth (TOTP) off. An account with TOTP enabled must also submit a
totp_codeat login, which is unsuitable for scripts.Rate limiting: the login endpoint is rate-limited per source IP. The correct pattern is "log in once → reuse the token for every pull" — do not re-login per request.
2.1 Login: POST /auth/login
TOKEN=$(curl -s https://portal.aiin1.ai/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{ "email": "billing-bot@yourcompany.com", "password": "YOUR_PASSWORD" }' \
| jq -r .access_token)Response:
{ "access_token": "eyJhbGci...", "token_type": "bearer", "expires_in": 900 }Send Authorization: Bearer $TOKEN on all subsequent requests.
2.2 Usage aggregation: GET /obs/usage
| Param | Type | Required | Description |
|---|---|---|---|
start / end |
date | no | Date range (YYYY-MM-DD, inclusive). Must be provided together, span ≤ 365 days, end must not be a future date. Falls back to range_days when omitted |
range_days |
int | no | Last N days (default 7) |
group |
string | no | Aggregation: date (default) / model / team / key / owner; comma-combine for a cross-tab (e.g. group=model,key) — group_key composes with | in the given order |
model |
string | no | Filter by model name |
apikey_id |
uuid | no | Filter by API key |
team_id |
uuid | no | Filter by team |
curl -s "https://portal.aiin1.ai/api/v1/obs/usage?start=2026-07-01&end=2026-07-31&group=model" \
-H "Authorization: Bearer $TOKEN"The response is an array; each row contains:
| Field | Description |
|---|---|
group_key / group_name |
Aggregation key (date, model name, team / key ID and name) |
request_count |
Request count |
prompt_tokens / completion_tokens / total_tokens |
Input / output / total tokens |
cache_creation_input_tokens / cache_read_input_tokens |
Cache write / hit tokens |
cost_usd |
Spend (USD) |
avg_latency_ms / error_count |
Average latency / error count |
2.3 Per-request detail export: GET /obs/usage/export (CSV)
Params: start, end (required), optional model / apikey_id / team_id filters. Streams CSV directly:
curl -s "https://portal.aiin1.ai/api/v1/obs/usage/export?start=2026-07-01&end=2026-07-31" \
-H "Authorization: Bearer $TOKEN" -o usage-202607.csvCSV columns: occurred_at, request_id, trace_id, model, apikey_id, team_id, subscription_id, prompt_tokens, completion_tokens, cache_creation_input_tokens, cache_read_input_tokens, total_tokens, latency_ms, status_code, error_code, input_per_1m_usd, output_per_1m_usd, cache_write_per_1m_usd, cache_read_per_1m_usd, price_multiplier, cost_usd
One row per request: token facts plus the unit prices and discount in effect for that request (*_per_1m_usd are list prices, price_multiplier is your discount factor), so you can independently recompute cost_usd. Time columns are rendered in the organization's timezone.
Excel variants at the same path: GET /obs/usage/export.xlsx (details) and GET /obs/usage/stats.xlsx (statistics), same params.
2.4 Ledger & invoices
| Endpoint | Description |
|---|---|
GET /billing/account |
Account snapshot: billing_mode, credit_balance_usd, credit_limit_usd |
GET /billing/ledger?page=1&page_size=100 |
Ledger entries (top-ups / charges / adjustments): type, direction, amount_usd, balance_after_usd, description, created_at |
GET /billing/invoices?start=&end=&page=&page_size= |
Invoice list: invoice_no, period_start/end, total, status, due_date |
GET /billing/invoices/{id} |
Invoice detail (with line items) |
GET /billing/invoices/{id}/pdf |
Invoice PDF download |
2.5 Full example: daily T+1 reconciliation script
#!/usr/bin/env bash
set -euo pipefail
BASE="https://portal.aiin1.ai/api/v1"
DAY=$(date -d "yesterday" +%F 2>/dev/null || date -v-1d +%F)
TOKEN=$(curl -sf "$BASE/auth/login" -H "Content-Type: application/json" \
-d "{\"email\":\"$BILLING_EMAIL\",\"password\":\"$BILLING_PASSWORD\"}" | jq -r .access_token)
# Yesterday's per-request detail CSV
curl -sf "$BASE/obs/usage/export?start=$DAY&end=$DAY" \
-H "Authorization: Bearer $TOKEN" -o "usage-$DAY.csv"
# Yesterday's per-model summary
curl -sf "$BASE/obs/usage?start=$DAY&end=$DAY&group=model" \
-H "Authorization: Bearer $TOKEN" > "usage-$DAY-by-model.json"
# Current balance (token channel; also fits a standalone balance-alert job)
curl -sf https://api.portal.aiin1.ai/v1/dashboard/billing/credit_grants \
-H "Authorization: Bearer $NEXARA_API_KEY" > "balance-$DAY.json"3. FAQ
Q: Can the two channels disagree?
No. The balance channel's month-to-date spend and the sum of per-request cost_usd from the detail channel come from the same ledger. The only thing to watch is the timezone: month boundaries and detail timestamps follow your organization's timezone — use the same timezone when aggregating on your side.
Q: What if the access_token expires? It lives for 15 minutes by design — a reconciliation script should "log in → pull → done". If a single pull exceeds 15 minutes (a very large export), split the date range into batches.
Q: Can I pull line-item details with the sk-nex- token directly?
The detail channel currently requires account login. If your use case strongly needs token-based detail queries, contact us.