Credits
Charged actions cost credits, bought by the organization. A key spends the organization's balance within three limits: the team's monthly limit, your personal monthly limit, and the key's own monthly cap if you set one. GET /api/v1/credits shows the balance, the reserved credits and the team and personal limits with this month's use; GET /api/v1/me adds the key's cap and what the key has spent this month.
Quote first, always
A charged execution without quotedCredits is refused with 400 quote_required. Call /quote with the same input: it runs the action in preview mode, computes the exact cost from the tariff and the territory, and returns quotedCredits. Nothing is charged by a quote. Then call /execute with quotedCredits set to that number.
Why: an agent must state what it is about to spend. If the tariff or the territory changed between the two calls, the execution is refused with 409 quote_changed and the new quotedCredits; nothing is charged. This is the same confirmation step a person sees in the web app.
Hold, commit, release
When an execution starts, the quoted credits are reserved (a hold). When the result is delivered they are committed; if the run fails, is cancelled or is blocked, the hold is released and the balance is untouched. Progressive jobs (imports, geocoding) commit pro rata for the part actually done when stopped midway.
result.creditsCharged is the amount really committed; it can be lower than quotedCredits when part of the work turned out unnecessary (the description of each action says when). analysis.isochrone, charged per call only on the API and MCP, returns the bands without charged and creditsCharged: a successful call costs the quoted credits.
When there is not enough
402 insufficient_credits, with blockedBy:
blockedBy |
Meaning |
|---|---|
organization_balance |
the organization's available balance does not cover the run |
team_limit |
the team's monthly limit would be exceeded |
user_limit |
your personal monthly limit would be exceeded |
api_key_limit |
the monthly cap of this key would be exceeded |
Nothing is charged on a 402. Credits are bought in the web app (Account → Billing) by whoever has billing rights.
Tariffs
Each charged action has a tariff code, shown as x-kstra-tariff in the specification, and a pricing model (per item, per unit such as 1,000 addresses, or flat); the description of each action states its price, and the actions that combine others (enrich.point, enrich.points, site.rank) are quoted with the tariffs of the analyses they run, one line each. Totals are rounded up to the whole credit, except the assistant's own lines which round to the tenth. Tariffs can change: that is exactly why the quote is mandatory and the execution is bound to it.
Volume
Every port charges the same for the same question: an enrich.point costs what the same analyses cost in the web app, and a batch of 500 points costs 500 points. One exception: analysis.isochrone costs 3 credits per call over the API and MCP, while drawing an area in the web app is free. The catchments that the charged analyses compute for themselves are included in their own price and cost nothing extra. There are no volume tiers in the tariffs. Volume is rewarded in the price of the credit: monthly plans make each credit up to about 40% cheaper than the smallest one-off pack, and enterprise contracts go further. If you plan to enrich thousands of points, buy the largest plan or write to info@k-stra.com.
Dataset storage
Datasets kept on K-Stra (the ones imported in the web app and read by actions through datasetId) take space, and space has a monthly charge on the same balance: the first 50 MB of the organization are free, beyond that 2 credits a month every 100 MB, on the month's average, taken on the 1st of each month. It appears among the organization's operations in the web app (Usage) as dataset.storage; over the API you see it in the balance of GET /api/v1/credits.
If the balance does not cover it, the organization's datasets are suspended: an action that reads one (a coverage or site comparison point with source: "dataset", a loyalty analysis) is refused with 400 validation_error and a detail saying so, before anything is charged. Buying credits pays the charge and reactivates them at the next request. After 90 days of suspension the datasets are deleted, with an email a week before.
Idempotency
Charged executions accept an idempotencyKey in the body, or the Idempotency-Key header, of at most 80 characters: a longer key in the body is refused with 400 validation_error, a longer header is ignored and the call counts as a new run. A retry with the same key inside the same organization never charges twice: the run is computed again and its credits are not taken a second time. Use a fresh key for each new run.