Raw schema
{
"type": "object",
"properties": {
"company_id": {
"type": "string",
"format": "uuid",
"description": "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."
},
"wait_for_pdf": {
"type": "boolean",
"default": false,
"description": "Same flag as `options.wait_for_pdf`. Only applies when the invoice is issued in this\ncall (`options.issue_directly: true`).\n"
},
"body": {
"$ref": "#/$defs/CreateInvoiceRequest"
},
"idempotency_key": {
"type": "string",
"pattern": "^[a-zA-Z0-9_-]+$",
"maxLength": 255,
"description": "Optional idempotency key for this operation. Omit it and one is derived from the request itself, which makes a blind retry safe but also collapses a SECOND, deliberately identical operation into the first for 24 hours. Set it β to an order id, or anything unique per intended operation β whenever you mean to create something that may look identical to what you just created."
}
},
"required": [
"company_id",
"body"
],
"additionalProperties": false,
"$defs": {
"InvoiceType": {
"type": "string",
"enum": [
"STANDARD",
"CORRECTIVE",
"SIMPLIFIED",
"PROFORMA"
],
"description": "- STANDARD: Standard invoice\n- CORRECTIVE: Corrects or cancels a previous invoice\n- SIMPLIFIED: Simplified invoice without all recipient requirements (up to 3,000β¬ VAT included)\n- PROFORMA: Commercial document (formal quote) with no fiscal validity.\n Never enters VeriFactu (no QR, no AEAT submission) and `verifactu_enabled`\n is always forced to `false`. Requires full recipient data, like STANDARD.\n Cannot be corrective nor reference a rectified invoice.\n"
},
"AlternativeIdentifier": {
"type": [
"object",
"null"
],
"required": [
"type",
"number"
],
"description": "Alternative identifier for customers without Spanish Tax ID.\n\n### VeriFactu rules (enforced server-side, returns `422 ALTERNATIVE_ID_INVALID` on violation)\n- If `country_code = ES`, then `type` **must** be `PASSPORT` (03) or `NOT_REGISTERED` (07).\n- If `type = NOT_REGISTERED` (07), then `country_code` **must** be `ES`.\n\n### Matrix of allowed combinations\n| `type` | `country_code = ES` | `country_code β ES` |\n|------------------------|:-------------------:|:-------------------:|\n| `NIF_IVA` (02) | β | β |\n| `PASSPORT` (03) | β | β |\n| `COUNTRY_ID` (04) | β | β |\n| `RESIDENCE_CERTIFICATE` (05) | β | β |\n| `OTHER_DOCUMENT` (06) | β | β |\n| `NOT_REGISTERED` (07) | β | β |\n",
"properties": {
"type": {
"type": "string",
"enum": [
"NIF_IVA",
"PASSPORT",
"COUNTRY_ID",
"RESIDENCE_CERTIFICATE",
"OTHER_DOCUMENT",
"NOT_REGISTERED",
"02",
"03",
"04",
"05",
"06",
"07"
],
"description": "Identifier type. Use descriptive names:\n- **NIF_IVA**: VAT-ID (intra-community EU) β *not allowed when `country_code = ES`*\n- **PASSPORT**: Passport β *allowed for any country*\n- **COUNTRY_ID**: Country of residence ID β *not allowed when `country_code = ES`*\n- **RESIDENCE_CERTIFICATE**: Residence certificate β *not allowed when `country_code = ES`*\n- **OTHER_DOCUMENT**: Other supporting document β *not allowed when `country_code = ES`*\n- **NOT_REGISTERED**: Not registered in AEAT β *requires `country_code = ES`*\n\n**β οΈ DEPRECATED numeric codes** (will be removed in v2):\n02, 03, 04, 05, 06, 07 β use the descriptive names above instead.\n"
},
"number": {
"type": "string",
"minLength": 1,
"maxLength": 20
},
"country_code": {
"type": "string",
"pattern": "^[A-Z]{2}$",
"minLength": 2,
"maxLength": 2,
"description": "ISO 3166-1 alpha-2 country code. Constrains the allowed `type` values;\nsee the VeriFactu rules on the parent schema.\n"
}
}
},
"Address": {
"description": "Address you send when you create or update a company, a customer or an onboarding.\nThe street number is mandatory here: an address without it is rejected with `422`.\n\nAddresses you read back are described by their own schema, and do not guarantee the\nstreet number: records registered before it was collected have none.\n",
"type": "object",
"required": [
"street",
"number",
"postal_code",
"city",
"province"
],
"properties": {
"street": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"pattern": "^[a-zA-Z0-9Γ-ΓΏ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/'ΒΊΒͺΒ°:;\"()&#]+$",
"description": "Full address (street, number, floor, etc.) - Latin characters only"
},
"number": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"description": "Street number"
},
"floor": {
"type": "string",
"maxLength": 10,
"description": "Floor or level"
},
"door": {
"type": "string",
"maxLength": 10,
"description": "Door or apartment"
},
"postal_code": {
"type": "string",
"minLength": 1,
"maxLength": 20,
"description": "Postal code (5 digits for Spain, free format for other countries)"
},
"city": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"pattern": "^[a-zA-Z0-9Γ-ΓΏ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ΒΊΒͺ()]+$",
"description": "City or town - Latin characters only"
},
"province": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"pattern": "^[a-zA-Z0-9Γ-ΓΏ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ΒΊΒͺ]+$",
"description": "Province or state - Latin characters only"
},
"country": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"pattern": "^[a-zA-Z0-9Γ-ΓΏ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ΒΊΒͺ]+$",
"description": "Country - Latin characters only.\nOmitted, the address is stored as `EspaΓ±a`.\n"
},
"country_code": {
"type": "string",
"pattern": "^[A-Z]{2}$",
"minLength": 2,
"maxLength": 2,
"description": "ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n"
}
},
"additionalProperties": false
},
"Phone": {
"type": "string",
"minLength": 9,
"maxLength": 20,
"pattern": "^[+]?[0-9\\s\\-\\(\\)]+$",
"description": "Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +"
},
"Email": {
"type": "string",
"format": "email",
"minLength": 5,
"maxLength": 255,
"description": "Email address (minimum valid email is 5 chars, e.g. a@b.co)"
},
"Recipient": {
"type": "object",
"properties": {
"customer_id": {
"type": "string",
"format": "uuid",
"description": "UUID of a registered customer. If present, the invoice uses the customer's\nstored data and all other recipient fields are ignored.\n"
},
"legal_name": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Recipient legal name. Required when customer_id is not provided\n(except for SIMPLIFIED invoices where all fields are optional).\n"
},
"trade_name": {
"type": [
"string",
"null"
],
"minLength": 1,
"maxLength": 255,
"description": "Recipient trade name (optional)"
},
"nif": {
"type": "string",
"pattern": "^[A-Za-z0-9]{9}$",
"minLength": 9,
"maxLength": 9,
"description": "Spanish Tax ID (9 alphanumeric characters).\nRequired when customer_id is not provided and alternative_id is absent.\nAlways optional for SIMPLIFIED invoices (with or without NIF: limit 3,000β¬ VAT included).\n"
},
"alternative_id": {
"allOf": [
{
"$ref": "#/$defs/AlternativeIdentifier"
},
{
"description": "Alternative identifier for foreign customers (mutually exclusive with nif)"
}
]
},
"address": {
"$ref": "#/$defs/Address"
},
"phone": {
"$ref": "#/$defs/Phone"
},
"email": {
"$ref": "#/$defs/Email"
}
},
"additionalProperties": false
},
"TaxType": {
"type": "string",
"enum": [
"IVA",
"IGIC",
"IPSI",
"OTHER"
],
"description": "Tax type by territory:\n- IVA: Iberian Peninsula and Balearic Islands (4%, 5%, 10%, 21%)\n- IGIC: Canary Islands (0%, 3%, 5%, 7%, 9.5%, 15%, 20%)\n- IPSI: Ceuta and Melilla (0.5%, 1%, 2%, 4%, 8%, 10%)\n- OTHER: Configurable 0%-100%\n\nUnder IVA and IPSI, 0% is not one of these rates: it is the exemption/non-subject\nsentinel and always travels with an `exemption_reason`. IGIC's 0% is a real rate.\nSee `TaxInfo` for the full rules.\n"
},
"RegimeKey": {
"type": "string",
"enum": [
"01",
"02",
"03",
"04",
"05",
"06",
"07",
"08",
"09",
"10",
"11",
"14",
"15",
"17",
"18",
"19",
"20"
],
"description": "Regime key according to VeriFactu regulations. Omitted, `01` (general regime) applies:\n- 01: General regime operation\n- 02: Export\n- 03: Used goods, art, antiques\n- 04: Investment gold\n- 05: Travel agencies\n- 06: Group of entities\n- 07: Cash basis\n- 08: IPSI/IVA/IGIC operations\n- 09: Mediating agencies\n- 10: Third-party collections\n- 11: Local rental\n- 14: VAT pending in certifications\n- 15: VAT pending successive tract\n- 17: OSS and IOSS\n- 18: Equivalence surcharge\n- 19: REAGYP\n- 20: Simplified regime\n\n**One exception to \"a key you send is the key you get\":** when the line ends up\ncarrying an equivalence surcharge β whether you sent `equivalence_surcharge_rate`\nor it was inherited from the company's tax configuration β a `01` is rewritten to\n`18`, because a surcharge under the general regime is fiscally incoherent. Send\n`equivalence_surcharge_rate: 0` explicitly to keep `01`. See\n`equivalence_surcharge_rate` in the invoice line for the full rules.\n"
},
"TaxInfo": {
"type": "object",
"required": [
"type",
"percentage"
],
"properties": {
"type": {
"$ref": "#/$defs/TaxType"
},
"percentage": {
"type": "number",
"minimum": 0,
"maximum": 100,
"description": "Tax percentage"
},
"regime_key": {
"$ref": "#/$defs/RegimeKey"
}
},
"description": "Complete tax information with cross-validations:\n- IVA: real rates 4, 5, 10, 21 (see below for 0)\n- IGIC: 0, 3, 5, 7, 9.5, 15, 20 β here 0 is the real \"Tipo Cero\"\n- IPSI: real rates 0.5, 1, 2, 4, 8, 10 (see below for 0)\n- OTHER: any percentage between 0 and 100\n\n**0 % under IVA and IPSI is not a rate, it is the exemption sentinel.** It is accepted\non a line, but only together with an `exemption_reason` (exempt or non-subject\noperation); on its own it says nothing and the line is rejected. That is why\n`GET /v1/tax-types` publishes 4, 5, 10 and 21 for IVA and not 0: the legitimate way\nto a 0 % IVA line is through an exemption reason, which the same response also\npublishes. IGIC is different β its 0 % is a real legal rate (basic necessities) and\nneeds no reason.\n\n**IVA 5 %** (RD-ley 11/2022 and its extensions, on electricity, gas and basic\nfoodstuffs) is no longer in force for new operations, but it stays valid: corrective\ninvoices and late-filed invoices for the periods when it applied must be able to carry\nit. Its equivalence surcharge pair is 0.625.\n\nException: when regime_key = \"17\" (OSS/IOSS) the invoice applies the destination\ncountry VAT instead of the Spanish one, so any percentage in the EU range [0, 27]\nis accepted regardless of the tax type set β including 0 without an exemption reason.\n",
"additionalProperties": false
},
"EquivalenceSurchargePercentage": {
"type": "number",
"enum": [
0,
0.5,
0.625,
1.4,
5.2
],
"description": "Equivalence surcharge percentage in decimal format.\nPairs allowed (rate β recargo): 4β0.5, 5β0.625 (RD-ley 11/2022), 10β1.4, 21β5.2.\nThe backend automatically normalizes equivalent formats (5.20 β 5.2).\n"
},
"IrpfPercentage": {
"type": "integer",
"enum": [
0,
1,
2,
7,
15,
19,
24
],
"description": "Personal income tax/withholding percentage in integer format.\nAllowed values: 0 (exempt), 1 (agricultural/livestock/forestry), 2 (reduced for modules), 7, 15, 19, 24 (non-residents).\n"
},
"ExemptionReason": {
"type": "string",
"enum": [
"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_E",
"ISP_ART_84_2_F",
"REGIMEN_ART_129",
"REGIMEN_ART_135",
"REGIMEN_ART_141",
"REGIMEN_ART_154",
"REGIMEN_ART_163_DECIES",
"OTRO"
],
"description": "Tax exemption reason code per Spanish VAT Law (Ley 37/1992 LIVA).\nVeriFactu mapping: EXENTA_ART_20βE1, EXENTA_ART_21βE2, EXENTA_ART_22βE3,\nEXENTA_ART_24βE4, EXENTA_ART_25βE5, restβE6. ISPβS2, NO_SUJETAβN1/N2.\nWhen OTRO, a custom text must be provided in exemption_reason_text.\n"
},
"InvoiceLineType": {
"type": "string",
"description": "Fiscal line type. `NORMAL` contributes to the taxable base and VAT;\n`SUPLIDO` is a payment made on behalf of the client and is excluded from both.\n",
"enum": [
"NORMAL",
"SUPLIDO"
]
},
"PaymentMethod": {
"type": "string",
"description": "Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n",
"enum": [
"NONE",
"BANK_TRANSFER",
"CARD",
"CASH",
"CHECK",
"DIRECT_DEBIT",
"BIZUM",
"OTHER"
]
},
"IBAN": {
"type": "string",
"pattern": "^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$",
"minLength": 15,
"maxLength": 34,
"description": "IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n"
},
"SWIFT": {
"type": "string",
"pattern": "^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$",
"minLength": 8,
"maxLength": 11,
"description": "SWIFT/BIC code"
},
"PaymentInfo": {
"type": "object",
"properties": {
"method": {
"allOf": [
{
"$ref": "#/$defs/PaymentMethod"
}
],
"description": "Preferred payment method. Omitted, `BANK_TRANSFER` applies.\nIf NONE is selected, no payment information will be shown on the invoice.\n"
},
"iban": {
"$ref": "#/$defs/IBAN"
},
"swift": {
"$ref": "#/$defs/SWIFT"
},
"payment_term_days": {
"type": [
"integer",
"null"
],
"minimum": 0,
"maximum": 365,
"description": "Payment term in days. When marking an invoice as paid, every field of this object\nthat travels replaces the stored one and every omitted field keeps its current value.\n"
}
},
"additionalProperties": false
},
"ExternalRef": {
"type": "string",
"maxLength": 255,
"description": "Client-supplied identifier from an external system (order, cart, contractβ¦).\nStored as-is, echoed back on read, and filterable via GET /v1/invoices?external_ref=.\nOptional. Enforced UNIQUE per issuer for live standard/simplified invoices:\ncreating a second invoice with the same reference returns 409\n(INVOICE_DUPLICATE_EXTERNAL_REFERENCE); deleting the existing one lets you recreate.\nCorrective invoices are exempt from that uniqueness: a corrective carries the same\norder reference as the invoice it corrects, so both can coexist.\nThis is a business key, NOT the Idempotency-Key (which guards request retries).\n"
},
"InvoiceMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Your own key/value pairs to cross-reference this invoice with records in\nyour system (order ids, tenants, internal codes). Namespace them to avoid\nclashing with the system keys BeeL adds on payment-generated invoices.\n"
},
"EmailConfiguration": {
"type": "object",
"required": [
"recipients"
],
"properties": {
"recipients": {
"type": "array",
"items": {
"$ref": "#/$defs/Email"
},
"minItems": 1,
"description": "List of recipient emails (at least 1 required)"
},
"cc": {
"type": "array",
"items": {
"$ref": "#/$defs/Email"
},
"description": "List of CC emails (optional)"
},
"subject": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "Custom email subject (optional, if not specified uses a default)"
},
"message": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "Custom message (optional, added to email body)"
}
},
"additionalProperties": false
},
"InvoiceProcessingOptions": {
"type": "object",
"description": "Controls how the invoice is processed after creation.\nAll fields default to `false` if not specified, **except `verifactu_enabled`**,\nwhich falls back to the company's declared preference (see its description).\n\n**Common combinations:**\n- Draft (default): omit `options` or set all to `false`\n- Issue immediately: `{ issue_directly: true }`\n- Issue + wait for PDF: `{ issue_directly: true, wait_for_pdf: true }`\n- Issue + send email: `{ issue_directly: true, send_automatically: true }`\n- Full automation: `{ issue_directly: true, wait_for_pdf: true, send_automatically: true, email_config: { ... } }`\n",
"properties": {
"verifactu_enabled": {
"type": "boolean",
"description": "Whether VeriFactu information should be generated for this invoice.\n\n**If omitted, the company's declared preference applies** (the\n\"apply VeriFactu by default\" setting, `apply_by_default`). If the company\nhas no VeriFactu configuration, it resolves to `false`.\nSend the field explicitly (`true` or `false`) to override the preference.\n\nA `PROFORMA` always forces `false`, whatever the preference or the value sent.\n"
},
"issue_directly": {
"type": "boolean",
"default": false,
"description": "If `true`, creates the invoice directly as **ISSUED** with a definitive number and PDF.\nIf `false` (default), creates as **DRAFT** without number (editable, no PDF).\n"
},
"wait_for_pdf": {
"type": "boolean",
"default": false,
"description": "Only applies when `issue_directly` is `true`.\nIf `true`, waits for PDF generation before returning the response (~1-3s).\nIf `false` (default), PDF is generated asynchronously in the background.\n"
},
"send_automatically": {
"type": "boolean",
"default": false,
"description": "Only applies when `issue_directly` is `true`.\nIf `true`, sends the invoice by email with PDF attachment after issuing.\nThe email is sent asynchronously after the invoice is issued.\n"
},
"attach_source_invoices": {
"type": "boolean",
"default": false,
"description": "Only applies when `send_automatically` is `true`. If `true`, the email sent after\nissuing also attaches a ZIP (`suplidos_<invoice-number>.zip`) with the PDFs of the\nsource invoices referenced by the invoice's SUPLIDO consolidation lines\n(`source_invoice_ids`). Each PDF inside the ZIP is named\n`<invoice-number>_<issuer-tax-id>.pdf`. Access to sources owned by managed accounts is\nre-checked with the same rules as issuing, and the request fails synchronously with an\nactionable error β never a partial ZIP β if the invoice has no consolidation sources\n(`ATTACH_SOURCE_INVOICES_NO_SOURCES`), a source is not reachable\n(`ATTACH_SOURCE_INVOICE_UNAVAILABLE`) or a source has no generated PDF\n(`ATTACH_SOURCE_PDF_MISSING`). The flag belongs to this issuing act only: it is never\nstored on the invoice.\n"
},
"email_config": {
"allOf": [
{
"$ref": "#/$defs/EmailConfiguration"
}
],
"description": "Only applies when `send_automatically` is `true`.\nOverrides default email settings. If not provided, uses the recipient's email.\n"
}
},
"additionalProperties": false
},
"CreateInvoiceRequest": {
"type": "object",
"required": [
"type",
"recipient",
"lines"
],
"properties": {
"type": {
"allOf": [
{
"$ref": "#/$defs/InvoiceType"
}
],
"description": "Invoice type to create. `CORRECTIVE` is **not** accepted here: a corrective\ninvoice is always created from the invoice it corrects, via\n`POST /v1/companies/{company_id}/invoices/{invoice_id}/corrective`, which is\nwhere its rectification type and VeriFactu code (R1βR5) are declared.\n"
},
"series_id": {
"type": "string",
"format": "uuid",
"description": "Invoicing series ID (if not specified, uses default)"
},
"operation_date": {
"type": "string",
"format": "date",
"description": "Date when the operation actually occurred. Optional.\n\nUse when invoicing for a past operation (e.g., services delivered last month\nbut invoiced this month). **Must be today or a past date.**\n\nIf omitted, the operation date is assumed to be the same as the issue date (today).\n\nThe `issue_date` is always set automatically to today per Spanish anti-fraud law\n(Ley Antifraude / VeriFactu). To issue an invoice on a future date, create a\ndraft and use `POST /v1/invoices/{invoice_id}/schedule`.\n"
},
"due_date": {
"type": "string",
"format": "date",
"description": "Payment due date. If not specified, calculated according to payment method.\n**Must be the same as or after the issue date (today).**\n"
},
"valid_until": {
"type": "string",
"format": "date",
"description": "Offer validity date. Only rendered on PROFORMA invoices; on any other\ninvoice type the field is inert (accepted and stored, but never shown on\nthe document). Optional and purely informational β nothing is triggered\nautomatically when it passes. Not to be confused with `due_date` (payment\ndue date).\n"
},
"recipient": {
"$ref": "#/$defs/Recipient"
},
"lines": {
"type": "array",
"items": {
"type": "object",
"required": [
"quantity"
],
"properties": {
"description": {
"type": "string",
"maxLength": 2000,
"description": "Description of invoiced concept. Required for NORMAL lines;\noptional for SUPLIDO lines (may be empty or absent).\n"
},
"quantity": {
"type": "number",
"description": "Product/service quantity (can be negative for franchises or discounts)"
},
"unit": {
"type": "string"
},
"unit_price": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 999999.9999,
"description": "Unit price before taxes.\nSupports up to 4 decimal places for micro-pricing (e.g., β¬0.0897/unit for labels, packaging).\n"
},
"total_excluding_tax": {
"type": "number",
"maximum": 99999999.99,
"description": "Declared line total excluding taxes (total-declared mode, e.g. 300 units\ninvoiced for exactly 1.00). The taxable base of the line is EXACTLY this\namount β it is never recalculated from the unit price. The unit price\nbecomes derived and informational (`total / quantity`, 4 decimals).\nEach line must carry exactly one of `unit_price`, `total_excluding_tax`\nor `total_including_tax` (anything else is rejected with\n`LINE_UNIT_PRICE_XOR_DECLARED_TOTAL`). Incompatible with\n`discount_percentage` (`LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT`): any\ndiscount is already included in the declared total. Can be negative\nin corrective invoices.\n"
},
"total_including_tax": {
"type": "number",
"maximum": 99999999.99,
"description": "Declared line total including taxes (tax-inclusive total-declared\nmode): what the customer paid for this line β taxable base + VAT +\nequivalence surcharge. IRPF withholding is NOT part of it (it is a\nretention, not price; it is computed on the derived base as usual).\nThe engine works the breakdown backwards from the unrounded base\n(`base_raw = total / (1 + vat + surcharge)`, DGT V1919-18) so the\nrounded amounts add up to the declared total exactly (e.g. 100.00\nat 21% β 82.64 + 17.36 = 100.00). On exempt or 0% lines it is\nequivalent to `total_excluding_tax` (base = total, quota 0).\nEach line must carry exactly one of `unit_price`, `total_excluding_tax`\nor `total_including_tax` (anything else is rejected with\n`LINE_UNIT_PRICE_XOR_DECLARED_TOTAL`). Incompatible with\n`discount_percentage` (`LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT`).\nCan be negative in corrective invoices.\n"
},
"discount_percentage": {
"type": "number",
"minimum": 0,
"maximum": 100,
"default": 0,
"description": "Discount percentage applied (0-100)"
},
"main_tax": {
"allOf": [
{
"$ref": "#/$defs/TaxInfo"
}
],
"description": "Main tax of the line: regime (IVA/IGIC/IPSI/OTHER), percentage and regime key.\n\n**Mandatory on `NORMAL` lines.** It is never defaulted: omitting it is rejected\nwith `422 LINE_MAIN_TAX_REQUIRED`, and is never filled in from the company's\n`default_main_tax` β that setting is a UI prefill, not an API default, because\nwhich tax a line bears is a fiscal decision that drives the VeriFactu breakdown\nand therefore the legal validity of the document.\n\n**Forbidden on `SUPLIDO` lines**, which are payments made on behalf of the\nclient and sit outside VAT (art. 78.Tres.3 LIVA): sending one is rejected with\n`422 LINE_SUPLIDO_MUST_HAVE_NO_TAX`. That conditional obligation is why the\nfield is not listed under `required`: OpenAPI 3.0 cannot express \"required\nunless `line_type` is `SUPLIDO`\".\n\nA 0 % under IVA or IPSI is not a rate but the exemption sentinel and needs an\n`exemption_reason`; see `TaxInfo`.\n"
},
"equivalence_surcharge_rate": {
"allOf": [
{
"$ref": "#/$defs/EquivalenceSurchargePercentage"
}
],
"description": "Equivalence surcharge rate for this line.\n\n**Default behaviour:** if omitted and the company has\n`apply_equivalence_surcharge: true` in its tax configuration,\nthe line inherits the surcharge β and its percentage is a legal\nfunction of the line's VAT rate, not the configured default:\n21 β 5.2, 10 β 1.4, 5 β 0.625, 4 β 0.5 (the pairs enumerated by\n`EquivalenceSurchargePercentage`). A company configured with\n`default_equivalence_surcharge: 5.2` therefore produces 1.4 on a\n10% line, not 5.2.\n\n**The inheritance also rewrites the line's `regime_key` from `01`\nto `18`** (special regime for equivalence surcharge). This is\ndeliberate: a surcharge and general regime `01` are fiscally\nincoherent, so the line comes back as `18` even if `01` was sent.\n\nTo issue a line **without** surcharge under such a company, send\n`equivalence_surcharge_rate: 0` explicitly β exactly as with\n`irpf_rate`: the `01` regime key is then respected and no\nsurcharge is applied. Sending an explicit rate greater than 0\ntogether with `regime_key: \"01\"` is **not** rejected: the very\nsame rewrite applies and the line comes back as `18`.\n\n**Any other regime with a surcharge is rejected** with\n`422 SURCHARGE_REQUIRES_REGIME`. Only the general regime `01`\n**rewrites**; REBU (`03`), exports (`02`), OSS (`17`)β¦ never do,\nbecause a surcharge under them is fiscally invalid β an error to\nsurface, not a shorthand to normalise.\n"
},
"irpf_rate": {
"allOf": [
{
"$ref": "#/$defs/IrpfPercentage"
}
],
"description": "IRPF withholding rate for this line.\n\n**Default behaviour:** if omitted, the line inherits the\naccount's default IRPF rate (configured in the tax profile,\ne.g. 15%). To issue a line **without** withholding you must\nsend `irpf_rate: 0` explicitly. On SIMPLIFIED invoices (F2)\nIRPF withholding is **not allowed** (AEAT forbids it on F2):\nsending an `irpf_rate` other than 0 is **rejected** with\n`SIMPLIFICADA_FORBIDS_IRPF` β it is not coerced to 0. Omit the\nfield or send `irpf_rate: 0` on F2 lines. On all other invoice\ntypes an explicit value is always respected.\n"
},
"exemption_reason": {
"anyOf": [
{
"$ref": "#/$defs/ExemptionReason"
},
{
"type": "null"
}
]
},
"exemption_reason_text": {
"type": [
"string",
"null"
],
"maxLength": 500,
"description": "Custom exemption text. Only used when exemption_reason is OTRO."
},
"line_type": {
"allOf": [
{
"$ref": "#/$defs/InvoiceLineType"
}
],
"default": "NORMAL",
"description": "Fiscal line type. Defaults to `NORMAL`.\nUse `SUPLIDO` for payments on behalf of the final client\n(art. 78.Tres.3 LIVA). Requires `source_invoice_reference`.\n"
},
"source_invoice_reference": {
"type": [
"string",
"null"
],
"maxLength": 50,
"description": "Reference to the original invoice issued by the third party in the\nclient's name. Required when `line_type=SUPLIDO`.\n"
},
"source_invoice_ids": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"description": "Ids of the issued invoices that make up the SUPLIDO. They may belong to the\nissuing account or to accounts it manages with VIEW access.\nTheir sum is the amount (never typed). Audit traceability.\n"
}
},
"additionalProperties": false
},
"minItems": 1
},
"payment_info": {
"$ref": "#/$defs/PaymentInfo"
},
"notes": {
"type": "string",
"maxLength": 1000
},
"external_ref": {
"allOf": [
{
"$ref": "#/$defs/ExternalRef"
}
],
"x-field-extra-annotation": "@com.fasterxml.jackson.annotation.JsonAlias(\"external_reference\")",
"description": "This field was previously named `external_reference`. The old name is still accepted as\nan alias for backwards compatibility and will be withdrawn in a future major version β\nsend `external_ref`.\n"
},
"metadata": {
"$ref": "#/$defs/InvoiceMetadata"
},
"options": {
"$ref": "#/$defs/InvoiceProcessingOptions"
}
},
"additionalProperties": false
}
}
}