Fetch credits, inspect the wallet, and buy packages.
Kendr’s billing model is wallet-based. The current balance lives on the customer account, active packages come from the live catalog, purchases credit the wallet, and successful queries deduct credits after the provider returns a successful response.
Where credits live
The live balance is exposed as user.credit_balance inside GET /api/me/dashboard.
Active packages are available in both GET /api/catalog and GET /api/me/dashboard.
Customer purchase history is returned as purchases on the dashboard payload.
Wallet debits are exposed through ledger entries and query responses such as remaining_credits.
Fetch the current credit balance
The dashboard endpoint is the main place to fetch credits. It returns the user record plus packages, purchases, ledger, API keys, and enabled surfaces in one call.
Curl with app session
curl https://kendr.org/api/me/dashboard \ -H "X-Kendr-Session: $KENDR_SESSION"
Curl with OAuth bearer
curl https://kendr.org/api/me/dashboard \ -H "Authorization: Bearer $KENDR_OAUTH_ACCESS_TOKEN"
JavaScript fetch
const response = await fetch('https://kendr.org/api/me/dashboard', {
headers: {
'X-Kendr-Session': process.env.KENDR_SESSION
}
});
const payload = await response.json();
console.log(payload.user.credit_balance);
console.log(payload.packages);
Python requests
import os
import requests
payload = requests.get(
'https://kendr.org/api/me/dashboard',
headers={'X-Kendr-Session': os.environ['KENDR_SESSION']},
timeout=30,
).json()
print(payload['user']['credit_balance'])
print(payload['packages'])
{
"ok": true,
"user": {
"id": 12,
"email": "user@example.com",
"full_name": "Example User",
"credit_balance": 250
},
"packages": [...],
"api_keys": [...],
"purchases": [...],
"ledger": [...],
"surfaces": [...]
}
Discover active packages before purchase
Do not hardcode package IDs or prices. Load them from the live catalog or dashboard payload before constructing a purchase request.
Curl
curl https://kendr.org/api/catalog
JavaScript
const catalog = await fetch('https://kendr.org/api/catalog').then(res => res.json());
console.log(catalog.packages);
Each package includes id, slug, name, description, credits, price_cents, currency, and sort metadata.
Purchase credits
Purchases are made through POST /api/me/purchases. The route accepts either package_id or package_slug. It returns the new balance and the purchased package metadata.
Curl by package ID
curl https://kendr.org/api/me/purchases \
-X POST \
-H "X-Kendr-Session: $KENDR_SESSION" \
-H "Content-Type: application/json" \
-d '{
"package_id": 3
}'
Curl by package slug
curl https://kendr.org/api/me/purchases \
-X POST \
-H "X-Kendr-Session: $KENDR_SESSION" \
-H "Content-Type: application/json" \
-d '{
"package_slug": "starter-250"
}'
JavaScript fetch
const purchase = await fetch('https://kendr.org/api/me/purchases', {
method: 'POST',
headers: {
'X-Kendr-Session': process.env.KENDR_SESSION,
'Content-Type': 'application/json'
},
body: JSON.stringify({ package_id: 3 })
}).then(res => res.json());
console.log(purchase.balance_after);
Python requests
import os
import requests
purchase = requests.post(
'https://kendr.org/api/me/purchases',
headers={
'X-Kendr-Session': os.environ['KENDR_SESSION'],
'Content-Type': 'application/json',
},
json={'package_id': 3},
timeout=30,
).json()
print(purchase['balance_after'])
{
"ok": true,
"purchase_id": 18,
"balance_after": 250,
"package": {
"id": 3,
"slug": "starter-250",
"name": "Starter 250",
"credits": 250,
"price_cents": 2500,
"currency": "USD"
},
"created_at": "2026-04-24T00:00:00Z"
}
Ledger and purchase history
The dashboard response exposes both purchases and ledger. Purchase entries describe package top-ups. Ledger entries describe both top-ups and usage debits.
| Field | Where it appears | Meaning |
|---|---|---|
| credits_delta | ledger | Positive for purchases, negative for usage. |
| balance_after | ledger | The wallet balance after the ledger entry was applied. |
| entry_type | ledger | Examples include purchase and usage. |
| external_reference | purchases | Purchase identifier recorded by the backend. |
| package_slug and package_name | purchases | The package that produced the credit top-up. |
When credits are charged
- Credits are deducted after POST /api/v1/query succeeds against a provider.
- The successful response includes credits_charged and remaining_credits.
- Provider fallback failures can appear in provider_attempts, but failed attempts do not directly charge the wallet.
- If the balance is below the surface cost, the query returns 402 and no charge is made.