Credits are prepaid, so running out blocks API calls instead of creating a bill. Topping up is human-only, so your job is to see it coming early enough that your human can act, and to cut the spend when it is more than the work needs.
GET /v1/billing/balance
It carries what is left, split grant vs paid, the spend per hour, and
runway_hours, the hours left at that rate. Watch runway_hours: the
balance alone does not tell you how long you have.
Responses also carry an X-Credits-Low header once the balance is close
enough to the cutoff to act on, so it reaches you on calls you were making
anyway. Read the balance when you see it.
GET /v1/usage?group_by=meter which meter the money goes to
GET /v1/usage?group_by=resource which VM, volume or snapshot
The hour in progress is flagged provisional until it closes; windows and
the other fields: Usage and billing.
GET /v1/billing/ledger is the full record, newest first, every debit linked
to the usage that caused it. It is mostly debits, so ?exclude=debit shows
whether a payment arrived.
Start from the meter at the top of group_by=meter, and do it while there is
runway left: every call below is a mutation, and the cutoff blocks those.
Stopping a VM stops its RAM charge and nothing else — the root disk, the address, its snapshots and its volumes bill whether it runs or not (lifecycle).
In this order:
snapshot-* meters). Each bills at
half the rate of the storage it covers, for as long as it exists;
deleting it stops the charge within the minute.volume-tb-hours). A detached volume costs
the same as an attached one.disk-tb-hours, ip-hours). Their disk and
address bill whether they run or not.When the spend is still too high for the work:
ram-gb-hours) on a VM whose
metrics show memory it does not use — available
memory above half for a week — and CPU to spare, since vCPUs drop with it:
sizing.egress-gb). A request it answers from its cache
is never metered: Put a CDN in front.ip-hours, disk-tb-hours). Each VM holds an
address and a root disk of its own, so services that fit on one machine
cost less there.disk-tb-hours). A root never shrinks, so
this means recreating the VM on a smaller one.volume-tb-hours). A volume never shrinks
either; copy its data to a new one, below.POST /v1/volumes {"name":"data2","size_gb":250} + Idempotency-Key
POST /v1/volumes/{new}/actions {"type":"attach","vm_id":"vm_..."}
# in the guest: make a filesystem on the new disk and mount it, copy with
# rsync -aHAX, stop whatever writes to the old one, copy again, then point
# /etc/fstab at the new UUID and unmount the old
POST /v1/vms/{id}/actions {"type":"stop"}
POST /v1/volumes/{old}/actions {"type":"detach"}
POST /v1/vms/{id}/actions {"type":"start"}
DELETE /v1/volumes/{old}
The detach refuses a volume the VM's snapshots include
(409 volume_in_snapshots, naming them); delete those first. Both volumes
bill, and count against the project's volume quota, until the old one is
deleted. Mounting by UUID:
Volumes.
402 credit_cutoff. Mutating calls are blocked; reads stay open, and so do
all of /v1/support and /v1/compliance, because case deadlines keep running
at zero. Running VMs are not killed.
After 7 days at zero the VMs are stopped, disks intact, and 30 days after that anything still there is deleted. A top-up at any point resumes everything.
POST /v1/billing/topup and PUT /v1/billing/refill answer
403 human_required, always, and retrying does not help.
GET /v1/billing/refill works with your key and reports the automatic refill
ceiling — read it before assuming a refill will cover what is coming.
So: watch runway_hours, tell your human what is spending and how long is
left, and scale down when the spend is more than the work needs or they are
not reachable. Top-ups happen in the dashboard, so there is no request to give
them.
Reference: Usage and billing.