Credits & Billing
Check your credit balance and understand how credits work.
All generations consume credits from your account. Credits come from your subscription plan, credit packs, and redemptions.
Endpoint
GET /api/v1/account/creditsThe endpoint takes no query parameters and no request body. It always reports the balance of the account the API key belongs to — there is no way to query another user.
curl
curl https://api.kolbo.ai/api/v1/account/credits \
-H "X-API-Key: YOUR_API_KEY"JavaScript
async function main() {
const response = await fetch("https://api.kolbo.ai/api/v1/account/credits", {
headers: { "X-API-Key": "YOUR_API_KEY" }
});
const data = await response.json();
console.log(data.credits.total);
}
main();Python
import requests
response = requests.get(
"https://api.kolbo.ai/api/v1/account/credits",
headers={"X-API-Key": "YOUR_API_KEY"}
)
print(response.json()["credits"]["total"])Response
{
"success": true,
"credits": {
"total": 1500,
"plan_credits": 1000,
"credit_pack": 400,
"redemption": 100
}
}Response Fields
| Field | Type | Description |
|---|---|---|
credits.total | number | Spendable balance. Normally the sum of the three buckets below. |
credits.plan_credits | number | Subscription bucket. 0 when there is no subscription record. |
credits.credit_pack | number | One-time purchase bucket. |
credits.redemption | number | Gift-code / promotion bucket. |
Balances are numbers, not integers — some charges (chat turns, for example) are billed in tenths of a credit, so expect values like 1499.7.
total is not always the sum of the three buckets. Legacy accounts predating the bucket split report all three buckets as 0 while total carries the real balance from the account's single legacy credit field. Always spend against total; treat the three buckets as informational.
total is a gross balance — it does not subtract in-flight reservations. Credits for a generation that is still running are held as a reservation and are already unavailable, but they are still counted in total. Immediately after firing a batch, total reads higher than what you can actually spend.
Credit Types
| Type | Source | Behavior |
|---|---|---|
plan_credits | Subscription plan | Paid personal credits roll over while paid access is active, with new monthly grants capped at three monthly allocations. Annual plans also allocate monthly. Free plans reset instead of accumulating. |
credit_pack | One-time purchases | Never expire; no monthly or 90-day reset. Separate from the subscription balance cap and retained after paid access ends. |
redemption | Gift codes, promotions | Never expire |
The three-allocation subscription cap is a balance cap, not a three-month expiry. When paid access ends, the subscription bucket returns to the free allowance; purchased pack credits remain. See Subscription & Billing for retention and comparison rules. The Developer USD wallet is a separate product; these credit-bucket rules describe the credit-billed API.
Credit Deduction
Credits are reserved when a generation starts and confirmed at the real, multiplier-adjusted cost when it finishes. If a generation fails or is cancelled, the reservation is released and any already-deducted credits are refunded.
Deduction Order
- Plan credits (used first)
- Credit pack credits
- Redemption credits
Legacy accounts with no buckets deduct from their single credit field instead. Every bucket is floored at zero, so a race can never drive a balance negative.
What a Generation Actually Cost
Poll GET /api/v1/generate/{generation_id}/status. Once state is completed the response carries the authoritative numbers:
| Field | Description |
|---|---|
credits_used | Total credits actually deducted for this generation, multiplier-adjusted. |
credits_breakdown | Array with one { model, amount } row per deduction linked to the generation. model is the billed model identifier; amount is what that row deducted. |
Both fields are omitted when no deduction rows exist yet — do not treat their absence as "free". Base vs. final cost and resolution per deduction are available from the caller-session endpoint below (recent[].base / final / resolution).
GET /api/v1/generate/creative-director/{id}/status never carries credits_used or credits_breakdown — each scene is billed independently. Reconcile Creative Director batches with the caller-session endpoint below.
Cancelling returns credits_refunded on the cancel response:
curl -X POST https://api.kolbo.ai/api/v1/generate/GENERATION_ID/cancel \
-H "X-API-Key: YOUR_API_KEY"{
"success": true,
"generation_id": "6650...",
"type": "video",
"state": "cancelled",
"credits_refunded": 40
}credits_refunded falls back to 0 when the cancel reports no refunded amount. Cancelling a batch also returns batch_cancelled_count. Cancel failures return 404 (NOT_FOUND, or no code at all when the id is not one of your API generations), 403 (FORBIDDEN), 409 (CANNOT_CANCEL, NOT_IN_PROGRESS) or 503 (CANCELLATION_SETTLEMENT_PENDING).
What a Whole Integration Session Cost
Every request may carry an optional X-Kolbo-Caller-Session-Id header — a stable identifier you choose for one run of your integration (see Authentication). Credit deductions made while that header is present are tagged with it, and you can aggregate them afterwards:
GET /api/credit-usage/by-caller-sessionThis endpoint lives under /api/credit-usage, not under /api/v1. It authenticates with the same X-API-Key header.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
caller_session_id | string | Conditional | The session id to aggregate. Wins over the header when both are sent. Required unless you send the same value in the X-Kolbo-Caller-Session-Id header on this request. Must be a string — an array or object value returns 400. Truncated to 128 characters. |
startDate | string | No | Lower bound on created_at. Any value new Date() can parse; unparseable values are ignored rather than rejected. |
endDate | string | No | Upper bound on created_at. Same parsing rule. |
curl "https://api.kolbo.ai/api/credit-usage/by-caller-session?caller_session_id=run-2026-07-27-a" \
-H "X-API-Key: YOUR_API_KEY"Response
{
"message": "Caller-session usage retrieved successfully",
"data": {
"caller_session_id": "run-2026-07-27-a",
"total": 184,
"count": 12,
"by_tool": [{ "generation_type": "image", "amount": 96, "count": 8 }],
"by_model": [{ "model": "nano-banana-2", "amount": 96, "count": 8 }],
"recent": [
{
"amount": 12,
"model": "nano-banana-2",
"generation_type": "image",
"generation_id": "6650...",
"created_at": "2026-07-27T10:00:00Z",
"base": 8,
"final": 12,
"resolution": "2K"
}
]
}
}Only deduction records are counted (refunds are not netted out). Charges where you were the requester on a shared project but another account paid are included. by_tool and by_model are sorted by amount, highest first.
total is the real, multiplier-adjusted spend — not an estimate from base credits. recent is capped at the 50 most recent deductions, newest first. Missing the id entirely returns 400 with caller_session_id required as a string (query param or X-Kolbo-Caller-Session-Id header).
Insufficient Credits
The generation routes listed in the table below run a pre-flight balance check before doing any work. It compares your total against a per-type minimum floor — a lower bound meant to reject requests that cannot succeed with any model of that type. Failing it returns 403:
{
"success": false,
"error": "Insufficient credits for image. Your balance is 1, minimum required: 2. Top up at app.kolbo.ai to continue.",
"code": "INSUFFICIENT_CREDITS",
"balance": 1,
"required": 2,
"pricing_url": "https://app.kolbo.ai/pricing?..."
}| Field | Description |
|---|---|
balance | Your current total (0 when the account has no subscription record). |
required | The floor for this generation type (table below). |
pricing_url | Link to the app's pricing page, where plans and credit packs are bought. |
Pre-flight minimums
| Generation type | Routes (under /api/v1) | Minimum total |
|---|---|---|
| Chat | POST /chat, POST /analyze/video | 1 |
| Image, image edit | POST /generate/image, POST /generate/image-edit | 2 |
| Speech, sound, transcription | POST /generate/speech, POST /generate/sound, POST /transcribe | 2 |
| Global image edit | POST /edit/image | 2 |
| Music | POST /generate/music (including composition_plan mode), POST /generate/music/extend, POST /generate/music/cover | 3 |
| Lipsync, Creative Director | POST /generate/lipsync, POST /generate/creative-director | 5 |
| Global video edit | POST /edit/video (skipped for operation: "draft_quote") | 5 |
| Video, video from image, elements, first & last frame | POST /generate/video, POST /generate/video/from-image, POST /generate/elements, POST /generate/first-last-frame | 10 |
| Video-to-video, 3D | POST /generate/video-from-video, POST /generate/3d | 20 |
| Audio separation | POST /audio/separate, POST /audio/clean-dialogue, POST /audio/ambience | 20 |
Any generation type not in this table falls back to a floor of 1. These are floors, not prices — clearing one says nothing about whether the model you picked is affordable.
Other credit-spending routes carry no SDK-layer floor at all — POST /visual-dna/character-sheet, POST /video/trim, POST /voices/clone, POST /generate/music/reference-audio, POST /generate/music/edit-section and the two paid /music-library actions go straight to the underlying controller, whose own reservation is the first and only credit check. Expect the insufficient-credits error from those to arrive later and in the controller's own shape, not as a synchronous INSUFFICIENT_CREDITS.
Passing this pre-flight check does not mean the generation is affordable. It only proves you clear the floor for that generation type — and the check is deliberately best-effort: if the balance lookup itself fails, the request is allowed through rather than blocked. The real reservation happens afterwards using the selected model's exact cost, and can still fail. Compute the expected cost from GET /api/v1/models (see Models & Pricing) before submitting anything expensive.
Getting More Credits
- Upgrade your plan at kolbo.ai/pricing
- Purchase credit packs from your dashboard
There is no API to buy credits — top-ups happen in the app only. To show a user what they could buy, read the read-only catalog:
GET /api/v1/account/planscurl https://api.kolbo.ai/api/v1/account/plans \
-H "X-API-Key: YOUR_API_KEY"The response carries your account's real plans, prices and promotions:
| Field | Description |
|---|---|
success | true. |
credits.total | Same spendable balance as /account/credits. |
current_plan | { key, name } of your subscription plan, or null. |
plans, credit_packs | Arrays with the same row shape: key, name, interval, credits, price, original_price, discount_percent, promo_text, currency (default usd), top_up_discount, subscriber_price, is_subscriber. price is what you would pay now (promotional or subscriber price when one applies); original_price is the list price when a discount applies, otherwise null. discount_percent / promo_text are set only when you are eligible for a promotion. top_up_discount marks plans whose subscribers get cheaper credit packs; on a pack, subscriber_price is that cheaper price and is_subscriber says whether you already qualify. |
pricing_url | Link to the app's pricing page — the only place a purchase can be made. |
This route never creates a checkout session or payment link.