Basalt docs
GitHub

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 200application/json

  • received · true — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · 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 200application/json

  • workspaceId · string (uuid) — required
  • status · "none" | "trialing" | "active" | "past_due" | "canceled" — required
  • planId · "free" | "team" | "business" | "self_hosted" | null — required
  • currentPeriodStart · string (date-time) | null — required
  • currentPeriodEnd · string (date-time) | null — required
  • cancelAtPeriodEnd · boolean — required
  • updatedAt · string (date-time) — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · 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 200application/json

  • workspaceId · string (uuid) — required
  • party · object — required
    • name · string — required, length 0–200
    • addressLines · string[] — required, 0–4 items
    • postalCode · string — required, length 0–20
    • city · string — required, length 0–120
    • countryCode · string | "" — required
    • vatId · string | null — required
    • email · string (email) | null — required
  • vatIdStatus · "absent" | "unchecked" | "valid" | "invalid" — required
  • vatIdCheckedAt · string (date-time) | null — required
  • taxTreatment · "domestic" | "eu_reverse_charge" | "eu_oss" | "non_eu" | "exempt" — required
  • updatedAt · string (date-time) — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · 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 bodyapplication/json, required

  • name · string — required, length 1–200
  • addressLines · string[] — 0–4 items, default []
  • postalCode · string — length 0–20, default ""
  • city · string — length 0–120, default ""
  • countryCode · string — required
  • email · string (email) | null — default null
  • vatId · string | null — default null

Response 200application/json

  • workspaceId · string (uuid) — required
  • party · object — required
    • name · string — required, length 0–200
    • addressLines · string[] — required, 0–4 items
    • postalCode · string — required, length 0–20
    • city · string — required, length 0–120
    • countryCode · string | "" — required
    • vatId · string | null — required
    • email · string (email) | null — required
  • vatIdStatus · "absent" | "unchecked" | "valid" | "invalid" — required
  • vatIdCheckedAt · string (date-time) | null — required
  • taxTreatment · "domestic" | "eu_reverse_charge" | "eu_oss" | "non_eu" | "exempt" — required
  • updatedAt · string (date-time) — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · 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 200application/json

  • items · object[] — required
    • id · string (uuid) — required
    • workspaceId · string (uuid) — required
    • type · "invoice" | "credit_note" — required
    • status · "draft" | "issued" | "void" — required
    • number · string | null — required
    • issuedAt · string (date-time) | null — required
    • currency · string — required
    • seller · object — required
      • name · string — required, length 1–200
      • addressLines · string[] — required, 0–4 items
      • postalCode · string — required, length 0–20
      • city · string — required, length 0–120
      • countryCode · string — required
      • vatId · string | null — required
      • email · string (email) | null — required
    • buyer · object — required
      • name · string — required, length 1–200
      • addressLines · string[] — required, 0–4 items
      • postalCode · string — required, length 0–20
      • city · string — required, length 0–120
      • countryCode · string — required
      • vatId · string | null — required
      • email · string (email) | null — required
    • lines · object[] — required
      • description · string — required, length 1–500
      • quantity · integer — required, -9007199254740991–9007199254740991
      • unitNetMinor · integer — required, -9007199254740991–9007199254740991
      • netMinor · integer — required, -9007199254740991–9007199254740991
      • taxRateBp · integer — required, 0–10000
      • taxMinor · integer — required, -9007199254740991–9007199254740991
      • periodStart · string (date-time) | null — required
      • periodEnd · string (date-time) | null — required
    • netMinor · integer — required, -9007199254740991–9007199254740991
    • taxMinor · integer — required, -9007199254740991–9007199254740991
    • grossMinor · integer — required, -9007199254740991–9007199254740991
    • taxTreatment · "domestic" | "eu_reverse_charge" | "eu_oss" | "non_eu" | "exempt" — required
    • taxCountry · string — required
    • taxNote · string | null — required
    • periodStart · string (date-time) | null — required
    • periodEnd · string (date-time) | null — required
    • paidAt · string (date-time) | null — required
    • cancelsInvoiceId · string (uuid) | null — required
    • canceledByInvoiceId · string (uuid) | null — required
    • providerInvoiceId · string | null — required
    • createdAt · string (date-time) — required
  • nextCursor · string | null — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · 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) — required
  • invoiceId · string (uuid) — required

Response 200application/json

  • id · string (uuid) — required
  • workspaceId · string (uuid) — required
  • type · "invoice" | "credit_note" — required
  • status · "draft" | "issued" | "void" — required
  • number · string | null — required
  • issuedAt · string (date-time) | null — required
  • currency · string — required
  • seller · object — required
    • name · string — required, length 1–200
    • addressLines · string[] — required, 0–4 items
    • postalCode · string — required, length 0–20
    • city · string — required, length 0–120
    • countryCode · string — required
    • vatId · string | null — required
    • email · string (email) | null — required
  • buyer · object — required
    • name · string — required, length 1–200
    • addressLines · string[] — required, 0–4 items
    • postalCode · string — required, length 0–20
    • city · string — required, length 0–120
    • countryCode · string — required
    • vatId · string | null — required
    • email · string (email) | null — required
  • lines · object[] — required
    • description · string — required, length 1–500
    • quantity · integer — required, -9007199254740991–9007199254740991
    • unitNetMinor · integer — required, -9007199254740991–9007199254740991
    • netMinor · integer — required, -9007199254740991–9007199254740991
    • taxRateBp · integer — required, 0–10000
    • taxMinor · integer — required, -9007199254740991–9007199254740991
    • periodStart · string (date-time) | null — required
    • periodEnd · string (date-time) | null — required
  • netMinor · integer — required, -9007199254740991–9007199254740991
  • taxMinor · integer — required, -9007199254740991–9007199254740991
  • grossMinor · integer — required, -9007199254740991–9007199254740991
  • taxTreatment · "domestic" | "eu_reverse_charge" | "eu_oss" | "non_eu" | "exempt" — required
  • taxCountry · string — required
  • taxNote · string | null — required
  • periodStart · string (date-time) | null — required
  • periodEnd · string (date-time) | null — required
  • paidAt · string (date-time) | null — required
  • cancelsInvoiceId · string (uuid) | null — required
  • canceledByInvoiceId · string (uuid) | null — required
  • providerInvoiceId · string | null — required
  • createdAt · string (date-time) — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · 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) — required
  • invoiceId · string (uuid) — required

Response 200application/json

  • invoiceId · string (uuid) — required
  • number · string — required
  • format · "html" — required
  • html · string — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · 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 bodyapplication/json, required

  • planId · "free" | "team" | "business" — required
  • returnPath · string — length 0–512, default "/"

Response 200application/json

  • url · string (uri) — required
  • expiresAt · string (date-time) — required

Response defaultapplication/json

  • error · object — required
    • code · "bad_request" | "validation_failed" | "unauthorized" | "forbidden" | "not_found" | "conflict" | "rate_limited" | "internal" — required
    • message · string — required