Billing and invoices
The workspace’s subscription and billing details, and the invoices this instance issues in the operator’s own number range — plus the payment provider’s callback.
8 operations. Every path is relative to the instance origin; every response body is JSON unless stated. See API for authentication, errors and pagination.
POST /api/v1/billing/webhook
Payment-provider callback. Authenticated by signature over the raw body, not by a session, and idempotent by provider event id — the same event WILL arrive twice.
receiveBillingWebhook · token scope: session only
Response 200 — application/json
received·true— required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/billing/subscription
The workspace’s subscription as the payment provider last reported it. Never contains a card, a provider credential, or a provider object.
getBillingSubscription · token scope: session only
Path parameters
workspaceId· string (uuid) — required
Response 200 — application/json
workspaceId· string (uuid) — requiredstatus·"none"|"trialing"|"active"|"past_due"|"canceled"— requiredplanId·"free"|"team"|"business"|"self_hosted"| null — requiredcurrentPeriodStart· string (date-time) | null — requiredcurrentPeriodEnd· string (date-time) | null — requiredcancelAtPeriodEnd· boolean — requiredupdatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/billing/customer
The billing details invoices are addressed to, plus the VAT treatment an invoice issued now would carry.
getBillingCustomer · token scope: session only
Path parameters
workspaceId· string (uuid) — required
Response 200 — application/json
workspaceId· string (uuid) — requiredparty· object — requiredname· string — required, length 0–200addressLines· string[] — required, 0–4 itemspostalCode· string — required, length 0–20city· string — required, length 0–120countryCode· string |""— requiredvatId· string | null — requiredemail· string (email) | null — required
vatIdStatus·"absent"|"unchecked"|"valid"|"invalid"— requiredvatIdCheckedAt· string (date-time) | null — requiredtaxTreatment·"domestic"|"eu_reverse_charge"|"eu_oss"|"non_eu"|"exempt"— requiredupdatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
PUT /api/v1/workspaces/{workspaceId}/billing/customer
Replace the billing details. Changing the VAT ID marks it unchecked again — an unchecked number never buys reverse charge. Issued invoices keep the copy they were issued with.
updateBillingCustomer · token scope: session only
Path parameters
workspaceId· string (uuid) — required
Request body — application/json, required
name· string — required, length 1–200addressLines· string[] — 0–4 items, default[]postalCode· string — length 0–20, default""city· string — length 0–120, default""countryCode· string — requiredemail· string (email) | null — defaultnullvatId· string | null — defaultnull
Response 200 — application/json
workspaceId· string (uuid) — requiredparty· object — requiredname· string — required, length 0–200addressLines· string[] — required, 0–4 itemspostalCode· string — required, length 0–20city· string — required, length 0–120countryCode· string |""— requiredvatId· string | null — requiredemail· string (email) | null — required
vatIdStatus·"absent"|"unchecked"|"valid"|"invalid"— requiredvatIdCheckedAt· string (date-time) | null — requiredtaxTreatment·"domestic"|"eu_reverse_charge"|"eu_oss"|"non_eu"|"exempt"— requiredupdatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/billing/invoices
The workspace’s invoices and credit notes, newest first. Drafts are included and are the ones without a number.
listInvoices · token scope: session only
Path parameters
workspaceId· string (uuid) — required
Query parameters
cursor· string — length 1–∞limit· integer — 1–100
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredworkspaceId· string (uuid) — requiredtype·"invoice"|"credit_note"— requiredstatus·"draft"|"issued"|"void"— requirednumber· string | null — requiredissuedAt· string (date-time) | null — requiredcurrency· string — requiredseller· object — requiredname· string — required, length 1–200addressLines· string[] — required, 0–4 itemspostalCode· string — required, length 0–20city· string — required, length 0–120countryCode· string — requiredvatId· string | null — requiredemail· string (email) | null — required
buyer· object — requiredname· string — required, length 1–200addressLines· string[] — required, 0–4 itemspostalCode· string — required, length 0–20city· string — required, length 0–120countryCode· string — requiredvatId· string | null — requiredemail· string (email) | null — required
lines· object[] — requireddescription· string — required, length 1–500quantity· integer — required, -9007199254740991–9007199254740991unitNetMinor· integer — required, -9007199254740991–9007199254740991netMinor· integer — required, -9007199254740991–9007199254740991taxRateBp· integer — required, 0–10000taxMinor· integer — required, -9007199254740991–9007199254740991periodStart· string (date-time) | null — requiredperiodEnd· string (date-time) | null — required
netMinor· integer — required, -9007199254740991–9007199254740991taxMinor· integer — required, -9007199254740991–9007199254740991grossMinor· integer — required, -9007199254740991–9007199254740991taxTreatment·"domestic"|"eu_reverse_charge"|"eu_oss"|"non_eu"|"exempt"— requiredtaxCountry· string — requiredtaxNote· string | null — requiredperiodStart· string (date-time) | null — requiredperiodEnd· string (date-time) | null — requiredpaidAt· string (date-time) | null — requiredcancelsInvoiceId· string (uuid) | null — requiredcanceledByInvoiceId· string (uuid) | null — requiredproviderInvoiceId· string | null — requiredcreatedAt· string (date-time) — required
nextCursor· string | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/billing/invoices/{invoiceId}
One invoice, complete: parties, lines, net/VAT/gross, period and VAT treatment. Enough to render the document without asking the payment provider anything.
getInvoice · token scope: session only
Path parameters
workspaceId· string (uuid) — requiredinvoiceId· string (uuid) — required
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredtype·"invoice"|"credit_note"— requiredstatus·"draft"|"issued"|"void"— requirednumber· string | null — requiredissuedAt· string (date-time) | null — requiredcurrency· string — requiredseller· object — requiredname· string — required, length 1–200addressLines· string[] — required, 0–4 itemspostalCode· string — required, length 0–20city· string — required, length 0–120countryCode· string — requiredvatId· string | null — requiredemail· string (email) | null — required
buyer· object — requiredname· string — required, length 1–200addressLines· string[] — required, 0–4 itemspostalCode· string — required, length 0–20city· string — required, length 0–120countryCode· string — requiredvatId· string | null — requiredemail· string (email) | null — required
lines· object[] — requireddescription· string — required, length 1–500quantity· integer — required, -9007199254740991–9007199254740991unitNetMinor· integer — required, -9007199254740991–9007199254740991netMinor· integer — required, -9007199254740991–9007199254740991taxRateBp· integer — required, 0–10000taxMinor· integer — required, -9007199254740991–9007199254740991periodStart· string (date-time) | null — requiredperiodEnd· string (date-time) | null — required
netMinor· integer — required, -9007199254740991–9007199254740991taxMinor· integer — required, -9007199254740991–9007199254740991grossMinor· integer — required, -9007199254740991–9007199254740991taxTreatment·"domestic"|"eu_reverse_charge"|"eu_oss"|"non_eu"|"exempt"— requiredtaxCountry· string — requiredtaxNote· string | null — requiredperiodStart· string (date-time) | null — requiredperiodEnd· string (date-time) | null — requiredpaidAt· string (date-time) | null — requiredcancelsInvoiceId· string (uuid) | null — requiredcanceledByInvoiceId· string (uuid) | null — requiredproviderInvoiceId· string | null — requiredcreatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
GET /api/v1/workspaces/{workspaceId}/billing/invoices/{invoiceId}/document
The issued invoice rendered as a self-contained HTML document (print to PDF). Drafts have no document — an unnumbered invoice must not be printable.
getInvoiceDocument · token scope: session only
Path parameters
workspaceId· string (uuid) — requiredinvoiceId· string (uuid) — required
Response 200 — application/json
invoiceId· string (uuid) — requirednumber· string — requiredformat·"html"— requiredhtml· string — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required
POST /api/v1/workspaces/{workspaceId}/billing/checkout
Begin or change a subscription on the payment provider’s hosted page. Answers a short-lived provider URL; card details are only ever entered there, never here.
startBillingCheckout · token scope: session only
Path parameters
workspaceId· string (uuid) — required
Request body — application/json, required
planId·"free"|"team"|"business"— requiredreturnPath· string — length 0–512, default"/"
Response 200 — application/json
url· string (uri) — requiredexpiresAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — required