Skip to content

Billing API ​

All endpoints under /api/billing require a bearer token (login token or API key). Reading uses the billing:read permission; adding credit uses billing:pay.

MicroApps is prepaid. You keep a credit balance, usage accrues against it hourly, and the month's usage is settled from your balance by a monthly invoice. Nothing auto-recharges - you top up when you want to. You need at least $3 of credit for anything that creates a billable resource (pods, networks, domains, firewalls, snapshots, backups, mailboxes - plus clone and restore), or those calls return 402. The billing model has the full picture.

Account stats ​

http
GET /api/billing/stats

Your available credit and this calendar month's usage so far.

json
{
  "availableCredit": 42.5,
  "totalUsage": 7.31
}

Both are USD, rounded to cents. totalUsage resets at the start of each month.

List invoices ​

http
GET /api/billing/invoices

A plain array of invoices. Each one covers a billing period and itemises what you used.

json
[
  {
    "id": "6a4d5b83b7006ccae6391820",
    "accountId": "6a4d5b83b7006ccae6391800",
    "amount": 5.97,
    "currency": "usd",
    "status": "paid",
    "periodStart": "2026-06-01T00:00:00Z",
    "periodEnd": "2026-06-30T23:59:59Z",
    "items": [
      { "description": "pod - my-app (small)", "hours": 720, "rate": 0.0072, "amount": 5.18 },
      { "description": "storage - my-app (small)", "hours": 720, "rate": 0.0011, "amount": 0.79 }
    ],
    "createdAt": "2026-07-01T00:05:00Z",
    "updatedAt": "2026-07-01T00:07:12Z"
  }
]

status is pending (raised, not yet settled from your balance) or paid. Each entry in items is one line of usage: description (the resource type, its pod name, and its size), hours (how long it ran), rate (its hourly rate), and amount (the two multiplied). Every pod produces two lines, one for compute and one for its storage. Once paid backups start, each backup adds a line of its own, such as backup - my-app (0.68 GB), whose rate is its size in GB times the per-GB hourly backup rate. The rates above are illustrative; the pricing page is authoritative.

Download an invoice as PDF ​

http
GET /api/billing/invoices/:id/pdf

Returns the invoice as a PDF (application/pdf), not JSON, as an attachment named invoice-<id>.pdf. Good for expense reports and accountants who like paper.

bash
curl https://cloud-api.microapps.io/api/billing/invoices/6a4d5b83b7006ccae6391820/pdf \
  -H "Authorization: Bearer $MICROAPPS_API_KEY" \
  -o invoice.pdf

List transactions ​

http
GET /api/billing/transactions

Every top-up and how it went, as a plain array.

json
[
  {
    "id": "6a4d5b83b7006ccae6391830",
    "accountId": "6a4d5b83b7006ccae6391800",
    "userId": "6a4d5b83b7006ccae6391801",
    "sessionId": "cs_test_a1B2c3D4e5F6g7H8i9J0kLmNoPqRsTuVwXyZ",
    "amount": 25,
    "currency": "usd",
    "status": "paid",
    "createdAt": "2026-07-01T09:12:00Z",
    "updatedAt": "2026-07-01T09:13:44Z"
  }
]
statusMeans
unpaidCheckout opened, payment not completed yet
paidPaid and credited to your balance
expiredNobody finished the checkout; the session timed out

Add credit (Stripe Checkout) ​

http
GET /api/billing/create-checkout-session?amount=25

amount is a whole number of US dollars, minimum 3, maximum 10000. You get back a Stripe-hosted checkout URL - send the customer there to pay. Top-ups are accepted regardless of any pending invoices; settlement runs within minutes of payment and takes whatever your balance covers. Note that an invoice left unpaid starts the dunning ladder described in the billing model (warning email, pods stopped after 2 business days, backed up and deleted after 3 more).

json
{ "checkoutSessionURL": "https://checkout.stripe.com/c/pay/cs_test_a1B2c3D4e5F6g7H8i9J0kLmNoPqRsTuVwXyZ" }

The session is good for about half an hour. Leave it and the transaction settles as expired; nothing is charged and nothing is credited.

ProblemStatusMessage
amount missing or not a positive integer400Invalid amount format:
amount below 3400Credit amount must be at least $3
amount above 10000400Amount cannot exceed $10,000: 20000

We never see or store card details; Stripe handles the payment. When the customer finishes, Stripe sends them back to the console.

Verify a payment ​

http
GET /api/billing/verify-payment?session_id=cs_test_a1B2c3D4e5F6g7H8i9J0kLmNoPqRsTuVwXyZ

Called when the customer returns from Stripe. It reconciles that one session and, if it is paid, applies the credit. Applying credit is idempotent - calling this twice for the same session will not double your balance. A session belonging to another account returns 404.

json
{
  "status": "paid",
  "amount": 25,
  "currency": "usd",
  "paid": true
}

status is the transaction's status after reconciliation; paid is the same fact as a boolean. You do not have to call this at all - a background sweep reconciles pending transactions anyway. It exists so the console can stop showing a spinner without waiting for the sweep.

curl example ​

Check your balance:

bash
curl https://cloud-api.microapps.io/api/billing/stats \
  -H "Authorization: Bearer $MICROAPPS_API_KEY"

Open a $25 top-up:

bash
curl "https://cloud-api.microapps.io/api/billing/create-checkout-session?amount=25" \
  -H "Authorization: Bearer $MICROAPPS_API_KEY"

See also ​

Built for the long tail.