Abonnements

Wiederkehrende Rechnungen: Abonnement-Vorlagen, ihre Einstellungen und die daraus erzeugten Rechnungen.

Recurring subscription templates, their settings, and generated invoices.

9 Operationen · Basis-URL https://api.fortlauf.de/v1

Operationen

  1. GET /subscription-settings Read the company's recurring-billing defaults
  2. PATCH /subscription-settings Store the company's recurring-billing defaults
  3. GET /subscriptions List subscription templates, ordered by creation date (paginated)
  4. POST /subscriptions Create a subscription template
  5. GET /subscriptions/{id} Get a subscription by id
  6. PUT /subscriptions/{id} Update a subscription template (full replace)
  7. PATCH /subscriptions/{id}/status Update subscription status (active / paused / cancelled / ended)
  8. GET /subscriptions/{id}/invoices List invoices generated from this subscription
  9. POST /subscriptions/{id}/generate-invoice Manually trigger invoice generation from a subscription template

Read the company's recurring-billing defaults

GET /subscription-settings

The defaults used to pre-fill a new recurring template's cadence, billing timing, currency and trial length. They belong to the COMPANY that issues the documents — one set per company, identical in the sandbox and in the live world — and one company's values are never visible to another. A company that has never configured them reads the shipped defaults with isDefault: true; nothing is stored by a read. Open to any active member. Session-authenticated surfaces only — API keys are refused.

Erforderlicher Scope
keiner
Zugang
nur mit angemeldeter Sitzung – ein API-Schlüssel wird abgelehnt (oidc-only)

Antworten

Store the company's recurring-billing defaults

PATCH /subscription-settings

Full replace of the four mutable default fields for the CALLING COMPANY only. All four are required — omitting one is refused rather than stored. Requires the administrator role; an ordinary or read-only member receives insufficient_role and nothing is written. Session-authenticated surfaces only — API keys are refused.

Erforderlicher Scope
keiner
Zugang
nur mit angemeldeter Sitzung – ein API-Schlüssel wird abgelehnt (oidc-only)

Request-Body erforderlich

application/json UpdateSubscriptionSettings

Antworten

  • 200

    The stored defaults.

    application/json SubscriptionSettings

  • 400

    Validation error.

    application/json ValidationError

  • 403

    Caller lacks the administrator role (insufficient_role), or presented a programmatic key on this session-authenticated surface (credential_not_accepted). Nothing was written in either case.

List subscription templates, ordered by creation date (paginated)

GET /subscriptions

Erforderlicher Scope
subscriptions:read
Zugang
API-Schlüssel oder angemeldete Sitzung

Parameter

Parameter In Typ Beschreibung
page Query integer

Page number (1-indexed).

Standard: 1
Bereich: ≥ 1
pageSize Query integer

Number of items per page.

Standard: 25
Bereich: ≥ 1, ≤ 100

Antworten

  • 200

    Paginated list of subscription summaries

    application/json object

  • 400

    The query string was refused. Three distinguishable facts share this status, and a client should branch on the error code rather than on the status: unknown_query_parameter — the request named one or more query parameters this deployment does not define, and parameters lists their names. Nothing was filtered and nothing was written. This is a DEPLOY-ORDER signal: it is what a client released ahead of the API sees, and it replaces the older behaviour in which an unrecognised parameter was silently ignored and the request answered 200 OK with the UNFILTERED collection — indistinguishable, to the caller, from the filter having been applied. validation_error — a parameter this endpoint does define carried an unusable value (including a required one being absent or too short). issues[] names the parameter and what was wrong with it. invalid_cursor — on cursor-paginated endpoints, the pagination cursor is malformed. No response on this path ever echoes a submitted VALUE; only parameter names appear.

    application/json UnknownQueryParameterError | ValidationError

Create a subscription template

POST /subscriptions

Honors the optional Idempotency-Key header so a retried creation is a replay, not a duplicate.

Erforderlicher Scope
subscriptions:write
Zugang
API-Schlüssel oder angemeldete Sitzung

Parameter

Parameter In Typ Beschreibung
Idempotency-Key Header string

Optional client-supplied key that makes this mutating request safe to retry. The FIRST request runs and its outcome is recorded keyed by (tenant, route, key); a REPLAY (same key + byte-identical body, after the first completed) returns the recorded response verbatim WITHOUT re-executing — so a network-blip retry never creates a duplicate customer/subscription/key. A key reused with a DIFFERENT body is 409 IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_BODY; a key whose first request is still in flight is 409 REQUEST_IN_PROGRESS (retryable). Keys expire after 24h — a key reused after expiry is a fresh request, not a replay. Transparent when omitted (the request runs normally).

Länge: max. 255

Request-Body erforderlich

application/json CreateSubscription

Antworten

  • 201

    The created subscription (or, on an Idempotency-Key replay, the recorded response)

    application/json Subscription

  • 400

    Validation error

    application/json ValidationError

  • 409

    Idempotency-Key conflict. IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_BODY — the key was already used with a different request body; REQUEST_IN_PROGRESS — the first request bearing this key is still in flight (retryable).

    application/json object

Get a subscription by id

GET /subscriptions/{id}

Erforderlicher Scope
subscriptions:read
Zugang
API-Schlüssel oder angemeldete Sitzung

Parameter

Parameter In Typ Beschreibung
id erforderlich Pfad string (uuid)

Antworten

  • 200

    The subscription

    application/json Subscription

  • 404

    Not found

Update a subscription template (full replace)

PUT /subscriptions/{id}

Erforderlicher Scope
subscriptions:write
Zugang
API-Schlüssel oder angemeldete Sitzung

Parameter

Parameter In Typ Beschreibung
id erforderlich Pfad string (uuid)

Request-Body erforderlich

application/json ReplaceSubscription

Antworten

  • 200

    The updated subscription

    application/json Subscription

  • 400

    Validation error

  • 404

    Not found

  • 409

    Subscription is cancelled or ended

  • 422

    The Leistungszeitraum anchor is locked after the first invoice (code: SUBSCRIPTION_ANCHOR_LOCKED). OR editing an already-active subscription into a snapshot that would mint an invalid invoice (code: SUBSCRIPTION_ACTIVATION_INVALID, with documentTarget/missing/remedies/findings).

Update subscription status (active / paused / cancelled / ended)

PATCH /subscriptions/{id}/status

Erforderlicher Scope
subscriptions:write
Zugang
API-Schlüssel oder angemeldete Sitzung

Parameter

Parameter In Typ Beschreibung
id erforderlich Pfad string (uuid)

Request-Body erforderlich

application/json object

Antworten

  • 200

    The updated subscription

    application/json Subscription

  • 400

    The request body is not valid JSON (invalid_json) or fails validation (validation_error, naming each problem in issues).

    application/json ValidationError

  • 404

    Not found

  • 422

    Activating a subscription whose synthetic invoice would be blocked by the target-gated preflight is refused (code: SUBSCRIPTION_ACTIVATION_INVALID, with documentTarget/missing/ remedies: ['fill_field','switch_target_b2b']/findings). The sub stays in its current state (no partial write).

List invoices generated from this subscription

GET /subscriptions/{id}/invoices

Erforderlicher Scope
subscriptions:read
Zugang
API-Schlüssel oder angemeldete Sitzung

Parameter

Parameter In Typ Beschreibung
id erforderlich Pfad string (uuid)

Antworten

  • 200

    Invoice summaries for this subscription

    application/json Array<InvoiceSummary>

  • 404

    Subscription not found

Manually trigger invoice generation from a subscription template

POST /subscriptions/{id}/generate-invoice

Honors the optional Idempotency-Key header so a retried trigger is a replay, not a second draft. This ad-hoc generate mints a draft with no natural idempotency (unlike the internal per-period billing run), so it is idempotency-wrapped like POST /invoices.

Erforderlicher Scope
subscriptions:write , documents:write
Zugang
API-Schlüssel oder angemeldete Sitzung

Parameter

Parameter In Typ Beschreibung
id erforderlich Pfad string (uuid)
Idempotency-Key Header string

Optional client-supplied key that makes this mutating request safe to retry. The FIRST request runs and its outcome is recorded keyed by (tenant, route, key); a REPLAY (same key + byte-identical body, after the first completed) returns the recorded response verbatim WITHOUT re-executing — so a network-blip retry never creates a duplicate customer/subscription/key. A key reused with a DIFFERENT body is 409 IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_BODY; a key whose first request is still in flight is 409 REQUEST_IN_PROGRESS (retryable). Keys expire after 24h — a key reused after expiry is a fresh request, not a replay. Transparent when omitted (the request runs normally).

Länge: max. 255

Antworten

  • 201

    The generated draft invoice (or, on an Idempotency-Key replay, the recorded response)

    application/json Invoice

  • 404

    Not found

  • 409

    Either a domain conflict (subscription not active, billing not started, or expired) or an Idempotency-Key conflict (IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_BODY / REQUEST_IN_PROGRESS).

    application/json object

Datenmodelle

Jedes Datenmodell dieser Gruppe einmal, mit allen Feldern – auch den verschachtelten. Verschachtelte Objekte sind aufklappbar; ein benannter Typ verweist auf seinen eigenen Abschnitt.

SubscriptionSettings object

Recurring-billing defaults for one company. isDefault says whether the four values came from a stored row or from the shipped defaults; createdAt/updatedAt are present only when a row is stored, because the shipped defaults have no timestamps to report.

Feld Typ Beschreibung
defaultCadence erforderlich string
Werte: "weekly", "monthly", "quarterly", "yearly"
defaultBillingTiming erforderlich string
Werte: "advance", "arrears"
defaultCurrency erforderlich string

ISO 4217 code (3 letters).

defaultTrialDays erforderlich integer
Bereich: ≥ 0, ≤ 365
isDefault erforderlich boolean

true when this company has configured nothing and the shipped defaults answered; false when the values come from a stored row.

createdAt string (date-time)
updatedAt string (date-time)

Verwendet von: GET /subscription-settings , PATCH /subscription-settings

UpdateSubscriptionSettings object

Full replace of the mutable subscription-defaults fields.

Feld Typ Beschreibung
defaultCadence erforderlich string
Werte: "weekly", "monthly", "quarterly", "yearly"
defaultBillingTiming erforderlich string
Werte: "advance", "arrears"
defaultCurrency erforderlich string
Länge: min. 3, max. 3
defaultTrialDays erforderlich integer
Bereich: ≥ 0, ≤ 365

Verwendet von: PATCH /subscription-settings

ValidationError object

A refused request body. error is validation_error when the body was read and failed validation (each problem is listed in issues), or invalid_json when the body is not valid JSON at all (then issues is absent). An unparsable body is answered 400 invalid_json on every operation that takes a JSON body. The submitted body is never echoed.

Feld Typ Beschreibung
error string
issues Array<object>
Felder
Feld Typ Beschreibung
path string
message string
code string

Optional machine-readable reason for the refusal, for a client that shows its own wording instead of message. Present only where an endpoint documents it; an issue without it is refused for the reason message states. Today: invalid_address (an entry of a copy list is not one valid address), too_many_addresses (more than 5 entries in one copy list), copies_require_email (copy recipients are set but email is empty), and service_timing_conflict (POST /invoices, PUT /invoices/{id}: the invoice would state both a single service date and a service period; the issue's path is deliveryDate). On the invoice saves and POST /invoices/preview-totals also reverse_charge_buyer_vat_id_required (a reverse-charge line needs the buyer's VAT identification number), vat_category_unavailable (the line's VAT category is not available), vat_rate_category_mismatch (the rate does not fit the line's VAT category), vat_exemption_reason_required / vat_exemption_reason_not_allowed (the exemption reason is missing, or not allowed for that category), and, only where the deployment enforces the check, unit_code_unknown, currency_code_unknown and vat_id_prefix_unknown (the same three also appear on quote and recurring-template saves, with the same paths). The set may grow, so treat an unknown value like an absent one. Never carries a submitted value.

Verwendet von: PATCH /subscription-settings , GET /subscriptions , POST /subscriptions , PATCH /subscriptions/{id}/status

SubscriptionSummary object

Lightweight subscription representation for the list endpoint.

Feld Typ Beschreibung
id erforderlich string (uuid)
name erforderlich string
buyerName erforderlich string
currency erforderlich string

ISO 4217

cadence erforderlich string
Werte: "weekly", "monthly", "quarterly", "yearly"
billingTiming erforderlich string
Werte: "advance", "arrears"
status erforderlich string
Werte: "active", "paused", "cancelled", "ended"
startsAt erforderlich string (date)
endsAt string (date) | null
servicePeriodAnchor string (date) | null

Optional Leistungszeitraum (BT-73/74) anchor, decoupled from startsAt. Null ⇒ the period is anchored to startsAt (legacy behavior). Setup-time only (locked after the first invoice is generated).

nextDueDate erforderlich string (date)

Computed at read time; when the next invoice is due.

mode Mode

Verwendet von: GET /subscriptions

PaginationMeta object

Pagination metadata returned alongside every paginated list.

Feld Typ Beschreibung
total erforderlich integer

Total number of records matching the current filter.

page erforderlich integer

Current page (1-indexed, echoes the request).

pageSize erforderlich integer

Records per page (echoes the request).

totalPages erforderlich integer

Total number of pages. Minimum 1, even when total is 0.

Verwendet von: GET /subscriptions

UnknownQueryParameterError object

The request named query parameters this endpoint does not define. A list endpoint refuses them rather than ignoring them, so a caller can never mistake an UNFILTERED collection for a filtered one.

Feld Typ Beschreibung
error erforderlich string
Werte: "unknown_query_parameter"
parameters erforderlich Array<string>

The unrecognised parameter NAMES, deduplicated and sorted. Bounded at ten entries, and a name longer than 64 characters is omitted — a parameter name is caller-supplied text, and this response never reflects unbounded caller input. The array may therefore be EMPTY while the refusal still stands: the refusal is decided by the request, not by the length of this list.

message string
requestId string

Verwendet von: GET /subscriptions

CreateSubscription object

Feld Typ Beschreibung
name erforderlich string
customerId string (uuid)
documentTarget string

Whether the recipient is a public authority. It decides the format every invoice this template generates is produced in. On a CREATE, omitting it takes the linked customer's setting, else an ordinary business. On the REPLACE it is REQUIRED — see ReplaceSubscription. Until it became required there, omitting it re-resolved the linked customer's setting, so re-linking a customer could change the format of every future invoice from this template without the property ever appearing in the request.

Werte: "b2b", "b2g"
currency erforderlich string

ISO 4217

cadence erforderlich string
Werte: "weekly", "monthly", "quarterly", "yearly"
billingTiming erforderlich string
Werte: "advance", "arrears"
startsAt erforderlich string (date)
endsAt string (date) | null
servicePeriodAnchor string (date)

Optional Leistungszeitraum (BT-73/74) anchor, decoupled from startsAt. When set, each generated invoice's service period is anchored to it and rolled by the Turnus; billing timing still governs when the invoice is issued. No proration — an offset first period still bills the full Turnus amount. Not applicable to weekly cadence; must sit within one Turnus of startsAt on either side.

buyerName erforderlich string
Länge: max. 200
buyerAddressLine1 string
Länge: max. 200
buyerPostalCode string
Länge: max. 20
buyerCity string
Länge: max. 100
buyerCountryCode string

ISO 3166-1 alpha-2; upper-cased server-side.

Länge: min. 2, max. 2
buyerVatId string

USt-IdNr (BT-48)

Länge: max. 40
buyerReference string
Länge: max. 200
buyerElectronicAddress string

EN 16931 BT-49 — the buyer's ELECTRONIC ROUTING address (a Leitweg-ID for B2G, or an email). Send the bare value: the scheme (0204 for a Leitweg-ID, EM for an email) is derived server-side, so a 0204:-prefixed value is rejected as malformed.

Länge: max. 200
buyerEmail string (email)
sellerName string
Länge: max. 200
sellerAddressLine1 string
Länge: max. 200
sellerPostalCode string
Länge: max. 20
sellerCity string
Länge: max. 100
sellerCountryCode string

ISO 3166-1 alpha-2; upper-cased server-side.

Länge: min. 2, max. 2
sellerVatId string
Länge: max. 40
sellerTaxNumber string
Länge: max. 100
title string

Document title / Betreff.

Länge: max. 500
text string

Body text rendered above the line items (notes renders below).

Länge: max. 5000
notes string
Länge: max. 2000
lineItems erforderlich Array<SubscriptionLineItem>
Elemente: min. 1, max. 1000

Verwendet von: POST /subscriptions

Subscription object

Feld Typ Beschreibung
id erforderlich string (uuid)
name erforderlich string
buyerName erforderlich string
currency erforderlich string

ISO 4217

cadence erforderlich string
Werte: "weekly", "monthly", "quarterly", "yearly"
billingTiming erforderlich string
Werte: "advance", "arrears"
status erforderlich string
Werte: "active", "paused", "cancelled", "ended"
startsAt erforderlich string (date)
endsAt string (date) | null
servicePeriodAnchor string (date) | null

Optional Leistungszeitraum (BT-73/74) anchor, decoupled from startsAt. Null ⇒ the period is anchored to startsAt (legacy behavior). Setup-time only (locked after the first invoice is generated).

nextDueDate erforderlich string (date)

Computed at read time; when the next invoice is due.

mode Mode
customerId string (uuid) | null
documentTarget string

The document-target snapshotted onto this subscription at creation (override > linked customer > 'b2b'), copied onto every invoice it generates. Always present (defaults to 'b2b').

Werte: "b2b", "b2g"
buyerAddressLine1 string | null
buyerPostalCode string | null
buyerCity string | null
buyerCountryCode string | null
buyerVatId string | null
buyerReference string | null
buyerElectronicAddress string | null
buyerEmail string (email) | null
sellerName string | null
notes string | null
title string | null
text string | null
lineItems Array<object>
lastGeneratedAt string (date-time) | null
createdAt string (date-time)
updatedAt string (date-time)

Verwendet von: POST /subscriptions , GET /subscriptions/{id} , PUT /subscriptions/{id} , PATCH /subscriptions/{id}/status

ReplaceSubscription object

Replace payload for a recurring template. Identical to the create payload with one difference: the public-sector/business target is REQUIRED. This body describes the whole template, so an omitted property states that the property has no value — and a recipient is always one or the other. Until this became required, omitting it re-resolved the linked customer's setting and then the stored value, so the format of every future invoice from this template could change because of a property the request never mentioned.

Feld Typ Beschreibung
name erforderlich string
customerId string (uuid)
documentTarget erforderlich string

Whether the recipient is a public authority. It decides the format every invoice this template generates is produced in. On a CREATE, omitting it takes the linked customer's setting, else an ordinary business. On the REPLACE it is REQUIRED — see ReplaceSubscription. Until it became required there, omitting it re-resolved the linked customer's setting, so re-linking a customer could change the format of every future invoice from this template without the property ever appearing in the request.

Werte: "b2b", "b2g"
currency erforderlich string

ISO 4217

cadence erforderlich string
Werte: "weekly", "monthly", "quarterly", "yearly"
billingTiming erforderlich string
Werte: "advance", "arrears"
startsAt erforderlich string (date)
endsAt string (date) | null
servicePeriodAnchor string (date)

Optional Leistungszeitraum (BT-73/74) anchor, decoupled from startsAt. When set, each generated invoice's service period is anchored to it and rolled by the Turnus; billing timing still governs when the invoice is issued. No proration — an offset first period still bills the full Turnus amount. Not applicable to weekly cadence; must sit within one Turnus of startsAt on either side.

buyerName erforderlich string
Länge: max. 200
buyerAddressLine1 string
Länge: max. 200
buyerPostalCode string
Länge: max. 20
buyerCity string
Länge: max. 100
buyerCountryCode string

ISO 3166-1 alpha-2; upper-cased server-side.

Länge: min. 2, max. 2
buyerVatId string

USt-IdNr (BT-48)

Länge: max. 40
buyerReference string
Länge: max. 200
buyerElectronicAddress string

EN 16931 BT-49 — the buyer's ELECTRONIC ROUTING address (a Leitweg-ID for B2G, or an email). Send the bare value: the scheme (0204 for a Leitweg-ID, EM for an email) is derived server-side, so a 0204:-prefixed value is rejected as malformed.

Länge: max. 200
buyerEmail string (email)
sellerName string
Länge: max. 200
sellerAddressLine1 string
Länge: max. 200
sellerPostalCode string
Länge: max. 20
sellerCity string
Länge: max. 100
sellerCountryCode string

ISO 3166-1 alpha-2; upper-cased server-side.

Länge: min. 2, max. 2
sellerVatId string
Länge: max. 40
sellerTaxNumber string
Länge: max. 100
title string

Document title / Betreff.

Länge: max. 500
text string

Body text rendered above the line items (notes renders below).

Länge: max. 5000
notes string
Länge: max. 2000
lineItems erforderlich Array<SubscriptionLineItem>
Elemente: min. 1, max. 1000

Verwendet von: PUT /subscriptions/{id}

InvoiceSummary object

Feld Typ Beschreibung
id string (uuid)
invoiceNumber string | null

Null on a freshly created draft unless an explicit invoiceNo was supplied at creation (numbers are no longer auto-assigned at draft creation — only at issue time, sticky thereafter). Use GET /invoices/next-number to preview what will be assigned.

issueDate string (date)

EN 16931 BT-2, the invoice date. It is always the day the invoice is issued (Europe/Berlin): on a draft it is provisional and reads as the day of the latest save; issuing sets it to the issue day, and a scheduled issuance to the day it runs. Frozen at issue.

status string

⚠ void is RESERVED AND NEVER WRITTEN. §14c UStG / GoBD forbid voiding an issued original; a cancellation is a separate 381 document referencing it, so api never writes this status anywhere. It stays in the enum because removing it would be a breaking contract change for no benefit. To detect a cancelled invoice read correctionState, never status.

Werte: "draft", "scheduled", "issued", "paid", "void"
currency string

ISO 4217

buyerName string | null
totalGross DecimalString
validationState string | null

Compliance-gate outcome. null until a validation attempt has run. 'legacy' = issued before the gate existed (backfilled when the gate was introduced).

Werte: "failed", "passed", "legacy"
correctionState string | null

The DERIVED correction state, computed on read from the document chain and never stored. cancelled = an ISSUED/PAID 381 (Storno) that reverses this invoice IN FULL references it; corrected = an ISSUED/PAID 384 (Berichtigung) does and no full 381 does; null = neither, INCLUDING the case where the only correction is still a DRAFT (a half-made Storno has cancelled nothing and must not switch off collection) AND the case where the only correction is a PARTIAL 381 (it reduces the open amount rather than settling the invoice, so the invoice stays in the open items and is still dunned for the remainder). Cancellation wins over correction. Naming + the null-for-none convention follow dauerrechnungState. This — not status: void, which the law forbids the system from ever writing — is what a "Storniert" view keys on. An invoice with a non-null correctionState is excluded from /dunning/overdue, from the per-customer open items, and from payment matching, and POST /invoices/{id}/reminders refuses it with 409 cancelled_by_correction. An invoice reduced by PARTIAL credit notes keeps a null correctionState and stays in all three, at its reduced open amount, until that amount reaches zero.

Werte: "cancelled", "corrected"
transmissionState TransmissionState
transmissionProblemReason TransmissionProblemReason
transmissionLastEventAt string (date-time) | null

When we learned the fact transmissionState reports. null when there is no such fact.

mode Mode

Verwendet von: GET /subscriptions/{id}/invoices

Invoice object

Feld Typ Beschreibung
id string (uuid)
invoiceNumber string | null

Null on a freshly created draft unless an explicit invoiceNo was supplied at creation (numbers are no longer auto-assigned at draft creation — only at issue time, sticky thereafter). Use GET /invoices/next-number to preview what will be assigned.

issueDate string (date)

EN 16931 BT-2, the invoice date. It is always the day the invoice is issued (Europe/Berlin): on a draft it is provisional and reads as the day of the latest save; issuing sets it to the issue day, and a scheduled issuance to the day it runs. Frozen at issue.

status string

⚠ void is RESERVED AND NEVER WRITTEN. §14c UStG / GoBD forbid voiding an issued original; a cancellation is a separate 381 document referencing it, so api never writes this status anywhere. It stays in the enum because removing it would be a breaking contract change for no benefit. To detect a cancelled invoice read correctionState, never status.

Werte: "draft", "scheduled", "issued", "paid", "void"
currency string

ISO 4217

buyerName string | null
totalGross DecimalString
validationState string | null

Compliance-gate outcome. null until a validation attempt has run. 'legacy' = issued before the gate existed (backfilled when the gate was introduced).

Werte: "failed", "passed", "legacy"
correctionState string | null

The DERIVED correction state, computed on read from the document chain and never stored. cancelled = an ISSUED/PAID 381 (Storno) that reverses this invoice IN FULL references it; corrected = an ISSUED/PAID 384 (Berichtigung) does and no full 381 does; null = neither, INCLUDING the case where the only correction is still a DRAFT (a half-made Storno has cancelled nothing and must not switch off collection) AND the case where the only correction is a PARTIAL 381 (it reduces the open amount rather than settling the invoice, so the invoice stays in the open items and is still dunned for the remainder). Cancellation wins over correction. Naming + the null-for-none convention follow dauerrechnungState. This — not status: void, which the law forbids the system from ever writing — is what a "Storniert" view keys on. An invoice with a non-null correctionState is excluded from /dunning/overdue, from the per-customer open items, and from payment matching, and POST /invoices/{id}/reminders refuses it with 409 cancelled_by_correction. An invoice reduced by PARTIAL credit notes keeps a null correctionState and stays in all three, at its reduced open amount, until that amount reaches zero.

Werte: "cancelled", "corrected"
transmissionState TransmissionState
transmissionProblemReason TransmissionProblemReason
transmissionLastEventAt string (date-time) | null

When we learned the fact transmissionState reports. null when there is no such fact.

mode Mode
sendState InvoiceSendState

What is on record about this invoice having gone out. Present on this read only.

transmission Transmission | null

What the transport reported about the latest system-performed dispatch of this invoice, and the remedies offered for it. Present on this read only; null when there is no system-performed dispatch to report on.

capabilities object

What this deployment currently accepts on this invoice. It rides inside this read so a client can offer only what would be accepted, without a second request.

Felder
Feld Typ Beschreibung
externalSendRecord erforderlich boolean

Whether a dispatch performed outside this application can be recorded.

adHocRecipient erforderlich boolean

Whether the send accepts a recipient and copies chosen for this one message.

dueDate string (date) | null

EN 16931 BT-9 payment due date. Frozen at issue; render clients fall back to issueDate + 30 days when null.

paymentTerms string | null

EN 16931 BT-20 payment terms / Zahlungsziel. Frozen at issue.

invoiceTypeCode string

UNTDID 1001 (BT-3), e.g. "380" (commercial invoice). Write requests are allowlist-checked (INVOICE_TYPE_CODES, default "380,381,384"); anything else is a 400. Frozen after issue — a PUT on a non-draft invoice is always rejected regardless of which fields it tries to change.

reversalScope nur lesbar string | null

Derived, read-only: whether a credit note (invoiceTypeCode="381") reverses its referenced original in full or only in part. A FULL reversal is titled „Stornorechnung" on the rendered document; a PARTIAL one is titled „Rechnungskorrektur". Re-derived on every draft edit and frozen at issue. "full" means all of: the same currency, numerically equal net, tax and gross totals, and the same set of value-bearing line facts (quantity, unit code, unit net price, VAT rate, VAT category). Free text — descriptions and exemption reason texts — is deliberately not part of the comparison, and the comparison is against the referenced original document, not against whatever remains outstanding on it after earlier corrections. null for every other document type, and for a credit note whose original could not be resolved. This field affects the printed title ONLY. It is never a second document type: a partial credit note keeps invoiceTypeCode="381", so how it is booked, whether it is dunned, and which preceding references it may carry are all unchanged.

Werte: "full", "partial"
precedingInvoice PrecedingInvoiceRef | null

EN 16931 BG-3 (BT-25 number / BT-26 issue date). Set only on a correction (invoiceTypeCode="384") that references an in-system original; both fields are snapshotted server-side from the resolved original at create/update time — never trusted from client input directly. null for any other invoiceTypeCode.

correctedBy Array<string (uuid)>

Derived, read-only: ids of correction invoices (invoiceTypeCode="384") whose precedingInvoice points at THIS invoice. Computed on every read via the preceding-invoice link — never stored, so an original is never mutated by a correction that targets it. Only populated on GET /invoices/{id} (empty on create/update/ finalize responses).

sourceOfferId string (uuid) | null

The INTERNAL backlink to the source Angebot this invoice was derived from (POST /offers/{id}/convert-to-invoice). NULL for every non-converted invoice. NOT the EN 16931 preceding-invoice reference — a quote is not a preceding invoice.

sourceOffer SourceOfferRef | null

The reverse projection of sourceOfferId — the source Angebot's id + number, for the invoice-detail "Entstanden aus Angebot AN-…" reference line. Resolved on every read (no migration) from the offer named by sourceOfferId; null for a non-converted invoice (or an offer no longer visible under scope). Only populated on GET /invoices/{id} (null on create/update/finalize responses).

correctionDocuments Array<CorrectionDocumentRef>

The reverse-link LABEL projection — the ISSUED/paid corrections (invoiceTypeCode="384") and credit notes / Stornos ("381") whose precedingInvoice points at THIS invoice, enriched with number + type code + issue date so a client can render "storniert durch (381) …" vs "korrigiert durch (384) …" without an N-fetch. The issued subset of the same reverse lookup as correctedBy (which stays the full, unfiltered id list). Computed on every read via the preceding-invoice link — never stored. Only populated on GET /invoices/{id} (empty on create/update/ finalize responses).

customerId string (uuid) | null

Soft link to the source customer; buyer is snapshotted

documentTarget string

The document-target (Rechnungsintent) snapshotted onto this invoice at creation (override > linked customer > 'b2b'), re-resolved on draft edit, frozen at issue. 'b2b' renders ZUGFeRD (EN 16931) with the German XRechnung CIUS rules (BR-DE-, e.g. BT-10) advisory; 'b2g' renders XRechnung + ZUGFeRD with BR-DE- as hard requirements.

Werte: "b2b", "b2g"
seller Party
sellerIsKleinunternehmer boolean

§19 UStG snapshot: whether the seller was a Kleinunternehmer at this invoice's CREATION, captured from the company profile's Kleinunternehmer setting and frozen on the invoice (like seller.taxNumber). Read-only; the §14 evaluator reads this immutable snapshot, never the live company flag.

isDauerrechnung boolean

The Dauerrechnung marker — an ORTHOGONAL invoice-level flag, NOT a new invoiceTypeCode (a Dauerrechnung stays a "380", or "384" on a reissue-as-Berichtigung). Set at create/draft, frozen at issue. The only consumer that branches on it is the §14 evaluator (Nr. 4 static-Objektnummer exemption; Nr. 6 period-satisfies). DATEV never branches on it — a Dauerrechnung books identically to its underlying 380/384.

dauerrechnungState string | null

DERIVED, read-only standing state. active = a Dauerrechnung chain head (no successor references it); superseded = a later invoice references it via precedingInvoice; null = not a Dauerrechnung (isDauerrechnung=false). Computed from the correctedBy chain, never stored (no anchor table). superseded only ever surfaces on GET /invoices/{id} (where correctedBy is resolved); a Dauerrechnung on a create/update/finalize response reads active.

Werte: "active", "superseded"
buyer Party
buyerReference string | null
buyerEmail string (email) | null

Snapshot recipient email

notes string | null
lineItems Array<InvoiceLineItem>
totals InvoiceTotals
taxBreakdown Array<TaxBreakdownEntry>
issuedAt string (date-time) | null

Set at issue time. Approximate (from updatedAt) for 'legacy' rows backfilled when the field was introduced; null for drafts.

processingRestricted boolean

DSGVO Art. 18 processing restriction. When true, the document is flagged restricted — it is still fully archived, exported, and DATEV-included (restriction limits processing, not existence). Set/cleared via PATCH /invoices/{id}/processing-restriction.

processingRestrictionReason string | null

Reason for the restriction; null when not restricted.

Werte: "article_18_gdpr_request", "legal_dispute", "disputed_accuracy"
restrictedAt string (date-time) | null

When the restriction was set (denormalized render-copy).

restrictedBy string (uuid) | null

users.id that set the restriction (denormalized render-copy).

createdAt string (date-time)
updatedAt string (date-time)

Verwendet von: POST /subscriptions/{id}/generate-invoice

Mode string

Mode echo ("unmissable live/test indicator"): the row's own live/test mode, echoed on every scoped-resource representation so a live vs. test record is unmissable. Read from the record's mode column (never re-derived from the request credential); live for legacy rows created before mode existed.

  • Werte: "live", "test"

Beispiel: "live"

Verwendet von: GET /subscriptions , POST /subscriptions , GET /subscriptions/{id} , PUT /subscriptions/{id} , PATCH /subscriptions/{id}/status , GET /subscriptions/{id}/invoices , POST /subscriptions/{id}/generate-invoice

SubscriptionLineItem object

A recurring line TEMPLATE. It carries the optional itemDescription (BT-154), which every generated invoice line inherits. It is narrower than CreateInvoiceLineItem in one respect: it carries no vatCategory and no vatExemptionReasonText. Such a key is refused with 400 validation_error, like any other key this schema does not list; the issue's path is lineItems.N.<key>.

Feld Typ Beschreibung
description erforderlich string
Länge: min. 1, max. 500
quantity erforderlich QuantityString
unitCode erforderlich string

EN 16931 BT-130 — the unit of measure each generated invoice line will carry. This is a CODED element: the value must come from the UN/ECE Recommendation 20 code list with the Recommendation 21 extension, as enforced by rule BR-CL-23, and NOT from your own vocabulary. Codes are UPPERCASE and are never corrected for you — "hur" is not "HUR". Common values: C62 (piece), HUR (hour), DAY, KGM (kilogram), MTR (metre), LTR (litre), MTK (square metre), KWH. The full accepted set is much wider than these examples; anything matching the published pattern and present in the code list is accepted.

ANNOUNCED NARROWING: this endpoint currently ACCEPTS values outside the code list and records them, so an existing integration keeps working. Refusal is a separate, later change. Send a listed code now; the pattern above is what will be enforced.

Länge: min. 2, max. 3
Muster: ^[A-Z0-9]{2,3}$
unitPriceNet erforderlich MoneyString
taxRatePercent erforderlich string

Percent as a decimal string, e.g. "19".

itemDescription string

EN 16931 BT-154 — optional longer item description, distinct from the item name (description, BT-153). The same field and bound as CreateInvoiceLineItem.itemDescription. Stored on the template and carried onto the matching line of every invoice the template generates (scheduled run and manual generation). Leading and trailing whitespace is trimmed. Omitting it on a replace stores no description for that line.

Länge: max. 1000

Verwendet von: POST /subscriptions , PUT /subscriptions/{id}

DecimalString string

A fixed-precision decimal as a string, e.g. "9542.50". Read shapes deliberately publish no scale: a document issued before the request scales below were introduced may carry more decimals than a new request may send, and such a document is served from the archive rather than re-created.

Beispiel: "9542.50"

Verwendet von: GET /subscriptions/{id}/invoices , POST /subscriptions/{id}/generate-invoice

TransmissionState string | null

What the TRANSPORT reported about this document's latest system-performed dispatch. A separate axis from sendState (who says it was sent) and from the sender kind (whose infrastructure carried it), and the three are never merged. transmitted is the highest claim this rail can ever make: a receiving mail system ACCEPTED the bytes. There is no delivered value and there will never be one — SMTP cannot report that a message reached a person, and a value that claimed it would be a fabricated fact on a retained document trail. A future rail that genuinely carries a delivery confirmation gets its own, different value. failed and undeliverable are different facts and are never merged: failed means nothing was ever handed over, undeliverable means it was and it came back. null means this document has no system-performed dispatch at all — a hand-recorded dispatch, a draft, or a document that was never mailable. It never means "unknown" and must not be rendered as a problem.

  • Werte: "not_sent", "queued", "held", "transmitted", "delayed", "undeliverable", "failed"

Verwendet von: GET /subscriptions/{id}/invoices , POST /subscriptions/{id}/generate-invoice

TransmissionProblemReason string | null

Why a document is in a delayed, undeliverable or failed state. null in every other state. ⚠ It carries a CLASS and never the report's own diagnostic text: that text is a fragment of third-party correspondence about somebody else's invoice and is neither stored nor published anywhere in this platform.

  • Werte: "hard_bounce", "soft_bounce", "smtp_rejected", "attempts_exhausted"

Verwendet von: GET /subscriptions/{id}/invoices , POST /subscriptions/{id}/generate-invoice

InvoiceSendState object

What this application knows about the invoice leaving the building. It is a class rather than a bare date, because a date alone cannot say whether we dispatched the document or somebody told us they had.

Feld Typ Beschreibung
class erforderlich string
Werte: "none", "system_transmitted", "user_asserted"
recordedAt string (date-time) | null

When we wrote the record down. Null when there is no record.

assertedOn string (date) | null

The date stated by the person who recorded it. Present only for user_asserted, and then always together with recordedAt.

Verwendet von: POST /subscriptions/{id}/generate-invoice

Transmission object

What the transport reported about one document's latest system-performed dispatch, with the remedies this API offers for it. Present on the single-invoice read; null when there is no system-performed dispatch to report on.

Feld Typ Beschreibung
state erforderlich TransmissionState
heldReason erforderlich TransmissionHeldReason
problemReason erforderlich TransmissionProblemReason
lastEventAt erforderlich string (date-time) | null
sender erforderlich object | null

The sender identity the message actually went out under, read from the send record's own snapshot. It is never re-derived from current settings: a sender identity can be changed, and re-reading it would show today's sender beside yesterday's message.

Felder
Feld Typ Beschreibung
kind erforderlich string
Werte: "tenant_smtp", "platform"
fromAddress erforderlich string | null
replyTo erforderlich string | null
recipientSuppressed erforderlich boolean

The recipient address is currently on this account's suppression list, so no further mail is sent to it until the address is changed.

actions erforderlich Array<string>

The remedies this API offers for this state, in the order they should be presented. The list is decided by the server and a client renders it as offered — a client that decides for itself whether a re-send is possible will eventually offer one the server refuses.

Verwendet von: POST /subscriptions/{id}/generate-invoice

PrecedingInvoiceRef object

EN 16931 BG-3 snapshot (BT-25 number / BT-26 issue date) — the original invoice a correction (invoiceTypeCode="384") restates.

Feld Typ Beschreibung
id erforderlich string (uuid)
invoiceNumber erforderlich string
issueDate erforderlich string (date)

Verwendet von: POST /subscriptions/{id}/generate-invoice

SourceOfferRef object

The source Angebot an invoice was derived from via POST /offers/{id}/convert-to-invoice — id + number, for the invoice-detail "Entstanden aus Angebot AN-…" reference line. NOT an EN 16931 preceding-invoice reference (a quote is not an invoice).

Feld Typ Beschreibung
id erforderlich string (uuid)
offerNumber erforderlich string

Angebotsnummer (e.g. AN-00042)

Verwendet von: POST /subscriptions/{id}/generate-invoice

CorrectionDocumentRef object

One issued correction / credit-note that references an invoice as its BG-3 preceding reference — number + UNTDID 1001 type code + issue date, so a client can label the reverse link ("storniert durch (381)" vs "korrigiert durch (384)").

Feld Typ Beschreibung
id erforderlich string (uuid)
invoiceNumber erforderlich string
invoiceTypeCode erforderlich string

UNTDID 1001

reversalScope erforderlich nur lesbar string | null

The referencing document's own reversal scope, so a client can label this reverse link with the same word that document carries on itself („Stornorechnung" when full, „Rechnungskorrektur" when partial). null for a correction ("384") and for a credit note whose scope was never recorded.

Werte: "full", "partial"
issueDate erforderlich string (date)

Verwendet von: POST /subscriptions/{id}/generate-invoice

Party object

Seller or buyer (EN 16931 BG-4 / BG-7, simplified).

Feld Typ Beschreibung
name erforderlich string
addressLine1 string | null
postalCode string | null
city string | null
countryCode string | null

ISO 3166-1 alpha-2

vatId string | null

USt-IdNr (EN 16931 BT-31 / BT-48)

taxNumber string | null

Steuernummer (seller snapshot on invoices)

Verwendet von: POST /subscriptions/{id}/generate-invoice

InvoiceLineItem object

A line (EN 16931 BG-25, simplified).

Feld Typ Beschreibung
id erforderlich string (uuid)
description erforderlich string
quantity erforderlich DecimalString
unitCode erforderlich string

EN 16931 BT-130 — the unit of measure of the invoiced quantity, from the UN/ECE Recommendation 20 code list with the Recommendation 21 extension (rule BR-CL-23). E.g. C62 (piece), HUR (hour), KGM.

NO PATTERN IS PUBLISHED ON THIS READ, deliberately: documents issued before the input boundary existed may carry a value outside the code list, and those documents are immutable and are streamed from the archive rather than re-rendered. Publishing a pattern here would make our own historical responses fail a client's schema validation.

unitPriceNet erforderlich DecimalString
lineNetAmount erforderlich DecimalString

Computed = quantity × unitPriceNet

taxRatePercent erforderlich DecimalString
itemDescription string | null

EN 16931 BT-154 — optional longer item description, distinct from the item name (description, BT-153). Renders as a PDF sub-line and serialises to CII ram:Description.

vatCategory string

EN 16931 BT-118 VAT category. O omitted per owner. A Kleinunternehmer seller's lines resolve to E server-side.

Werte: "S", "Z", "E", "AE", "K", "G"
Standard: "S"
vatExemptionReasonCode string | null

EN 16931 BT-121 VATEX exemption reason code (late-binding / StB-gated).

vatExemptionReasonText string | null

EN 16931 BT-120 exemption reason free-text.

Verwendet von: POST /subscriptions/{id}/generate-invoice

InvoiceTotals object

Document totals (EN 16931 BG-22, simplified).

Feld Typ Beschreibung
totalNet DecimalString
totalTax DecimalString
totalGross DecimalString

Verwendet von: POST /subscriptions/{id}/generate-invoice

TaxBreakdownEntry object

One VAT group (EN 16931 BG-23, simplified).

Feld Typ Beschreibung
taxRatePercent DecimalString
taxableAmount DecimalString
taxAmount DecimalString

Verwendet von: POST /subscriptions/{id}/generate-invoice

QuantityString string

An invoiced quantity as a string, with at most four decimal places. Unlike a price, a quantity is not rounded before use — the line total is price × quantity, rounded once — so a fractional quantity such as "0.25" is ordinary and carries a wider scale than a monetary amount.

  • Muster: ^\d+(\.\d{1,4})?$

Beispiel: "0.25"

Verwendet von: POST /subscriptions , PUT /subscriptions/{id}

MoneyString string

A monetary amount as a string, with at most two decimal places — the scale amounts are billed in. A finer value is refused rather than rounded: rounding it would change the number the caller sent, and because a unit price is rounded to whole cents before being multiplied by the quantity, that change is then multiplied too. A price of "12.999" at quantity 1000 billed 13000.00 against an honest 12999.00; "0.005" at the same quantity billed double.

  • Muster: ^\d+(\.\d{1,2})?$

Beispiel: "9542.50"

Verwendet von: POST /subscriptions , PUT /subscriptions/{id}

TransmissionHeldReason string | null

Why the queue is holding this message back. Set only in the held state, null otherwise. A held message consumes no delivery attempt and is re-tried automatically once the condition clears.

  • Werte: "tenant_paused", "entity_cap", "domain_cap", "recipient_suppressed"

Verwendet von: POST /subscriptions/{id}/generate-invoice

Nach oben · Alle Ressourcengruppen · OpenAPI-Spezifikation (YAML)