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) |
| 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).
Every finished job reports what it cost in meta.credits:
"credits": { "reserved": 12, "settled": 7, "breakdown": { "compute": 5, "proxy": 2, "llm": 0, "captcha": 0 } }
The prices are also on Plans and pricing.
#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:
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
- 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 answers402 insufficient_creditsand no job is created. - Settle. When the job ends, its actual cost is charged from the reservation.
- 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:
{
"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:
promo: promotional credits, which expire first;allowance: your plan's monthly allowance, which expires at the end of the period;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 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
queuedwithmeta.blocked_reason: "insufficient_credits", and thejob.blockedevent fires once; it runs when credits arrive (see Queueing); - 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.
#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,
evaluatesteps 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.
- Estimate it:
POST /v1/jobs/estimatewith the program returnscredits_minandcredits_maxattier_expected: "http". Five pages are five requests: five credits of compute, plus datacenter proxy traffic at 0.05 per megabyte. - Cap it: add
"max_credits": 10to the program's options, so a site change that sends it through far more pages fails withmax_credits_exceededinstead of spending. - Run it, and read
meta.credits:reservedis the estimate with its margin,settledthe actual cost, and the difference was released when the job ended. - Watch the balance: every response carries
X-Credits-Remaining. On the day 80 % of the allowance is used,credits.lowarrives withlevel: 80. - If the balance runs out, the hourly schedule pauses with
paused_reason: "credits", and a new job answers402. Buying a pack on the billing page sendscredits.recharged, and the schedule resumes by itself.
#Pitfalls
402on 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_tierso 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, list ledger entries, get usage
- Estimate a job
- Credits schema and ledger entry schema
- The
credits.low,credits.exhausted,credits.rechargedandjob.blockedevents - Plans and pricing
kaab creditsandkaab usage