# Credits and billing

What a job costs, how credits are reserved and settled, the pools they come from, running out, plans, packs, auto-recharge and overage.

Everything Kaabist does for you is paid in credits: a job reserves what it may cost when you create it and settles what it did cost when it ends. Knowing how that works tells you what a program will cost, why a job is waiting, and what happens on the day the balance reaches zero.

## When to use it

Read this page before you put a program on a schedule or behind your own product, so you can estimate its cost and cap it with `max_credits`. Come back to it when a request answers `402 insufficient_credits`, when a job sits in `queued` with `meta.blocked_reason`, or when you choose between a bigger plan, credit packs and auto-recharge.

You buy credits with a plan's monthly allowance, with credit packs, or automatically. Paddle is the merchant of record: it takes the payment, adds tax for your country and sends the invoices.

## What a job costs

| Item | Price in credits |
|---|---|
| Compute, http tier | 1 per request |
| Compute, browser tier | 5, plus 1 for every started ten seconds past the first thirty |
| Compute, stealth tier | 20, plus 1 for every started ten seconds past the first thirty |
| Proxy traffic | per megabyte: datacenter 0.05, residential 0.5, mobile 2 |
| LLM (Kaabist's model) | per thousand input and per thousand output tokens, at the model's own rates ([by model](https://docs.kaab.ist/reference/plans#what-a-credit-buys)) |
| Captcha | 2 per solve |
| Session verification | 1 (http probe), 5 (browser probe) |

Model tokens are priced as the model's vendor prices them: what the model reads (input) and what it writes (output, its reasoning included) separately, output costing several times more. A job's `llm` line adds the two.

A job that escalates pays the compute of every tier it ran at. Time a job spends parked, waiting for input or for you, is free. A canary probe pays half its compute. A result served from the cache pays its compute and nothing else. If a provider is your own (bring your own proxy, LLM or captcha solver), its line costs nothing. A job that fails because of an internal error is refunded in full. A job created with a test key (`sk_test_`) reserves and costs nothing; it counts against a daily quota instead (see [Limits](https://docs.kaab.ist/concepts/limits#test-keys)).

Every finished job reports what it cost in `meta.credits`:

```json
"credits": { "reserved": 12, "settled": 7, "breakdown": { "compute": 5, "proxy": 2, "llm": 0, "captcha": 0 } }
```

The prices are also on [Plans and pricing](https://docs.kaab.ist/reference/plans).

### Estimating before you run

`POST /v1/jobs/estimate` takes the same body as `POST /v1/jobs` and answers `{ "credits_min", "credits_max", "tier_expected", "cache" }` without running anything:

### TypeScript

```ts
const estimate = await kaab.jobs.estimate({
  url: `${site}/p/1`,
  extract: { title: "h1", price: { selector: ".price", type: "money" } },
});
console.log(
  `between ${estimate.credits_min} and ${estimate.credits_max} credits at ${estimate.tier_expected} tier`,
);
```

### Capping a job

`options.max_credits` is the most a job may spend. The worker keeps a running tally with the same prices settlement uses, and a job that would go past the cap stops and fails with `max_credits_exceeded`. Set it on any program whose cost depends on the page, such as a paginated list or a browser flow that may wait on slow pages.

## Reserve, settle, release

1. **Reserve.** Creating a job reserves what it is expected to cost: the price of its expected work at the tier it starts at (from the program's history, or the tier's price and three seconds a step for a browser program), with half again as a margin, and never more than `max_credits`. If the reservation cannot be made, the request answers `402 insufficient_credits` and no job is created.
2. **Settle.** When the job ends, its actual cost is charged from the reservation.
3. **Release.** What the reservation held beyond the actual cost is given back at the same moment.

A job that parks gives its reservation back, and takes one again when you resume it; if it cannot, the resume answers `402` and the job stays parked. An escalation reserves the difference for the stronger tier. A retry inside a job never reserves twice. `GET /v1/credits` shows the result:

```json
{
  "balance": 9840,
  "reserved": 60,
  "available": 9780,
  "pools": [{ "type": "allowance", "amount": 9780, "expires_at": "2026-11-01T00:00:00Z" }],
  "auto_recharge": null
}
```

`available` is `balance − reserved`: what new jobs can still take. Every API response carries it as `X-Credits-Remaining` (cached for up to ten seconds), so a client can watch it without an extra call.

## Where credits come from, and in what order they are spent

`pools` lists every lot with credits left, in the order they are consumed:

1. **`promo`**: promotional credits, which expire first;
2. **`allowance`**: your plan's monthly allowance, which expires at the end of the period;
3. **`purchased`**: credit packs (1 000, 10 000 or 100 000 credits), which last twelve months.

Within a pool, the credits that expire soonest are spent first. A fourth entry, **`overage`**, appears with a negative amount while overage is owed.

`GET /v1/ledger` lists every entry behind your balance. The ledger is append-only: `purchase`, `grant`, `subscription_allowance`, `reserve`, `settle`, `release`, `refund`, `expire` and `adjust` are each their own entry, with the pool it touched and the job it belongs to, so an invoice can always be traced to the jobs behind it.

`GET /v1/usage?from=…&to=…&group_by=day|program|tier|tag` aggregates finished jobs: how many, what they cost, and the four itemised units (compute, proxy megabytes, LLM tokens, captcha solves). Grouping by `tag` counts a job under each of its tags, so those rows sum to more than your total when jobs carry several: `customer:42` means "what did customer 42 cost", not a share of something.

## Running low and running out

You are told by e-mail and by the `credits.low` [event](https://docs.kaab.ist/reference/events) when 80 % and then 95 % of the period's allowance is used (once per level per period), by `credits.exhausted` when nothing more can be spent, and by `credits.recharged` when credits arrive again.

When nothing is left:

- new jobs are refused with `402 insufficient_credits`;
- a queued job that needs a reservation it does not hold waits in `queued` with `meta.blocked_reason: "insufficient_credits"`, and the `job.blocked` event fires once; it runs when credits arrive (see [Queueing](https://docs.kaab.ist/concepts/queueing#worked-example));
- schedules and canaries pause (`paused_reason: "credits"`) and resume by themselves when credits arrive;
- a parked job cannot be resumed until credits arrive;
- jobs already running finish, and everything you have already run stays readable, along with the panel, webhooks and every read endpoint.

### Overage

Organisations with a payment method can run past zero up to their plan's overage limit. The overage is invoiced at the end of the period in whole packs of 1 000 credits, and whatever the rounding bought beyond the overage is added as purchased credits. The free plan has no overage.

### Auto-recharge

Auto-recharge buys a pack whenever your available credits drop below a threshold you choose. It charges your plan's payment method, tries at most once every ten minutes, and waits a day after a declined payment.

## Plans

Every organisation starts on the free plan: 500 credits a month, the http tier only, one job at a time. The browser and stealth tiers, bring-your-own providers, `evaluate` and programs that sign in need a verified payment method, which buying a plan or a pack adds; the tiers above http, bring-your-own providers and `evaluate` also need a plan that includes them. Upgrading takes effect immediately; a downgrade takes effect at the end of the period; cancelling returns the organisation to the free plan when the period ends. What each plan includes, including its allowance, overage limit, concurrency and retention, is on [Plans and pricing](https://docs.kaab.ist/reference/plans).

## The billing page

**Billing** in the panel is where an owner or admin buys and changes things; everybody else sees it read-only, with a note that an owner or admin makes purchases. Owners and admins without two-factor authentication see a prompt to set it up first, because purchases need it.

From top to bottom:

- **Current plan.** The plan's name and status, the allowance used this period as a bar with "used / total", the renewal date and the percentage used, the credits available now (with how many came from packs, and a link to the ledger), and, on a plan with overage, how much is owed of the limit, invoiced at the end of the period. A scheduled downgrade shows as "changes to *plan* at the end of this period". **Payment method & invoices** opens Paddle's customer portal. Without a payment method, the card says which features need one.
- **Plans.** A comparison table, one column per plan, with rows for credits a month, overage allowed, highest tier, concurrent jobs per tier, API requests a minute, shortest schedule, seats, result retention, bring-your-own providers, `evaluate` steps and regions. Each other plan has an **Upgrade** or **Downgrade** button; enterprise says "Contact us". Prices exclude tax.
- **Credit packs.** One card per pack size, with its price and price per 1 000 credits, valid for 12 months, and a **Buy** button.
- **Auto-recharge.** An on/off switch, "when available credits fall below" a number, the pack to buy, and **Save**. Without a subscription it explains that it needs one. A failed recharge shows when it failed and that it is retried a day later.

Buying opens Paddle's checkout. When you come back, the page says the payment was received and updates by itself when Paddle confirms it, usually within seconds; if the confirmation is slow, it says so, and nothing is charged twice.

**Credits** (linked from Billing) shows the available balance, what running jobs have reserved, the pools with their expiry, the auto-recharge setting, and the ledger, filterable by entry type and exportable as CSV. A banner across the panel says when credits are running low, when they have run out, and when a payment failed.

## Worked example

A program reads a shop's catalogue (`https://shop.example.com/c/shoes`) over five pages at the http tier, and a schedule runs it every hour.

1. Estimate it: `POST /v1/jobs/estimate` with the program returns `credits_min` and `credits_max` at `tier_expected: "http"`. Five pages are five requests: five credits of compute, plus datacenter proxy traffic at 0.05 per megabyte.
2. Cap it: add `"max_credits": 10` to the program's options, so a site change that sends it through far more pages fails with `max_credits_exceeded` instead of spending.
3. Run it, and read `meta.credits`: `reserved` is the estimate with its margin, `settled` the actual cost, and the difference was released when the job ended.
4. Watch the balance: every response carries `X-Credits-Remaining`. On the day 80 % of the allowance is used, `credits.low` arrives with `level: 80`.
5. If the balance runs out, the hourly schedule pauses with `paused_reason: "credits"`, and a new job answers `402`. Buying a pack on the billing page sends `credits.recharged`, and the schedule resumes by itself.

## Pitfalls

- **`402` on creation means the reservation failed, not the job.** Nothing was created and nothing was charged. Retry after credits arrive.
- **Parked jobs hold no credits.** A job that has waited three days for input needs a fresh reservation to resume.
- **Escalation is paid twice.** A job that starts at http and moves to a browser pays both. If a site always needs a browser, set `prefer_tier` so it starts there.
- **Proxy traffic is billed per megabyte.** Browser jobs that load images and fonts move more bytes; asset blocking is on by default for that reason.
- **Overage needs a payment method.** Without one, the balance stops at zero.

## Reference

- [Get credits](https://docs.kaab.ist/reference/api/credits/get-credits), [list ledger entries](https://docs.kaab.ist/reference/api/ledger/list-ledger-entries), [get usage](https://docs.kaab.ist/reference/api/usage/get-usage)
- [Estimate a job](https://docs.kaab.ist/reference/api/jobs/estimate-job)
- [Credits schema](https://docs.kaab.ist/reference/api/schemas/credits) and [ledger entry schema](https://docs.kaab.ist/reference/api/schemas/ledger-entry)
- The `credits.low`, `credits.exhausted`, `credits.recharged` and `job.blocked` [events](https://docs.kaab.ist/reference/events)
- [Plans and pricing](https://docs.kaab.ist/reference/plans)
- [`kaab credits`](https://docs.kaab.ist/reference/cli/kaab-credits) and [`kaab usage`](https://docs.kaab.ist/reference/cli/kaab-usage)
