Developers/Guides

Billing and payments

Every organisation has a billing mode set by PostBuddy: PREPAID (the default), TRIAL or INVOICE. The mode decides what happens when an item becomes READY:

  • PREPAID: the unit price of the item is reserved on the balance. Without enough available balance the item stays HELD with the warning code insufficient_balance and the Owners and Admins are notified. At the production cutoff the reservation becomes a charge; cancelling before the cutoff releases it.
  • TRIAL: the same flow against a free allowance (a number of items and an end date). An exhausted or expired trial behaves as PREPAID with a zero balance.
  • INVOICE: no balance. The item is reserved against the credit limit; when the outstanding amount plus the reserved amount would exceed the limit the item stays HELD with credit_limit_reached. Charges are invoiced monthly.

Test items never touch the ledger.

Summary

GET /v1/billing/summary returns the figures in cents:

FieldMeaning
balanceCentsPrepaid balance from top-ups, refunds and adjustments minus charges
reservedCentsReserved for READY items (prepaid) or scheduled, uncharged items (invoice)
availableCentsbalanceCents minus reservedCents
outstandingCentsCharged and not yet paid (invoice organisations)
creditLimitCents, creditHeadroomCentsThe credit limit and what is left of it (INVOICE)
trialitemsRemaining, expiresAt and active (TRIAL)
lowBalanceThresholdCentsThe low balance notification threshold from the organisation settings

Ledger

GET /v1/billing/ledger lists the append-only ledger newest first with a cursor. Each entry carries type (TOP_UP, RESERVATION, RELEASE, CHARGE, REFUND, ADJUSTMENT, SUBSCRIPTION_FEE, INVOICE_PAYMENT), the semantic amountCents and what the entry did to the figures (balanceDeltaCents, reservedDeltaCents, outstandingDeltaCents). Item entries reference the item (referenceType item, referenceId), payments reference the payment. Filter with type (comma separated), from, to and referenceId:

HTTP
GET /v1/billing/ledger?type=CHARGE,REFUND&from=2026-10-01T00:00:00Z&limit=100

Top-ups and payments

Prepaid and trial organisations request a top-up with POST /v1/billing/top-ups:

JSON
{ "amountCents": 25000 }

The response holds the pending payment and the instructions of the payment provider. Under the manual provider these are bank transfer instructions with a reference to quote on the transfer:

JSON
{
  "payment": {
    "id": "pay_01JA7K3M9QX2T5V8W0Y4Z6B1C3",
    "kind": "TOP_UP",
    "provider": "manual",
    "status": "PENDING",
    "amountCents": 25000,
    "currency": "EUR",
    "method": null,
    "reference": "PB-7K3M9QX2",
    "externalReference": null,
    "paidAt": null,
    "invoiceId": null,
    "ledgerEntryId": null,
    "notes": null,
    "requestedByType": "API_KEY",
    "completedAt": null,
    "cancelledAt": null,
    "createdAt": "2026-10-15T09:30:00.000Z"
  },
  "instructions": {
    "method": "BANK_TRANSFER",
    "beneficiary": "PostBuddy B.V.",
    "iban": "NL91ABNA0417164300",
    "bic": "ABNANL2A",
    "amountCents": 25000,
    "currency": "EUR",
    "reference": "PB-7K3M9QX2",
    "note": "Quote the reference on the transfer; the balance is updated once the payment is registered."
  },
  "redirectUrl": null
}

The balance is credited when PostBuddy registers the payment as received; the organisation is notified (payment.received) and the ledger shows a TOP_UP entry referencing the payment. GET /v1/billing/payments lists requests and registered payments; POST /v1/billing/payments/{id}/cancel withdraws a pending request. Invoice payments are registered the same way against the outstanding amount.

Low balance

Owners set lowBalanceThresholdCents in the organisation settings. When the available balance drops below it, the Owners and Admins receive one balance.low notification; it is sent again after the balance went back above the threshold and crosses it once more. Items blocked for funds raise balance.insufficient at once.

Prices and quotes are covered in the OpenAPI reference (POST /v1/quotes, GET /v1/billing/prices).

Plans and entitlements

Your organisation runs on a plan assigned by PostBuddy: a monthly fee and a set of entitlements (the number of Postflows, a monthly item allowance with a hard or soft cap, the enabled products, storage, fonts, import rows, webhook endpoints and the features qrTracking, samples and apiAccess). GET /v1/organisation/plan returns the plan, the effective entitlements and your usage against them, so an integration can show "3 of 5 Postflows used" before a limit is hit. At the point of use the API answers 403 with a stable code: postflow_limit_reached (creating a Postflow), product_not_entitled (a template, item or Postbatch for a product outside the plan), feature_not_entitled (a live key without apiAccess, a trackable QR element without qrTracking) and allowance_exceeded (the monthly item allowance under a hard cap, the webhook endpoint, font or storage limit, an import with more rows than the plan allows). A soft allowance lets the extra items through at the list price. Test mode is never limited.

Invoices

GET /v1/billing/invoices lists your invoices and credit notes; GET /v1/billing/invoices/{id} adds the lines and the parties, and GET /v1/billing/invoices/{id}/pdf answers a signed download link valid for ten minutes. A prepaid top-up produces its invoice when PostBuddy registers the payment (paid at issue; the VAT is split out of the amount you paid). Invoice billing produces one invoice per calendar month with the usage per product, finish, destination and run, the subscription fee and any adjustments, due after your payment term. Credit notes reference the invoice they credit. Invoices are immutable once issued. GET /v1/billing/statements/{YYYY-MM} returns the usage statement of a month for any billing mode (?format=csv for a CSV body). The event invoice.issued fires for every invoice and credit note.