X-Account-Id on these
calls — the organization you authenticated as is the whole scope.
Prices
Public and unauthenticated — the whole catalogue, identical for everyone.
Usage and invoices
What is accruing now, and what has already been billed.
Credits
How grants are consumed and where they show up on an invoice.
The collection timeline
Retry days, past due, and what non-payment eventually costs you.
The public price catalogue
GET /v1/prices takes no credentials. It is one of only two unauthenticated
endpoints on the platform — the other is GET https://iam.basaltic.sh/v1/regions.
It is public because there is nothing tenant-specific in it. There are no
account-level rates, discounts or committed-use terms in this table — every
caller gets the same numbers, which is precisely why it is safe to publish
and useful to read. It exists so that a pricing page or a cost estimator
reads the rate billing will actually charge, instead of keeping its own copy
that drifts the next time something is repriced.
X-RateLimit-Remaining and X-RateLimit-Reset
rather than hard-coding that; on a 429, wait Retry-After seconds, since
retrying early extends the window. Responses carry
Cache-Control: public, max-age=300 — the catalogue changes when something is
repriced, not per request, so caching it for five minutes costs you nothing.
Filters
family is how the managed products are told apart from the general compute
flavors they share a resource_type with — load balancer replicas and database
cluster nodes are billed as instances, but they are their own family.
at is what you use to explain a past invoice: pass the invoice’s
period_start and you get the rates that were in force then. as_of in the
response echoes the instant the rows were selected as of, so a client can say
which revision of the catalogue it is holding.
Money is a decimal string, never a JSON number, everywhere in this API.
"0.085" survives a round trip through any language’s JSON parser exactly;
a float does not. The quoted rate is the one that will be charged, so it
cannot be allowed to round differently on the way out.Month-to-date usage
amount carries four decimal places while the total carries two. That is
not inconsistency — early in a month a line can be worth a fraction of a cent,
and rounding it to two places would render it as 0.00 and make it look like
nothing is accruing. The total, and every figure on an invoice, stays at the
ledger’s two.
Invoices
An invoice is generated on the 1st of each month, covering the previous UTC calendar month, one per organization.period_start is the first day of the billed month and period_end is
exclusive — the first day of the following month. Late-arriving usage from
older months sweeps into the next invoice generated rather than reopening a
closed one, so an invoice’s line items are not always confined to its labelled
period.
The arithmetic is subtotal - credits_applied = total. Usage lines carry
kind: "usage"; credit lines carry kind: "credit" and a negative amount.
items is populated only on the detail endpoint. GET /v1/invoices returns
the invoice documents without line items, because a list of a year’s invoices
with every line expanded is a large response nobody asked for.Statuses
due_at equals issued_at. An invoice is due when it is issued, and the first
charge attempt happens immediately — the days that follow are retries, not a
grace period.
Small invoices are written off rather than charged. A total below 1.00
in the invoice currency is written off at generation, and the invoice reads
paid without any payment ever having been attempted. The cost of collecting
a sub-unit amount exceeds the amount.The PDF statement
pdf_url field on an invoice is the path to
this endpoint, not a pre-signed link you can hand to someone else.
Credits
amount it was issued for and the remaining
balance, plus a source — promo, coupon, adjustment or migration — and
an optional expires_at.
Grants are consumed at invoice generation, soonest-expiring first, until the
subtotal is covered. Each consumed slice becomes its own negative line on the
invoice and its own credit_applied entry in the ledger, so you can always
trace which grant paid for what.
Credits are applied automatically. There is no endpoint to apply one to a
particular invoice, and none to redeem a code — a code is redeemed in the
console, which is what creates the grant.
Transactions and payments
GET /v1/transactions is the ledger: payment, refund, adjustment,
credit_grant and credit_applied entries.
GET /v1/payments lists charge attempts. Each row carries attempt, a 1-based
counter within the collection schedule for its invoice, and a status of
pending, processing, succeeded, failed or refunded. Several rows
against one invoice is the normal shape of a retry sequence, not a sign of
duplicate charges.
What happens to an unpaid invoice
Collection runs on a fixed schedule from the moment the invoice is issued: If none of the three attempts collects, the invoice moves topast_due.
Settle a past_due invoice from the console. That is also where you fix the
payment method that caused the declines — the API has no path to either.
Pagination
GET /v1/invoices, /v1/credits, /v1/transactions and /v1/payments all
page the same way: pass limit (default 20, maximum 100) and echo back
meta.marker from the previous page.
Permissions
GET /v1/prices needs no permission, because it needs no identity.
Next
Rate limits
How the
X-RateLimit-* headers work, and signing every other request.Policies
Who in your organization can read the bill.
Regions
Why billing has no region segment.
API reference
Every billing operation, with request and response schemas.