Billing API
Read a team's credit and charges, pay with a checkout and manage add-ons.
Team Billing
GET /api/v1/teams/{teamSlug}/billingEvery member of the team may read it.
Response 200: the team's plan and pending_plan, its period, its
balance_cents, has_paid, whether a payment has reached the team,
pause_at, when its apps stop if they are due to, next_charge, the soonest
charge its credit has to meet (at, amount_cents, name), or null when none
is due, this period's usage, topup_limits (min_cents, max_cents), the last
50 ledger entries, its topups, its bundles: each bundle it holds,
an install of it with an app left, oldest first, with its install_id,
bundle_id and name, its monthly price_cents as it stands, which its next
charge takes, and trial_ends_at, when the free trial its install started ends,
or null for an install that paid its first month as it installed, and its
addons: each add-on it pays for, oldest first, with its purchase_id, kind,
name, app, app_slug, price_cents, which its next charge takes, and
ends_at, when it stops if it is being removed.
Checkouts
One route for anything bought. Owners and admins buy; anyone else gets 403
role_required.
GET /api/v1/teams/{teamSlug}/checkouts/terms?kind=credit
GET /api/v1/teams/{teamSlug}/checkouts/terms?kind=addon&item={addonID}&project={projectSlug}
GET /api/v1/teams/{teamSlug}/checkouts/terms?kind=bundle&item={bundleID}Response 200: what the dialog shows and sends back: due_cents, what leaves
the team's credit today; monthly_cents; next_charge_at; credit_cents;
short_cents; pay_cents, what is short, at least the smallest top-up;
topup_limits; public_key, Revolut's public key, empty while the checkout uses
its hosted page; mode, prod or sandbox; and for an add-on item, project,
app, name and move, up or down when it changes what the app has of that
kind. A move down takes effect at the next charge, with nothing due today. For a
solution, item and name are the bundle's, and due_cents and monthly_cents
its price for the team; it refuses as an install does (404 bundle_not_found, 409 bundle_not_offered, 409 bundle_installed).
POST /api/v1/teams/{teamSlug}/checkoutsBody {"kind": "credit", "amount_cents": 5000} or \{"kind": "addon", "item": "...", "project": "...", "amount_cents": ..., "monthly_cents": ..., "pay_cents": ...\}
or \{"kind": "bundle", "item": "...", "amount_cents": ..., "monthly_cents": ..., "pay_cents": ...\}: the amounts the dialog showed. amount_cents is what is due
today for an add-on or a solution, or what to add for credit.
Response 201: checkout. When credit covered it, its state is done and
the add-on is on. Otherwise it is open, with token for Revolut's widget and
checkout_url for its hosted page, and nothing is on until Revolut's webhook, on a
re-read order, says the payment landed. A payment always lands as credit first.
Every order is in euros, in cents, and a payment Revolut reports at another
amount or currency is not credited. A solution is only ever paid for here: the
webhook installs it once the payment lands, its first month taken at the price
shown, and the hourly read of open orders installs one the webhook missed. One
the team's credit covers is refused with 409 invalid_request, and installed from
its page instead.
Refusals 409 price_changed with terms, the terms as they stand, when any
amount differs; 409 addon_not_offered, and it answers so for a team that has
never paid; 409 addon_already_on; 409 project_stopped for an app that is stopped,
which is started first; 400 amount_out_of_range with min and max;
503 payments_unavailable; 502 payment_not_started.
GET /api/v1/teams/{teamSlug}/checkouts/{checkoutID}Response 200: the id, kind, state, kept, payment and amount_cents.
state is open, done, credited, when the payment stayed as credit and nothing
was switched on, with kept saying why (already_on, not_offered, app_gone,
price_changed, short, expired, cannot_install), or expired, when it was
not paid within its life. payment is its top-up's state, and only failed,
cancelled or declined there means Revolut refused it: an hourly read of each
order still open credits a payment whose webhook never came.
Add-ons
GET /api/v1/teams/{teamSlug}/projects/{projectSlug}/addonsEvery member may read it.
Response 200: security_pack, backup_retention_days,
included_backup_days, can_buy, and rows, one for each kind that can be bought
or that the app has: its kind; options, each with id, name, days and
price_cents; purchase with id, addon_id, name, price_cents, which its
next charge takes, next_charge_at, ends_at, ends_now, when removing it stops it at
once since its month has not been paid for, and moves_to; and given, when staff gave
it free. A team that has never paid is offered nothing, and an add-on
nobody can buy has no row.
DELETE /api/v1/teams/{teamSlug}/projects/{projectSlug}/addons/{purchaseID}
POST /api/v1/teams/{teamSlug}/projects/{projectSlug}/addons/{purchaseID}/keepDELETE has a purchase stop at the end of the month paid for, or at once in a month
not yet charged, with no refund and no more charges. keep takes back a removal, or a move down still to come. Each answers
as the GET does, and 409 addon_not_on when the purchase has ended. Owners and
admins only.
Staff give an add-on free with PUT .../addons, for platform admins alone:
{"waf": bool, "security_pack": bool, "backup_retention_days": n}, any of them. It
is never charged.