---
title: Billing profiles
path: concepts/billing-profiles
status: published
---

# Billing profiles

Two distinct objects hold the billing-side identity of every invoice:

- `tenant_billing_profiles` — the **buyer**. One row per tenant. Carries company name, address, EU VAT number, contact email, preferred language, and the names of the templates this tenant gets.
- `partner_configuration` — the **seller**. One row per partner. Carries legal name, address, VAT, bank details (IBAN/BIC), and the default templates the partner's tenants inherit.

At invoice finalisation time, both rows are *snapshotted* into the invoice itself (`buyer_snapshot` and `seller_snapshot` JSON columns) so the invoice stays immutable even if either profile is edited later.

## Tenant billing profile

The full schema:

```
tenant_billing_profiles
  tenant_id (PK in spirit, unique),
  company_name,
  address_line1, address_line2,
  postal_code, city, state, country_code,
  vat_number,
  tax_exempt (bool),
  contact_email, phone,
  is_business (bool),
  peppol_id, peppol_scheme,           -- for Peppol e-invoicing
  leitweg_id,                          -- for German XRechnung
  preferred_einvoice_format,           -- ubl | xrechnung | cii | zugferd | facturx
  preferred_language,                  -- en | nl | de | fr | es | it
  invoice_template_name,               -- which designer template (see Templates)
  email_template_name,                 -- which email template
  buyer_reference,                     -- customer-side PO/reference for invoices
  created_at, updated_at
```

A tenant can perform any commerce action (subscribe, get an invoice) *only* if this profile exists. Triggering its first creation emits the `tenant.billing_linked.v1` event; subsequent edits emit `tenant.billing_updated.v1` with `changed_fields[]`.

Endpoints:
- Self-service (the tenant edits its own): `GET/PUT /billing/billing-profile` — see [Billing (tenant)](../reference/api/billing).
- Admin: `PUT /admin/tenants/{tenant_id}/billing-profile` — see [Admin — tenants](../reference/api/admin-tenants).

## Partner configuration (seller side)

```
partner_configuration
  partner_id,
  partner_name,
  billing_model,                       -- pass_through | wholesale | self_billed
  commission_rate,                     -- decimal % for reseller revenue split
  allowed_services, allowed_plans,
  branding,                            -- JSON: theme, logo URL, footer text, etc.
  default_plan_slug,
  provider_config,
  invoice_template_name, email_template_name,
  legal_name,                          -- "ScaiLabs B.V."
  seller_address_line1, seller_address_line2,
  seller_postal_code, seller_city, seller_country_code,
  seller_vat_number,
  seller_email, seller_phone,
  invoice_logo_url, invoice_footer_text,
  seller_peppol_id, seller_peppol_scheme,
  ...
```

A partner is considered **billable** once `legal_name` AND `seller_country_code` are both set. The first time those fields cross from null → set, `partner.billing_linked.v1` fires. Subsequent changes to any seller field emit `partner.billing_updated.v1` with `changed_fields[]`.

Endpoint: `PATCH /admin/partners/{partner_id}` — see [Admin — partners](../reference/api/admin-partners).

## Snapshots at finalisation

When an invoice is finalised:

1. The tenant's billing profile is copied into `invoices.buyer_snapshot` (JSON).
2. The partner's relevant seller fields are copied into `invoices.seller_snapshot`.
3. The VAT determination is recomputed and frozen into `invoices.vat_details`.

After that point, edits to the tenant profile do NOT propagate. Generating a credit note from the same invoice will reuse the snapshots, ensuring downstream documents reference the original buyer/seller exactly as they were at the time.

If the tenant moves countries, gets a new VAT number, etc., the *next* invoice picks up the new state, but the existing ones stay correct for audit purposes.

## Template assignment

Both invoice templates and email templates resolve through a two-step chain at render time:

1. Try the **tenant's** assigned template (`tenant_billing_profiles.invoice_template_name` / `.email_template_name`).
2. Fall back to the **partner's** assigned template (`partner_configuration.invoice_template_name` / `.email_template_name`).
3. Fall back to the built-in filesystem default.

Each step also tries the tenant's `preferred_language` first, falling back to the any-language template variant. See [Templates](./templates).

## E-invoicing identifiers

Several optional fields on the buyer side cover European e-invoicing requirements:

- **Peppol** — used in the Netherlands, Nordics, Belgium. `peppol_id` + `peppol_scheme` together identify the receiver in the Peppol network.
- **Leitweg-ID** — required for German XRechnung-format invoices to public-sector buyers.
- **`preferred_einvoice_format`** — `ubl`, `xrechnung`, `cii`, `zugferd`, `facturx`, or null for PDF-only. Drives the format of the XML attachment shipped alongside the PDF.

The seller side mirrors these so the operator (or reseller) can act as an e-invoicing sender.

## Editing a billing profile mid-stream

Profile edits are non-blocking — any in-flight subscription continues, and the next invoice picks up the new buyer info. The only special case is `country_code`, which changes VAT treatment (domestic ↔ intra-EU ↔ export). The next finalisation will recompute. If you need to *correct* a previously-issued invoice for a buyer-side error, issue a credit note and a fresh invoice — never edit a finalised one.
