# Create a corrective invoice API Reference

Issues a corrective invoice that amends the invoice in the path. It is a new fiscal
document with its own number, not an edit of the original.

- **`rectification_type`:** `TOTAL` leaves the original `VOIDED` and rectifies what is
  still invoiced on it: every line of the original and of its live correctives (voided ones
  do not count), negated. It takes no `lines` — sending them fails with
  `422 RECTIFICATIVA_TOTAL_CON_LINEAS`. `PARTIAL` leaves the original `RECTIFIED` and
  requires the adjustment `lines`.
- **Never more than was invoiced:** a `PARTIAL` may raise any amount, but may not take the
  taxable base of any rate (tax, rate and equivalence surcharge; `SUPLIDO` lines by their
  amount) below zero once the previous correctives are counted. That fails with
  `422 CORRECTIVE_EXCEEDS_INVOICED_AMOUNT`, and `error.details` (`CorrectiveInvoiceErrorDetails`)
  carries `tax_group` (for example `IVA 21%`) and `max_reduction`, how much of that rate is
  left to rectify. A
  `TOTAL` on an invoice that previous correctives already brought to zero fails with
  `422 CORRECTIVE_NOTHING_LEFT_TO_RECTIFY`.
- **Not for the withholding alone:** a `PARTIAL` whose lines leave the taxable base of
  every rate unchanged and only change the withholding fails with
  `422 CORRECTIVE_WITHHOLDING_ONLY`. A withholding is not a cause for a corrective: void
  the invoice and issue a new one without it.
- **The original's PDF:** unchanged by either type. The corrective has its own PDF; the
  original keeps the one that was delivered, and its new status is in `status`.
- **Total of 0:** a corrective whose `total_to_pay` is 0 has nothing to refund or
  collect, so it is issued as `PAID`, with `payment_date` equal to `issue_date`.
- **What can be rectified:** an ordinary or simplified invoice in `ISSUED`, `SENT`,
  `PAID`, `OVERDUE` or `RECTIFIED`. Rectifying a corrective fails with
  `422 CORRECTIVE_NOT_RECTIFIABLE` — to fix an erroneous corrective, issue another one
  against the original invoice.
- **Repeat rectifications:** several `PARTIAL` correctives are allowed, but a `VOIDED`
  invoice is no longer rectifiable, so a second `TOTAL` against the same invoice fails
  with `422 INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS`.
- **Correcting the recipient's data:** when the invoice recorded its recipient with a wrong
  name, tax ID or address, send the corrected `recipient` with `rectification_type`
  `PARTIAL`, `rectification_code` `R4` and no `lines`. The corrective carries the corrected
  recipient and does not change the amounts: its lines negate what is still invoiced and
  repeat it, so every rate nets to zero. A different person is not a data correction
  (`422 CORRECTIVE_RECIPIENT_IS_ANOTHER_PERSON`): correct the invoice in full and issue a new
  one to the right customer.
- **Original rejected by the AEAT:** when VeriFactu rejected the original's record and it
  has not been resubmitted, the original is not in the AEAT's books: fix and resubmit it
  first. Until then the request fails with `422 CORRECTIVE_ORIGINAL_RECORD_REJECTED`.
- **Exchange invoice recorded as F3:** correcting a full invoice issued in exchange for
  simplified invoices is not available yet: `422 EXCHANGE_INVOICE_NOT_CORRECTABLE`.
  Contact support.
- **Deadline:** four years from when the tax accrued (the original's operation date) or,
  for a cause of article 80 of the VAT Act, from the `circumstance_date` you declare. Past
  it the request fails with `422 CORRECTIVE_OUT_OF_TIME`, with `deadline` and
  `counted_from` in `error.details` (`CorrectiveInvoiceErrorDetails`).
- **What the reason code requires** (Ley 37/1992, art. 80): `R2` (insolvency) and `R3` (bad
  debt) need a recipient established in Spain, the Canary Islands, Ceuta or Melilla —an
  `R2` also accepts a recipient in another EU member state, for insolvency proceedings
  there— and fail otherwise with `422 CORRECTIVE_RECIPIENT_NOT_ESTABLISHED`. An `R3` needs
  at least six months since the original's operation date
  (`422 CORRECTIVE_BAD_DEBT_TOO_EARLY`, with `earliest_date`; one year when the previous
  year's turnover exceeded 6,010,121.04 €, which is the issuer's to apply), and on an operation
  with a base of 50 € or less it needs `recipient_is_business`
  (`422 CORRECTIVE_BAD_DEBT_BASE_TOO_LOW`). The other conditions of each code (claims,
  guarantees, related parties, filing with the AEAT) are the issuer's to meet.
- **Fiscal inheritance on a `PARTIAL`:** a line that omits `irpf_rate` or
  `equivalence_surcharge_rate` takes it from the **original invoice** — the document
  being amended — and never from the company's current tax profile, so a profile that
  changed after the original was issued does not leak into the credit note. An explicit
  value always wins, `0` included. The surcharge inherits the *regime* (on/off), not the
  rate: the rate is re-derived from each corrective line's own VAT (21→5.2, 10→1.4,
  5→0.62, 4→0.5), and an original outside the regime pins the line to `0`. `SUPLIDO`
  lines are out of it on both sides. When the original is not unambiguous BeeL does not
  pick for you: different IRPF rates per line fail with
  `422 CORRECTIVE_ORIGINAL_MIXED_IRPF`, and a surcharge applied on some lines but not
  others fails with `422 CORRECTIVE_ORIGINAL_MIXED_SURCHARGE`. Declare the figure on every
  line to get past either — both only fire when some line actually needs to inherit.
- **`series_id`:** when omitted, the document is numbered in the company's default
  corrective series, never in the series of the original: corrective invoices go in a
  series of their own (RD 1619/2012, art. 6.1.a). If the company has none, it is created
  on first use (code `R`, or the next free one that cannot repeat another series'
  numbers). An explicit `series_id` must be a corrective series.
- **Numbering conflict:** if the number the series would assign is already used by another
  invoice of the same company, in this series or in another one, the request fails with
  `400 SERIES_NUMBER_COLLISION` without issuing anything or consuming a number. The series
  needs review, so contact support.


## POST /v1/companies/{company_id}/invoices/{invoice_id}/corrective

**Create a corrective invoice**

Issues a corrective invoice that amends the invoice in the path. It is a new fiscal
document with its own number, not an edit of the original.

- **`rectification_type`:** `TOTAL` leaves the original `VOIDED` and rectifies what is
  still invoiced on it: every line of the original and of its live correctives (voided ones
  do not count), negated. It takes no `lines` — sending them fails with
  `422 RECTIFICATIVA_TOTAL_CON_LINEAS`. `PARTIAL` leaves the original `RECTIFIED` and
  requires the adjustment `lines`.
- **Never more than was invoiced:** a `PARTIAL` may raise any amount, but may not take the
  taxable base of any rate (tax, rate and equivalence surcharge; `SUPLIDO` lines by their
  amount) below zero once the previous correctives are counted. That fails with
  `422 CORRECTIVE_EXCEEDS_INVOICED_AMOUNT`, and `error.details` (`CorrectiveInvoiceErrorDetails`)
  carries `tax_group` (for example `IVA 21%`) and `max_reduction`, how much of that rate is
  left to rectify. A
  `TOTAL` on an invoice that previous correctives already brought to zero fails with
  `422 CORRECTIVE_NOTHING_LEFT_TO_RECTIFY`.
- **Not for the withholding alone:** a `PARTIAL` whose lines leave the taxable base of
  every rate unchanged and only change the withholding fails with
  `422 CORRECTIVE_WITHHOLDING_ONLY`. A withholding is not a cause for a corrective: void
  the invoice and issue a new one without it.
- **The original's PDF:** unchanged by either type. The corrective has its own PDF; the
  original keeps the one that was delivered, and its new status is in `status`.
- **Total of 0:** a corrective whose `total_to_pay` is 0 has nothing to refund or
  collect, so it is issued as `PAID`, with `payment_date` equal to `issue_date`.
- **What can be rectified:** an ordinary or simplified invoice in `ISSUED`, `SENT`,
  `PAID`, `OVERDUE` or `RECTIFIED`. Rectifying a corrective fails with
  `422 CORRECTIVE_NOT_RECTIFIABLE` — to fix an erroneous corrective, issue another one
  against the original invoice.
- **Repeat rectifications:** several `PARTIAL` correctives are allowed, but a `VOIDED`
  invoice is no longer rectifiable, so a second `TOTAL` against the same invoice fails
  with `422 INVOICE_NOT_CORRECTIBLE_IN_CURRENT_STATUS`.
- **Correcting the recipient's data:** when the invoice recorded its recipient with a wrong
  name, tax ID or address, send the corrected `recipient` with `rectification_type`
  `PARTIAL`, `rectification_code` `R4` and no `lines`. The corrective carries the corrected
  recipient and does not change the amounts: its lines negate what is still invoiced and
  repeat it, so every rate nets to zero. A different person is not a data correction
  (`422 CORRECTIVE_RECIPIENT_IS_ANOTHER_PERSON`): correct the invoice in full and issue a new
  one to the right customer.
- **Original rejected by the AEAT:** when VeriFactu rejected the original's record and it
  has not been resubmitted, the original is not in the AEAT's books: fix and resubmit it
  first. Until then the request fails with `422 CORRECTIVE_ORIGINAL_RECORD_REJECTED`.
- **Exchange invoice recorded as F3:** correcting a full invoice issued in exchange for
  simplified invoices is not available yet: `422 EXCHANGE_INVOICE_NOT_CORRECTABLE`.
  Contact support.
- **Deadline:** four years from when the tax accrued (the original's operation date) or,
  for a cause of article 80 of the VAT Act, from the `circumstance_date` you declare. Past
  it the request fails with `422 CORRECTIVE_OUT_OF_TIME`, with `deadline` and
  `counted_from` in `error.details` (`CorrectiveInvoiceErrorDetails`).
- **What the reason code requires** (Ley 37/1992, art. 80): `R2` (insolvency) and `R3` (bad
  debt) need a recipient established in Spain, the Canary Islands, Ceuta or Melilla —an
  `R2` also accepts a recipient in another EU member state, for insolvency proceedings
  there— and fail otherwise with `422 CORRECTIVE_RECIPIENT_NOT_ESTABLISHED`. An `R3` needs
  at least six months since the original's operation date
  (`422 CORRECTIVE_BAD_DEBT_TOO_EARLY`, with `earliest_date`; one year when the previous
  year's turnover exceeded 6,010,121.04 €, which is the issuer's to apply), and on an operation
  with a base of 50 € or less it needs `recipient_is_business`
  (`422 CORRECTIVE_BAD_DEBT_BASE_TOO_LOW`). The other conditions of each code (claims,
  guarantees, related parties, filing with the AEAT) are the issuer's to meet.
- **Fiscal inheritance on a `PARTIAL`:** a line that omits `irpf_rate` or
  `equivalence_surcharge_rate` takes it from the **original invoice** — the document
  being amended — and never from the company's current tax profile, so a profile that
  changed after the original was issued does not leak into the credit note. An explicit
  value always wins, `0` included. The surcharge inherits the *regime* (on/off), not the
  rate: the rate is re-derived from each corrective line's own VAT (21→5.2, 10→1.4,
  5→0.62, 4→0.5), and an original outside the regime pins the line to `0`. `SUPLIDO`
  lines are out of it on both sides. When the original is not unambiguous BeeL does not
  pick for you: different IRPF rates per line fail with
  `422 CORRECTIVE_ORIGINAL_MIXED_IRPF`, and a surcharge applied on some lines but not
  others fails with `422 CORRECTIVE_ORIGINAL_MIXED_SURCHARGE`. Declare the figure on every
  line to get past either — both only fire when some line actually needs to inherit.
- **`series_id`:** when omitted, the document is numbered in the company's default
  corrective series, never in the series of the original: corrective invoices go in a
  series of their own (RD 1619/2012, art. 6.1.a). If the company has none, it is created
  on first use (code `R`, or the next free one that cannot repeat another series'
  numbers). An explicit `series_id` must be a corrective series.
- **Numbering conflict:** if the number the series would assign is already used by another
  invoice of the same company, in this series or in another one, the request fails with
  `400 SERIES_NUMBER_COLLISION` without issuing anything or consuming a number. The series
  needs review, so contact support.

### Authentication

Accepts any of:

- `ApiKeyAuth` (HTTP bearer, token format `beel_sk_*`)

### Parameters

- **company_id** (required) in path `string`: Unique identifier (UUID) of the company the operation acts on — its identifier, not its NIF. It is the only source of context: the account that owns it is derived from it, and the `BeeL-Active-Company` header plays no part. A company you do not reach answers `403`, and so does a company that does not exist, so the existence of a company in another account is never disclosed.
- **invoice_id** (required) in path: Invoice ID
- **Idempotency-Key** (optional) in header `string`: Idempotency key to prevent duplicates in sensitive operations. - Any unique client-generated string (e.g. an order id). A UUID also works but is not required - Allowed characters: letters, digits, `_` and `-` (max 255 chars) - Retrying with the same key replays the first response when it was a success (2xx) or a server error (5xx): same status and body, plus the header `Idempotency-Replay: true`. After a 5xx, check whether the operation took effect before retrying with a **new** key - A 4xx is not stored: the key is released, so the corrected request can reuse it - Stored responses expire 24 hours after processing The key is scoped per user and environment, and bound to the request body, so retrying after a network timeout replays the stored response instead of repeating the operation. | Status | Code | When | |---|---|---| | `400` | `INVALID_IDEMPOTENCY_KEY` | The key breaks the format rules above. | | `409` | `IDEMPOTENCY_KEY_PROCESSING` | The first request is still in flight. Wait for the `Retry-After` seconds (2) and retry with the same key. | | `409` | `IDEMPOTENCY_KEY_MISMATCH` | The key was already used with a **different** body. Use a new key. |

### Request Body

Required.

**Content `application/json`:**

- **rectification_type** (required) `RectificationType`: Type of rectification applied to a corrective invoice: - TOTAL: Rectifies everything still invoiced on the original, its live correctives included (status → VOIDED) - PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** (required) `VeriFactuRectificationCode`: Rectification codes according to VeriFactu regulations (AEAT): - R1: Error founded in law and Art. 80 One, Two and Six LIVA - R2: Article 80 Three LIVA (Bankruptcy proceedings) - R3: Article 80 Four LIVA (Uncollectable debts) - R4: Other causes - R5: Corrective of a simplified invoice - ONLY for simplified invoices
- **reason** (required) `string`: Detailed reason for rectification (minimum 10 characters) (example: "Amount correction due to calculation error in hours worked during the project")
- **lines** `array[object]`: **TOTAL**: not accepted. A `TOTAL` corrective rectifies what is still invoiced on the original —its lines and those of its live correctives, negated— and a request with `lines` fails with `422 RECTIFICATIVA_TOTAL_CON_LINEAS`. **PARTIAL**: required. The adjustment lines, with positive or negative amounts; they may not take the base of any rate below zero (`422 CORRECTIVE_EXCEEDS_INVOICED_AMOUNT`).
  - **description** `string`: Concept description. Required for NORMAL lines; optional for SUPLIDO lines. (example: "Adjustment for incorrectly invoiced hours")
  - **quantity** (required) `number`: Quantity (can be negative for corrective invoices) (example: -10)
  - **unit** `string`: No description (example: "hours")
  - **unit_price** `number`: Unit price before taxes (can be negative in corrective invoices). Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging). Final amounts are always rounded to 2 decimals. (example: 50)
  - **total_excluding_tax** `number`: Declared line total excluding taxes (total-declared mode, e.g. 300 units invoiced for exactly 1.00). The taxable base of the line is EXACTLY this amount — it is never recalculated from the unit price. The unit price becomes derived and informational (`total / quantity`, 4 decimals). Each line must carry exactly one of `unit_price`, `total_excluding_tax` or `total_including_tax` (anything else is rejected with `LINE_UNIT_PRICE_XOR_DECLARED_TOTAL`). Incompatible with `discount_percentage` (`LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT`): any discount is already included in the declared total. Can be negative in corrective invoices. (example: 1)
  - **total_including_tax** `number`: Declared line total including taxes (tax-inclusive total-declared mode): what the customer paid for this line — taxable base + VAT + equivalence surcharge. IRPF withholding is NOT part of it (it is a retention, not price; it is computed on the derived base as usual). The engine works the breakdown backwards from the unrounded base (`base_raw = total / (1 + vat + surcharge)`, DGT V1919-18) so the rounded amounts add up to the declared total exactly (e.g. 100.00 at 21% → 82.64 + 17.36 = 100.00). On exempt or 0% lines it is equivalent to `total_excluding_tax` (base = total, quota 0). Each line must carry exactly one of `unit_price`, `total_excluding_tax` or `total_including_tax` (anything else is rejected with `LINE_UNIT_PRICE_XOR_DECLARED_TOTAL`). Incompatible with `discount_percentage` (`LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT`). Can be negative in corrective invoices. (example: 100)
  - **discount_percentage** `number`: No description
  - **main_tax** `TaxInfo`: Complete tax information with cross-validations: - IVA: real rates 4, 10, 21, and the temporary 2, 5 and 7.5 (see below for 0) - IGIC: 0, 3, 5, 7, 9.5, 15, 20 — here 0 is the real "Tipo Cero" - IPSI: real rates 0.5, 1, 2, 4, 8, 10 (see below for 0) - OTHER: any percentage between 0 and 100 **0 % under IVA and IPSI is not a rate, it is the exemption sentinel.** It is accepted on a line, but only together with an `exemption_reason` (exempt or non-subject operation); on its own it says nothing and the line is rejected. That is why `GET /v1/tax-types` publishes the IVA rates without 0: the legitimate way to a 0 % IVA line is through an exemption reason, which the same response also publishes. IGIC is different — its 0 % is a real legal rate (basic necessities) and needs no reason. **IVA 5 %** (the temporary rate applied from 2022 to electricity, gas and certain foodstuffs) is no longer in force for new operations. AEAT only accepts it on operations dated from 2022-07-01 to 2024-09-30: send the `operation_date` of that period, because without one the issue date decides and a line at 5 % is rejected with `422 VAT_RATE_NOT_ACCEPTED_ON_DATE`. Its equivalence surcharge pair is 0.5 up to 2022-12-31 and 0.62 from 2023-01-01. **IVA 2 % and 7.5 %** (temporary rates of the last quarter of 2024) are accepted only on operations dated from 2024-10-01 to 2024-12-31, with surcharges 0.26 and 1. Exception: when regime_key = "17" (OSS/IOSS) the invoice applies the destination country VAT instead of the Spanish one, so any percentage in the EU range [0, 27] is accepted regardless of the tax type set — including 0 without an exemption reason.
  - **equivalence_surcharge_rate**: Equivalence surcharge rate for this line of the corrective invoice. **Default behaviour:** if omitted, the line inherits the surcharge **regime** of the invoice being amended — not the company's current tax profile, whose default does not apply to corrective invoices. What travels from the original is the on/off signal, not the rate: the rate is re-derived from this line's own VAT (21→5.2, 10→1.4, 5→0.62, 4→0.5), so a corrective line at 10% gets 1.4 even when the original line it amends was at 21%. If the original was outside the regime the line is pinned to `0`, so today's profile never adds a surcharge to the credit note of an invoice that carried none. An explicit value is always respected. If the original applies the surcharge on some lines but not others there is no regime to inherit and the request fails with `422 CORRECTIVE_ORIGINAL_MIXED_SURCHARGE`: send `equivalence_surcharge_rate` on every line. `SUPLIDO` lines never carry a surcharge and are ignored on both sides.
  - **irpf_rate**: IRPF withholding rate for this line of the corrective invoice. **Default behaviour:** if omitted, the line inherits the rate of the invoice being amended — **not** the account's default IRPF rate from the tax profile, whose default does not apply to corrective invoices: a profile that changed after the original was issued must not alter what the credit note withholds. An explicit value is always respected, `0` included, which is how you issue a line **without** withholding. If the original withholds different rates on different lines there is nothing unambiguous to inherit and the request fails with `422 CORRECTIVE_ORIGINAL_MIXED_IRPF`: send `irpf_rate` on every line. `SUPLIDO` lines never carry IRPF and are ignored on both sides. On SIMPLIFIED invoices (F2) IRPF withholding is **not allowed** (AEAT forbids it on F2): sending an `irpf_rate` other than 0 is **rejected** with `SIMPLIFICADA_FORBIDS_IRPF` — it is not coerced to 0. Omit the field or send `irpf_rate: 0` on F2 lines.
  - **exemption_reason** `ExemptionReason`: Tax exemption reason code per the Spanish VAT Law (Ley 37/1992, LIVA), with the VeriFactu code each one is reported as. - `EXENTA_ART_20`: exempt, art. 20 (domestic operations such as medical, educational, cultural and financial services, or housing rentals). E1. - `EXENTA_ART_21`: exempt, art. 21 (exports of goods). E2. - `EXENTA_ART_22`: exempt, art. 22 (operations treated as exports). E3. - `EXENTA_ART_24`: exempt, art. 24 (free zones, warehouses and customs regimes). E4. - `EXENTA_ART_25`: exempt, art. 25 (intra-community supplies of goods). E5. - `EXENTA_ART_26`: exempt, art. 26 (intra-community acquisitions of goods). It exempts the buyer's acquisition, not a supply the seller invoices, so an invoice line that carries it is rejected with `EXEMPTION_NOT_FOR_ISSUED_INVOICE`; a supply to another Member State is `EXENTA_ART_25`. - `NO_SUJETA_ART_7_9`: not subject under art. 7 (such as the transfer of a business as a going concern, art. 7.1º). N1. - `NO_SUJETA_LOCALIZACION`: not subject by the place-of-supply rules (intra-community or non-EU services, arts. 69 and 70). N2. - `ISP_ART_84_2_A` … `ISP_ART_84_2_F`: reverse charge (the invoice states «inversión del sujeto pasivo»), art. 84.Uno.2.º letters a) (supplier not established in Spain), b) (unwrought or semi-finished gold), c) (scrap, waste and recovery materials, plastic, paper, cardboard, glass and textile waste, and semi-finished non-ferrous metal products), d) (greenhouse gas emission allowances), e) (certain real estate supplies: in insolvency proceedings, with the exemption waived, or enforcing a security) and f) (construction or renovation works). S2. - `ISP_ART_84_2_G`: reverse charge of letter g) (silver, platinum, palladium, mobile phones, consoles, laptops and tablets). The law requires these supplies to be invoiced in a special series, so an invoice line that carries it is rejected with `REVERSE_CHARGE_CASE_NOT_SUPPORTED`. - `EXENTA_ART_140`: investment gold exemption, art. 140 bis (usually with `regime_key` `04`). E6. - `REGIMEN_ART_129` (agriculture, livestock and fishing, arts. 124 to 134 bis), `REGIMEN_ART_135` (second-hand goods, art and antiques), `REGIMEN_ART_141` (travel agencies), `REGIMEN_ART_154` (equivalence surcharge) and `REGIMEN_ART_163_DECIES` (cash basis, arts. 163 decies to 163 sexiesdecies): operations of special regimes, which VeriFactu identifies by the regime key rather than by an exemption code. An invoice line that carries one is rejected with `EXEMPTION_REGIME_NOT_SUPPORTED_IN_VERIFACTU`; declare the regime with `regime_key` instead. - `OTRO`: any other provision. Requires the text in `exemption_reason_text`. E6.
  - **exemption_reason_text** `string`: No description
- **circumstance_date** `string` (date): When the circumstance that causes the rectification took place, if it is one of article 80 of the VAT Act (Ley 37/1992): a discount granted after the sale, an operation cancelled or a price changed after it took place, the customer's insolvency, a bad debt. Optional. A corrective must be issued within four years from when the tax accrued or, for those causes, from when the circumstance took place (RD 1619/2012, art. 15.3). Without this date the four years count from the original's operation date (its `operation_date`, or its `issue_date` when it has none), the stricter of the two. Past the deadline the request fails with `422 CORRECTIVE_OUT_OF_TIME`. Only for `R1`, `R2`, `R3` and `R5`: `R4` covers causes other than article 80, and sending it with `R4` fails with `422 CORRECTIVE_CIRCUMSTANCE_DATE_NOT_APPLICABLE`. It must lie between the original's operation date and today (`422 CORRECTIVE_CIRCUMSTANCE_DATE_OUT_OF_RANGE`). (example: "2026-03-10")
- **recipient_is_business** `boolean`: Declares that the recipient acted as a business or professional in the operation being rectified. Optional, and it only matters for a bad-debt corrective (`R3`) on an operation whose taxable base is 50 € or less: the law allows that reduction only when the recipient acted as a business or professional, and the invoice does not say so (Ley 37/1992, art. 80.Cuatro.A.3.ª). Without it, that `R3` fails with `422 CORRECTIVE_BAD_DEBT_BASE_TOO_LOW`. (example: true)
- **notes** `string`: Additional observations about the rectification (example: "Rectification requested by the customer due to quantity error")
- **series_id** `string` (uuid): Series for the corrective invoice. Optional: if not specified, the company's **default series for corrective invoices** is used — not the original invoice's series, which is an ordinary or simplified one and cannot hold a corrective. If the company has no default corrective series, one is created on first use; a series of the wrong type fails with `422 SERIES_INCOMPATIBLE_DOC_TYPE`. (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **external_ref** `ExternalRef`: Client-supplied identifier from an external system (order, cart, contract…). Stored as-is, echoed back on read, and filterable via GET /v1/invoices?external_ref=. Optional. Enforced UNIQUE per issuer for live standard/simplified invoices: creating a second invoice with the same reference returns 409 (INVOICE_DUPLICATE_EXTERNAL_REFERENCE); deleting the existing one lets you recreate. Corrective invoices are exempt from that uniqueness: a corrective carries the same order reference as the invoice it corrects, so both can coexist. This is a business key, NOT the Idempotency-Key (which guards request retries).
- **metadata** `InvoiceMetadata`: Your own key/value pairs to cross-reference this invoice with records in your system (order ids, tenants, internal codes). Namespace them to avoid clashing with the system keys BeeL adds on payment-generated invoices.
- **recipient**: Only to correct the recipient's data. A corrective invoice carries the recipient of the invoice it corrects, with that invoice's data, except when the invoice recorded that same recipient with a wrong name, tax ID or address: then send the corrected recipient here, with `rectification_type` `PARTIAL`, `rectification_code` `R4` and no `lines`. That corrective leaves the amounts unchanged and the original `RECTIFIED`. - When the original went to a registered customer, send that same `customer_id`, with its data already fixed; another customer fails with `422 CORRECTIVE_RECIPIENT_IS_ANOTHER_PERSON` — an invoice issued to another person is corrected in full (`TOTAL`) and issued again to the right customer. - The same name, tax ID and address as recorded fail with `422 CORRECTIVE_RECIPIENT_UNCHANGED`. - A `recipient` in any other corrective fails with `422 CORRECTIVE_RECIPIENT_NOT_ACCEPTED`, and nothing is created.
- **options** `InvoiceProcessingOptions`: Controls how the invoice is processed after creation. All fields default to `false` if not specified. VeriFactu is **not** an option here: whether an invoice is registered with AEAT is a fact of the tax identity (NIF x environment), resolved at issue time against the company's regime. See `verifactu.enabled` in the invoice response for what was applied. **Common combinations:** - Draft (default): omit `options` or set all to `false` - Issue immediately: `{ issue_directly: true }` - Issue + wait for PDF: `{ issue_directly: true, wait_for_pdf: true }` - Issue + send email: `{ issue_directly: true, send_automatically: true }` - Full automation: `{ issue_directly: true, wait_for_pdf: true, send_automatically: true, email_config: { ... } }`

**Example `corrective_total_r1`** — Total corrective R1 - Error founded in law:

```json
{
  "rectification_type": "TOTAL",
  "rectification_code": "R1",
  "reason": "Spanish VAT was charged on a service not subject to it in Spain (Art. 69 LIVA): the invoice is rectified in full and reissued without VAT.",
  "notes": "The correct invoice is issued separately, without Spanish VAT."
}
```

**Example `corrective_total_cancellation_r1`** — Total corrective R1 - Operation cancelled by agreement:

```json
{
  "rectification_type": "TOTAL",
  "rectification_code": "R1",
  "reason": "Order cancelled by agreement with the customer before delivery: the operation is left without effect (Art. 80 Dos LIVA).",
  "circumstance_date": "2026-03-10",
  "notes": "Cancellation agreed with the customer on 10/03/2026. No amount pending collection."
}
```

**Example `corrective_partial_r2`** — Partial corrective R2 - Customer insolvency:

```json
{
  "rectification_type": "PARTIAL",
  "rectification_code": "R2",
  "reason": "Customer declared insolvent by order of 10/02/2026 (Commercial Court No. 2 Madrid, case 123/2026): the unpaid part of the invoice is reduced under Art. 80 Tres LIVA.",
  "circumstance_date": "2026-02-10",
  "lines": [
    {
      "description": "Unpaid amount at the insolvency declaration",
      "quantity": -16,
      "unit": "hours",
      "unit_price": 37.5,
      "discount_percentage": 0,
      "main_tax": {
        "type": "IVA",
        "percentage": 21,
        "regime_key": "01"
      }
    }
  ],
  "notes": "Credit communicated to the insolvency administrator."
}
```

**Example `corrective_partial_r3`** — Partial corrective R3 - Bad debt:

```json
{
  "rectification_type": "PARTIAL",
  "rectification_code": "R3",
  "reason": "Bad debt under Art. 80 Cuatro LIVA: more than six months since the tax accrued without collection, claimed by notarial demand.",
  "circumstance_date": "2026-05-04",
  "lines": [
    {
      "description": "Bad debt adjustment - unpaid amount",
      "quantity": -40,
      "unit": "hours",
      "unit_price": 37.5,
      "discount_percentage": 0,
      "main_tax": {
        "type": "IVA",
        "percentage": 21,
        "regime_key": "01"
      }
    }
  ],
  "notes": "Notarial demand of 04/05/2026 (Protocol 456/2026). Operation of 15/10/2025."
}
```

**Example `corrective_r1_partial_discount`** — R1 corrective (partial) - post-issuance discount:

```json
{
  "rectification_type": "PARTIAL",
  "rectification_code": "R1",
  "reason": "Descuento comercial post-emisión acordado con el cliente (5 horas no facturables)",
  "lines": [
    {
      "description": "Ajuste por horas no facturables — Sprint mayo",
      "quantity": -5,
      "unit": "hours",
      "unit_price": 75,
      "main_tax": {
        "type": "IVA",
        "percentage": 21,
        "regime_key": "01"
      }
    }
  ],
  "options": {
    "issue_directly": true
  }
}
```

**Example `corrective_recipient_data_r4`** — R4 corrective - recipient's data recorded wrong:

```json
{
  "rectification_type": "PARTIAL",
  "rectification_code": "R4",
  "reason": "The customer's tax ID was mistyped on the invoice",
  "recipient": {
    "customer_id": "8f1e2a3b-4c5d-6e7f-8091-a2b3c4d5e6f7"
  }
}
```

**Example `corrective_r5_partial_simplified_return`** — R5 corrective (partial) - item returned on a simplified invoice:

```json
{
  "rectification_type": "PARTIAL",
  "rectification_code": "R5",
  "reason": "El cliente devolvió uno de los dos artículos del tique",
  "lines": [
    {
      "description": "Devolución - camiseta talla M",
      "quantity": -1,
      "unit_price": 16.53,
      "main_tax": {
        "type": "IVA",
        "percentage": 21,
        "regime_key": "01"
      }
    }
  ]
}
```

### Responses

#### 201: Corrective invoice created successfully

**Headers:**

- `Location` `string`: URI of the created resource — its canonical GET (`/v1/companies/{company_id}/...` or `/v1/accounts/{account_id}/...`).

**Content `application/json`:**

- **success** (required) `boolean`: No description (example: true)
- **data** (required): The payload. An object for a single resource; an object holding the named collection (and its `pagination`) for a listing. Never a bare array at this level in v1.
- **meta** `ResponseMeta`
- **data** `Invoice`: A stored invoice. Being stored is what makes `id`, `created_at` and `updated_at` part of its contract: every one of them always travels.

**Example `corrective_invoice_created_success`** — Corrective invoice created (201):

```json
{
  "success": true,
  "data": {
    "id": "b8a4d0f3-c2e5-49b7-d4f0-c3f2b9e6d1f5",
    "invoice_number": "A/2025/0043-R",
    "series": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "code": "A"
    },
    "number": 43,
    "type": "CORRECTIVE",
    "status": "ISSUED",
    "issue_date": "2025-01-25",
    "rectified_invoice_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "rectification_reason": "Partial correction for bad debt under Art. 80 Cuatro LIVA",
    "rectification_type": "PARTIAL",
    "rectification_code": "R3",
    "issuer": {
      "legal_name": "Tu Empresa SL",
      "nif": "B12345674",
      "address": {
        "street": "Calle Ejemplo",
        "number": "123",
        "postal_code": "28001",
        "city": "Madrid",
        "province": "Madrid",
        "country": "España"
      }
    },
    "recipient": {
      "customer_id": "123e4567-e89b-12d3-a456-426614174000",
      "legal_name": "Cliente Ejemplo SL",
      "nif": "B87654321"
    },
    "lines": [
      {
        "description": "Bad debt adjustment - Full cancellation of outstanding amount",
        "quantity": -40,
        "unit": "hours",
        "unit_price": 37.5,
        "discount_percentage": 0,
        "taxable_base": -1500,
        "main_tax": {
          "type": "IVA",
          "percentage": 21,
          "regime_key": "01"
        },
        "line_total": -1815
      }
    ],
    "totals": {
      "taxable_base": -1500,
      "total_vat": -315,
      "total_irpf": 0,
      "total_equivalence_surcharge": 0,
      "vat_breakdown": [
        {
          "type": 21,
          "base": -1500,
          "amount": -315
        }
      ],
      "invoice_total": -1815
    },
    "verifactu": {
      "enabled": true,
      "invoice_hash": "B8A4D0F3C2E549B7D4F0C3F2B9E6D1F5A8C2E7B0D4F8C3A6B1E9D2F7A5C8E3B0",
      "qr_url": "https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?nif=B12345674&numserie=A%2F2025%2F0043-R&fecha=25-01-2025&importe=-1815.00",
      "registered_at": "2025-01-25T11:00:00Z",
      "submission_status": "ACCEPTED"
    },
    "pdf_download_url": "/v1/companies/7c9e6679-7425-40de-944b-e07fc1f90ae7/invoices/b8a4d0f3-c2e5-49b7-d4f0-c3f2b9e6d1f5/pdf",
    "created_at": "2025-01-25T11:00:00Z",
    "updated_at": "2025-01-25T11:00:00Z"
  },
  "meta": {
    "timestamp": "2025-01-25T11:00:00Z",
    "request_id": "a5b6c7d8-e9f0-4a1b-2c3d-4e5f6a7b8c9d"
  }
}
```

#### 400: `INVALID_JSON_FORMAT` — the body is not valid JSON, or a property has the wrong type or format
(a string where a number is expected, a date that does not parse, a malformed UUID, a boolean
that is not `true`/`false`). The `details` object follows `FieldDeserializationError`:
`field`, `invalid_value` and, where there is one, `expected_format` (or `allowed_values`, for a
boolean). A property the operation does not declare is not a format error: it is ignored.

A value outside an **enum**'s vocabulary is not answered here. The property is a well-formed
string that names nothing the operation knows, so it is judged as content: `422`
(`VALIDATION_ERROR`), with the same `FieldDeserializationError` shape in `details`
(`field`, `invalid_value`, `allowed_values`).


**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")
- **error**: No description

**Example:**

```json
{
  "success": false,
  "error": {
    "code": "INVALID_JSON_FORMAT",
    "message": "The field 'due_date' has an invalid date format: '2026-03-04fds'. Expected format: YYYY-MM-DD.",
    "details": {
      "field": "due_date",
      "invalid_value": "2026-03-04fds",
      "expected_format": "YYYY-MM-DD"
    }
  },
  "meta": {
    "timestamp": "2026-03-05T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
```

#### 401: Missing or invalid authentication. Like every other error, `message`/`detail` is
localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English when the
header is missing or asks for none of those.


**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

**Example:**

```json
{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Authentication is required to access this resource"
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
```

#### 403: Your account does not own or manage this company, or does not hold the required
access over it. A NIF that does not exist answers the same way.


**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

#### 404: The resource addressed by the path does not exist, or is not one this credential can see —
the two are answered identically, so existence is never disclosed. `error.code` names the
kind of resource that was missing, so a client can tell which of several ids in a path
failed to resolve:

- `INVOICE_NOT_FOUND` — the `{invoice_id}` (invoices, proformas and their sub-resources).
- `RECURRING_NOT_FOUND` — the `{recurring_invoice_id}`.
- `CLIENT_NOT_FOUND` — the `{customer_id}`.
- `INVOICE_CLIENT_NOT_FOUND` — the `customer_id` referenced by an invoice body does not
  resolve to a customer of the issuing company.
- `PRODUCT_NOT_FOUND` — the `{product_id}`.
- `SERIES_NOT_FOUND` — the `{series_id}`.
- `WEBHOOK_SUBSCRIPTION_NOT_FOUND`, `DELIVERY_LOG_NOT_FOUND` — the `{webhook_id}` and the
  `{delivery_id}`.
- `NOT_FOUND` — the generic fallback, for the few resources that carry no code of their own.

Some resources declare a more specific `404` response of their own (`CONNECTION_NOT_FOUND`,
`MEMBER_NOT_FOUND`, `GRANT_NOT_FOUND`, `INVITATION_NOT_FOUND`, `REQUEST_LOG_NOT_FOUND`); it
is documented on the operation.

A `404` with `ENDPOINT_NOT_FOUND` is a different answer: the **path itself** does not exist
in this API (a typo in the route, or a resource that was never here). It says nothing about
any resource. When the path exists but not with that method, the answer is `405`, not `404`.


**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

**Example:**

```json
{
  "success": false,
  "error": {
    "code": "INVOICE_NOT_FOUND",
    "message": "Invoice not found"
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
```

#### 409: The request is well formed but collides with the state that is already there. Three
families, told apart by `error.code`:

- **Uniqueness** — something with that identity already exists (`CLIENT_DUPLICATE`,
  `PRODUCT_DUPLICATE`, `SERIES_CODE_DUPLICATED`, `NIF_ALREADY_REGISTERED`,
  `MEMBER_ALREADY_IN_ACCOUNT`, `INVOICE_DUPLICATE_EXTERNAL_REFERENCE`).
- **Lifecycle** — the transition does not apply from where the resource is
  (`INVOICE_ALREADY_VOIDED`, `PROFORMA_ALREADY_CONVERTED`, `CLIENT_HAS_INVOICES`,
  `RECURRING_ALREADY_ENDED`, `RECURRING_OCCURRENCE_ALREADY_CONSUMED` — the occurrence the
  recurring template points at has already been billed; read its history instead of
  retrying).
  Read the resource before retrying: the state you assumed is not its state.
- **Concurrency and idempotency** — another write got there first
  (`CONCURRENT_MODIFICATION`), or the `Idempotency-Key` you sent is still in flight
  (`IDEMPOTENCY_KEY_PROCESSING`, retry after a moment) or was already used for a
  different body (`IDEMPOTENCY_KEY_MISMATCH`, use a new key).


**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

**Example:**

```json
{
  "success": false,
  "error": {
    "code": "CONCURRENT_MODIFICATION",
    "message": "The resource was modified by another request; read it again and retry"
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
```

#### 422: Validation error, or the company/NIF is not ready to issue in this environment (`error.code` `EMISSION_NOT_READY`). A `PARTIAL` corrective whose lines leave a fiscal figure undeclared also lands here when the original invoice is ambiguous: `CORRECTIVE_ORIGINAL_MIXED_IRPF` (different IRPF rates per line) and `CORRECTIVE_ORIGINAL_MIXED_SURCHARGE` (equivalence surcharge on some lines only). Separately: on a line priced by declared total (`total_excluding_tax` or `total_including_tax`) the unit price is not sent — it is derived as total ÷ quantity — so a quotient that does not fit the field storing it is rejected with `error.code` `LINE_UNIT_PRICE_OUT_OF_RANGE` and an `error.details` that follows `LineUnitPriceOutOfRangeDetails`: `field` names the offending line (`lines[0]`), not a `unit_price` you never sent, while `max` and `derived_unit_price` carry the limit and the quotient as JSON numbers, so they can be compared without parsing `error.message`.

**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

**Example `incompatible_series`** — Explicit series of the wrong type (422):

```json
{
  "success": false,
  "error": {
    "code": "SERIES_INCOMPATIBLE_DOC_TYPE",
    "message": "The selected series is not compatible with this document type. Please select a series of the correct type.",
    "details": {
      "expected_document_type": "CORRECTIVE",
      "defaults_status_endpoint": "GET /v1/companies/{company_id}/series/defaults"
    }
  },
  "meta": {
    "timestamp": "2025-02-01T10:20:00Z",
    "request_id": "b2b2b2b2-0810-4000-a000-000000000422"
  }
}
```

**Example `original_mixed_irpf`** — Original invoice with mixed IRPF rates (422):

```json
{
  "success": false,
  "error": {
    "code": "CORRECTIVE_ORIGINAL_MIXED_IRPF",
    "message": "The original invoice applies different IRPF withholding rates per line, so there is none to inherit. Set irpf_rate on every line of the corrective invoice."
  },
  "meta": {
    "timestamp": "2025-02-01T10:25:00Z",
    "request_id": "b2b2b2b2-1435-4000-a000-000000001435"
  }
}
```

**Example `original_mixed_surcharge`** — Original invoice with a mixed equivalence surcharge regime (422):

```json
{
  "success": false,
  "error": {
    "code": "CORRECTIVE_ORIGINAL_MIXED_SURCHARGE",
    "message": "The original invoice applies the equivalence surcharge on some lines but not others, so there is no regime to inherit. Set equivalence_surcharge_rate on every line of the corrective invoice."
  },
  "meta": {
    "timestamp": "2025-02-01T10:30:00Z",
    "request_id": "b2b2b2b2-1435-4000-a000-000000001436"
  }
}
```

#### 429: Rate limit exceeded

**Headers:**

- `Retry-After` `integer`: Seconds until the rate limit resets
- `RateLimit-Limit` `integer`: Maximum requests allowed in the window
- `RateLimit-Remaining` `integer`: Remaining requests in the current window
- `RateLimit-Reset` `integer`: Seconds until the current window resets

**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

**Example:**

```json
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please try again in 60 seconds."
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
```

#### 500: Internal server error

**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

**Example:**

```json
{
  "success": false,
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Internal server error"
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
```

#### default: Any status code the operation does not list above. Every operation declares it, so a
generated client always has a branch to fall into and never loses the cause of a failure
it did not anticipate.

This is where the transport-level answers land — `405`, `406`, `415` and `429` — together
with any status a future version of the API starts returning. All of them carry the same
error envelope as the codes listed explicitly, so `error.code` is what tells them apart:
switching on the status code alone is not enough. See «Transport-level errors» in the
API description for when each one is produced.

A `502` carrying `EXTERNAL_SERVICE_ERROR` also lands here: an outbound integration the
operation depends on failed or did not answer in time. It is a transient condition — retry
with the same `Idempotency-Key` where the operation accepts one.

One exception to the envelope: a failure of the network edge that never reaches the
application (`502`, `503`, `504`, `524`) is generated by Cloudflare and its body is not
BeeL's — it may not even be JSON. Treat those as "no answer", and retry.


**Content `application/json`:**

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

**Example:**

```json
{
  "success": false,
  "error": {
    "code": "UNSUPPORTED_MEDIA_TYPE",
    "message": "Unsupported media type: text/plain. Supported: application/json"
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
```

---

# Related Schema Definitions

## CreateCorrectiveInvoiceRequest

- **rectification_type** (required) `RectificationType`: Type of rectification applied to a corrective invoice: - TOTAL: Rectifies everything still invoiced on the original, its live correctives included (status → VOIDED) - PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** (required) `VeriFactuRectificationCode`: Rectification codes according to VeriFactu regulations (AEAT): - R1: Error founded in law and Art. 80 One, Two and Six LIVA - R2: Article 80 Three LIVA (Bankruptcy proceedings) - R3: Article 80 Four LIVA (Uncollectable debts) - R4: Other causes - R5: Corrective of a simplified invoice - ONLY for simplified invoices
- **reason** (required) `string`: Detailed reason for rectification (minimum 10 characters) (example: "Amount correction due to calculation error in hours worked during the project")
- **lines** `array[object]`: **TOTAL**: not accepted. A `TOTAL` corrective rectifies what is still invoiced on the original —its lines and those of its live correctives, negated— and a request with `lines` fails with `422 RECTIFICATIVA_TOTAL_CON_LINEAS`. **PARTIAL**: required. The adjustment lines, with positive or negative amounts; they may not take the base of any rate below zero (`422 CORRECTIVE_EXCEEDS_INVOICED_AMOUNT`).
  - **description** `string`: Concept description. Required for NORMAL lines; optional for SUPLIDO lines. (example: "Adjustment for incorrectly invoiced hours")
  - **quantity** (required) `number`: Quantity (can be negative for corrective invoices) (example: -10)
  - **unit** `string`: No description (example: "hours")
  - **unit_price** `number`: Unit price before taxes (can be negative in corrective invoices). Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging). Final amounts are always rounded to 2 decimals. (example: 50)
  - **total_excluding_tax** `number`: Declared line total excluding taxes (total-declared mode, e.g. 300 units invoiced for exactly 1.00). The taxable base of the line is EXACTLY this amount — it is never recalculated from the unit price. The unit price becomes derived and informational (`total / quantity`, 4 decimals). Each line must carry exactly one of `unit_price`, `total_excluding_tax` or `total_including_tax` (anything else is rejected with `LINE_UNIT_PRICE_XOR_DECLARED_TOTAL`). Incompatible with `discount_percentage` (`LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT`): any discount is already included in the declared total. Can be negative in corrective invoices. (example: 1)
  - **total_including_tax** `number`: Declared line total including taxes (tax-inclusive total-declared mode): what the customer paid for this line — taxable base + VAT + equivalence surcharge. IRPF withholding is NOT part of it (it is a retention, not price; it is computed on the derived base as usual). The engine works the breakdown backwards from the unrounded base (`base_raw = total / (1 + vat + surcharge)`, DGT V1919-18) so the rounded amounts add up to the declared total exactly (e.g. 100.00 at 21% → 82.64 + 17.36 = 100.00). On exempt or 0% lines it is equivalent to `total_excluding_tax` (base = total, quota 0). Each line must carry exactly one of `unit_price`, `total_excluding_tax` or `total_including_tax` (anything else is rejected with `LINE_UNIT_PRICE_XOR_DECLARED_TOTAL`). Incompatible with `discount_percentage` (`LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT`). Can be negative in corrective invoices. (example: 100)
  - **discount_percentage** `number`: No description
  - **main_tax** `TaxInfo`: Complete tax information with cross-validations: - IVA: real rates 4, 10, 21, and the temporary 2, 5 and 7.5 (see below for 0) - IGIC: 0, 3, 5, 7, 9.5, 15, 20 — here 0 is the real "Tipo Cero" - IPSI: real rates 0.5, 1, 2, 4, 8, 10 (see below for 0) - OTHER: any percentage between 0 and 100 **0 % under IVA and IPSI is not a rate, it is the exemption sentinel.** It is accepted on a line, but only together with an `exemption_reason` (exempt or non-subject operation); on its own it says nothing and the line is rejected. That is why `GET /v1/tax-types` publishes the IVA rates without 0: the legitimate way to a 0 % IVA line is through an exemption reason, which the same response also publishes. IGIC is different — its 0 % is a real legal rate (basic necessities) and needs no reason. **IVA 5 %** (the temporary rate applied from 2022 to electricity, gas and certain foodstuffs) is no longer in force for new operations. AEAT only accepts it on operations dated from 2022-07-01 to 2024-09-30: send the `operation_date` of that period, because without one the issue date decides and a line at 5 % is rejected with `422 VAT_RATE_NOT_ACCEPTED_ON_DATE`. Its equivalence surcharge pair is 0.5 up to 2022-12-31 and 0.62 from 2023-01-01. **IVA 2 % and 7.5 %** (temporary rates of the last quarter of 2024) are accepted only on operations dated from 2024-10-01 to 2024-12-31, with surcharges 0.26 and 1. Exception: when regime_key = "17" (OSS/IOSS) the invoice applies the destination country VAT instead of the Spanish one, so any percentage in the EU range [0, 27] is accepted regardless of the tax type set — including 0 without an exemption reason.
  - **equivalence_surcharge_rate**: Equivalence surcharge rate for this line of the corrective invoice. **Default behaviour:** if omitted, the line inherits the surcharge **regime** of the invoice being amended — not the company's current tax profile, whose default does not apply to corrective invoices. What travels from the original is the on/off signal, not the rate: the rate is re-derived from this line's own VAT (21→5.2, 10→1.4, 5→0.62, 4→0.5), so a corrective line at 10% gets 1.4 even when the original line it amends was at 21%. If the original was outside the regime the line is pinned to `0`, so today's profile never adds a surcharge to the credit note of an invoice that carried none. An explicit value is always respected. If the original applies the surcharge on some lines but not others there is no regime to inherit and the request fails with `422 CORRECTIVE_ORIGINAL_MIXED_SURCHARGE`: send `equivalence_surcharge_rate` on every line. `SUPLIDO` lines never carry a surcharge and are ignored on both sides.
  - **irpf_rate**: IRPF withholding rate for this line of the corrective invoice. **Default behaviour:** if omitted, the line inherits the rate of the invoice being amended — **not** the account's default IRPF rate from the tax profile, whose default does not apply to corrective invoices: a profile that changed after the original was issued must not alter what the credit note withholds. An explicit value is always respected, `0` included, which is how you issue a line **without** withholding. If the original withholds different rates on different lines there is nothing unambiguous to inherit and the request fails with `422 CORRECTIVE_ORIGINAL_MIXED_IRPF`: send `irpf_rate` on every line. `SUPLIDO` lines never carry IRPF and are ignored on both sides. On SIMPLIFIED invoices (F2) IRPF withholding is **not allowed** (AEAT forbids it on F2): sending an `irpf_rate` other than 0 is **rejected** with `SIMPLIFICADA_FORBIDS_IRPF` — it is not coerced to 0. Omit the field or send `irpf_rate: 0` on F2 lines.
  - **exemption_reason** `ExemptionReason`: Tax exemption reason code per the Spanish VAT Law (Ley 37/1992, LIVA), with the VeriFactu code each one is reported as. - `EXENTA_ART_20`: exempt, art. 20 (domestic operations such as medical, educational, cultural and financial services, or housing rentals). E1. - `EXENTA_ART_21`: exempt, art. 21 (exports of goods). E2. - `EXENTA_ART_22`: exempt, art. 22 (operations treated as exports). E3. - `EXENTA_ART_24`: exempt, art. 24 (free zones, warehouses and customs regimes). E4. - `EXENTA_ART_25`: exempt, art. 25 (intra-community supplies of goods). E5. - `EXENTA_ART_26`: exempt, art. 26 (intra-community acquisitions of goods). It exempts the buyer's acquisition, not a supply the seller invoices, so an invoice line that carries it is rejected with `EXEMPTION_NOT_FOR_ISSUED_INVOICE`; a supply to another Member State is `EXENTA_ART_25`. - `NO_SUJETA_ART_7_9`: not subject under art. 7 (such as the transfer of a business as a going concern, art. 7.1º). N1. - `NO_SUJETA_LOCALIZACION`: not subject by the place-of-supply rules (intra-community or non-EU services, arts. 69 and 70). N2. - `ISP_ART_84_2_A` … `ISP_ART_84_2_F`: reverse charge (the invoice states «inversión del sujeto pasivo»), art. 84.Uno.2.º letters a) (supplier not established in Spain), b) (unwrought or semi-finished gold), c) (scrap, waste and recovery materials, plastic, paper, cardboard, glass and textile waste, and semi-finished non-ferrous metal products), d) (greenhouse gas emission allowances), e) (certain real estate supplies: in insolvency proceedings, with the exemption waived, or enforcing a security) and f) (construction or renovation works). S2. - `ISP_ART_84_2_G`: reverse charge of letter g) (silver, platinum, palladium, mobile phones, consoles, laptops and tablets). The law requires these supplies to be invoiced in a special series, so an invoice line that carries it is rejected with `REVERSE_CHARGE_CASE_NOT_SUPPORTED`. - `EXENTA_ART_140`: investment gold exemption, art. 140 bis (usually with `regime_key` `04`). E6. - `REGIMEN_ART_129` (agriculture, livestock and fishing, arts. 124 to 134 bis), `REGIMEN_ART_135` (second-hand goods, art and antiques), `REGIMEN_ART_141` (travel agencies), `REGIMEN_ART_154` (equivalence surcharge) and `REGIMEN_ART_163_DECIES` (cash basis, arts. 163 decies to 163 sexiesdecies): operations of special regimes, which VeriFactu identifies by the regime key rather than by an exemption code. An invoice line that carries one is rejected with `EXEMPTION_REGIME_NOT_SUPPORTED_IN_VERIFACTU`; declare the regime with `regime_key` instead. - `OTRO`: any other provision. Requires the text in `exemption_reason_text`. E6.
  - **exemption_reason_text** `string`: No description
- **circumstance_date** `string` (date): When the circumstance that causes the rectification took place, if it is one of article 80 of the VAT Act (Ley 37/1992): a discount granted after the sale, an operation cancelled or a price changed after it took place, the customer's insolvency, a bad debt. Optional. A corrective must be issued within four years from when the tax accrued or, for those causes, from when the circumstance took place (RD 1619/2012, art. 15.3). Without this date the four years count from the original's operation date (its `operation_date`, or its `issue_date` when it has none), the stricter of the two. Past the deadline the request fails with `422 CORRECTIVE_OUT_OF_TIME`. Only for `R1`, `R2`, `R3` and `R5`: `R4` covers causes other than article 80, and sending it with `R4` fails with `422 CORRECTIVE_CIRCUMSTANCE_DATE_NOT_APPLICABLE`. It must lie between the original's operation date and today (`422 CORRECTIVE_CIRCUMSTANCE_DATE_OUT_OF_RANGE`). (example: "2026-03-10")
- **recipient_is_business** `boolean`: Declares that the recipient acted as a business or professional in the operation being rectified. Optional, and it only matters for a bad-debt corrective (`R3`) on an operation whose taxable base is 50 € or less: the law allows that reduction only when the recipient acted as a business or professional, and the invoice does not say so (Ley 37/1992, art. 80.Cuatro.A.3.ª). Without it, that `R3` fails with `422 CORRECTIVE_BAD_DEBT_BASE_TOO_LOW`. (example: true)
- **notes** `string`: Additional observations about the rectification (example: "Rectification requested by the customer due to quantity error")
- **series_id** `string` (uuid): Series for the corrective invoice. Optional: if not specified, the company's **default series for corrective invoices** is used — not the original invoice's series, which is an ordinary or simplified one and cannot hold a corrective. If the company has no default corrective series, one is created on first use; a series of the wrong type fails with `422 SERIES_INCOMPATIBLE_DOC_TYPE`. (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **external_ref** `ExternalRef`: Client-supplied identifier from an external system (order, cart, contract…). Stored as-is, echoed back on read, and filterable via GET /v1/invoices?external_ref=. Optional. Enforced UNIQUE per issuer for live standard/simplified invoices: creating a second invoice with the same reference returns 409 (INVOICE_DUPLICATE_EXTERNAL_REFERENCE); deleting the existing one lets you recreate. Corrective invoices are exempt from that uniqueness: a corrective carries the same order reference as the invoice it corrects, so both can coexist. This is a business key, NOT the Idempotency-Key (which guards request retries).
- **metadata** `InvoiceMetadata`: Your own key/value pairs to cross-reference this invoice with records in your system (order ids, tenants, internal codes). Namespace them to avoid clashing with the system keys BeeL adds on payment-generated invoices.
- **recipient**: Only to correct the recipient's data. A corrective invoice carries the recipient of the invoice it corrects, with that invoice's data, except when the invoice recorded that same recipient with a wrong name, tax ID or address: then send the corrected recipient here, with `rectification_type` `PARTIAL`, `rectification_code` `R4` and no `lines`. That corrective leaves the amounts unchanged and the original `RECTIFIED`. - When the original went to a registered customer, send that same `customer_id`, with its data already fixed; another customer fails with `422 CORRECTIVE_RECIPIENT_IS_ANOTHER_PERSON` — an invoice issued to another person is corrected in full (`TOTAL`) and issued again to the right customer. - The same name, tax ID and address as recorded fail with `422 CORRECTIVE_RECIPIENT_UNCHANGED`. - A `recipient` in any other corrective fails with `422 CORRECTIVE_RECIPIENT_NOT_ACCEPTED`, and nothing is created.
- **options** `InvoiceProcessingOptions`: Controls how the invoice is processed after creation. All fields default to `false` if not specified. VeriFactu is **not** an option here: whether an invoice is registered with AEAT is a fact of the tax identity (NIF x environment), resolved at issue time against the company's regime. See `verifactu.enabled` in the invoice response for what was applied. **Common combinations:** - Draft (default): omit `options` or set all to `false` - Issue immediately: `{ issue_directly: true }` - Issue + wait for PDF: `{ issue_directly: true, wait_for_pdf: true }` - Issue + send email: `{ issue_directly: true, send_automatically: true }` - Full automation: `{ issue_directly: true, wait_for_pdf: true, send_automatically: true, email_config: { ... } }`

## RectificationType

Type of rectification applied to a corrective invoice:
- TOTAL: Rectifies everything still invoiced on the original, its live correctives included (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)

Type: `string` — one of: TOTAL, PARTIAL

## VeriFactuRectificationCode

Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Corrective of a simplified invoice - ONLY for simplified invoices

Type: `string` — one of: R1, R2, R3, R4, R5

## TaxInfo

Complete tax information with cross-validations:
- IVA: real rates 4, 10, 21, and the temporary 2, 5 and 7.5 (see below for 0)
- IGIC: 0, 3, 5, 7, 9.5, 15, 20 — here 0 is the real "Tipo Cero"
- IPSI: real rates 0.5, 1, 2, 4, 8, 10 (see below for 0)
- OTHER: any percentage between 0 and 100

**0 % under IVA and IPSI is not a rate, it is the exemption sentinel.** It is accepted
on a line, but only together with an `exemption_reason` (exempt or non-subject
operation); on its own it says nothing and the line is rejected. That is why
`GET /v1/tax-types` publishes the IVA rates without 0: the legitimate way
to a 0 % IVA line is through an exemption reason, which the same response also
publishes. IGIC is different — its 0 % is a real legal rate (basic necessities) and
needs no reason.

**IVA 5 %** (the temporary rate applied from 2022 to electricity, gas and certain
foodstuffs) is no longer in force for new operations. AEAT only accepts it on operations
dated from 2022-07-01 to 2024-09-30: send the `operation_date` of that period, because
without one the issue date decides and a line at 5 % is rejected with
`422 VAT_RATE_NOT_ACCEPTED_ON_DATE`. Its equivalence surcharge pair is 0.5 up to 2022-12-31
and 0.62 from 2023-01-01. **IVA 2 % and 7.5 %** (temporary rates of the last quarter of 2024)
are accepted only on operations dated from 2024-10-01 to 2024-12-31, with surcharges 0.26
and 1.

Exception: when regime_key = "17" (OSS/IOSS) the invoice applies the destination
country VAT instead of the Spanish one, so any percentage in the EU range [0, 27]
is accepted regardless of the tax type set — including 0 without an exemption reason.

- **type** (required) `TaxType`: Tax type by territory: - IVA: Iberian Peninsula and Balearic Islands (4%, 10%, 21%; 2%, 5% and 7.5% only on operations of their period) - IGIC: Canary Islands (0%, 3%, 5%, 7%, 9.5%, 15%, 20%) - IPSI: Ceuta and Melilla (0.5%, 1%, 2%, 4%, 8%, 10%) - OTHER: Configurable 0%-100% Under IVA and IPSI, 0% is not one of these rates: it is the exemption/non-subject sentinel and always travels with an `exemption_reason`. IGIC's 0% is a real rate. See `TaxInfo` for the full rules.
- **percentage** (required) `number`: Tax percentage (example: 21)
- **regime_key** `RegimeKey`: Regime key according to VeriFactu regulations. Omitted, `01` (general regime) applies: - 01: General regime operation - 02: Export (IVA and IGIC; not IPSI, whose AEAT list is `01, 08, 11, 18, 19, 20`) - 03: Used goods, art, antiques (not accepted, see below) - 04: Investment gold - 05: Travel agencies - 06: Group of entities (not accepted, see below) - 07: Cash basis - 08: Operation subject to another indirect tax — IPSI or IGIC on an IVA line, IPSI or IVA on an IGIC line. It is **not** the general regime of IGIC, which is `01`. - 09: Mediating agencies - 10: Third-party collections - 11: Local rental - 14: VAT pending in certifications (not accepted, see below) - 15: VAT pending successive tract - 17: OSS and IOSS - 18: Equivalence surcharge - 19: REAGYP - 20: Simplified regime **What AEAT requires with each key** (Validaciones VERI*FACTU 3.1.3.15.6), checked on IVA and IGIC lines before the invoice is numbered. Otherwise the request is rejected with `422` and the code in brackets: - `04`: only reverse charge (an `ISP_ART_84_2_*` reason) or an exemption (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). - `08`: only `exemption_reason: NO_SUJETA_LOCALIZACION`, at 0 % (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). - `10`: only `exemption_reason: NO_SUJETA_ART_7_9`, on a `STANDARD` invoice whose recipient has a `nif` (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`, `REGIME_KEY_REQUIRES_STANDARD_INVOICE`, `REGIME_KEY_REQUIRES_RECIPIENT_NIF`). - `11` (IVA): a subject line only at 21 %, and no reverse charge (`REGIME_KEY_REQUIRES_VAT_RATE`, `REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). - `06` and `14` are not accepted (`REGIME_KEY_NOT_SUPPORTED`): AEAT requires with them data the invoice does not carry (a cost-based taxable base; an operation date after the issue date and a public-administration recipient). - `03` (used goods) is not accepted (`REGIME_KEY_NOT_SUPPORTED`): under it the invoice must not show the tax separately (RD 1619/2012, art. 16.2.c), and it always does. The corrective of an invoice that already carried `03` keeps it. - `05` (travel agencies) and `07` (cash basis) are accepted, and the invoice PDF carries the mention of their regime (RD 1619/2012, art. 6.1 n and p). `07`: no reverse charge, no non-subject reason and, of the exemptions, only art. 20 or `OTRO` (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`). `GET /v1/tax-types` only offers the keys that are accepted. **One exception to "a key you send is the key you get":** when the line ends up carrying an equivalence surcharge — whether you sent `equivalence_surcharge_rate` or it was inherited from the company's tax configuration — a `01` is rewritten to `18`, because a surcharge under the general regime is fiscally incoherent. Send `equivalence_surcharge_rate: 0` explicitly to keep `01`. See `equivalence_surcharge_rate` in the invoice line for the full rules.

## ExemptionReason

Tax exemption reason code per the Spanish VAT Law (Ley 37/1992, LIVA), with the
VeriFactu code each one is reported as.

- `EXENTA_ART_20`: exempt, art. 20 (domestic operations such as medical, educational,
  cultural and financial services, or housing rentals). E1.
- `EXENTA_ART_21`: exempt, art. 21 (exports of goods). E2.
- `EXENTA_ART_22`: exempt, art. 22 (operations treated as exports). E3.
- `EXENTA_ART_24`: exempt, art. 24 (free zones, warehouses and customs regimes). E4.
- `EXENTA_ART_25`: exempt, art. 25 (intra-community supplies of goods). E5.
- `EXENTA_ART_26`: exempt, art. 26 (intra-community acquisitions of goods). It exempts the
  buyer's acquisition, not a supply the seller invoices, so an invoice line that carries it
  is rejected with `EXEMPTION_NOT_FOR_ISSUED_INVOICE`; a supply to another Member State is
  `EXENTA_ART_25`.
- `NO_SUJETA_ART_7_9`: not subject under art. 7 (such as the transfer of a business as
  a going concern, art. 7.1º). N1.
- `NO_SUJETA_LOCALIZACION`: not subject by the place-of-supply rules (intra-community
  or non-EU services, arts. 69 and 70). N2.
- `ISP_ART_84_2_A` … `ISP_ART_84_2_F`: reverse charge (the invoice states «inversión del
  sujeto pasivo»), art. 84.Uno.2.º letters a) (supplier not established in Spain), b) (unwrought
  or semi-finished gold), c) (scrap, waste and recovery materials, plastic, paper, cardboard, glass and textile waste, and semi-finished non-ferrous metal products), d) (greenhouse gas emission
  allowances), e) (certain real estate supplies: in insolvency proceedings, with the exemption
  waived, or enforcing a security) and f) (construction or renovation works). S2.
- `ISP_ART_84_2_G`: reverse charge of letter g) (silver, platinum, palladium, mobile phones,
  consoles, laptops and tablets). The law requires these supplies to be invoiced in a special
  series, so an invoice line that carries it is rejected with
  `REVERSE_CHARGE_CASE_NOT_SUPPORTED`.
- `EXENTA_ART_140`: investment gold exemption, art. 140 bis (usually with `regime_key`
  `04`). E6.
- `REGIMEN_ART_129` (agriculture,
  livestock and fishing, arts. 124 to 134 bis), `REGIMEN_ART_135` (second-hand goods,
  art and antiques), `REGIMEN_ART_141` (travel agencies), `REGIMEN_ART_154` (equivalence
  surcharge) and `REGIMEN_ART_163_DECIES` (cash basis, arts. 163 decies to 163
  sexiesdecies): operations of special regimes, which VeriFactu identifies by the regime
  key rather than by an exemption code. An
  invoice line that carries one is rejected with `EXEMPTION_REGIME_NOT_SUPPORTED_IN_VERIFACTU`;
  declare the regime with `regime_key` instead.
- `OTRO`: any other provision. Requires the text in `exemption_reason_text`. E6.

Type: `string` — one of: EXENTA_ART_20, EXENTA_ART_21, EXENTA_ART_22, EXENTA_ART_24, EXENTA_ART_25, EXENTA_ART_26, EXENTA_ART_140, NO_SUJETA_ART_7_9, NO_SUJETA_LOCALIZACION, ISP_ART_84_2_A, ISP_ART_84_2_B, ISP_ART_84_2_C, ISP_ART_84_2_D, ISP_ART_84_2_E, ISP_ART_84_2_F, ISP_ART_84_2_G, REGIMEN_ART_129, REGIMEN_ART_135, REGIMEN_ART_141, REGIMEN_ART_154, REGIMEN_ART_163_DECIES, OTRO

## ExternalRef

Client-supplied identifier from an external system (order, cart, contract…).
Stored as-is, echoed back on read, and filterable via GET /v1/invoices?external_ref=.
Optional. Enforced UNIQUE per issuer for live standard/simplified invoices:
creating a second invoice with the same reference returns 409
(INVOICE_DUPLICATE_EXTERNAL_REFERENCE); deleting the existing one lets you recreate.
Corrective invoices are exempt from that uniqueness: a corrective carries the same
order reference as the invoice it corrects, so both can coexist.
This is a business key, NOT the Idempotency-Key (which guards request retries).

Type: `string`

## InvoiceMetadata

Your own key/value pairs to cross-reference this invoice with records in
your system (order ids, tenants, internal codes). Namespace them to avoid
clashing with the system keys BeeL adds on payment-generated invoices.

Type: `object`

## InvoiceProcessingOptions

Controls how the invoice is processed after creation.
All fields default to `false` if not specified.

VeriFactu is **not** an option here: whether an invoice is registered with AEAT is a
fact of the tax identity (NIF x environment), resolved at issue time against the
company's regime. See `verifactu.enabled` in the invoice response for what was applied.

**Common combinations:**
- Draft (default): omit `options` or set all to `false`
- Issue immediately: `{ issue_directly: true }`
- Issue + wait for PDF: `{ issue_directly: true, wait_for_pdf: true }`
- Issue + send email: `{ issue_directly: true, send_automatically: true }`
- Full automation: `{ issue_directly: true, wait_for_pdf: true, send_automatically: true, email_config: { ... } }`

- **issue_directly** `boolean`: If `true`, creates the invoice directly as **ISSUED** with a definitive number and PDF. If `false` (default), creates as **DRAFT** without number (editable, no PDF).
- **wait_for_pdf** `boolean`: Only applies when `issue_directly` is `true`. If `true`, waits for PDF generation before returning the response (~1-3s). If `false` (default), PDF is generated asynchronously in the background.
- **send_automatically** `boolean`: Only applies when `issue_directly` is `true`. If `true`, sends the invoice by email with PDF attachment after issuing. The email is sent asynchronously after the invoice is issued.
- **attach_source_invoices** `boolean`: Only applies when `send_automatically` is `true`. If `true`, the email sent after issuing also attaches a ZIP (`suplidos_<invoice-number>.zip`) with the PDFs of the source invoices referenced by the invoice's SUPLIDO consolidation lines (`source_invoice_ids`). Each PDF inside the ZIP is named `<invoice-number>_<issuer-tax-id>.pdf`. Access to sources owned by managed accounts is re-checked with the same rules as issuing, and the request fails synchronously with an actionable error — never a partial ZIP — if the invoice has no consolidation sources (`ATTACH_SOURCE_INVOICES_NO_SOURCES`), a source is not reachable (`ATTACH_SOURCE_INVOICE_UNAVAILABLE`) or a source has no generated PDF (`ATTACH_SOURCE_PDF_MISSING`). The flag belongs to this issuing act only: it is never stored on the invoice.
- **email_config**: Only applies when `send_automatically` is `true`. Overrides default email settings. If it names no recipients, the email goes to the customer's `billing_emails`, or to the customer's `email` when there are none.

## SuccessResponse

The envelope every successful JSON response of the BeeL. API is wrapped in. There are no
bare resources in v1 and none are planned: the payload always hangs off `data`.

- A **single resource** is an object in `data`.
- A **collection** hangs off a named key inside `data`, together with its `pagination`,
  also inside `data` — `data: {invoices: [...], pagination: {...}}`.
- A collection carries `pagination` unless its operation declares itself a **closed
  catalogue**: a fixed, bounded list with nothing to page through. The declaration is
  explicit in the operation; a missing `pagination` is never something to infer.
- `GET /v1/accounts` pages by cursor (`data: {accounts: [...], next_cursor}`). It is a
  documented variant of pagination, not another envelope.

Putting the array straight into `data` with `pagination` as its sibling is the shape a v2
would adopt; v1 is not being flipped to it.

- **success** (required) `boolean`: No description (example: true)
- **data** (required): The payload. An object for a single resource; an object holding the named collection (and its `pagination`) for a listing. Never a bare array at this level in v1.
- **meta** `ResponseMeta`

## ResponseMeta

- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")

## Invoice

A stored invoice. Being stored is what makes `id`, `created_at` and `updated_at`
part of its contract: every one of them always travels.

- **invoice_number** `string`: Complete invoice number (series + sequential). **Null for draft invoices** — assigned automatically when issued. (example: "2025/0001")
- **series** (required) `SeriesInfo`
- **number** `integer`: Sequential number within the series. **Null for draft invoices** — assigned automatically when issued. (example: 1)
- **type** (required) `InvoiceType`: - STANDARD: Standard invoice - CORRECTIVE: Corrects or cancels a previous invoice - SIMPLIFIED: Simplified invoice (ticket), for a recipient that is not identified. BeeL. requires a STANDARD invoice when the recipient is identified, at any amount: a SIMPLIFIED invoice whose recipient carries an `nif` or `alternative_id` is rejected with `SIMPLIFIED_INVOICE_FORBIDS_IDENTIFIED_RECIPIENT`. The only amount BeeL enforces is a cap of 3,000€ VAT included (`SIMPLIFIED_INVOICE_EXCEEDS_LEGAL_LIMIT`). The general limit of RD 1619/2012 is 400€ (art. 4.1.a); up to 3,000€ applies only to the activities listed in art. 4.2. BeeL does not check which activity the issuer carries out. - PROFORMA: Commercial document (formal quote) with no fiscal validity. Never enters VeriFactu (no QR, no AEAT submission): `verifactu.enabled` is always `false`, whatever the company's regime. Requires full recipient data, like STANDARD. Cannot be corrective nor reference a rectified invoice.
- **status** (required) `InvoiceStatus`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date - DRAFT: Draft invoice not sent yet (modifiable) - ISSUED: Finalized invoice with definitive number but not sent - SENT: Invoice sent to customer - PAID: Invoice paid - OVERDUE: Reserved. No operation sets this status and it is not computed from `due_date`; an unpaid invoice past its due date keeps its status (`ISSUED` or `SENT`). Compare `due_date` with today to find overdue invoices. - RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices) - VOIDED: Cancelled invoice. Reached either through a direct void request or through a TOTAL corrective invoice; `void_cause` tells the two apart. - CONVERTED: Proforma converted into an invoice (terminal; the proforma survives as the record of the accepted quote, linked to the created invoice) - ACTIVE: Active proforma. The single working state of a proforma (non-fiscal document): born numbered (PRO-...) and editable, never reaching the fiscal statuses. It transitions to CONVERTED when turned into an invoice, or to VOIDED when the offer is rejected/withdrawn (POST /v1/invoices/{invoice_id}/void). - EXPIRED: Proforma whose offer validity (`valid_until`) has passed. Derived on read and never stored; the proforma stays convertible and editable.
- **issue_date** (required) `string` (date): Invoice issue date. Always set to the current date when the invoice is created. If the operation occurred on a different date, use `operation_date`. (example: "2025-01-15")
- **operation_date** `string` (date): Date when the operation actually occurred. Used when invoicing for a past operation. If null, the operation date is the same as the issue date. (example: "2025-01-10")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **valid_until** `string` (date): Offer validity date. Only rendered on PROFORMA invoices; on any other invoice type the field is inert (accepted and stored, but never shown on the document). Purely informational — nothing is triggered automatically when it passes. Not to be confused with `due_date`, the payment due date. (example: "2025-02-28")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement). Set by the user when marking the invoice as paid. An invoice issued already paid gets its `issue_date`: one whose `total_to_pay` is 0, or one issued from a payment already confirmed by a payment integration. Only present when status is PAID. Contrast with `paid_at`, which is the system timestamp of when the status change was recorded. (example: "2025-01-20")
- **sent_at** `string` (date-time): Moment the email provider ACCEPTED the invoice email — **not** the moment it reached the recipient's mailbox. Present when status is SENT or later. What happened afterwards (delivered, bounced, opened) is not a single timestamp: it lives in `sending_history`, one record per email with its own status and timestamp. On a resend, `sent_at` moves to the latest accepted send while `sending_history` keeps every one of them. (example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system. Automatically set when the invoice status changes to PAID. Contrast with `payment_date`, which is the business date chosen by the user. (example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued. Only present for drafts created from recurring invoices with `draft_in_advance` enabled. (example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed. Only present when status is SCHEDULED. (example: "2025-02-15")
- **scheduled_action** `GenerationAction`: Action to perform when processing a scheduled invoice: - DRAFT: Create as draft for manual review - ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `IssuerData`
- **recipient** (required) `RecipientData`: Recipient data as stored on the invoice. Only `legal_name` is always present; the other fields appear when the invoice stores them.
- **lines** (required) `array[InvoiceLine]`: Invoice lines. Can be empty: drafts may not have lines yet, and a handful of legacy imported invoices were recorded without them. Creating an invoice still requires at least one line.
- **totals** (required) `InvoiceTotals`
- **payment_info** `PaymentInfo`
- **notes** `string`: Additional observations or notes
- **replaced_invoice_ids** `array[string]`: Only on a full invoice issued in exchange for simplified invoices: the simplified invoices it replaces, each now `VOIDED` with `void_cause` `EXCHANGED`. With VeriFactu, the invoice is recorded as `F3` identifying them.
- **void_cause** `VoidCause`: Why a `VOIDED` invoice reached that status: - VOID_REQUEST: Voided directly via `POST /v1/invoices/{invoice_id}/void`. The original VeriFactu record is cancelled with the tax authority. - TOTAL_CORRECTIVE: Voided as a result of issuing a TOTAL corrective invoice over it. The original VeriFactu record stays untouched; the corrective invoice is reported as a new record instead. - EXCHANGED: A simplified invoice replaced by a full invoice issued in exchange for it (`replaced_invoice_ids` of that invoice). Its VeriFactu record is not cancelled: the exchange invoice is recorded as `F3`, identifying it as replaced. Only present on voided invoices.
- **void_reason** `string`: Reason recorded when the invoice was voided (only for voided invoices).
- **voided_at** `string` (date-time): System timestamp when the invoice was voided. Automatically set at the moment the void takes place and never supplied by the caller — a void cannot be dated, so the deprecated `void_date` field of the void request has no effect on it. Invoices voided before this field existed carry the day they were voided on with a time of `00:00Z`, because only the day was retained for them. (example: "2025-01-20T09:12:44Z")
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **source_proforma_id** `string` (uuid): UUID of the source proforma this invoice was converted from (only for invoices created via `convert-to-invoice`).
- **converted_invoice_id** `string` (uuid): UUID of the live (non-deleted) invoice this proforma was converted into — the inverse of `source_proforma_id`, derived at read time (not persisted). Only present on the detail endpoint (`GET /v1/invoices/{invoice_id}`) for a proforma in `CONVERTED` status; never included in list rows.
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `RectificationType`: Type of rectification applied to a corrective invoice: - TOTAL: Rectifies everything still invoiced on the original, its live correctives included (status → VOIDED) - PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `VeriFactuRectificationCode`: Rectification codes according to VeriFactu regulations (AEAT): - R1: Error founded in law and Art. 80 One, Two and Six LIVA - R2: Article 80 Three LIVA (Bankruptcy proceedings) - R3: Article 80 Four LIVA (Uncollectable debts) - R4: Other causes - R5: Corrective of a simplified invoice - ONLY for simplified invoices
- **external_ref** `string`: Client-supplied external reference set at creation (order/cart/contract id). (example: "ORD-2025-0042")
- **metadata** `object`: Additional metadata in key-value format. Invoices auto-generated from a connected payment platform carry system keys you can filter on: - external_customer_id: Payment-platform customer (e.g. Stripe `cus_…`), present when the payment carried a customer (absent on flows with no customer, e.g. Terminal / payment links without customer collection) - external_payment_id: Canonical payment reference. On Stripe this is always the PaymentIntent id (`pi_…`); the Charge, Stripe Invoice and Checkout Session ids are never used here, so every event of the same payment carries the same value. - payment_intent_id: Stripe PaymentIntent id, when the payment has one - charge_id: Stripe Charge id, when the payment has one - payment_provider: Origin platform (e.g. STRIPE_CONNECT) Plus any keys you set yourself on manually-created invoices (order ids, tenants, …). See the "Filtering by metadata" guide for the full list and query rules. (example: {"external_customer_id":"cus_ULGk8bzIr88aag","external_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","payment_intent_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","payment_provider":"STRIPE_CONNECT","external_order_id":"ORD-2025-0042"})
- **send_automatically** `boolean`: Whether the invoice will be automatically sent by email after issuing. Only relevant for DRAFT and SCHEDULED invoices.
- **email_config**: Email configuration used when `send_automatically` is true. If it names no recipients, the email goes to the customer's `billing_emails`, or to the customer's `email` when there are none.
- **pdf_download_url** `string`: Relative URL of the endpoint that returns the PDF download link. Relative to the API base URL (e.g., https://app.beel.es/api). Note it is a link to a link: calling it returns a pre-signed URL that expires in five minutes. Null while there is no PDF to link to: they are produced asynchronously after issuing, so poll until the field appears. It is also null on a handful of very old invoices that have no downloadable PDF at all. (example: "/v1/companies/7c9e6679-7425-40de-944b-e07fc1f90ae7/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `VeriFactu`: **Record of what was applied to this invoice** — not a per-invoice preference. Whether an invoice is registered with the AEAT is a fact of the *taxpayer*: if the issuing tax ID is under the VeriFactu regime in that environment, every one of its invoices is registered; if it is not, none is. That is resolved once, at issue time, against the state of the account at that instant, and what this block reports is the outcome — the receipt of an irreversible decision. It cannot be requested, overridden or changed per invoice. Present on every invoice, whatever its status. **Absent on a proforma**: a proforma is not a fiscal document and is never registered, so there is no outcome to report — read `verifactu` as "not applicable" when the key is missing or carries no value.
- **attachments** `array[InvoiceAttachment]`: Files attached to the invoice, reserved for per-invoice attachments. To send the supporting invoices of a SUPLIDO consolidation, use `options.attach_source_invoices` when issuing: they travel as a ZIP attached to the outgoing email, and appear on the email delivery record rather than here.
- **sending_history** `array[InvoiceSendRecord]`: Emails through which this invoice was sent, oldest first. Resending appends a record, it never replaces the previous one, and a batch send (one email with several invoices) is recorded in every invoice it carried. Only populated in single-invoice responses (`GET /v1/invoices/{invoice_id}` and the lifecycle endpoints); the list endpoint omits it.
- **email_delivery** `InvoiceEmailDeliveryOutcome`: What became of the invoice's automatic email in the act that produced this response. Only present in the response to issuing an invoice (`POST .../invoices/{invoice_id}/issue`). Issuing is a fiscal act and never fails because of the email, so a send the sending policy refuses still answers `200` — this object is how it says so. Without it, a refused send and an invoice that never asked for one looked identical.
- **deleted_at** `string` (date-time): No description
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description

## ErrorResponse

Error response shared by all BeeL. APIs.

The payload carries **two contracts at once** (additive, non-breaking):

- **Legacy** (`success`, `error.{code,message,details}`, `meta`) — kept
  intact for existing consumers.
- **RFC 9457** (`type`, `title`, `detail`, `instance`) — new fields
  for integrators following Problem Details for HTTP APIs. The
  `type` URI is the stable, shareable link to the error's
  documentation page (e.g. `https://docs.beel.es/errors/{code}`).

Future migration: the legacy fields will be deprecated via
`Deprecation`/`Sunset` headers after a sufficient adoption window,
and the response Content-Type will move to
`application/problem+json`.

- **success** (required) `boolean`: No description (example: false)
- **error** (required) `ErrorDetail`
- **meta** `ResponseMeta`
- **type** `string` (uri): Stable URI that identifies the problem type and where the integrator will find its documentation. (example: "https://docs.beel.es/errors/INVOICE_NO_LINES")
- **title** `string`: Short summary of the problem type. Stable between occurrences of the same `type`. (example: "INVOICE_NO_LINES")
- **detail** `string`: Specific message for this occurrence, localized according to `Accept-Language` (`es`, `en`, `ca`); defaults to English. Matches the legacy `error.message`. (example: "The invoice must have at least one line")
- **instance** `string` (uri-reference): URI that identifies the specific occurrence of the problem — typically the path of the affected resource. (example: "/v1/invoices/abc-123")

## ErrorDetail

- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})

## TaxType

Tax type by territory:
- IVA: Iberian Peninsula and Balearic Islands (4%, 10%, 21%; 2%, 5% and 7.5% only on operations of their period)
- IGIC: Canary Islands (0%, 3%, 5%, 7%, 9.5%, 15%, 20%)
- IPSI: Ceuta and Melilla (0.5%, 1%, 2%, 4%, 8%, 10%)
- OTHER: Configurable 0%-100%

Under IVA and IPSI, 0% is not one of these rates: it is the exemption/non-subject
sentinel and always travels with an `exemption_reason`. IGIC's 0% is a real rate.
See `TaxInfo` for the full rules.

Type: `string` — one of: IVA, IGIC, IPSI, OTHER

## RegimeKey

Regime key according to VeriFactu regulations. Omitted, `01` (general regime) applies:
- 01: General regime operation
- 02: Export (IVA and IGIC; not IPSI, whose AEAT list is `01, 08, 11, 18, 19, 20`)
- 03: Used goods, art, antiques (not accepted, see below)
- 04: Investment gold
- 05: Travel agencies
- 06: Group of entities (not accepted, see below)
- 07: Cash basis
- 08: Operation subject to another indirect tax — IPSI or IGIC on an IVA line, IPSI or IVA
  on an IGIC line. It is **not** the general regime of IGIC, which is `01`.
- 09: Mediating agencies
- 10: Third-party collections
- 11: Local rental
- 14: VAT pending in certifications (not accepted, see below)
- 15: VAT pending successive tract
- 17: OSS and IOSS
- 18: Equivalence surcharge
- 19: REAGYP
- 20: Simplified regime

**What AEAT requires with each key** (Validaciones VERI*FACTU 3.1.3.15.6), checked on
IVA and IGIC lines before the invoice is numbered. Otherwise the request is rejected with
`422` and the code in brackets:
- `04`: only reverse charge (an `ISP_ART_84_2_*` reason) or an exemption
  (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`).
- `08`: only `exemption_reason: NO_SUJETA_LOCALIZACION`, at 0 %
  (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`).
- `10`: only `exemption_reason: NO_SUJETA_ART_7_9`, on a `STANDARD` invoice whose
  recipient has a `nif` (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`,
  `REGIME_KEY_REQUIRES_STANDARD_INVOICE`, `REGIME_KEY_REQUIRES_RECIPIENT_NIF`).
- `11` (IVA): a subject line only at 21 %, and no reverse charge
  (`REGIME_KEY_REQUIRES_VAT_RATE`, `REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`).
- `06` and `14` are not accepted (`REGIME_KEY_NOT_SUPPORTED`): AEAT requires with them
  data the invoice does not carry (a cost-based taxable base; an operation date after the
  issue date and a public-administration recipient).
- `03` (used goods) is not accepted (`REGIME_KEY_NOT_SUPPORTED`): under it the invoice
  must not show the tax separately (RD 1619/2012, art. 16.2.c), and it always does. The
  corrective of an invoice that already carried `03` keeps it.
- `05` (travel agencies) and `07` (cash basis) are accepted, and the invoice PDF carries
  the mention of their regime (RD 1619/2012, art. 6.1 n and p). `07`: no reverse charge,
  no non-subject reason and, of the exemptions, only art. 20 or `OTRO`
  (`REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED`).
`GET /v1/tax-types` only offers the keys that are accepted.

**One exception to "a key you send is the key you get":** when the line ends up
carrying an equivalence surcharge — whether you sent `equivalence_surcharge_rate`
or it was inherited from the company's tax configuration — a `01` is rewritten to
`18`, because a surcharge under the general regime is fiscally incoherent. Send
`equivalence_surcharge_rate: 0` explicitly to keep `01`. See
`equivalence_surcharge_rate` in the invoice line for the full rules.

Type: `string` — one of: 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 14, 15, 17, 18, 19, 20

## InvoiceBase

The shape of an invoice, shared by the persisted resource and by the computed
preview of one. It does not require the three fields that only a stored row can
have — `id`, `created_at` and `updated_at`. Read `Invoice` or `NextOccurrence`,
never this one: it is not the payload of any operation.

- **invoice_number** `string`: Complete invoice number (series + sequential). **Null for draft invoices** — assigned automatically when issued. (example: "2025/0001")
- **series** (required) `SeriesInfo`
- **number** `integer`: Sequential number within the series. **Null for draft invoices** — assigned automatically when issued. (example: 1)
- **type** (required) `InvoiceType`: - STANDARD: Standard invoice - CORRECTIVE: Corrects or cancels a previous invoice - SIMPLIFIED: Simplified invoice (ticket), for a recipient that is not identified. BeeL. requires a STANDARD invoice when the recipient is identified, at any amount: a SIMPLIFIED invoice whose recipient carries an `nif` or `alternative_id` is rejected with `SIMPLIFIED_INVOICE_FORBIDS_IDENTIFIED_RECIPIENT`. The only amount BeeL enforces is a cap of 3,000€ VAT included (`SIMPLIFIED_INVOICE_EXCEEDS_LEGAL_LIMIT`). The general limit of RD 1619/2012 is 400€ (art. 4.1.a); up to 3,000€ applies only to the activities listed in art. 4.2. BeeL does not check which activity the issuer carries out. - PROFORMA: Commercial document (formal quote) with no fiscal validity. Never enters VeriFactu (no QR, no AEAT submission): `verifactu.enabled` is always `false`, whatever the company's regime. Requires full recipient data, like STANDARD. Cannot be corrective nor reference a rectified invoice.
- **status** (required) `InvoiceStatus`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date - DRAFT: Draft invoice not sent yet (modifiable) - ISSUED: Finalized invoice with definitive number but not sent - SENT: Invoice sent to customer - PAID: Invoice paid - OVERDUE: Reserved. No operation sets this status and it is not computed from `due_date`; an unpaid invoice past its due date keeps its status (`ISSUED` or `SENT`). Compare `due_date` with today to find overdue invoices. - RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices) - VOIDED: Cancelled invoice. Reached either through a direct void request or through a TOTAL corrective invoice; `void_cause` tells the two apart. - CONVERTED: Proforma converted into an invoice (terminal; the proforma survives as the record of the accepted quote, linked to the created invoice) - ACTIVE: Active proforma. The single working state of a proforma (non-fiscal document): born numbered (PRO-...) and editable, never reaching the fiscal statuses. It transitions to CONVERTED when turned into an invoice, or to VOIDED when the offer is rejected/withdrawn (POST /v1/invoices/{invoice_id}/void). - EXPIRED: Proforma whose offer validity (`valid_until`) has passed. Derived on read and never stored; the proforma stays convertible and editable.
- **issue_date** (required) `string` (date): Invoice issue date. Always set to the current date when the invoice is created. If the operation occurred on a different date, use `operation_date`. (example: "2025-01-15")
- **operation_date** `string` (date): Date when the operation actually occurred. Used when invoicing for a past operation. If null, the operation date is the same as the issue date. (example: "2025-01-10")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **valid_until** `string` (date): Offer validity date. Only rendered on PROFORMA invoices; on any other invoice type the field is inert (accepted and stored, but never shown on the document). Purely informational — nothing is triggered automatically when it passes. Not to be confused with `due_date`, the payment due date. (example: "2025-02-28")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement). Set by the user when marking the invoice as paid. An invoice issued already paid gets its `issue_date`: one whose `total_to_pay` is 0, or one issued from a payment already confirmed by a payment integration. Only present when status is PAID. Contrast with `paid_at`, which is the system timestamp of when the status change was recorded. (example: "2025-01-20")
- **sent_at** `string` (date-time): Moment the email provider ACCEPTED the invoice email — **not** the moment it reached the recipient's mailbox. Present when status is SENT or later. What happened afterwards (delivered, bounced, opened) is not a single timestamp: it lives in `sending_history`, one record per email with its own status and timestamp. On a resend, `sent_at` moves to the latest accepted send while `sending_history` keeps every one of them. (example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system. Automatically set when the invoice status changes to PAID. Contrast with `payment_date`, which is the business date chosen by the user. (example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued. Only present for drafts created from recurring invoices with `draft_in_advance` enabled. (example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed. Only present when status is SCHEDULED. (example: "2025-02-15")
- **scheduled_action** `GenerationAction`: Action to perform when processing a scheduled invoice: - DRAFT: Create as draft for manual review - ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `IssuerData`
- **recipient** (required) `RecipientData`: Recipient data as stored on the invoice. Only `legal_name` is always present; the other fields appear when the invoice stores them.
- **lines** (required) `array[InvoiceLine]`: Invoice lines. Can be empty: drafts may not have lines yet, and a handful of legacy imported invoices were recorded without them. Creating an invoice still requires at least one line.
- **totals** (required) `InvoiceTotals`
- **payment_info** `PaymentInfo`
- **notes** `string`: Additional observations or notes
- **replaced_invoice_ids** `array[string]`: Only on a full invoice issued in exchange for simplified invoices: the simplified invoices it replaces, each now `VOIDED` with `void_cause` `EXCHANGED`. With VeriFactu, the invoice is recorded as `F3` identifying them.
- **void_cause** `VoidCause`: Why a `VOIDED` invoice reached that status: - VOID_REQUEST: Voided directly via `POST /v1/invoices/{invoice_id}/void`. The original VeriFactu record is cancelled with the tax authority. - TOTAL_CORRECTIVE: Voided as a result of issuing a TOTAL corrective invoice over it. The original VeriFactu record stays untouched; the corrective invoice is reported as a new record instead. - EXCHANGED: A simplified invoice replaced by a full invoice issued in exchange for it (`replaced_invoice_ids` of that invoice). Its VeriFactu record is not cancelled: the exchange invoice is recorded as `F3`, identifying it as replaced. Only present on voided invoices.
- **void_reason** `string`: Reason recorded when the invoice was voided (only for voided invoices).
- **voided_at** `string` (date-time): System timestamp when the invoice was voided. Automatically set at the moment the void takes place and never supplied by the caller — a void cannot be dated, so the deprecated `void_date` field of the void request has no effect on it. Invoices voided before this field existed carry the day they were voided on with a time of `00:00Z`, because only the day was retained for them. (example: "2025-01-20T09:12:44Z")
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **source_proforma_id** `string` (uuid): UUID of the source proforma this invoice was converted from (only for invoices created via `convert-to-invoice`).
- **converted_invoice_id** `string` (uuid): UUID of the live (non-deleted) invoice this proforma was converted into — the inverse of `source_proforma_id`, derived at read time (not persisted). Only present on the detail endpoint (`GET /v1/invoices/{invoice_id}`) for a proforma in `CONVERTED` status; never included in list rows.
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `RectificationType`: Type of rectification applied to a corrective invoice: - TOTAL: Rectifies everything still invoiced on the original, its live correctives included (status → VOIDED) - PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `VeriFactuRectificationCode`: Rectification codes according to VeriFactu regulations (AEAT): - R1: Error founded in law and Art. 80 One, Two and Six LIVA - R2: Article 80 Three LIVA (Bankruptcy proceedings) - R3: Article 80 Four LIVA (Uncollectable debts) - R4: Other causes - R5: Corrective of a simplified invoice - ONLY for simplified invoices
- **external_ref** `string`: Client-supplied external reference set at creation (order/cart/contract id). (example: "ORD-2025-0042")
- **metadata** `object`: Additional metadata in key-value format. Invoices auto-generated from a connected payment platform carry system keys you can filter on: - external_customer_id: Payment-platform customer (e.g. Stripe `cus_…`), present when the payment carried a customer (absent on flows with no customer, e.g. Terminal / payment links without customer collection) - external_payment_id: Canonical payment reference. On Stripe this is always the PaymentIntent id (`pi_…`); the Charge, Stripe Invoice and Checkout Session ids are never used here, so every event of the same payment carries the same value. - payment_intent_id: Stripe PaymentIntent id, when the payment has one - charge_id: Stripe Charge id, when the payment has one - payment_provider: Origin platform (e.g. STRIPE_CONNECT) Plus any keys you set yourself on manually-created invoices (order ids, tenants, …). See the "Filtering by metadata" guide for the full list and query rules. (example: {"external_customer_id":"cus_ULGk8bzIr88aag","external_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","payment_intent_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","payment_provider":"STRIPE_CONNECT","external_order_id":"ORD-2025-0042"})
- **send_automatically** `boolean`: Whether the invoice will be automatically sent by email after issuing. Only relevant for DRAFT and SCHEDULED invoices.
- **email_config**: Email configuration used when `send_automatically` is true. If it names no recipients, the email goes to the customer's `billing_emails`, or to the customer's `email` when there are none.
- **pdf_download_url** `string`: Relative URL of the endpoint that returns the PDF download link. Relative to the API base URL (e.g., https://app.beel.es/api). Note it is a link to a link: calling it returns a pre-signed URL that expires in five minutes. Null while there is no PDF to link to: they are produced asynchronously after issuing, so poll until the field appears. It is also null on a handful of very old invoices that have no downloadable PDF at all. (example: "/v1/companies/7c9e6679-7425-40de-944b-e07fc1f90ae7/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `VeriFactu`: **Record of what was applied to this invoice** — not a per-invoice preference. Whether an invoice is registered with the AEAT is a fact of the *taxpayer*: if the issuing tax ID is under the VeriFactu regime in that environment, every one of its invoices is registered; if it is not, none is. That is resolved once, at issue time, against the state of the account at that instant, and what this block reports is the outcome — the receipt of an irreversible decision. It cannot be requested, overridden or changed per invoice. Present on every invoice, whatever its status. **Absent on a proforma**: a proforma is not a fiscal document and is never registered, so there is no outcome to report — read `verifactu` as "not applicable" when the key is missing or carries no value.
- **attachments** `array[InvoiceAttachment]`: Files attached to the invoice, reserved for per-invoice attachments. To send the supporting invoices of a SUPLIDO consolidation, use `options.attach_source_invoices` when issuing: they travel as a ZIP attached to the outgoing email, and appear on the email delivery record rather than here.
- **sending_history** `array[InvoiceSendRecord]`: Emails through which this invoice was sent, oldest first. Resending appends a record, it never replaces the previous one, and a batch send (one email with several invoices) is recorded in every invoice it carried. Only populated in single-invoice responses (`GET /v1/invoices/{invoice_id}` and the lifecycle endpoints); the list endpoint omits it.
- **email_delivery** `InvoiceEmailDeliveryOutcome`: What became of the invoice's automatic email in the act that produced this response. Only present in the response to issuing an invoice (`POST .../invoices/{invoice_id}/issue`). Issuing is a fiscal act and never fails because of the email, so a send the sending policy refuses still answers `200` — this object is how it says so. Without it, a refused send and an invoice that never asked for one looked identical.
- **deleted_at** `string` (date-time): No description

## SeriesInfo

- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")

## InvoiceType

- STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice (ticket), for a recipient that is not identified. BeeL.
  requires a STANDARD invoice when the recipient is identified, at any amount: a
  SIMPLIFIED invoice whose recipient carries an `nif` or `alternative_id` is rejected
  with `SIMPLIFIED_INVOICE_FORBIDS_IDENTIFIED_RECIPIENT`. The only amount BeeL
  enforces is a cap of 3,000€ VAT included (`SIMPLIFIED_INVOICE_EXCEEDS_LEGAL_LIMIT`). The
  general limit of RD 1619/2012 is 400€ (art. 4.1.a); up to 3,000€ applies only to the
  activities listed in art. 4.2. BeeL does not check which activity the issuer carries
  out.
- PROFORMA: Commercial document (formal quote) with no fiscal validity.
  Never enters VeriFactu (no QR, no AEAT submission): `verifactu.enabled` is
  always `false`, whatever the company's regime. Requires full recipient data,
  like STANDARD.
  Cannot be corrective nor reference a rectified invoice.

Type: `string` — one of: STANDARD, CORRECTIVE, SIMPLIFIED, PROFORMA

## InvoiceStatus

- SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Reserved. No operation sets this status and it is not computed from `due_date`;
  an unpaid invoice past its due date keeps its status (`ISSUED` or `SENT`). Compare
  `due_date` with today to find overdue invoices.
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Cancelled invoice. Reached either through a direct void request or
  through a TOTAL corrective invoice; `void_cause` tells the two apart.
- CONVERTED: Proforma converted into an invoice (terminal; the proforma survives
  as the record of the accepted quote, linked to the created invoice)
- ACTIVE: Active proforma. The single working state of a proforma (non-fiscal
  document): born numbered (PRO-...) and editable, never reaching the fiscal
  statuses. It transitions to CONVERTED when turned into an invoice, or to VOIDED
  when the offer is rejected/withdrawn (POST /v1/invoices/{invoice_id}/void).
- EXPIRED: Proforma whose offer validity (`valid_until`) has passed. Derived on read
  and never stored; the proforma stays convertible and editable.

Type: `string` — one of: SCHEDULED, DRAFT, ISSUED, SENT, PAID, OVERDUE, RECTIFIED, VOIDED, CONVERTED, ACTIVE, EXPIRED

## GenerationAction

Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email

Type: `string` — one of: DRAFT, ISSUE_AND_SEND

## IssuerData

- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters). Valid formats: - DNI: 8 digits + letter (e.g., 12345678A) - NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A) - CIF: Letter + 7 digits + digit/letter (e.g., B12345674) (example: "12345678A")
- **address**: Issuer address as stored. Optional and absent when the company has not registered its address yet: an address is either complete or it is not there, so no partial address and no placeholder is ever returned in its place.
- **phone** `Phone`: A phone number, as the record holds it: digits, spaces, dashes, parentheses and an optional leading `+`, up to 20 characters. This is the schema a **response** carries, and the length above is the only rule it states. It deliberately does not repeat the character rule, because a number can reach a record through a path that predates that rule or never passed through this API at all — a payment provider's customer data, a bulk import. Read the field defensively and do not assume it parses. What a **request** has to satisfy is `PhoneInput`, which adds the rules this API enforces on the way in.
- **email** `Email`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **website** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.) (example: "Nº Colegiado: 12345")

## RecipientData

Recipient data as stored on the invoice. Only `legal_name` is always present; the other
fields appear when the invoice stores them.

- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters), when the invoice identifies its recipient with one. Valid formats: - DNI: 8 digits + letter (e.g., 12345678A) - NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A) - CIF: Letter + 7 digits + digit/letter (e.g., B12345674) (example: "12345678A")
- **alternative_id**: No description
- **address**: Recipient address as stored (optional for simplified invoices). Read shape: an invoice recorded without recipient address still carries the stamped country code, so no field is guaranteed.
- **phone** `Phone`: A phone number, as the record holds it: digits, spaces, dashes, parentheses and an optional leading `+`, up to 20 characters. This is the schema a **response** carries, and the length above is the only rule it states. It deliberately does not repeat the character rule, because a number can reach a record through a path that predates that rule or never passed through this API at all — a payment provider's customer data, a bulk import. Read the field defensively and do not assume it parses. What a **request** has to satisfy is `PhoneInput`, which adds the rules this API enforces on the way in.
- **email** `Email`: Email address (minimum valid email is 5 chars, e.g. a@b.co)

## InvoiceLine

- **description** `string`: Description of the invoiced concept. Required for NORMAL lines; optional for SUPLIDO lines (may be empty or absent). (example: "Web application development")
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices) (example: 40)
- **unit** `string`: No description (example: "hours")
- **unit_price** (required) `number`: Unit price before taxes (can be negative in corrective invoices). Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging). Final amounts are always rounded to 2 decimals. This range is wider than the `maximum` the request accepts for `unit_price`, and on purpose: on a line priced by declared total the unit price is not sent but derived (total ÷ quantity), so what comes back can exceed what you are allowed to send. (example: 50)
- **discount_percentage** `number`: Discount percentage applied (0-100) (example: 10)
- **main_tax** `TaxInfo`: Complete tax information with cross-validations: - IVA: real rates 4, 10, 21, and the temporary 2, 5 and 7.5 (see below for 0) - IGIC: 0, 3, 5, 7, 9.5, 15, 20 — here 0 is the real "Tipo Cero" - IPSI: real rates 0.5, 1, 2, 4, 8, 10 (see below for 0) - OTHER: any percentage between 0 and 100 **0 % under IVA and IPSI is not a rate, it is the exemption sentinel.** It is accepted on a line, but only together with an `exemption_reason` (exempt or non-subject operation); on its own it says nothing and the line is rejected. That is why `GET /v1/tax-types` publishes the IVA rates without 0: the legitimate way to a 0 % IVA line is through an exemption reason, which the same response also publishes. IGIC is different — its 0 % is a real legal rate (basic necessities) and needs no reason. **IVA 5 %** (the temporary rate applied from 2022 to electricity, gas and certain foodstuffs) is no longer in force for new operations. AEAT only accepts it on operations dated from 2022-07-01 to 2024-09-30: send the `operation_date` of that period, because without one the issue date decides and a line at 5 % is rejected with `422 VAT_RATE_NOT_ACCEPTED_ON_DATE`. Its equivalence surcharge pair is 0.5 up to 2022-12-31 and 0.62 from 2023-01-01. **IVA 2 % and 7.5 %** (temporary rates of the last quarter of 2024) are accepted only on operations dated from 2024-10-01 to 2024-12-31, with surcharges 0.26 and 1. Exception: when regime_key = "17" (OSS/IOSS) the invoice applies the destination country VAT instead of the Spanish one, so any percentage in the EU range [0, 27] is accepted regardless of the tax type set — including 0 without an exemption reason.
- **equivalence_surcharge_rate** `number`: Equivalence surcharge rate the line was issued with. It is what the invoice holds, not what a request accepts (see `EquivalenceSurchargePercentage`): invoices issued with VAT at 5 % before the surcharge was corrected to 0.62 keep the `0.625` they were issued with, because an issued invoice never changes. Their billing record declares 0.62, as the AEAT information note on the new surcharge rates allows. (example: 5.2)
- **irpf_rate** `number`: Withholding (IRPF) rate the line holds. It is what the invoice holds, not what a request accepts (see `IrpfPercentage`): a line saved with a rate the table no longer has keeps it, and an issued invoice never changes. (example: 15)
- **exemption_reason** `ExemptionReason`: Tax exemption reason code per the Spanish VAT Law (Ley 37/1992, LIVA), with the VeriFactu code each one is reported as. - `EXENTA_ART_20`: exempt, art. 20 (domestic operations such as medical, educational, cultural and financial services, or housing rentals). E1. - `EXENTA_ART_21`: exempt, art. 21 (exports of goods). E2. - `EXENTA_ART_22`: exempt, art. 22 (operations treated as exports). E3. - `EXENTA_ART_24`: exempt, art. 24 (free zones, warehouses and customs regimes). E4. - `EXENTA_ART_25`: exempt, art. 25 (intra-community supplies of goods). E5. - `EXENTA_ART_26`: exempt, art. 26 (intra-community acquisitions of goods). It exempts the buyer's acquisition, not a supply the seller invoices, so an invoice line that carries it is rejected with `EXEMPTION_NOT_FOR_ISSUED_INVOICE`; a supply to another Member State is `EXENTA_ART_25`. - `NO_SUJETA_ART_7_9`: not subject under art. 7 (such as the transfer of a business as a going concern, art. 7.1º). N1. - `NO_SUJETA_LOCALIZACION`: not subject by the place-of-supply rules (intra-community or non-EU services, arts. 69 and 70). N2. - `ISP_ART_84_2_A` … `ISP_ART_84_2_F`: reverse charge (the invoice states «inversión del sujeto pasivo»), art. 84.Uno.2.º letters a) (supplier not established in Spain), b) (unwrought or semi-finished gold), c) (scrap, waste and recovery materials, plastic, paper, cardboard, glass and textile waste, and semi-finished non-ferrous metal products), d) (greenhouse gas emission allowances), e) (certain real estate supplies: in insolvency proceedings, with the exemption waived, or enforcing a security) and f) (construction or renovation works). S2. - `ISP_ART_84_2_G`: reverse charge of letter g) (silver, platinum, palladium, mobile phones, consoles, laptops and tablets). The law requires these supplies to be invoiced in a special series, so an invoice line that carries it is rejected with `REVERSE_CHARGE_CASE_NOT_SUPPORTED`. - `EXENTA_ART_140`: investment gold exemption, art. 140 bis (usually with `regime_key` `04`). E6. - `REGIMEN_ART_129` (agriculture, livestock and fishing, arts. 124 to 134 bis), `REGIMEN_ART_135` (second-hand goods, art and antiques), `REGIMEN_ART_141` (travel agencies), `REGIMEN_ART_154` (equivalence surcharge) and `REGIMEN_ART_163_DECIES` (cash basis, arts. 163 decies to 163 sexiesdecies): operations of special regimes, which VeriFactu identifies by the regime key rather than by an exemption code. An invoice line that carries one is rejected with `EXEMPTION_REGIME_NOT_SUPPORTED_IN_VERIFACTU`; declare the regime with `regime_key` instead. - `OTRO`: any other provision. Requires the text in `exemption_reason_text`. E6.
- **exemption_reason_text** `string`: Custom exemption text. Only used when exemption_reason is OTRO.
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices) (example: 1800)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices) (example: 2178)
- **pricing_mode** `string`: How the line amount was entered. `UNIT_PRICE` = classic mode: the amount is derived from `unit_price` (`quantity × unit_price × (1 − discount / 100)`). `TOTAL_EXCLUDING_TAX` = total-declared mode: `total_excluding_tax` is the exact taxable base and `unit_price` is derived and informational (`total / quantity`, 4 decimals). `TOTAL_INCLUDING_TAX` = tax-inclusive total-declared mode: `total_including_tax` is what the customer paid (taxable base + VAT + equivalence surcharge) and the engine works the breakdown backwards so the rounded amounts add up to the declared total exactly. — one of: UNIT_PRICE, TOTAL_EXCLUDING_TAX, TOTAL_INCLUDING_TAX
- **total_excluding_tax** `number`: Declared line total excluding taxes. Only present on lines with `pricing_mode = TOTAL_EXCLUDING_TAX`. Unlike `line_total`, it never includes taxes nor subtracts IRPF withholding. (example: 1)
- **total_including_tax** `number`: Declared line total including taxes (taxable base + VAT + equivalence surcharge; IRPF withholding is never subtracted). Only present on lines with `pricing_mode = TOTAL_INCLUDING_TAX`. The invariant `taxable_base + VAT + surcharge = total_including_tax` holds exactly. (example: 100)
- **line_type**: Fiscal line type. - **NORMAL**: standard line; contributes to the taxable base and VAT. - **SUPLIDO**: payment made on behalf of the final client (art. 78.Tres.3 LIVA); excluded from the taxable base, VAT and VeriFactu.
- **source_invoice_reference** `string`: Reference to the original invoice issued by the third party in the client's name. Required when line_type=SUPLIDO.
- **source_invoice_ids** `array[string]`: Ids of the issued invoices that make up the SUPLIDO. They may belong to the issuing account or to accounts it manages with VIEW access. Their sum is the disbursement amount (never typed by hand). Audit traceability. Only present on lines with line_type=SUPLIDO.

## InvoiceTotals

- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: Total discounts applied (can be negative in corrective invoices) (example: 0)
- **vat_breakdown** `array[object]`: No description
  - **type** (required) `number`: No description (example: 21)
  - **base** (required) `number`: No description (example: 2000)
  - **amount** (required) `number`: No description (example: 420)
  - **regime_key** `string`: VeriFactu regime key of the rows grouped here. Rows are grouped by (tax type, rate, regime key), so an invoice mixing general-regime and equivalence-surcharge lines at the same rate yields TWO rows at `type: 21` that only this field tells apart (`01` vs `18`). Index by `(type, regime_key)`, never by `type` alone. (example: "18")
- **total_vat** (required) `number`: Total indirect tax (IVA, IGIC, IPSI and other rates), not only VAT. Can be negative in corrective invoices. (example: 420)
- **surcharge_breakdown** `array[object]`: No description
  - **type** (required) `number`: No description
  - **base** (required) `number`: No description
  - **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`: No description
  - **type** (required) `number`: No description
  - **base** (required) `number`: No description
  - **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **total_disbursements** `number`: Sum of SUPLIDO lines (payments on behalf of the client, art. 78.Tres.3 LIVA). Excluded from the taxable base, VAT and VeriFactu. (example: 0)
- **total_to_pay** `number`: Total amount paid by the client = `invoice_total` + `total_disbursements`. This is the amount on the PDF and the actual charge. When there are no disbursements (suplidos) it matches `invoice_total`. (example: 2120)

## PaymentInfo

- **method**: Preferred payment method. Omitted, `BANK_TRANSFER` applies. If NONE is selected, no payment information will be shown on the invoice.
- **iban** `IBAN`: IBAN (International Bank Account Number). Required when payment method is BANK_TRANSFER.
- **swift** `SWIFT`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days. When marking an invoice as paid, every field of this object that travels replaces the stored one and every omitted field keeps its current value. (example: 30)

## VoidCause

Why a `VOIDED` invoice reached that status:
- VOID_REQUEST: Voided directly via `POST /v1/invoices/{invoice_id}/void`. The
  original VeriFactu record is cancelled with the tax authority.
- TOTAL_CORRECTIVE: Voided as a result of issuing a TOTAL corrective invoice over
  it. The original VeriFactu record stays untouched; the corrective invoice is
  reported as a new record instead.
- EXCHANGED: A simplified invoice replaced by a full invoice issued in exchange for it
  (`replaced_invoice_ids` of that invoice). Its VeriFactu record is not cancelled: the
  exchange invoice is recorded as `F3`, identifying it as replaced.

Only present on voided invoices.

Type: `string` — one of: VOID_REQUEST, TOTAL_CORRECTIVE, EXCHANGED

## VeriFactu

**Record of what was applied to this invoice** — not a per-invoice preference.

Whether an invoice is registered with the AEAT is a fact of the *taxpayer*: if the issuing
tax ID is under the VeriFactu regime in that environment, every one of its invoices is
registered; if it is not, none is. That is resolved once, at issue time, against the state
of the account at that instant, and what this block reports is the outcome — the receipt of
an irreversible decision. It cannot be requested, overridden or changed per invoice.

Present on every invoice, whatever its status. **Absent on a proforma**: a proforma is not a
fiscal document and is never registered, so there is no outcome to report — read
`verifactu` as "not applicable" when the key is missing or carries no value.

- **enabled** `boolean`: Whether this invoice was registered with the AEAT under VeriFactu. Read-only: it records the regime of the issuing tax ID at the moment of issuance.
- **invoice_hash** `string`: SHA-256 hash of the registration record, as VeriFactu defines it. Present from the moment the registration is submitted, while `submission_status` is still `PENDING`, and kept whatever the AEAT answers. (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **registration_number** `string`: Identifier (UUID) of this record in the VeriFactu submission, assigned when it is submitted. It is not an AEAT code: quote it when you ask BeeL about the record. (example: "4f8c2a1e-9b3d-4e7a-8c5f-1d2e3f4a5b6c")
- **qr_url** `string`: AEAT verification URL encoded in the invoice QR code. Present from the moment the registration is submitted, while `submission_status` is still `PENDING`. (example: "https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?nif=B12345674&numserie=A%2F2025%2F0042&fecha=20-01-2025&importe=1590.00")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs. Present from the moment the registration is submitted, while `submission_status` is still `PENDING`; it does not wait for the AEAT to accept the record. (example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registered_at** `string` (date-time): VeriFactu registration date and time
- **submission_status** `VeriFactuSubmissionStatus`: Submission status of an invoice's VeriFactu record to AEAT. Single vocabulary for the whole axis: the same values are published in `verifactu.submission_status` of an invoice and accepted by the `verifactu_status` filter of `GET /v1/invoices`, so a value read from an invoice can be fed straight back into the filter. * `PENDING` — queued, AEAT has not answered yet. A temporary AEAT server error also stays `PENDING`: BeeL. retries it automatically, and it only becomes `REJECTED` if the retries run out. * `ACCEPTED` — accepted by AEAT (with or without non-blocking warnings). * `VOIDED` — a cancellation record was accepted by AEAT. * `REJECTED` — rejected by AEAT, or the submission was rejected by the provider before reaching AEAT (see `error_code` / `error_message`). * `NOT_SUBMITTED` — the invoice is issued with VeriFactu enabled but has no live record: the submission fell through (lost event, exhausted retries) and AEAT does not know the invoice exists. Transient right after issuing (the async submission may still be in flight); if it persists, the registration needs to be re-driven. Drafts and scheduled invoices have no submission to describe yet and omit the field. Invoices with `verifactu.enabled = false` are outside this axis and are selected with the `verifactu_enabled` filter.
- **skip_reason**: Why this invoice was not submitted to AEAT, when a submission was expected and omitted. Null in every other case, including invoices that are not subject to VeriFactu at all.
- **error_code** `string`: Error code returned by AEAT. Present when the AEAT reported a remark or an error on the record. (example: "3000")
- **error_message** `string`: Human-readable reason for the outcome. When the AEAT reported a remark or an error on the record, it is the AEAT's own description. When BeeL. decided the outcome (the submission was rejected before reaching the AEAT, or BeeL. stopped waiting for a final answer), it is a message written by BeeL., in the language of the request. (example: "Factura ya existe en el sistema")

## InvoiceAttachment

A file attached to the invoice.

- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description

## InvoiceSendRecord

One email through which an invoice was sent, as recorded in the delivery
read-model. Batch sends (one email carrying several invoices) produce one
record in each of the invoices they carry.

- **id** (required) `string` (uuid): Id of the delivery record (same id as in `GET /v1/emails`).
- **recipients** (required) `array[string]`: Recipient addresses (To)
- **cc** `array[string]`: Carbon-copy addresses (CC)
- **subject** `string`: No description
- **status** (required) `EmailDeliveryStatus`: Status of an email. The history records every email the system decided to send, not only the ones that went out: an email stopped by policy is listed as REJECTED rather than omitted. - QUEUED: authorised and recorded, not dispatched yet - REJECTED: stopped by policy and never sent (terminal, not retried). In test environments invoices may only be emailed to the account owner's own address (`+tag` aliases included), so a message addressed elsewhere lands here - SENT: successfully sent to the provider - FAILED: sending failed - DELIVERED / BOUNCED / OPENED: reported by the provider's webhooks
- **sent_at** `string` (date-time): Moment the email provider ACCEPTED the message — not the moment it reached the mailbox. Later outcomes (delivered, bounced, opened) are reflected in `status` as the provider reports them. Absent while there is no such moment: the history records decisions, and a `QUEUED` record has not been dispatched yet, a `REJECTED` one never will be, and a `FAILED` one never got that far. Read `status` to tell those apart; do not read an absent `sent_at` as "sent long ago". It is omitted, never sent as `null`. (example: "2025-01-29T18:45:00Z")
- **external_message_id** `string`: Message id at the email provider, when available.
- **error** `string`: Why the email did not go out, present only when `status` is `FAILED` or `REJECTED`. A short explanation in the language of the request, meant to be shown to a person; do not parse it; branch on `status` instead.

## InvoiceEmailDeliveryOutcome

What became of the invoice's automatic email in the act that produced this response.

Only present in the response to issuing an invoice (`POST .../invoices/{invoice_id}/issue`).
Issuing is a fiscal act and never fails because of the email, so a send the sending
policy refuses still answers `200` — this object is how it says so. Without it, a
refused send and an invoice that never asked for one looked identical.

- **status** (required) `string`: - `SENT` — the email was authorised and accepted for delivery. Delivery itself is asynchronous; follow it in `sending_history`. - `REJECTED` — the sending policy refused it. Nothing was queued and nothing will be retried; the refusal is recorded in the delivery ledger. - `NOT_REQUESTED` — the invoice does not send automatically. — one of: SENT, REJECTED, NOT_REQUESTED (example: "REJECTED")
- **reason** `string`: Translation key explaining a `REJECTED` outcome, deliberately generic. Null for the other statuses. (example: "error.email.envio_no_permitido")

## Phone

A phone number, as the record holds it: digits, spaces, dashes, parentheses and an
optional leading `+`, up to 20 characters.

This is the schema a **response** carries, and the length above is the only rule it
states. It deliberately does not repeat the character rule, because a number can reach a
record through a path that predates that rule or never passed through this API at all —
a payment provider's customer data, a bulk import. Read the field defensively and do not
assume it parses.

What a **request** has to satisfy is `PhoneInput`, which adds the rules this API enforces
on the way in.

Type: `string`

## Email

Email address (minimum valid email is 5 chars, e.g. a@b.co)

Type: `string` (email)

## IBAN

IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.

Type: `string`

## SWIFT

SWIFT/BIC code

Type: `string`

## VeriFactuSubmissionStatus

Submission status of an invoice's VeriFactu record to AEAT.

Single vocabulary for the whole axis: the same values are published in
`verifactu.submission_status` of an invoice and accepted by the `verifactu_status`
filter of `GET /v1/invoices`, so a value read from an invoice can be fed straight
back into the filter.

* `PENDING` — queued, AEAT has not answered yet. A temporary AEAT server error also
  stays `PENDING`: BeeL. retries it automatically, and it only becomes `REJECTED` if the
  retries run out.
* `ACCEPTED` — accepted by AEAT (with or without non-blocking warnings).
* `VOIDED` — a cancellation record was accepted by AEAT.
* `REJECTED` — rejected by AEAT, or the submission was rejected by the provider
  before reaching AEAT (see `error_code` / `error_message`).
* `NOT_SUBMITTED` — the invoice is issued with VeriFactu enabled but has no live
  record: the submission fell through (lost event, exhausted retries) and AEAT
  does not know the invoice exists. Transient right after issuing (the async
  submission may still be in flight); if it persists, the registration needs to
  be re-driven.

Drafts and scheduled invoices have no submission to describe yet and omit the
field. Invoices with `verifactu.enabled = false` are outside this axis and are
selected with the `verifactu_enabled` filter.

Type: `string` — one of: PENDING, ACCEPTED, VOIDED, REJECTED, NOT_SUBMITTED

## EmailDeliveryStatus

Status of an email.

The history records every email the system decided to send, not only the ones that
went out: an email stopped by policy is listed as REJECTED rather than omitted.

- QUEUED: authorised and recorded, not dispatched yet
- REJECTED: stopped by policy and never sent (terminal, not retried). In test
  environments invoices may only be emailed to the account owner's own address
  (`+tag` aliases included), so a message addressed elsewhere lands here
- SENT: successfully sent to the provider
- FAILED: sending failed
- DELIVERED / BOUNCED / OPENED: reported by the provider's webhooks

Type: `string` — one of: QUEUED, REJECTED, SENT, FAILED, DELIVERED, BOUNCED, OPENED


---

Full OpenAPI spec: https://docs.beel.es/api/openapi