Skip to content

Billing & Usage

The billing system tracks resource usage at hourly granularity per project and product, generates monthly invoices, and manages payment methods through Stripe.

Endpoints

Method Path Description
GET /billing/usage?organization_id=<uuid> Get usage data for a period
GET /subscriptions List subscriptions
GET /subscriptions/{id} Show a subscription
PATCH /organizations/{id} Update organization name / billing address
GET /invoices List invoices
GET /invoices/{id} Show invoice with line items
GET /organizations/{id}/invoices List EasyBill invoices
GET /organizations/{id}/invoices/{invoice_id} Show EasyBill invoice
GET /organizations/{id}/invoices/download?invoice_id=<id> Download invoice PDF
GET /organizations/{id}/payment_methods List payment methods
POST /organizations/{id}/payment_methods/create_and_attach Attach a Stripe payment method
PUT /organizations/{id}/payment_methods/{payment_method_id}/set_default Set default payment method
DELETE /organizations/{id}/payment_methods/{payment_method_id} Remove a payment method

Usage data

GET /billing/usage?organization_id=<uuid>&from=2026-01-01T00:00:00Z&to=2026-01-31T23:59:59Z
Authorization: Bearer <token>

Returns resource consumption broken down by project and product for the requested window. Use this to build cost forecasts and chargeback reports.

Subscriptions

Subscriptions link a product to a project with a start (and optional end) date. Hourly usage entries are recorded against active subscriptions.

GET /subscriptions
Authorization: Bearer <token>

Subscription fields:

Field Description
id Subscription UUID
organization_id Organization UUID
project_id Project UUID (nullable — org-level subscriptions have none)
product_id Product UUID
start_date ISO 8601 datetime the subscription began
end_date ISO 8601 datetime the subscription ended; null if active

Organization billing address

The organization's name and billing address feed EasyBill invoicing (VAT handling, invoice header). Update them with:

PATCH /organizations/{id}
Authorization: Bearer <token>
Content-Type: application/json

{
  "organization": {
    "address": {
      "street": "Musterstraße 1",
      "city": "Hamburg",
      "zip_code": "20095",
      "country": "DE"
    }
  }
}

Address fields: first_name, name, email, street, city, state, zip_code, country — see the Address schema in the interactive reference.

country is an ISO 3166-1 alpha-2 code, uppercase (DE, AT, CH, …), or null. On write, hq accepts an alpha-2 code in any case or a known country name in English or German (for the EU/EFTA/UK/US set) and normalizes it to uppercase alpha-2; anything else is rejected with 422 Unprocessable Content. This endpoint returns a bare Rails errors.details hash — no message text and no errors/request_id envelope:

{
  "address.country": [
    { "error": "inclusion", "value": "Freedonia" }
  ]
}

An unrecognised country always reports "error": "inclusion" (the value you sent is echoed back in "value"); build any user-facing message client-side from that code rather than relying on server text.

This is a deliberate deviation from the standard ErrorEnvelope shape used by the rest of the API.

An empty string ("") normalizes to null, clearing the country.

Partial address updates merge — omit keys you don't change

address updates merge into the existing address rather than replacing it wholesale. Send only the keys you intend to change; omit the rest. Do not send "" for a field you want to leave untouched — for most address fields (unlike country) an empty string is written literally and blanks that field. To update just the city, for example, send { "organization": { "address": { "city": "Hamburg" } } } with no other address keys.

Invoices

The platform generates two invoice representations:

Internal invoices (/invoices) reflect the platform's usage metering:

GET /invoices/{id}
Authorization: Bearer <token>

Fields: period, total (Money object: {cents, currency_iso}), and items (array of line items with product, project, unit price, and unit).

EasyBill invoices (/organizations/{id}/invoices) are the legally binding invoices delivered via the EasyBill integration. Download a PDF:

GET /organizations/{id}/invoices/download?invoice_id=<id>
Authorization: Bearer <token>

Returns application/pdf.

Payment methods

Payment methods are Stripe payment instruments attached to an organization.

GET /organizations/{id}/payment_methods
Authorization: Bearer <token>

Payment method fields:

Field Description
id Internal UUID
payment_type card, sepa_debit, etc.
default Whether this is the default payment method
brand Card brand (e.g. visa); null for non-card methods
last4 Last four digits of the card number
exp_month / exp_year Card expiry
iban IBAN (SEPA debit only)

Attach a payment method

Use the Stripe.js PaymentElement in the dashboard to collect card details and generate a Stripe paymentMethodId, then attach it:

POST /organizations/{id}/payment_methods/create_and_attach
Authorization: Bearer <token>
Content-Type: application/json

{ "payment_method_id": "pm_..." }

Create a Stripe payment intent (for setup flow)

POST /organizations/{id}/payment_methods/payment_intent
Authorization: Bearer <token>

Returns { "client_secret": "seti_...secret_..." } for use with Stripe.js confirmSetup.

Authorization

Billing read operations require the billing:read permission. Update operations (setting default, removing a payment method) require billing:update. See RBAC Presets for which roles carry these permissions.