---
title: "Update an invoice"
method: PATCH
path: "/v1/companies/{company_id}/invoices/{invoice_id}"
tags: ["CompanyInvoices"]
---

# Update an invoice

`PATCH /v1/companies/{company_id}/invoices/{invoice_id}`

## Request

- Base URL: `https://app.beel.es/api`
- URL: `https://app.beel.es/api/v1/companies/{company_id}/invoices/{invoice_id}`
- Auth: HTTP bearer

Updates only the fields present in the body, leaving every other field of the invoice as
it is.

- **Status:** only an invoice in `DRAFT` or `SCHEDULED`, or a proforma in `ACTIVE`, can be
  modified; any other status answers `422` with `STATUS_NOT_MODIFIABLE`. An issued one is
  amended with a corrective invoice (`POST …/{invoice_id}/corrective`) or voided.
- **Series:** changing `series_id` never moves the invoice to another NIF — a series of
  another company is not visible from here.

## Headers

- `Idempotency-Key` string

## Request body

- UpdateInvoiceRequest: Partial update for a DRAFT invoice. Only fields present in the body are applied; omitted fields preserve their existing value.
  - `type` 'STANDARD' | 'CORRECTIVE' | 'SIMPLIFIED' | 'PROFORMA': - 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.
  - `series_id` string, uuid: Universally Unique Identifier (UUID v4)
  - `operation_date` string, date, nullable: Date when the operation occurred. **Must be today or a past date**, and not more than twenty years before today (AEAT does not accept an older one): an older date answers `422 OPERATION_DATE_TOO_OLD`, on update and again on issue. Set to null to clear (operation date = issue date). If not provided, keeps the existing value.
  - `due_date` string, date, nullable: New due date. Must be the same as or after `issue_date`. Set to null to clear the due date. If not provided, keeps the existing value.
  - `valid_until` string, date, nullable: Offer validity date. Only rendered on PROFORMA invoices; on any other invoice type the field is inert. Purely informational. Set to null to clear it. If not provided, keeps the existing value.
  - `recipient` Recipient: Invoice recipient: either a registered customer (`customer_id`) or the recipient's data inline (`legal_name`, `nif`, `address`…), never both. Sending `customer_id` together with any other recipient field returns 422 `RECIPIENT_CUSTOMER_AND_DATA_EXCLUSIVE`, on create and on edit. All fields are optional at schema level, but for an ad-hoc recipient (no customer_id) on non-SIMPLIFIED invoices the API requires legal_name, address and nif (or alternative_id); omitting the address returns 422 RECIPIENT_ADDRESS_REQUIRED.
    - `customer_id` string, uuid: UUID of a registered customer. The invoice takes the recipient data stored on that customer. Send it alone: combined with any other recipient field it returns 422 `RECIPIENT_CUSTOMER_AND_DATA_EXCLUSIVE`. To change the recipient's data, edit the customer or send the data inline without `customer_id`.
    - `legal_name` string: Recipient legal name. Required when customer_id is not provided (except for SIMPLIFIED invoices where all fields are optional).
    - `trade_name` string, nullable: Recipient trade name (optional)
    - `nif` string: Spanish Tax ID (9 alphanumeric characters). Required when customer_id is not provided and alternative_id is absent. Not accepted on SIMPLIFIED invoices: BeeL. requires a STANDARD invoice when the recipient is identified.
    - `alternative_id` object, nullable: Alternative identifier for foreign customers (mutually exclusive with nif). Not accepted on SIMPLIFIED invoices, like `nif`: BeeL. requires a STANDARD invoice when the recipient is identified.
      - `type` 'NIF_IVA' | 'PASSPORT' | 'COUNTRY_ID' | 'RESIDENCE_CERTIFICATE' | 'OTHER_DOCUMENT' | 'NOT_REGISTERED' | '02' | '03' | '04' | '05' | '06' | '07', required: Identifier type. Use descriptive names: - **NIF_IVA**: EU VAT number (intra-community) — *only for an EU member state other than Spain, with that country's VAT number structure* - **PASSPORT**: Passport — *allowed for any country* - **COUNTRY_ID**: Country of residence ID — *not allowed when `country_code = ES`* - **RESIDENCE_CERTIFICATE**: Residence certificate — *not allowed when `country_code = ES`* - **OTHER_DOCUMENT**: Other supporting document — *not allowed when `country_code = ES`* - **NOT_REGISTERED**: Not registered in AEAT — *requires `country_code = ES`* **⚠️ DEPRECATED numeric codes** (will be removed in v2): 02, 03, 04, 05, 06, 07 — use the descriptive names above instead.
      - `number` string, required: Identifier number. For `NIF_IVA`, the full EU VAT number with its country prefix (e.g. `FR40303265045`); see the VeriFactu rules on the parent schema.
      - `country_code` string: ISO 3166-1 alpha-2 code of the country that issued the document. Required except for `PASSPORT` and `NOT_REGISTERED`, where omitting it means `ES`. Constrains the allowed `type` values; see the VeriFactu rules on the parent schema.
    - `address` Address: Address you send when you create or update a company, a customer or an onboarding. A required field made only of whitespace passes the length checks below but leaves the address without that part, so it is rejected with `422`: `STREET_EMPTY`, `POSTAL_CODE_EMPTY`, `CITY_EMPTY` or `PROVINCE_EMPTY`. Addresses you read back are described by their own schema.
      - `street` string, required: Full address (street, number, floor, etc.) - Latin characters only
      - `number` string: Street number. Optional: omit it when the address has none, or when `street` already carries the address in full.
      - `floor` string: Floor or level
      - `door` string: Door or apartment
      - `postal_code` string, required: Postal code (5 digits for Spain, free format for other countries)
      - `city` string, required: City or town - Latin characters only
      - `province` string: Province or state - Latin characters only. Required for an address in Spain (`country_code` `ES`, or no country at all); optional elsewhere, where many addresses have none. A Spanish address without it is rejected with a `422`.
      - `country` string: Country of the address, as its ISO 3166-1 alpha-2 code (`GB`) or its official name in Spanish, English or Catalan (`Reino Unido`, `United Kingdom`, `Regne Unit`; case and accents are ignored). Anything else, such as `UK`, is rejected with `422 COUNTRY_CODE_REQUIRED`: send `country_code` instead. If it names a different country than `country_code`, `422 COUNTRY_CODE_MISMATCH` (`España` alone yields to a foreign `country_code`: it was the old default). What is stored and returned is always the Spanish name derived from the resulting code, never the text sent. With neither field present, the address is Spanish (`España`).
      - `country_code` string: ISO 3166-1 alpha-2 country code: the canonical field that decides the country of the address. It must be a real country code (`GB`, not `UK`); otherwise `422 COUNTRY_CODE_REQUIRED`. When it is omitted, the code comes from `country` (see there). With neither field present, the address is stored as `ES`.
    - `phone` string: A phone number as this API accepts it: 9 to 20 characters, and only digits, spaces, dashes, parentheses and an optional leading `+`. Every request that takes a phone number uses this schema. It is `Phone` plus the rules enforced on input. A value this schema accepts always satisfies `Phone`, so anything you send here is something a response can return.
    - `email` string, email: Email address (minimum valid email is 5 chars, e.g. a@b.co)
  - `lines` object[]
    - `description` string: Required for NORMAL lines; optional for SUPLIDO lines.
    - `quantity` number, required
    - `unit` string
    - `unit_price` number: Unit price before taxes. `0` is accepted (a discount granted before or simultaneously with the sale, e.g. a free introductory month). 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.
    - `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.
    - `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.
    - `discount_percentage` number
    - `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.
      - `type` 'IVA' | 'IGIC' | 'IPSI' | 'OTHER', required: 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` number, required: Tax percentage
      - `regime_key` '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10' | '11' | '14' | '15' | '17' | '18' | '19' | '20': 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.
    - `equivalence_surcharge_rate` 0 | 0.26 | 0.5 | 0.62 | 1 | 1.4 | 1.75 | 5.2: Equivalence surcharge percentage in decimal format, one of the values AEAT accepts. Pairs allowed (VAT rate ↔ surcharge): 21↔5.2, 21↔1.75 (tobacco products), 10↔1.4, 4↔0.5, and the temporary ones, only on operations of their period: 5↔0.5 up to 2022-12-31, 5↔0.62 from 2023-01-01 to 2024-09-30, and 7.5↔1 and 2↔0.26 from 2024-10-01 to 2024-12-31. A pair outside its period is rejected with `422 SURCHARGE_RATE_NOT_ACCEPTED_ON_DATE`. `GET /v1/tax-types` publishes every pair with its `valid_from` / `valid_until`. The backend automatically normalizes equivalent formats (5.20 → 5.2).
    - `irpf_rate` 0 | 1 | 2 | 2.8 | 6 | 7 | 7.6 | 9.5 | 15 | 19 | 24: Withholding (IRPF) percentage, as the IRPF regulation (Royal Decree 439/2007) sets it: 0 (no withholding), 1 (pig fattening and poultry, and some activities under objective estimation), 2 (other agricultural, livestock and forestry activities), 7 (professional activity in its first three years, and the other 7 % cases), 15 (professional activities, and intellectual property income), 19 (rent of urban property and other income of art. 75.2.b; also the general rate of the Corporate Income Tax withholding) and 24 (image rights). A company that pays Corporate Income Tax can only use 0, 19, 24 and 9.5: see `WithholdingOptions`. Ceuta and Melilla: income with the Ceuta and Melilla deduction bears the base rate reduced as the law sets it. Under IRPF, 15 % and 7 % (professional activities) and 19 % (rent of urban property located there) are reduced by 60 %: 6, 2.8 and 7.6. Under Corporate Income Tax, 19 % on those rents is halved: 9.5, which only a company can use (`IRPF_RATE_ONLY_FOR_CORPORATE_ISSUER` otherwise). Whether the reduction applies is the issuer's choice: the NIF does not show it. The value counts, not how it is written: `15.0` is `15` and `2.80` is `2.8`.
    - `exemption_reason` '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': 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, nullable
    - `line_type` 'NORMAL' | 'SUPLIDO': Fiscal line type. `NORMAL` contributes to the taxable base and VAT; `SUPLIDO` is a payment made on behalf of the client and is excluded from both.
    - `source_invoice_reference` string, nullable: Reference to the original invoice issued by the third party in the client's name. Required when `line_type=SUPLIDO`.
    - `source_invoice_ids` 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 amount (never typed). Audit traceability.
  - `payment_info` PaymentInfo
    - `method` 'NONE' | 'BANK_TRANSFER' | 'CARD' | 'CASH' | 'CHECK' | 'DIRECT_DEBIT' | 'BIZUM' | 'OTHER': Payment method shown on invoices and recurring invoices. - `NONE`: no payment information is shown. - `BANK_TRANSFER`: bank transfer to the IBAN of the payment details; the only method that requires an IBAN. - `CARD`: card payment. - `CASH`: cash payment. - `CHECK`: payment by cheque. - `DIRECT_DEBIT`: direct debit from the customer's bank account. - `BIZUM`: payment through Bizum. - `OTHER`: any other method.
    - `iban` string: IBAN (International Bank Account Number). Required when payment method is BANK_TRANSFER.
    - `swift` string: SWIFT/BIC code
    - `payment_term_days` integer, nullable: 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.
  - `notes` string
  - `custom_fields` InvoiceCustomFieldInput[], nullable: Replaces the custom fields of the invoice as a whole: the list sent becomes the new list. Omit it to keep the current ones; send `null` or `[]` to remove them all. The same rules as on creation apply: at most one value per `key`, a `key` the company does not have answers `422 CUSTOM_FIELD_UNKNOWN` and an archived field answers `409 CUSTOM_FIELD_ARCHIVED`, even when the draft already carries it. Every field in the list is saved again with the label it has now. Only a draft, a scheduled invoice or an active proforma can change them; any other status answers `422 STATUS_NOT_MODIFIABLE`. When the request changes the recipient and omits `custom_fields`, the saved fields are carried over to the new customer; one archived since is left out, with no error. They are informational: they are not part of the VeriFactu record sent to the AEAT and do not enter its hash.
    - `key` string, required: Identifier of the custom field within the company, chosen when the field is created: lowercase letters, digits and `_`, up to 64 characters. It never changes. BeeL. gives it no meaning of its own.
    - `value` string, required: Text of the value. Leading and trailing spaces are removed; a value that is empty after that answers `422`. When an option of the field is equivalent (it matches ignoring case, accents and repeated spaces), the invoice stores the text of that option, archived options included. Otherwise the text is stored as sent and, when the invoice has a registered customer (`recipient.customer_id`), it is added as an option of that customer; with recipient data sent inline, no option is created. On a field with `suggest_values: false` the value is never compared with the options and never creates one: the invoice stores the text as sent, without the leading and trailing spaces.
  - `options` object: Processing options for the draft. Fields are optional and follow partial update semantics: omitted fields preserve the existing value.
    - `send_automatically` boolean: Whether the invoice should be auto-emailed after issuing.
    - `email_config` EmailConfiguration: Who the invoice is emailed to when `send_automatically` is true. Every address in `recipients` and `cc` must have a domain with a dot, or the request answers `422 INVALID_EMAIL_FORMAT`. With `send_automatically` true and no recipients here, no `customer_id` and no recipient email, there is nobody to send to: `422` `AUTOMATIC_EMAIL_CONFIG_INVALID`.
      - `recipients` Email[], required: List of recipient emails (at least 1 required)
      - `cc` Email[]: List of CC emails (optional)
      - `subject` string: Custom email subject (optional, if not specified uses a default)
      - `message` string: Custom message (optional, added to email body)

## Response `200`

Invoice updated successfully

- object: 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` boolean, required
  - `data` object, required: 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, nullable: Complete invoice number (series + sequential). **Null for draft invoices** — assigned automatically when issued.
    - `series` SeriesInfo, required
      - `id` string, uuid, required: Invoice series UUID
      - `code` string, required: Alphanumeric series code
    - `number` integer, nullable: Sequential number within the series. **Null for draft invoices** — assigned automatically when issued.
    - `type` 'STANDARD' | 'CORRECTIVE' | 'SIMPLIFIED' | 'PROFORMA', required: - 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` 'SCHEDULED' | 'DRAFT' | 'ISSUED' | 'SENT' | 'PAID' | 'OVERDUE' | 'RECTIFIED' | 'VOIDED' | 'CONVERTED' | 'ACTIVE' | 'EXPIRED', required: - 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: Unpaid invoice in `ISSUED` or `SENT` status, with a total above zero, whose `due_date` is earlier than the current day in Europe/Madrid. A periodic process sets it, so it can lag behind the due date. It changes to `PAID` when the invoice is paid. - 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` string, date, required: 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`.
    - `operation_date` string, date, nullable: 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.
    - `due_date` string, date: Payment due date (must be the same as or after `issue_date`)
    - `valid_until` string, date, nullable: 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.
    - `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. Present once a payment has been recorded; it stays through later status changes (RECTIFIED, VOIDED). Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
    - `sent_at` string, date-time, nullable: 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.
    - `paid_at` string, date-time, nullable: 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.
    - `auto_emit_after` string, date, nullable: 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.
    - `scheduled_for` string, date, nullable: Date when the invoice should be automatically processed. Only present when status is SCHEDULED.
    - `scheduled_action` 'DRAFT' | 'ISSUE_AND_SEND': 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` IssuerData, required
      - `legal_name` string, required: Issuer legal name
      - `trade_name` string, nullable: Issuer trade name (optional)
      - `nif` string, required: 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)
      - `address` AddressResponse: An address as stored. Nothing is guaranteed: the address of a company created by signup is empty until onboarding fills it in, so every field may be absent. `Address` (the request shape) does require them — that is a rule of admission, not a fact about what is stored.
        - `street` string: Full address (street, number, floor, etc.)
        - `number` string: Street number. Absent when the stored address has none.
        - `floor` string: Floor or level
        - `door` string: Door or apartment
        - `postal_code` string: Postal code (5 digits for Spain, free format for other countries)
        - `city` string: City or town
        - `province` string: Province or state. Outside Spain an address may have none.
        - `country` string: Country name: the Spanish name derived from `country_code`. Addresses stored before the country was validated may hold the name as it was sent.
        - `country_code` string: ISO 3166-1 alpha-2 country code
      - `phone` string: 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` string, email: Email address (minimum valid email is 5 chars, e.g. a@b.co)
      - `website` string, nullable: Issuer website (optional)
      - `logo_url` string, nullable: Issuer logo URL (optional)
      - `additional_info` string, nullable: Additional issuer information (collegiate number, professional registration, etc.)
    - `recipient` RecipientData, required: 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, nullable: Customer UUID in the system (optional)
      - `legal_name` string, required: Recipient legal name
      - `trade_name` string, nullable: Recipient trade name (optional)
      - `nif` string, nullable: 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)
      - `alternative_id` object, nullable: Alternative identifier for foreign customers (mutually exclusive with nif), when the invoice identifies its recipient with one.
        - `type` 'NIF_IVA' | 'PASSPORT' | 'COUNTRY_ID' | 'RESIDENCE_CERTIFICATE' | 'OTHER_DOCUMENT' | 'NOT_REGISTERED' | '02' | '03' | '04' | '05' | '06' | '07', required: Identifier type. Use descriptive names: - **NIF_IVA**: EU VAT number (intra-community) — *only for an EU member state other than Spain, with that country's VAT number structure* - **PASSPORT**: Passport — *allowed for any country* - **COUNTRY_ID**: Country of residence ID — *not allowed when `country_code = ES`* - **RESIDENCE_CERTIFICATE**: Residence certificate — *not allowed when `country_code = ES`* - **OTHER_DOCUMENT**: Other supporting document — *not allowed when `country_code = ES`* - **NOT_REGISTERED**: Not registered in AEAT — *requires `country_code = ES`* **⚠️ DEPRECATED numeric codes** (will be removed in v2): 02, 03, 04, 05, 06, 07 — use the descriptive names above instead.
        - `number` string, required: Identifier number. For `NIF_IVA`, the full EU VAT number with its country prefix (e.g. `FR40303265045`); see the VeriFactu rules on the parent schema.
        - `country_code` string: ISO 3166-1 alpha-2 code of the country that issued the document. Required except for `PASSPORT` and `NOT_REGISTERED`, where omitting it means `ES`. Constrains the allowed `type` values; see the VeriFactu rules on the parent schema.
      - `address` AddressResponse: An address as stored. Nothing is guaranteed: the address of a company created by signup is empty until onboarding fills it in, so every field may be absent. `Address` (the request shape) does require them — that is a rule of admission, not a fact about what is stored.
        - `street` string: Full address (street, number, floor, etc.)
        - `number` string: Street number. Absent when the stored address has none.
        - `floor` string: Floor or level
        - `door` string: Door or apartment
        - `postal_code` string: Postal code (5 digits for Spain, free format for other countries)
        - `city` string: City or town
        - `province` string: Province or state. Outside Spain an address may have none.
        - `country` string: Country name: the Spanish name derived from `country_code`. Addresses stored before the country was validated may hold the name as it was sent.
        - `country_code` string: ISO 3166-1 alpha-2 country code
      - `phone` string: 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` string, email: Email address (minimum valid email is 5 chars, e.g. a@b.co)
    - `lines` InvoiceLine[], required: 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.
      - `description` string: Description of the invoiced concept. Required for NORMAL lines; optional for SUPLIDO lines (may be empty or absent).
      - `quantity` number, required: Product/service quantity (can be negative in corrective invoices)
      - `unit` string
      - `unit_price` number, required: 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.
      - `discount_percentage` number: Discount percentage applied (0-100)
      - `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.
        - `type` 'IVA' | 'IGIC' | 'IPSI' | 'OTHER', required: 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` number, required: Tax percentage
        - `regime_key` '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '10' | '11' | '14' | '15' | '17' | '18' | '19' | '20': 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.
      - `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.
      - `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.
      - `exemption_reason` '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': 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, nullable: Custom exemption text. Only used when exemption_reason is OTRO.
      - `taxable_base` number: Line taxable base (after discount, can be negative in corrective invoices)
      - `line_total` number, required: Line total with taxes (can be negative in corrective invoices)
      - `pricing_mode` 'UNIT_PRICE' | 'TOTAL_EXCLUDING_TAX' | 'TOTAL_INCLUDING_TAX': 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.
      - `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.
      - `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.
      - `line_type` 'NORMAL' | 'SUPLIDO': Fiscal line type. `NORMAL` contributes to the taxable base and VAT; `SUPLIDO` is a payment made on behalf of the client and is excluded from both.
      - `source_invoice_reference` string, nullable: Reference to the original invoice issued by the third party in the client's name. Required when line_type=SUPLIDO.
      - `source_invoice_ids` 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.
    - `totals` InvoiceTotals, required
      - `taxable_base` number, required: Total taxable base (can be negative in corrective invoices)
      - `total_discounts` number: Total discounts applied (can be negative in corrective invoices)
      - `vat_breakdown` object[]
        - `type` number, required
        - `base` number, required
        - `amount` number, required
        - `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.
      - `total_vat` number, required: Total indirect tax (IVA, IGIC, IPSI and other rates), not only VAT. Can be negative in corrective invoices.
      - `surcharge_breakdown` object[]
        - `type` number, required
        - `base` number, required
        - `amount` number, required
      - `total_equivalence_surcharge` number, required: Total equivalence surcharge (can be negative in corrective invoices)
      - `irpf_breakdown` object[]
        - `type` number, required
        - `base` number, required
        - `amount` number, required
      - `total_irpf` number, required: Total personal income tax withheld (can be negative in corrective invoices)
      - `invoice_total` number, required: Fiscal total of the invoice: taxable base + VAT + equivalence surcharge − IRPF (can be negative in corrective invoices). It does **not** include disbursements (SUPLIDO lines), so on an invoice made only of disbursements it is 0. What the client actually pays is `total_to_pay`.
      - `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 the amounts declared to VeriFactu.
      - `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`.
    - `payment_info` PaymentInfo
      - `method` 'NONE' | 'BANK_TRANSFER' | 'CARD' | 'CASH' | 'CHECK' | 'DIRECT_DEBIT' | 'BIZUM' | 'OTHER': Payment method shown on invoices and recurring invoices. - `NONE`: no payment information is shown. - `BANK_TRANSFER`: bank transfer to the IBAN of the payment details; the only method that requires an IBAN. - `CARD`: card payment. - `CASH`: cash payment. - `CHECK`: payment by cheque. - `DIRECT_DEBIT`: direct debit from the customer's bank account. - `BIZUM`: payment through Bizum. - `OTHER`: any other method.
      - `iban` string: IBAN (International Bank Account Number). Required when payment method is BANK_TRANSFER.
      - `swift` string: SWIFT/BIC code
      - `payment_term_days` integer, nullable: 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.
    - `notes` string: Additional observations or notes
    - `replaced_invoice_ids` 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` 'VOID_REQUEST' | 'TOTAL_CORRECTIVE' | 'EXCHANGED': 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, nullable: 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.
    - `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, nullable: UUID of the recurring invoice that generated this invoice (if any)
    - `recurring_invoice_name` string, nullable: Name of the recurring invoice (denormalized for display)
    - `rectification_type` 'TOTAL' | 'PARTIAL': 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` 'R1' | 'R2' | 'R3' | 'R4' | 'R5': 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, nullable: Client-supplied external reference set at creation (order/cart/contract id).
    - `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.
    - `send_automatically` boolean, nullable: Whether the invoice will be automatically sent by email after issuing. Only relevant for DRAFT and SCHEDULED invoices.
    - `email_config` EmailConfiguration: Who the invoice is emailed to when `send_automatically` is true. Every address in `recipients` and `cc` must have a domain with a dot, or the request answers `422 INVALID_EMAIL_FORMAT`. With `send_automatically` true and no recipients here, no `customer_id` and no recipient email, there is nobody to send to: `422` `AUTOMATIC_EMAIL_CONFIG_INVALID`.
      - `recipients` Email[], required: List of recipient emails (at least 1 required)
      - `cc` Email[]: List of CC emails (optional)
      - `subject` string: Custom email subject (optional, if not specified uses a default)
      - `message` string: Custom message (optional, added to email body)
    - `pdf_download_url` string, nullable: 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.
    - `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.
      - `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.
      - `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.
      - `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`.
      - `qr_base64` string, nullable: 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.
      - `registered_at` string, date-time: VeriFactu registration date and time
      - `submission_status` 'PENDING' | 'ACCEPTED' | 'ACCEPTED_WITH_ERRORS' | 'VOIDED' | 'REJECTED' | 'NOT_SUBMITTED': 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. `ACCEPTED` does not include the records accepted with errors, which have their own value. New values may be added over time: treat any value you do not recognise as an unknown status. * `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. So does a submission that failed because of a technical problem on BeeL.'s side: BeeL. submits it again once the problem is fixed. Do not void it or issue another invoice for it. * `ACCEPTED` — accepted by AEAT without remarks. * `ACCEPTED_WITH_ERRORS` — accepted by AEAT, which also reported errors in the record (see `error_code` / `error_message`). The record stands, but the data AEAT flagged must be reviewed. Do not treat it as a clean `ACCEPTED`. * `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` 'CONNECTION_DISABLED' | 'CONFIG_MISSING' | 'CONFIG_DISABLED' | 'NIF_NOT_REGISTERED': Reason why an automatically generated invoice was not submitted to AEAT. Present only when a submission was expected and was omitted, so an invoice that was skipped can be told apart from one that never had to be submitted. Every value is resolved by the issuer from their own settings. * `CONNECTION_DISABLED` — automatic submission is turned off on the payment connection that produced the invoice. * `CONFIG_MISSING` — the issuing tax ID has no VeriFactu configuration. * `CONFIG_DISABLED` — VeriFactu is disabled for the issuing tax ID. * `NIF_NOT_REGISTERED` — the issuing tax ID is not yet registered with AEAT, so the submission would be rejected.
      - `error_code` string, nullable: Error code of the outcome. When the AEAT reported a remark or an error on the record, it is the AEAT's own code (numeric, for example `1105`), on a rejection (`REJECTED`) and also on an acceptance with errors (`ACCEPTED_WITH_ERRORS`). When the submission was rejected before reaching the AEAT for a reason BeeL. recognises, it is a BeeL. code: * `RECIPIENT_VAT_NOT_IN_VIES` — the customer's VAT number is not registered in VIES. * `RECIPIENT_VAT_INVALID_FORMAT` — the customer's VAT number does not have a valid format. * `RECIPIENT_VAT_COUNTRY_NOT_EU` — the country of the customer's VAT number is not an EU member state. * `ISSUE_DATE_NOT_SUBMISSION_DATE` — the issue date is not the date of the submission. * `INVOICE_NUMBER_TAKEN_IN_AEAT` — the AEAT already has this invoice's number and issue date for a different invoice. A `REJECTED` can arrive without it: `error_message` always says why.
      - `error_message` string, nullable: 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.
    - `attachments` 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.
      - `id` string, uuid
      - `name` string
      - `url` string
      - `type` string
    - `sending_history` 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.
      - `id` string, uuid, required: Id of the delivery record (same id as in `GET /v1/emails`).
      - `recipients` string[], required: Recipient addresses (To)
      - `cc` string[]: Carbon-copy addresses (CC)
      - `subject` string
      - `status` 'QUEUED' | 'REJECTED' | 'SENT' | 'FAILED' | 'DELIVERED' | 'BOUNCED' | 'OPENED', required: 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`.
      - `external_message_id` string, nullable: Message id at the email provider, when available.
      - `error` string, nullable: 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.
    - `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.
      - `status` 'SENT' | 'REJECTED' | 'NOT_REQUESTED', required: - `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.
      - `reason` string, nullable: Translation key explaining a `REJECTED` outcome, deliberately generic. Null for the other statuses.
    - `deleted_at` string, date-time, nullable
    - `id` string, uuid, required: Unique invoice UUID
    - `created_at` string, date-time, required
    - `updated_at` string, date-time, required
    - `custom_fields` InvoiceCustomField[], required: The company's custom fields saved on this invoice, each with the label and value it was saved with; an empty array when it carries none. They are informational: they are not part of the VeriFactu record sent to the AEAT and do not enter its hash. Unlike `metadata`, which holds identifiers for your integration, they are what a person reads, filters and exports.
      - `key` string, required: Identifier of the custom field within the company, chosen when the field is created: lowercase letters, digits and `_`, up to 64 characters. It never changes. BeeL. gives it no meaning of its own.
      - `label` string, required: Label of the field when the invoice was saved.
      - `value` string, required: Text stored on the invoice. It is the text the `custom_fields` filter of the invoice list compares.
  - `meta` ResponseMeta
    - `timestamp` string, date-time
    - `request_id` string

## Other responses

- `400`: One of: - `INVALID_JSON_FORMAT`: the body is not valid JSON, or a property has the wrong type or format. `details` follows `FieldDeserializationError`: `field`, `invalid_value` and, where there is one, `expected_format`. - `SIMPLIFIED_INVOICE_EXCEEDS_LEGAL_LIMIT`: a `SIMPLIFIED` invoice whose total, VAT included, is above 3,000€. The same answer when the invoice is created and when an edit takes it over the cap, whether the edit changes the lines or changes `type` to `SIMPLIFIED`. Issue a `STANDARD` invoice with the customer identified instead. Other `error.code` values with this status: - `EXEMPTION_INCOMPATIBLE_WITH_REGIME` — the line's `exemption_reason` cannot be declared under its `regime_key` (e.g. E2/E3 with key `01`); change the key or the reason. - `EXEMPTION_REGIME_NOT_SUPPORTED_IN_VERIFACTU` — `REGIMEN_ART_*` reasons are special regimes, not exemptions; declare the matching `regime_key` instead of an exemption reason. - `ISP_INCOMPATIBLE_WITH_SURCHARGE` — a reverse-charge line (`ISP_*`) cannot carry an equivalence surcharge; remove the surcharge or the reverse-charge reason. - `LINE_SUPLIDO_SOURCE_INVOICE_NOT_FOUND` — an id in `source_invoice_ids` does not exist, is in another environment, or is not visible to this account or its managed accounts. - `LINE_SUPLIDO_SOURCE_INVOICE_NOT_ISSUED` — a source invoice in `source_invoice_ids` is still a draft (or not in an issued state); issue it first. - `LINE_SUPLIDO_TOO_MANY_SOURCES` — more than 200 distinct `source_invoice_ids` in one request; split the suplido across invoices. - `LINE_SUPLIDO_TOO_MANY_SOURCE_ACCOUNTS` — the `source_invoice_ids` belong to more than 50 managed accounts; split the request. - `LINE_TOTAL_INCONSISTENT` — the computed line amounts do not add up to its total within 1 cent; this is an internal safeguard, report it with the request id. - `OSS_REGIME_INCOMPATIBLE_WITH_ISP` — regime key `17` (OSS/IOSS) cannot be combined with a reverse-charge `exemption_reason`; choose one. - `RECIPIENT_REQUIRED_FOR_ORDINARY` — the edit sent an empty `recipient` on a non-simplified invoice; its recipient can be replaced but not removed.
- `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.
- `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. That case answers `error.code` `ACTIVE_COMPANY_NOT_ACCESSIBLE`.
- `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}`. - `PROFILE_NOT_FOUND` — the credential's account has no company profile yet: its holder has not completed onboarding, so there is no issuer to act as. - `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`. Other `error.code` values with this status: - `INVOICE_SERIES_NOT_FOUND` — the `series_id` does not exist in this company and environment (a Test series is invisible from Live and vice versa). List the series and send an existing id, or omit it to use the default.
- `409`: The request is well formed but collides with the state that is already there, told apart by `error.code`: - `CUSTOM_FIELD_ARCHIVED` — a `key` in `custom_fields` names a field the company has archived, even one the draft already carries. Reactivate the field, or send `custom_fields` without it. Nothing changes. - `CONCURRENT_MODIFICATION` — another write changed the invoice first; read it again and retry. - `IDEMPOTENCY_KEY_PROCESSING` — the `Idempotency-Key` you sent is still in flight; retry after a moment. `IDEMPOTENCY_KEY_MISMATCH` — it was already used for a different body; use a new key.
- `422`: Validation error. 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`. A `unit_price` you send with more than 4 decimal places is rejected with `error.code` `LINE_UNIT_PRICE_TOO_MANY_DECIMALS` instead of being rounded. A SIMPLIFIED invoice whose recipient carries a NIF or an alternative identifier is rejected with `SIMPLIFIED_INVOICE_FORBIDS_IDENTIFIED_RECIPIENT`, at any amount: issue a STANDARD invoice instead. Fiscal rules on the lines answer `422` too, each with its own `error.code`. A `SIMPLIFIED` invoice (or its R5 corrective) cannot carry reverse charge (`SIMPLIFICADA_FORBIDS_ISP`), an equivalence surcharge (`SIMPLIFICADA_FORBIDS_SURCHARGE`) or an operation of art. 4.4 RD 1619/2012 such as an intra-EU supply (`SIMPLIFICADA_FORBIDS_CROSS_BORDER`). An `exemption_reason` that needs the recipient to carry a specific identifier type answers `EXEMPTION_REQUIRES_RECIPIENT_ID_TYPE` (today, `EXENTA_ART_25` needs `NIF_IVA`); one no longer accepted on a new invoice answers `EXEMPTION_NOT_FOR_ISSUED_INVOICE`; a `regime_key` that requires an exemption the line does not carry answers `REGIME_REQUIRES_INCOMPATIBLE_EXEMPTION`. A VAT `percentage` that is not one of the accepted rates answers `INVALID_PERCENTAGE`, and one AEAT does not accept on the operation date (the issue date when there is none) answers `VAT_RATE_NOT_ACCEPTED_ON_DATE`, whose message names the dates that rate is accepted. A number outside what its field stores answers `VALUE_OUT_OF_RANGE`. Other `error.code` values with this status: - `CUSTOM_FIELD_UNKNOWN` — a `key` in `custom_fields` is not a custom field of this company in this environment; create it with `PUT …/custom-fields/{key}` or fix the key. - `DUE_DATE_BEFORE_ISSUE_DATE` — `due_date` is earlier than the issue date (today on create, the stored one on edit); send a due date on or after it. - `EXEMPT_ZERO_RATE_REQUIRES_REASON` — a 0 % IVA or IPSI line is the exemption sentinel and needs an `exemption_reason`; add one or use a real rate. - `INVALID_IVA_SURCHARGE_PAIR` — the equivalence surcharge does not match the line's VAT rate (21↔5.2, 10↔1.4, 5↔0.62, 4↔0.5); fix either rate. - `INVALID_REGIME_KEY_FOR_TAX_TYPE` — the `regime_key` does not exist for that tax type (e.g. `18` under IGIC); `details.allowed_values` lists the accepted keys. - `IRPF_RATE_NOT_FOR_CORPORATE_ISSUER` — the issuer is a company (corporate income tax), which can only withhold 0, 19 or 24 %; use one of those. - `IRPF_RATE_ONLY_FOR_CORPORATE_ISSUER` — the rate (e.g. 9.5 % Ceuta/Melilla) only applies to corporate issuers; an individual issuer must use a personal-income-tax rate. - `LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT` — a line with `total_excluding_tax` or `total_including_tax` cannot also send `discount_percentage`; the total already includes any discount. - `LINE_EXEMPTION_TEXT_REQUIRED` — `exemption_reason: OTRO` needs `exemption_reason_text` explaining the exemption; add it. - `LINE_EXEMPTION_WITH_TAX` — the line declares an `exemption_reason` but a non-zero rate; exempt or non-subject lines go at 0 %. - `LINE_INVALID_QUANTITY` — `quantity` is 0; send a non-zero quantity (negative values are allowed for discounts or franchises). - `LINE_MAIN_TAX_REQUIRED` — a `NORMAL` line has no `main_tax`; it is never defaulted from the company settings, so send it explicitly. - `LINE_NORMAL_DESCRIPTION_REQUIRED` — a `NORMAL` line has an empty or blank `description`; describe the invoiced concept. - `LINE_SUPLIDO_MUST_HAVE_NO_IRPF` — a `SUPLIDO` line is outside VAT and cannot carry `irpf_rate`; omit it or send 0. - `LINE_SUPLIDO_MUST_HAVE_NO_RECARGO` — a `SUPLIDO` line cannot carry an equivalence surcharge; omit `equivalence_surcharge_rate` or send 0. - `LINE_SUPLIDO_MUST_HAVE_NO_TAX` — a `SUPLIDO` line (payment on the client's behalf, art. 78.Tres.3 LIVA) cannot carry a `main_tax` with a non-zero rate; remove it. - `LINE_SUPLIDO_REFERENCE_REQUIRED` — a `SUPLIDO` line needs `source_invoice_reference` (or `source_invoice_ids`, from which it is built); say which third-party invoice it passes on. - `LINE_UNIT_PRICE_XOR_DECLARED_TOTAL` — each line must carry exactly one of `unit_price`, `total_excluding_tax` or `total_including_tax`; none or several were sent. - `NEGATIVE_TOTAL_REQUIRES_RECTIFICATIVE` — the lines add up to a negative total; only a corrective invoice can be negative. Correct the original with `POST …/corrective`. - `OPERATION_DATE_AFTER_ISSUE_DATE` — `operation_date` is later than the issue date (today when issuing); send today or a past date. - `OPERATION_DATE_TOO_OLD` — `operation_date` is more than twenty years before the issue date; AEAT does not accept it. Send a more recent date. - `PERCENTAGE_OUT_OF_RANGE` — a percentage (discount, tax, surcharge or withholding) is below 0 or above 100. - `PROFORMA_TYPE_CHANGE_FORBIDDEN` — an edit cannot turn a proforma into an invoice or an invoice into a proforma; use `convert-to-invoice` or create a new document. - `RECIPIENT_CUSTOMER_AND_DATA_EXCLUSIVE` — `customer_id` was sent together with inline recipient fields; send one or the other. - `RECIPIENT_ID_REQUIRED` — a standard invoice needs an identified recipient: a `customer_id`, or inline data with `nif` or `alternative_id`. - `RECIPIENT_UNREGISTERED_ID_MUST_BE_DNI_OR_NIE` — an `alternative_id` of type `NOT_REGISTERED` with country `ES` must be a DNI or NIE; a company (CIF) is always registered, send it as `nif`. - `REGIME_KEY_CLASSIFICATION_NOT_ACCEPTED` — AEAT does not accept that `exemption_reason` (or its absence) with the line's `regime_key`; the message lists the reasons it admits. - `REGIME_KEY_NOT_SUPPORTED` — BeeL. cannot declare that `regime_key` to AEAT (e.g. `06`, `14`); use another key. - `REGIME_KEY_REQUIRES_STANDARD_INVOICE` — the line's `regime_key` is only accepted on a standard (F1) invoice; change the invoice type or the key. - `REGIME_KEY_REQUIRES_VAT_RATE` — the line's `regime_key` only admits one VAT rate (named in the message); use that rate or an exemption reason. - `REVERSE_CHARGE_CASE_NOT_SUPPORTED` — that reverse-charge case (e.g. `ISP_ART_84_2_G`, which needs a special series) is not supported; issue it outside BeeL. or use another reason. - `SIMPLIFICADA_FORBIDS_IRPF` — a simplified invoice cannot carry IRPF withholding; remove `irpf_rate` or issue a standard invoice. - `STATUS_NOT_MODIFIABLE` — the invoice's current status does not allow this change: only drafts, scheduled invoices and active proformas can be edited, and only issued, sent or overdue invoices can be marked paid. - `SURCHARGE_RATE_NOT_ACCEPTED_ON_DATE` — AEAT does not accept that surcharge rate on the operation date (or issue date if none); send the right `operation_date` or rate. - `SURCHARGE_REQUIRES_REGIME` — an equivalence surcharge was sent with a `regime_key` other than `01`/`18` (e.g. `02`, `03`, `17`); only regime `18` admits it. - `TYPE_CHANGE_CORRECTIVE_FORBIDDEN` — a draft cannot change `type` to or from `CORRECTIVE`; correctives are created from the original with `POST …/corrective`.
- `429`: Rate limit exceeded. `RATE_LIMIT_EXCEEDED` when the request rate of your credential is over its limit; `TOO_MANY_REQUESTS` when an email the operation sends is held back because too many went out to that recipient in a short time. Either way, retry after the `Retry-After` seconds. `QUOTA_EXCEEDED` is the other `429`: the operation would go over a quota of your plan for the current period (issued invoices, for instance). Retrying does not help until the quota resets or the plan changes. `error.details` carries `feature_code`, `current_usage`, `quota_limit` and `reset_date`, and `RateLimit-Reset` the seconds until the reset when it is known.
- `500`: Internal server error
- `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 `402` carrying `SUBSCRIPTION_REQUIRED` lands here when the account has no active subscription. `error.details` says why and what to do: `current_status` (absent if it never had one), `required_permission` and `action`. A `503` carrying `SERVICE_UNAVAILABLE` lands here too, with a `Retry-After` header: a dependency of BeeL itself (the database, the email provider) was momentarily unavailable and nothing was done. Retry after those seconds. 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.

---

[API](https://skmtc.dev/beel/apis/beel-public-api.md) · [All operations](https://skmtc.dev/beel/apis/beel-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/beel/apis/beel-public-api/revisions/ffbc0ae31f79?raw)
