BeeL
Ce que fait ce MCP
Provides Spanish company administration and VeriFactu-compliant invoicing, including customers, products, invoice issuance, corrections, delivery, and tax validation.
Outils
Schéma d’entrée
{'type': 'object', '$defs': {'Environment': {'enum': ['TEST', 'PROD'], 'type': 'string', 'description': 'Mode a record lives in — its Test/Live twin. It decides where invoices, customers and\nquota are accounted.\n\nFor a company it also decides which AEAT its NIF is registered against: switching a\ncompany on in `PROD` is what registers it with the real AEAT, so `aeat_environment`\nis that same mode and uses this same enum.\n'}, 'ActivateCompanyRequest': {'type': 'object', 'required': ['environment'], 'properties': {'cancel_url': {'type': 'string', 'format': 'uri', 'description': 'Where Stripe returns if the checkout is abandoned.'}, 'environment': {'$ref': '#/$defs/Environment'}, 'success_url': {'type': 'string', 'description': "Where Stripe returns after the card is captured. Only used when switching on in Live with no card on file. May embed Stripe's `{CHECKOUT_SESSION_ID}` template, which is why it is a plain string and not a `uri`: the braces are not legal URI characters."}}, 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/ActivateCompanyRequest'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company being switched 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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'AccessLevel': {'enum': ['NONE', 'VIEW', 'OPERATE'], 'type': 'string', 'description': "How much access an actor has to an account or a company. The same three values are used everywhere access is granted or reported — whether the actor is a member of the account or a provisioner managing it on someone's behalf.\n\n`NONE` — no access to the data.\n`VIEW` — read invoices, customers, products, series and fiscal data.\n`OPERATE` — everything in `VIEW`, plus creating and editing them. Issuing invoices for an account you manage additionally requires a signed fiscal representation from the account holder (see `/v1/accounts/{account_id}/companies/{company_id}/representation`).\n\nAccess level never affects billing: whoever provisioned an account pays for its subscription regardless of the level they keep over it."}, 'ChangeAccessLevelRequest': {'type': 'object', 'required': ['access_level'], 'properties': {'access_level': {'$ref': '#/$defs/AccessLevel'}}, 'description': 'Updates the access you hold over an account you provisioned.', 'additionalProperties': False}}, 'required': ['account_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/ChangeAccessLevelRequest'}, 'account_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'ConvertProformaToInvoiceRequest': {'type': 'object', 'properties': {'issue': {'type': 'boolean', 'default': False, 'description': 'If `true`, emit the resulting invoice atomically in the same act\n(assigns a fiscal number and runs the quota/ledger/VeriFactu→PDF flow).\nIf `false` or omitted, the invoice is left in `DRAFT`.\n'}, 'verifactu_enabled': {'type': 'boolean', 'description': 'Whether the resulting invoice generates VeriFactu information.\n\n**If omitted, the company\'s declared preference applies** (the "apply VeriFactu by\ndefault" setting, `apply_by_default`) — the same resolution used when creating an\ninvoice. Send the field explicitly (`true` or `false`) to override it.\n\nThe proforma itself never carries VeriFactu, so it has no preference to pass on: the\ninvoice born from the conversion is a new fiscal document and follows the company\'s\npolicy, exactly like one created from scratch.\n\nThis matters most with `issue: true`, where there is no draft left to edit before\nthe invoice reaches AEAT.\n'}}, 'additionalProperties': False}}, 'required': ['company_id', 'invoice_id'], 'properties': {'body': {'$ref': '#/$defs/ConvertProformaToInvoiceRequest'}, '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'Language': {'enum': ['es', 'en', 'ca'], 'type': 'string', 'description': 'Supported languages'}, 'CreateClaimTokenRequest': {'type': 'object', 'properties': {'email': {'type': 'string', 'format': 'email', 'description': "The holder's email address, used as their login. **Required when the account has no holder** (else `422`). If the account already has one, it must match theirs — a different address returns `409 CLAIM_TOKEN_HOLDER_MISMATCH` rather than silently replacing the holder."}, 'language': {'allOf': [{'$ref': '#/$defs/Language'}], 'description': 'Preferred language for a holder created by this call. Defaults to `es`. Ignored when the account already has a holder.'}}, 'description': 'Optional body for issuing a claim token. Send `email` when the account has **no holder yet** (it was provisioned without one): the person is created at that point. Omit the body entirely to re-issue the token for the holder the account already has.', 'additionalProperties': False}}, 'required': ['account_id'], 'properties': {'body': {'$ref': '#/$defs/CreateClaimTokenRequest'}, 'account_id': {'type': 'string', 'format': 'uuid'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, 'EntityType': {'enum': ['INDIVIDUAL', 'LEGAL_ENTITY'], 'type': 'string', 'description': 'Taxpayer type.\nINDIVIDUAL: Natural person (individual self-employed).\nLEGAL_ENTITY: Legal entity (company with legal form: SL, SA, etc.).\n'}, 'SeriesCode': {'type': 'string', 'pattern': '^[A-Z0-9\\-_]{1,50}$', 'maxLength': 50, 'minLength': 1, 'description': 'Alphanumeric series code (used in {CODIGO} variable).\nAllows uppercase letters, numbers, hyphens and underscores.\n'}, 'Environment': {'enum': ['TEST', 'PROD'], 'type': 'string', 'description': 'Mode a record lives in — its Test/Live twin. It decides where invoices, customers and\nquota are accounted.\n\nFor a company it also decides which AEAT its NIF is registered against: switching a\ncompany on in `PROD` is what registers it with the real AEAT, so `aeat_environment`\nis that same mode and uses this same enum.\n'}, 'CounterReset': {'enum': ['NEVER', 'ANNUAL', 'MONTHLY'], 'type': 'string', 'description': 'Counter reset policy:\n- NEVER: Counter never resets (continuous numbering)\n- ANNUAL: Counter resets yearly\n- MONTHLY: Counter resets monthly\n'}, 'SeriesFormat': {'type': 'string', 'pattern': '^[A-Z0-9\\-_/{}:]*$', 'maxLength': 255, 'minLength': 1, 'description': 'Format template with available variables (UPPERCASE ONLY):\n- {CODIGO}: Series code (e.g., "FAC")\n- {YYYY}: Year with 4 digits (e.g., "2025")\n- {YY}: Year with 2 digits (e.g., "25")\n- {MM}: Month with 2 digits (e.g., "01")\n- {NUM}: Sequential number without padding (e.g., "1")\n- {NUM:X}: Sequential number with padding (e.g., {NUM:4} → "0001")\n\n**REQUIRED**: Must contain at least {NUM} or {NUM:X}\n**IMPORTANT**: Only uppercase (rejects {yy}, {mm}, {codigo}, etc.)\n\nValid examples:\n- "{CODIGO}-{YYYY}-{NUM:4}" → "FAC-2025-0001"\n- "{CODIGO}/{NUM:6}" → "FAC/000001"\n- "{YYYY}{MM}-{NUM:3}" → "202501-001"\n'}, 'CompanyNumbering': {'type': 'object', 'properties': {'code': {'$ref': '#/$defs/SeriesCode'}, 'format': {'allOf': [{'$ref': '#/$defs/SeriesFormat'}], 'description': "Format template the ordinary series' invoice numbers are printed with\n(`{CODIGO}`, `{YYYY}`/`{YY}`, `{MM}`, `{NUM}`/`{NUM:X}` — must contain `{NUM}`\nor `{NUM:X}`). Defaults to `{CODIGO}-{YYYY}-{NUM:4}` when omitted.\n"}, 'corrective': {'$ref': '#/$defs/CompanySeriesNumbering'}, 'simplified': {'$ref': '#/$defs/CompanySeriesNumbering'}, 'counter_reset': {'allOf': [{'$ref': '#/$defs/CounterReset'}], 'description': "When the ordinary series' counter resets (`NEVER`/`ANNUAL`/`MONTHLY`).\nDefaults to `ANNUAL` when omitted — so a custom `format` without a year token\nmust come with `counter_reset: NEVER`.\n"}, 'initial_number': {'type': 'integer', 'format': 'int64', 'maximum': 999999, 'minimum': 1, 'description': 'Number the ordinary series counter starts at. If the last invoice issued\nelsewhere was `2026-0150`, send `151`. Defaults to 1 when omitted.\n'}}, 'description': 'Configuration of the invoice series the company is born with. Optional and additive:\nomit it — or any field — and the system default applies for that field: series\n`F`/`S`/`R`, format `{CODIGO}-{YYYY}-{NUM:4}`, `ANNUAL` counter reset, starting at 1,\nexactly as before.\n\nSend it when the business already issued invoices with another system this year and\nwants to **continue** its numbering, or simply wants its series born with a specific\nshape — this is the only moment it can be expressed in the same call. Once a series\nissues its first invoice its numbering is frozen by law: `PATCH\n/v1/companies/{company_id}/series/{series_id}` then rejects `initial_number` with\n`SERIES_INITIAL_NUMBER_LOCKED_HAS_INVOICES`.\n\nIt covers the **three** series a company is born with:\n\n* the **ordinary** one (real invoices) — the fields at this level, default `F`.\n* the **simplified** one (ticket-style invoices) — `simplified`, default `S`.\n* the **corrective** one (rectificativas) — `corrective`, default `R`.\n\nEach series takes `code`, `initial_number`, `format` and `counter_reset`, all\noptional and independent: omit a field and that series keeps the system default\nfor it.\n\n`format` and `counter_reset` must be able to tell reset periods apart, with the\nsame rules and error codes as `POST /v1/companies/{company_id}/series`: a `MONTHLY` reset\nrequires `{MM}` plus a year token in the format\n(`SERIES_MONTHLY_REQUIRES_MONTH_AND_YEAR`); an `ANNUAL` reset requires a year token\n(`SERIES_ANNUAL_REQUIRES_YEAR`). Mind the default reset is `ANNUAL`: a format\nwithout a year token (e.g. `{CODIGO}-{NUM:6}`) also needs `counter_reset: NEVER`\nin the same series block.\n\nThe list of series is **not** negotiable — a company always starts with exactly\nthese three, one default per document type, because a company without a default\nseries cannot issue at all (`NO_DEFAULT_SERIES`). You configure how each of them is\nborn, not which ones exist. More series can be added later with\n`POST /v1/companies/{company_id}/series`.\n\n**Per environment**: each activation is self-contained and seeds exactly what its\nrequest carries. Activating the same NIF in the other environment later does **not**\ncopy this configuration — repeat your `numbering` block in that activation call if\nyou want the same series there; without it the other environment gets the system\ndefaults.\n\nOnly valid when the request activates the company: with `activate: false` no series\nare seeded, so a `numbering` block that asks for anything is rejected with `422`\n`NUMBERING_REQUIRES_ACTIVATION` instead of being silently discarded.\n', 'additionalProperties': False}, 'LegalRepresentative': {'type': 'object', 'required': ['full_name', 'nif', 'address'], 'properties': {'nif': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Tax ID of the legal representative (DNI/CIF/NIE)'}, 'address': {'allOf': [{'$ref': '#/$defs/Address'}, {'description': 'Address of the legal representative'}]}, 'full_name': {'type': 'string', 'maxLength': 255, 'minLength': 1, 'description': 'Full name of the legal representative'}}, 'description': 'Legal representative data for a legal entity.\nOnly used when entity_type = LEGAL_ENTITY.\n', 'additionalProperties': False}, 'CreateCompanyRequest': {'type': 'object', 'required': ['nif', 'legal_name', 'entity_type', 'address'], 'properties': {'nif': {'type': 'string', 'description': 'NIF/CIF of the business'}, 'address': {'$ref': '#/$defs/Address'}, 'activate': {'type': 'boolean', 'default': True, 'description': 'Whether to **switch the company on** in `aeat_environment` as part of this call.\n\nCreating a company and activating it are two different acts. The company record is free\nand always creatable; the activation is what seeds the invoice series, registers the\nNIF and — in `PROD` — is what gets billed.\n\n* `true` (default) — unchanged behaviour: the company is created and switched on in\n `aeat_environment`, with its default series seeded there.\n* `false` — only the company record is created. It is switched on nowhere, has\n no series and cannot issue yet; `aeat_environment` is ignored. Activate it later\n with `POST /v1/companies/{company_id}/activations`, which is also\n the only door that opens a Stripe Checkout when the account has no card on file.\n\nSeries numbering travels with the activation that seeds it: a request with\n`activate: false` and a `numbering` block that asks for anything is rejected with\n`422` `NUMBERING_REQUIRES_ACTIVATION` — the later activation door does not accept\nnumbering, so silently accepting it here would discard it forever. Either drop the\n`numbering` block or activate a mode in the same call.\n'}, 'numbering': {'$ref': '#/$defs/CompanyNumbering'}, 'legal_form': {'type': 'string', 'description': 'Legal form (SL, SA, ...). Recommended for LEGAL_ENTITY.'}, 'legal_name': {'type': 'string', 'description': 'Legal/fiscal name'}, 'trade_name': {'type': 'string', 'description': 'Commercial/trade name (optional)'}, 'entity_type': {'$ref': '#/$defs/EntityType'}, 'aeat_environment': {'allOf': [{'$ref': '#/$defs/Environment'}], 'default': 'TEST', 'description': 'AEAT/VeriFactu environment to register this NIF against.\n* `TEST` — Sandbox NIF, invoices reach VeriFactu test (default).\n* `PROD` — Production NIF; requires the AEAT representation\n model to be signed (`POST /v1/companies/{company_id}/representation/submit`)\n before real invoices can be issued.\n\nThis field was previously named `environment`. The old name is still accepted as an\nalias for backwards compatibility and will be withdrawn in a future major version —\nsend `aeat_environment`.\n', 'x-field-extra-annotation': '@com.fasterxml.jackson.annotation.JsonAlias("environment")'}, 'default_main_tax': {'$ref': '#/$defs/TaxInfo'}, 'default_irpf_rate': {'type': 'number', 'maximum': 100, 'minimum': 0, 'description': "Default IRPF retention rate for this company's invoices. Omit it and the company is created with no withholding — BeeL never assumes a rate nobody declared."}, 'legal_representative': {'$ref': '#/$defs/LegalRepresentative'}}, 'additionalProperties': False}, 'CompanySeriesNumbering': {'type': 'object', 'properties': {'code': {'$ref': '#/$defs/SeriesCode'}, 'format': {'allOf': [{'$ref': '#/$defs/SeriesFormat'}], 'description': "Format template this series' invoice numbers are printed with. Defaults to\n`{CODIGO}-{YYYY}-{NUM:4}` when omitted.\n"}, 'counter_reset': {'allOf': [{'$ref': '#/$defs/CounterReset'}], 'description': "When this series' counter resets (`NEVER`/`ANNUAL`/`MONTHLY`). Defaults to\n`ANNUAL` when omitted — so a custom `format` without a year token must come\nwith `counter_reset: NEVER`.\n"}, 'initial_number': {'type': 'integer', 'format': 'int64', 'maximum': 999999, 'minimum': 1, 'description': "Number this series' counter starts at, to continue the numbering already used\nelsewhere. Defaults to 1 when omitted.\n"}}, 'description': 'How one of the series the company is born with should be seeded. All fields are\noptional and independent: omit one and it falls back to the system default. Same\nformat/reset compatibility rules and error codes as the parent block.\n', 'additionalProperties': False}}, 'required': ['account_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateCompanyRequest'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, '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'}, 'IrpfPercentage': {'enum': [0, 1, 2, 7, 15, 19, 24], 'type': 'integer', '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': {'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'], 'type': 'string', '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'}, 'InvoiceMetadata': {'type': 'object', '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', 'additionalProperties': True}, 'RectificationType': {'enum': ['TOTAL', 'PARTIAL'], 'type': 'string', 'description': 'Type of rectification applied to a corrective invoice:\n- TOTAL: Completely cancels the original invoice (status → VOIDED)\n- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)\n'}, 'EmailConfiguration': {'type': 'object', 'required': ['recipients'], 'properties': {'cc': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'description': 'List of CC emails (optional)'}, 'message': {'type': 'string', 'maxLength': 2000, 'minLength': 1, 'description': 'Custom message (optional, added to email body)'}, 'subject': {'type': 'string', 'maxLength': 200, 'minLength': 1, 'description': 'Custom email subject (optional, if not specified uses a default)'}, 'recipients': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'minItems': 1, 'description': 'List of recipient emails (at least 1 required)'}}, 'additionalProperties': False}, 'InvoiceProcessingOptions': {'type': 'object', 'properties': {'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"}, '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'}, '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'}, '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'}, '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"}}, '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", 'additionalProperties': False}, 'VeriFactuRectificationCode': {'enum': ['R1', 'R2', 'R3', 'R4', 'R5'], 'type': 'string', 'description': 'Rectification codes according to VeriFactu regulations (AEAT):\n- R1: Error founded in law and Art. 80 One, Two and Six LIVA\n- R2: Article 80 Three LIVA (Bankruptcy proceedings)\n- R3: Article 80 Four LIVA (Uncollectable debts)\n- R4: Other causes\n- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices\n'}, 'CreateCorrectiveInvoiceRequest': {'type': 'object', 'required': ['rectification_type', 'rectification_code', 'reason'], 'properties': {'lines': {'type': 'array', 'items': {'type': 'object', 'required': ['quantity'], 'properties': {'unit': {'type': 'string'}, 'main_tax': {'$ref': '#/$defs/TaxInfo'}, 'quantity': {'type': 'number', 'description': 'Quantity (can be negative for corrective invoices)'}, '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"}, 'unit_price': {'type': 'number', 'maximum': 999999.9999, 'description': 'Unit price before taxes (can be negative in corrective invoices).\nSupports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).\nFinal amounts are always rounded to 2 decimals.\n'}, 'description': {'type': 'string', 'maxLength': 2000, 'description': 'Concept description. Required for NORMAL lines; optional for\nSUPLIDO lines.\n'}, 'exemption_reason': {'anyOf': [{'$ref': '#/$defs/ExemptionReason'}, {'type': 'null'}]}, 'discount_percentage': {'type': 'number', 'default': 0, 'maximum': 100, 'minimum': 0}, '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'}, 'exemption_reason_text': {'type': ['string', 'null'], 'maxLength': 500}, 'equivalence_surcharge_rate': {'$ref': '#/$defs/EquivalenceSurchargePercentage'}}, 'additionalProperties': False}, 'description': '**TOTAL**: Optional (if not sent, original invoice lines are copied negated)\n**PARTIAL**: REQUIRED (adjustment lines with positive or negative amounts)\n'}, 'notes': {'type': 'string', 'maxLength': 1000, 'description': 'Additional observations about the rectification'}, 'reason': {'type': 'string', 'maxLength': 1000, 'minLength': 10, 'description': 'Detailed reason for rectification (minimum 10 characters)'}, 'options': {'$ref': '#/$defs/InvoiceProcessingOptions'}, 'metadata': {'$ref': '#/$defs/InvoiceMetadata'}, 'series_id': {'type': 'string', 'format': 'uuid', 'description': "Series for the corrective invoice. Optional: if not specified, the company's\n**default series for corrective invoices** is used — not the original invoice's\nseries, which is an ordinary or simplified one and cannot hold a corrective.\nIf the company has no default corrective series the request fails with\n`422 SERIES_DEFAULT_NOT_FOUND`; a series of the wrong type fails with\n`422 SERIES_INCOMPATIBLE_DOC_TYPE`.\n"}, 'external_ref': {'$ref': '#/$defs/ExternalRef'}, 'rectification_code': {'$ref': '#/$defs/VeriFactuRectificationCode'}, 'rectification_type': {'$ref': '#/$defs/RectificationType'}}, 'additionalProperties': False}, 'EquivalenceSurchargePercentage': {'enum': [0, 0.5, 0.625, 1.4, 5.2], 'type': 'number', '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'}}, 'required': ['company_id', 'invoice_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateCorrectiveInvoiceRequest'}, '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'NIF': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Spanish Tax ID (9 characters, uppercase only). Structural validation:\n- DNI: 8 digits + 1 letter (e.g., 12345678A)\n- NIE: X/Y/Z + 7 digits + 1 letter (e.g., X1234567A)\n- CIF: Organization letter + 7 digits + 1 control digit/letter (e.g., B12345674)\n'}, 'IBAN': {'type': 'string', 'pattern': '^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$', 'maxLength': 34, 'minLength': 15, 'description': 'IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Phone': {'type': 'string', 'pattern': '^[+]?[0-9\\s\\-\\(\\)]+$', 'maxLength': 20, 'minLength': 9, 'description': 'Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +'}, 'SWIFT': {'type': 'string', 'pattern': '^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$', 'maxLength': 11, 'minLength': 8, 'description': 'SWIFT/BIC code'}, 'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'PaymentInfo': {'type': 'object', 'properties': {'iban': {'$ref': '#/$defs/IBAN'}, 'swift': {'$ref': '#/$defs/SWIFT'}, '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'}, 'payment_term_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, '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}, 'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'AlternativeIdentifier': {'type': ['object', 'null'], 'required': ['type', 'number'], 'properties': {'type': {'enum': ['NIF_IVA', 'PASSPORT', 'COUNTRY_ID', 'RESIDENCE_CERTIFICATE', 'OTHER_DOCUMENT', 'NOT_REGISTERED', '02', '03', '04', '05', '06', '07'], 'type': 'string', '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', 'maxLength': 20, 'minLength': 1}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code. Constrains the allowed `type` values;\nsee the VeriFactu rules on the parent schema.\n'}}, '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'}, 'CreateCustomerRequest': {'type': 'object', 'required': ['legal_name', 'address'], 'properties': {'nif': {'allOf': [{'$ref': '#/$defs/NIF'}], 'description': 'Spanish Tax ID (required if id_otro is not provided)'}, 'email': {'type': ['string', 'null'], 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'notes': {'type': ['string', 'null'], 'description': 'Additional notes about the customer (optional)'}, 'phone': {'$ref': '#/$defs/Phone'}, 'address': {'$ref': '#/$defs/Address'}, 'website': {'type': ['string', 'null'], 'pattern': '^(https?://.+|)$', 'maxLength': 255, 'description': 'Website URL'}, 'legal_name': {'type': 'string', 'pattern': '^\\S.*$', 'maxLength': 120, 'minLength': 1, 'description': 'Customer legal name (required).\n\nWhen you also send a Spanish `nif`, how it is used depends on the customer:\nfor an **individual** the AEAT census matches NIF and name together, so a\nname it does not recognise makes the customer invalid; for a **company**\nthe name is **not verified** and only the CIF decides.\n'}, 'trade_name': {'type': ['string', 'null'], 'maxLength': 120, 'description': "Customer trade name. Optional, but **not empty by default**: leave it out on creation\nand it is filled with `legal_name`, which is what then shows as the recipient's trade\nname on the invoice PDF. Send it explicitly if the two differ.\n\nThe default applies **on creation only**. A `PUT` replaces the customer whole, so\nomitting `trade_name` there **clears** it instead of refilling it from `legal_name`.\n"}, 'alternative_id': {'$ref': '#/$defs/AlternativeIdentifier'}, 'billing_emails': {'type': ['array', 'null'], 'items': {'$ref': '#/$defs/Email'}, 'description': 'Additional emails for invoice delivery (optional)'}, 'contact_person': {'type': ['string', 'null'], 'maxLength': 200, 'description': 'Contact person name (optional)'}, 'general_discount': {'type': ['number', 'null'], 'maximum': 100, 'minimum': 0, 'description': 'General discount percentage (optional)'}, 'preferred_payment_method': {'$ref': '#/$defs/PaymentInfo'}}, 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateCustomerRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'NIF': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Spanish Tax ID (9 characters, uppercase only). Structural validation:\n- DNI: 8 digits + 1 letter (e.g., 12345678A)\n- NIE: X/Y/Z + 7 digits + 1 letter (e.g., X1234567A)\n- CIF: Organization letter + 7 digits + 1 control digit/letter (e.g., B12345674)\n'}, 'IBAN': {'type': 'string', 'pattern': '^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$', 'maxLength': 34, 'minLength': 15, 'description': 'IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Phone': {'type': 'string', 'pattern': '^[+]?[0-9\\s\\-\\(\\)]+$', 'maxLength': 20, 'minLength': 9, 'description': 'Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +'}, 'SWIFT': {'type': 'string', 'pattern': '^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$', 'maxLength': 11, 'minLength': 8, 'description': 'SWIFT/BIC code'}, 'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'PaymentInfo': {'type': 'object', 'properties': {'iban': {'$ref': '#/$defs/IBAN'}, 'swift': {'$ref': '#/$defs/SWIFT'}, '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'}, 'payment_term_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, '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}, 'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'AlternativeIdentifier': {'type': ['object', 'null'], 'required': ['type', 'number'], 'properties': {'type': {'enum': ['NIF_IVA', 'PASSPORT', 'COUNTRY_ID', 'RESIDENCE_CERTIFICATE', 'OTHER_DOCUMENT', 'NOT_REGISTERED', '02', '03', '04', '05', '06', '07'], 'type': 'string', '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', 'maxLength': 20, 'minLength': 1}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code. Constrains the allowed `type` values;\nsee the VeriFactu rules on the parent schema.\n'}}, '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'}, 'CreateCustomerRequest': {'type': 'object', 'required': ['legal_name', 'address'], 'properties': {'nif': {'allOf': [{'$ref': '#/$defs/NIF'}], 'description': 'Spanish Tax ID (required if id_otro is not provided)'}, 'email': {'type': ['string', 'null'], 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'notes': {'type': ['string', 'null'], 'description': 'Additional notes about the customer (optional)'}, 'phone': {'$ref': '#/$defs/Phone'}, 'address': {'$ref': '#/$defs/Address'}, 'website': {'type': ['string', 'null'], 'pattern': '^(https?://.+|)$', 'maxLength': 255, 'description': 'Website URL'}, 'legal_name': {'type': 'string', 'pattern': '^\\S.*$', 'maxLength': 120, 'minLength': 1, 'description': 'Customer legal name (required).\n\nWhen you also send a Spanish `nif`, how it is used depends on the customer:\nfor an **individual** the AEAT census matches NIF and name together, so a\nname it does not recognise makes the customer invalid; for a **company**\nthe name is **not verified** and only the CIF decides.\n'}, 'trade_name': {'type': ['string', 'null'], 'maxLength': 120, 'description': "Customer trade name. Optional, but **not empty by default**: leave it out on creation\nand it is filled with `legal_name`, which is what then shows as the recipient's trade\nname on the invoice PDF. Send it explicitly if the two differ.\n\nThe default applies **on creation only**. A `PUT` replaces the customer whole, so\nomitting `trade_name` there **clears** it instead of refilling it from `legal_name`.\n"}, 'alternative_id': {'$ref': '#/$defs/AlternativeIdentifier'}, 'billing_emails': {'type': ['array', 'null'], 'items': {'$ref': '#/$defs/Email'}, 'description': 'Additional emails for invoice delivery (optional)'}, 'contact_person': {'type': ['string', 'null'], 'maxLength': 200, 'description': 'Contact person name (optional)'}, 'general_discount': {'type': ['number', 'null'], 'maximum': 100, 'minimum': 0, 'description': 'General discount percentage (optional)'}, 'preferred_payment_method': {'$ref': '#/$defs/PaymentInfo'}}, 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'type': 'object', 'required': ['customers'], 'properties': {'customers': {'type': 'array', 'items': {'$ref': '#/$defs/CreateCustomerRequest'}, 'maxItems': 500, 'minItems': 1}}, 'additionalProperties': False}, 'dry_run': {'type': 'boolean', 'default': False, 'description': 'Validate the batch without persisting it (`true`), or validate and create it (`false`,\nthe default). Either way the batch is atomic.\n'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'AccountRole': {'enum': ['OWNER', 'ADMIN', 'MEMBER'], 'type': 'string', 'description': "Who administers the account. Independent of `access_level`, which says how much access someone has to a given company.\n\n`OWNER` — full control, including billing, API keys and transferring ownership. Exactly one per account, so it is never an accepted value when you SET a role (inviting a member or changing one's role): both reject it with `422 OWNER_ROLE_NOT_ASSIGNABLE`. Ownership moves only through `PUT /v1/accounts/{account_id}/owner`.\n`ADMIN` — everything an `OWNER` can do, except transferring ownership.\n`MEMBER` — no account administration. Access to each company is granted individually and reported as `access_level`; a member only sees the companies granted to them."}, 'GrantAssignment': {'type': 'object', 'required': ['company_id', 'access_level'], 'properties': {'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company within the account.'}, 'access_level': {'enum': ['VIEW', 'OPERATE'], 'type': 'string', 'description': 'Access the member gets over this company. `NONE` is not accepted here: a grant that\ngrants nothing is not a grant. Remove access by deleting the grant\n(`DELETE /v1/accounts/{account_id}/members/{member_id}/grants/{company_id}`).\n'}}, 'description': "A member's access to a specific company.", 'additionalProperties': False}, 'CreateInvitationRequest': {'type': 'object', 'required': ['invited_email', 'account_role', 'grants'], 'properties': {'grants': {'type': 'array', 'items': {'$ref': '#/$defs/GrantAssignment'}, 'default': [], 'description': 'Initial grants (only when `account_role` is `MEMBER`). Required: send `[]` to invite with no company access yet (granted later). An explicit `null` is rejected with 400.'}, 'send_email': {'type': 'boolean', 'default': False, 'description': 'If `true`, an invitation email with the acceptance link is sent to `invited_email` in addition to returning the token. Defaults to `false` (you deliver the token/link yourself).'}, 'account_role': {'$ref': '#/$defs/AccountRole'}, 'invited_email': {'type': 'string', 'format': 'email', 'minLength': 1, 'description': 'Email address of the invited person.'}}, 'description': 'Invites a person to join the active account.', 'additionalProperties': False}}, 'required': ['account_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateInvitationRequest'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'IBAN': {'type': 'string', 'pattern': '^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$', 'maxLength': 34, 'minLength': 15, 'description': 'IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Phone': {'type': 'string', 'pattern': '^[+]?[0-9\\s\\-\\(\\)]+$', 'maxLength': 20, 'minLength': 9, 'description': 'Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +'}, 'SWIFT': {'type': 'string', 'pattern': '^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$', 'maxLength': 11, 'minLength': 8, 'description': 'SWIFT/BIC code'}, 'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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"}, 'Recipient': {'type': 'object', 'properties': {'nif': {'type': 'string', 'pattern': '^[A-Za-z0-9]{9}$', 'maxLength': 9, 'minLength': 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'}, 'email': {'$ref': '#/$defs/Email'}, 'phone': {'$ref': '#/$defs/Phone'}, 'address': {'$ref': '#/$defs/Address'}, 'legal_name': {'type': 'string', 'maxLength': 255, 'minLength': 1, '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'], 'maxLength': 255, 'minLength': 1, 'description': 'Recipient trade name (optional)'}, '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"}, 'alternative_id': {'allOf': [{'$ref': '#/$defs/AlternativeIdentifier'}, {'description': 'Alternative identifier for foreign customers (mutually exclusive with nif)'}]}}, 'additionalProperties': False}, 'RegimeKey': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, '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'}, 'InvoiceType': {'enum': ['STANDARD', 'CORRECTIVE', 'SIMPLIFIED', 'PROFORMA'], 'type': 'string', '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'}, 'PaymentInfo': {'type': 'object', 'properties': {'iban': {'$ref': '#/$defs/IBAN'}, 'swift': {'$ref': '#/$defs/SWIFT'}, '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'}, 'payment_term_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, '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}, 'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'IrpfPercentage': {'enum': [0, 1, 2, 7, 15, 19, 24], 'type': 'integer', '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': {'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'], 'type': 'string', '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': {'enum': ['NORMAL', 'SUPLIDO'], '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'}, 'InvoiceMetadata': {'type': 'object', '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', 'additionalProperties': True}, 'EmailConfiguration': {'type': 'object', 'required': ['recipients'], 'properties': {'cc': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'description': 'List of CC emails (optional)'}, 'message': {'type': 'string', 'maxLength': 2000, 'minLength': 1, 'description': 'Custom message (optional, added to email body)'}, 'subject': {'type': 'string', 'maxLength': 200, 'minLength': 1, 'description': 'Custom email subject (optional, if not specified uses a default)'}, 'recipients': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'minItems': 1, 'description': 'List of recipient emails (at least 1 required)'}}, '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'}, 'lines': {'type': 'array', 'items': {'type': 'object', 'required': ['quantity'], 'properties': {'unit': {'type': 'string'}, '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'}, 'quantity': {'type': 'number', 'description': 'Product/service quantity (can be negative for franchises or discounts)'}, '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"}, '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'}, 'unit_price': {'type': 'number', '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', 'exclusiveMinimum': 0}, 'description': {'type': 'string', 'maxLength': 2000, 'description': 'Description of invoiced concept. Required for NORMAL lines;\noptional for SUPLIDO lines (may be empty or absent).\n'}, 'exemption_reason': {'anyOf': [{'$ref': '#/$defs/ExemptionReason'}, {'type': 'null'}]}, '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'}, 'discount_percentage': {'type': 'number', 'default': 0, 'maximum': 100, 'minimum': 0, 'description': 'Discount percentage applied (0-100)'}, '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'}, 'exemption_reason_text': {'type': ['string', 'null'], 'maxLength': 500, 'description': 'Custom exemption text. Only used when exemption_reason is OTRO.'}, '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"}, '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'}}, 'additionalProperties': False}, 'minItems': 1}, 'notes': {'type': 'string', 'maxLength': 1000}, 'options': {'$ref': '#/$defs/InvoiceProcessingOptions'}, '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'}, 'metadata': {'$ref': '#/$defs/InvoiceMetadata'}, 'recipient': {'$ref': '#/$defs/Recipient'}, 'series_id': {'type': 'string', 'format': 'uuid', 'description': 'Invoicing series ID (if not specified, uses default)'}, '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'}, 'external_ref': {'allOf': [{'$ref': '#/$defs/ExternalRef'}], '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', 'x-field-extra-annotation': '@com.fasterxml.jackson.annotation.JsonAlias("external_reference")'}, 'payment_info': {'$ref': '#/$defs/PaymentInfo'}, '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'}}, 'additionalProperties': False}, 'AlternativeIdentifier': {'type': ['object', 'null'], 'required': ['type', 'number'], 'properties': {'type': {'enum': ['NIF_IVA', 'PASSPORT', 'COUNTRY_ID', 'RESIDENCE_CERTIFICATE', 'OTHER_DOCUMENT', 'NOT_REGISTERED', '02', '03', '04', '05', '06', '07'], 'type': 'string', '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', 'maxLength': 20, 'minLength': 1}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code. Constrains the allowed `type` values;\nsee the VeriFactu rules on the parent schema.\n'}}, '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'}, 'InvoiceProcessingOptions': {'type': 'object', 'properties': {'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"}, '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'}, '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'}, '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'}, '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"}}, '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", 'additionalProperties': False}, 'EquivalenceSurchargePercentage': {'enum': [0, 0.5, 0.625, 1.4, 5.2], 'type': 'number', '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'}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateInvoiceRequest'}, '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'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'CreateInvoiceBatchRequest': {'type': 'object', 'required': ['operation', 'invoice_ids'], 'properties': {'operation': {'enum': ['ISSUE', 'STATUS'], 'type': 'string', 'description': '- **ISSUE**: issue the draft invoices, each one assigned its definitive number.\n- **STATUS**: change the status of the invoices; requires `new_status`.\n'}, 'new_status': {'enum': ['SENT', 'PAID'], 'type': 'string', 'description': 'Target status. Required when `operation` is `STATUS`.'}, 'invoice_ids': {'type': 'array', 'items': {'$ref': '#/$defs/UUID'}, 'maxItems': 50, 'minItems': 1}, 'payment_date': {'type': 'string', 'format': 'date', 'description': 'Payment date. Required when `new_status` is `PAID`.'}}, 'description': 'Applies one operation to a set of invoices of this company. Only the operations that share\na result shape live here; downloading PDFs, sending email and exporting have their own\nsibling sub-resources because each returns something different.\n', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateInvoiceBatchRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Language': {'enum': ['es', 'en', 'ca'], 'type': 'string', 'description': 'Supported languages'}, 'CreateInvoiceDeliveryRequest': {'type': 'object', 'required': ['invoice_ids', 'recipients'], 'properties': {'cc': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'description': "CC recipients. Copied addresses count as recipients of the message: they are subject\nto the same sending restrictions and to the same quota as the addresses in `recipients`.\nWhen omitted, the CC addresses configured in the sender's email defaults apply; send an\nempty array to deliver the message without any copy.\n"}, 'message': {'type': 'string', 'maxLength': 2000, 'description': 'Custom message body. Defaults to the standard template.'}, 'subject': {'type': 'string', 'maxLength': 200, 'description': 'Custom email subject. Defaults to the standard template.'}, 'language': {'allOf': [{'$ref': '#/$defs/Language'}], 'description': 'Email language. Defaults to the language of the requesting user.'}, 'recipients': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'minItems': 1, 'description': 'Email recipients. At least one is required: no address is inferred from any profile.\n'}, 'invoice_ids': {'type': 'array', 'items': {'$ref': '#/$defs/UUID'}, 'maxItems': 200, 'minItems': 1}}, 'description': 'One email delivery carrying several invoices of this company as attachments.', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateInvoiceDeliveryRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'InvoiceDerivationMode': {'enum': ['DUPLICATE'], 'type': 'string', 'description': 'How to derive the new invoice from `from_invoice_id`.\n\n- **DUPLICATE**: copy an existing invoice into a fresh draft. The source invoice is not\n modified.\n\nTurning a proforma into an invoice is **not** a derivation mode: it is a fiscal act that\nnumbers a document and moves the source proforma to a terminal status, so it keeps its own\ndedicated operation.\n'}, 'CreateInvoiceDerivationRequest': {'type': 'object', 'required': ['from_invoice_id', 'mode'], 'properties': {'mode': {'$ref': '#/$defs/InvoiceDerivationMode'}, 'notes': {'type': 'string', 'maxLength': 2000, 'description': 'Observations for the new draft. Defaults to those of the source invoice.'}, 'series_id': {'allOf': [{'$ref': '#/$defs/UUID'}], 'description': 'Series for the new draft. Defaults to the series of the source invoice.'}, 'from_invoice_id': {'allOf': [{'$ref': '#/$defs/UUID'}], 'description': 'Invoice this one is derived from. It must belong to the company in the path; an\ninvoice you cannot reach is reported the same way as one that does not exist.\n'}}, 'description': 'Derives a new draft invoice from an existing one. It is a sibling sub-resource of\n`invoices` and not a variant of the create request on purpose: this call does not describe\nan invoice, it names one, so it carries neither `type`, nor `recipient`, nor `lines`.\nEverything the new draft needs is copied from the source invoice, which is left untouched.\n', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateInvoiceDerivationRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, 'ProductCategory': {'enum': ['PRODUCT', 'SERVICE', 'CONSULTING', 'SOFTWARE', 'TRAINING', 'OTHER'], 'type': 'string', 'description': 'Product/service category:\n* PRODUCT - Physical, tangible products\n* SERVICE - General services\n* CONSULTING - Consulting and advisory services\n* SOFTWARE - Development, licenses, SaaS\n* TRAINING - Courses, workshops, training\n* OTHER - Other unclassified types\n'}, 'CreateProductRequest': {'type': 'object', 'required': ['name'], 'properties': {'code': {'type': ['string', 'null'], 'pattern': '^[a-zA-Z0-9_-]*$', 'maxLength': 50, 'description': 'Unique alphanumeric product code (optional)'}, 'name': {'type': 'string', 'maxLength': 255, 'description': 'Product/service name'}, 'unit': {'type': 'string', 'maxLength': 50, 'description': 'Unit of measure (optional)'}, 'category': {'$ref': '#/$defs/ProductCategory'}, 'main_tax': {'$ref': '#/$defs/TaxInfo'}, 'irpf_rate': {'type': 'number', 'maximum': 100, 'minimum': 0, 'multipleOf': 0.01, 'description': 'IRPF withholding percentage (optional)'}, 'description': {'type': 'string', 'description': 'Detailed description (optional)'}, 'default_price': {'type': 'number', 'minimum': 0, 'multipleOf': 0.0001, 'description': 'Suggested default price (optional)'}, 'equivalence_surcharge_rate': {'type': 'number', 'maximum': 100, 'minimum': 0, 'multipleOf': 0.01, 'description': 'Equivalence surcharge percentage (optional).\n\nMust be coherent with `main_tax.regime_key`: a surcharge > 0 is\nonly valid under regime `18`. When `regime_key` is omitted it is\nderived automatically (`18` with a surcharge > 0, `01` otherwise).\nAn explicit `regime_key` that does not admit a surcharge combined\nwith a surcharge > 0 is rejected with a 422\n(`SURCHARGE_REQUIRES_REGIME`), and an explicit regime `18` without\na surcharge > 0 is rejected with a 422\n(`REGIME_REQUIRES_SURCHARGE`).\n'}}, 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateProductRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, 'ProductCategory': {'enum': ['PRODUCT', 'SERVICE', 'CONSULTING', 'SOFTWARE', 'TRAINING', 'OTHER'], 'type': 'string', 'description': 'Product/service category:\n* PRODUCT - Physical, tangible products\n* SERVICE - General services\n* CONSULTING - Consulting and advisory services\n* SOFTWARE - Development, licenses, SaaS\n* TRAINING - Courses, workshops, training\n* OTHER - Other unclassified types\n'}, 'CreateProductRequest': {'type': 'object', 'required': ['name'], 'properties': {'code': {'type': ['string', 'null'], 'pattern': '^[a-zA-Z0-9_-]*$', 'maxLength': 50, 'description': 'Unique alphanumeric product code (optional)'}, 'name': {'type': 'string', 'maxLength': 255, 'description': 'Product/service name'}, 'unit': {'type': 'string', 'maxLength': 50, 'description': 'Unit of measure (optional)'}, 'category': {'$ref': '#/$defs/ProductCategory'}, 'main_tax': {'$ref': '#/$defs/TaxInfo'}, 'irpf_rate': {'type': 'number', 'maximum': 100, 'minimum': 0, 'multipleOf': 0.01, 'description': 'IRPF withholding percentage (optional)'}, 'description': {'type': 'string', 'description': 'Detailed description (optional)'}, 'default_price': {'type': 'number', 'minimum': 0, 'multipleOf': 0.0001, 'description': 'Suggested default price (optional)'}, 'equivalence_surcharge_rate': {'type': 'number', 'maximum': 100, 'minimum': 0, 'multipleOf': 0.01, 'description': 'Equivalence surcharge percentage (optional).\n\nMust be coherent with `main_tax.regime_key`: a surcharge > 0 is\nonly valid under regime `18`. When `regime_key` is omitted it is\nderived automatically (`18` with a surcharge > 0, `01` otherwise).\nAn explicit `regime_key` that does not admit a surcharge combined\nwith a surcharge > 0 is rejected with a 422\n(`SURCHARGE_REQUIRES_REGIME`), and an explicit regime `18` without\na surcharge > 0 is rejected with a 422\n(`REGIME_REQUIRES_SURCHARGE`).\n'}}, 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'type': 'object', 'required': ['products'], 'properties': {'products': {'type': 'array', 'items': {'$ref': '#/$defs/CreateProductRequest'}, 'maxItems': 100, 'minItems': 1}}, 'additionalProperties': False}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'ExemptionReason': {'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'], 'type': 'string', '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'}, 'RecurringLineRequest': {'type': 'object', 'required': ['description', 'quantity', 'unit_price', 'vat_rate'], 'properties': {'unit': {'type': 'string', 'maxLength': 20}, 'quantity': {'type': 'number', 'minimum': 0.01}, 'tax_type': {'type': 'string', 'description': 'Tax type. Omitted, `IVA` applies.'}, 'vat_rate': {'type': 'number'}, 'irpf_rate': {'type': ['number', 'null']}, 'regime_key': {'type': 'string', 'description': 'VeriFactu regime key. Omitted, `01` (general regime) applies.'}, 'unit_price': {'type': 'number', 'minimum': 0}, 'description': {'type': 'string', 'maxLength': 2000}, 'exemption_reason': {'anyOf': [{'$ref': '#/$defs/ExemptionReason'}, {'type': 'null'}]}, 'discount_percentage': {'type': 'number', 'maximum': 100, 'minimum': 0}, 'exemption_reason_text': {'type': ['string', 'null'], 'maxLength': 500, 'description': 'Custom exemption text. Only used when `exemption_reason` is `OTRO`.\n\nSame shape as an invoice line: the template declares WHY the operation carries no tax,\nand every invoice it generates inherits it. A 0% line without a reason is rejected on\nwrite — VeriFactu does not accept an exempt line with no explicit motive.\n'}, 'equivalence_surcharge_rate': {'type': ['number', 'null']}}, 'description': 'Recurring-invoice line. Unlike invoice lines (which nest tax data under a `main_tax` object),\nrecurring lines use flat tax fields: `vat_rate`, `tax_type`, `regime_key`,\n`equivalence_surcharge_rate` and `irpf_rate`. Do not send a `main_tax` object here.\n', 'additionalProperties': False}, 'RecurringEmailConfigRequest': {'type': ['object', 'null'], 'properties': {'cc': {'type': 'array', 'items': {'type': 'string'}}, 'message': {'type': ['string', 'null']}, 'subject': {'type': ['string', 'null']}, 'recipients': {'type': 'array', 'items': {'type': 'string'}}}}, 'CreateRecurringInvoiceRequest': {'type': 'object', 'required': ['name', 'day_of_month', 'start_date', 'series_id', 'invoice_type', 'lines'], 'properties': {'name': {'type': 'string', 'maxLength': 255}, 'lines': {'type': 'array', 'items': {'$ref': '#/$defs/RecurringLineRequest'}, 'minItems': 1}, 'notes': {'type': ['string', 'null']}, 'end_date': {'type': ['string', 'null'], 'format': 'date'}, 'frequency': {'enum': ['MONTHLY'], 'type': 'string', 'description': 'Generation cadence. Only `MONTHLY` is supported today; the field exists in the\nrequest so an unsupported cadence is rejected instead of silently creating a\nmonthly template. Omitted, `MONTHLY` applies.\n'}, 'series_id': {'type': 'string', 'format': 'uuid'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Date the subscription started. A past date is accepted and stored as sent — useful\nwhen migrating subscriptions from another system — but it never anchors generation\nin the past: `next_generation` moves to the first upcoming `day_of_month`. Invoices\nare never back-dated, so the missed periods are not generated.\n'}, 'customer_id': {'type': ['string', 'null'], 'format': 'uuid'}, 'day_of_month': {'type': 'integer', 'maximum': 31, 'minimum': 1}, 'invoice_type': {'enum': ['STANDARD', 'SIMPLIFIED'], 'type': 'string'}, 'payment_iban': {'type': ['string', 'null']}, 'preview_days': {'type': 'integer', 'default': 0, 'maximum': 30, 'minimum': 0, 'description': 'Days before emission date to create a draft for review. 0 means immediate emission.'}, 'payment_swift': {'type': ['string', 'null']}, 'payment_method': {'anyOf': [{'allOf': [{'$ref': '#/$defs/PaymentMethod'}]}, {'type': 'null'}]}, 'payment_term_days': {'type': ['integer', 'null']}, 'verifactu_enabled': {'type': 'boolean', 'description': 'Whether the invoices generated by this template carry VeriFactu information.\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\nThe resolved value is **frozen into the template at creation time** and is\nreturned by the API: changing the company preference later does not alter\ntemplates that already exist. Edit the template to change it.\n'}, 'send_automatically': {'type': 'boolean', 'default': False}, 'email_configuration': {'$ref': '#/$defs/RecurringEmailConfigRequest'}}, 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateRecurringInvoiceRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'RecurringEmailConfigRequest': {'type': ['object', 'null'], 'properties': {'cc': {'type': 'array', 'items': {'type': 'string'}}, 'message': {'type': ['string', 'null']}, 'subject': {'type': ['string', 'null']}, 'recipients': {'type': 'array', 'items': {'type': 'string'}}}}, 'CreateRecurringInvoiceDerivationRequest': {'type': 'object', 'required': ['from_invoice_id', 'name', 'day_of_month', 'start_date'], 'properties': {'name': {'type': 'string', 'maxLength': 255}, 'end_date': {'type': ['string', 'null'], 'format': 'date'}, 'frequency': {'enum': ['MONTHLY'], 'type': 'string', 'description': 'Generation cadence. Only `MONTHLY` is supported today; the field exists in the\nrequest so an unsupported cadence is rejected instead of silently creating a\nmonthly template. Omitted, `MONTHLY` applies.\n'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Date the subscription started. A past date is accepted and stored as sent — useful\nwhen migrating subscriptions from another system — but it never anchors generation\nin the past: `next_generation` moves to the first upcoming `day_of_month`. Invoices\nare never back-dated, so the missed periods are not generated.\n'}, 'day_of_month': {'type': 'integer', 'maximum': 31, 'minimum': 1}, 'from_invoice_id': {'type': 'string', 'format': 'uuid', 'description': 'Invoice the template is derived from. It must belong to the company in the path; an\ninvoice you cannot reach is reported the same way as one that does not exist.\n'}, 'verifactu_enabled': {'type': 'boolean', 'description': 'Whether the invoices this template generates enter VeriFactu.\n\nOmitting it inherits the value from the source invoice: pointing at one of your\nVeriFactu invoices and asking for it every month keeps VeriFactu. Send `true` or\n`false` explicitly to override that inheritance.\n'}, 'send_automatically': {'type': 'boolean', 'default': False}, 'email_configuration': {'$ref': '#/$defs/RecurringEmailConfigRequest'}}, 'description': 'Derives a recurring invoice template from an existing invoice: lines, recipient, series and\npayment data are taken from it, so only the recurrence is described here. The source invoice\nis not modified.\n\nDeliberately not a variant of `CreateRecurringInvoiceRequest`: that one requires `series_id`,\n`invoice_type` and `lines`, which this call does not carry. Relaxing them there would let a\ntemplate be created from scratch with no lines at all.\n', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateRecurringInvoiceDerivationRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'SeriesCode': {'type': 'string', 'pattern': '^[A-Z0-9\\-_]{1,50}$', 'maxLength': 50, 'minLength': 1, 'description': 'Alphanumeric series code (used in {CODIGO} variable).\nAllows uppercase letters, numbers, hyphens and underscores.\n'}, 'CounterReset': {'enum': ['NEVER', 'ANNUAL', 'MONTHLY'], 'type': 'string', 'description': 'Counter reset policy:\n- NEVER: Counter never resets (continuous numbering)\n- ANNUAL: Counter resets yearly\n- MONTHLY: Counter resets monthly\n'}, 'DocumentType': {'enum': ['UNASSIGNED', 'STANDARD', 'SIMPLIFIED', 'CORRECTIVE', 'PROFORMA'], 'type': 'string', 'description': 'Document type associated with a series. Values mirror `InvoiceType`,\nso the series a document needs is named exactly like the document:\n- UNASSIGNED: Legacy series, compatible with any invoice type\n- STANDARD: Standard invoice\n- SIMPLIFIED: Simplified invoice\n- CORRECTIVE: Corrects or cancels a previous invoice\n- PROFORMA: Proforma (commercial document, non-fiscal numbering)\n'}, 'SeriesFormat': {'type': 'string', 'pattern': '^[A-Z0-9\\-_/{}:]*$', 'maxLength': 255, 'minLength': 1, 'description': 'Format template with available variables (UPPERCASE ONLY):\n- {CODIGO}: Series code (e.g., "FAC")\n- {YYYY}: Year with 4 digits (e.g., "2025")\n- {YY}: Year with 2 digits (e.g., "25")\n- {MM}: Month with 2 digits (e.g., "01")\n- {NUM}: Sequential number without padding (e.g., "1")\n- {NUM:X}: Sequential number with padding (e.g., {NUM:4} → "0001")\n\n**REQUIRED**: Must contain at least {NUM} or {NUM:X}\n**IMPORTANT**: Only uppercase (rejects {yy}, {mm}, {codigo}, etc.)\n\nValid examples:\n- "{CODIGO}-{YYYY}-{NUM:4}" → "FAC-2025-0001"\n- "{CODIGO}/{NUM:6}" → "FAC/000001"\n- "{YYYY}{MM}-{NUM:3}" → "202501-001"\n'}, 'CreateSeriesRequest': {'type': 'object', 'required': ['name', 'code', 'format'], 'properties': {'code': {'$ref': '#/$defs/SeriesCode'}, 'name': {'type': 'string', 'maxLength': 100, 'minLength': 1, 'description': 'Descriptive name of the series'}, 'active': {'type': 'boolean', 'default': True, 'description': 'Whether the series is active'}, 'format': {'$ref': '#/$defs/SeriesFormat'}, 'description': {'type': ['string', 'null'], 'maxLength': 1000, 'description': 'Optional series description'}, 'counter_reset': {'allOf': [{'$ref': '#/$defs/CounterReset'}], 'default': 'ANNUAL', 'description': "When this series' counter resets. Defaults to `ANNUAL` when omitted — so a format\nwithout a year token must come with `counter_reset: NEVER`.\n"}, 'document_type': {'$ref': '#/$defs/DocumentType'}, 'default_series': {'type': 'boolean', 'default': False, 'description': 'Whether this is the default series for its document_type.\n\n**Auto-promotion:** the domain guarantees that, while at least one\nseries exists for a given `(document_type, environment)`, exactly one\nof them is the default. So if you create the **first** series of a\n`document_type` (no default exists yet for that type and environment),\nit is marked as default **even if you send `false`** — the response\nwill then return `default_series: true`. Send `true` to also unmark\nthe current default of that type.\n'}, 'initial_number': {'type': 'integer', 'format': 'int64', 'default': 1, 'maximum': 999999, 'minimum': 1, 'description': 'Initial number for this series counter.\nUseful when migrating from another system and wanting to continue existing numbering.\nFor example, if the last invoices were 2024-0150, you can set initial_number=151.\nDefault value is 1.\n'}}, 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateSeriesRequest'}, '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'WebhookEventTypeEnum': {'enum': ['invoice.issued', 'invoice.email.sent', 'invoice.voided', 'recurring_invoice.paused', 'verifactu.status.updated', 'account.claimed', 'company.created', 'representation.signed'], 'type': 'string', 'description': 'Available webhook event types:\n- `invoice.issued` — Invoice issued and finalized\n- `invoice.email.sent` — Invoice sent by email\n- `invoice.voided` — Invoice voided\n- `recurring_invoice.paused` — A schedule stopped generating on its own (downgrade or a\n permanent generation failure); the invoice it was going to issue will not arrive\n- `verifactu.status.updated` — VeriFactu status changed (see `VeriFactuSubmissionStatus`)\n- `account.claimed` — A provisioned account was claimed by its holder\n- `company.created` — A company was created inside a provisioned account\n- `representation.signed` — Fiscal representation signed for a NIF (production invoicing enabled)\n\nThe `account.*` events are delivered only to the **provisioner** that created the\naccount; a subscription on any other account never receives them.\n'}, 'WebhookAccountRelationship': {'enum': ['own', 'managed', 'all'], 'type': 'string', 'description': 'Which accounts a subscription receives events from — the same vocabulary as the\n`account_relationship` field in every delivered event envelope. One term to ask for\nevents, the same term to route them on arrival.\n\n* `own` (default) — only your own account.\n* `managed` — only accounts you manage (accounts you provisioned). Whether you actually\n receive them also depends on the management relationship granting data visibility; a\n billing-only relationship does not.\n* `all` — both.\n\nA delivered event is always `own` or `managed` (never `all`): its\n`account_relationship`, alongside `account_id` and `account_external_ref`, tells you\nwhich account it belongs to.\n'}, 'CreateWebhookSubscriptionRequest': {'type': 'object', 'required': ['url', 'events'], 'properties': {'url': {'type': 'string', 'format': 'uri', 'description': 'HTTPS endpoint URL that will receive webhook POST requests.'}, 'events': {'type': 'array', 'items': {'$ref': '#/$defs/WebhookEventTypeEnum'}, 'minItems': 1, 'description': 'List of event types to subscribe to.'}, 'account_relationship': {'allOf': [{'$ref': '#/$defs/WebhookAccountRelationship'}], 'default': 'own', 'description': 'Which accounts this subscription receives events from. Defaults to `own`. Same field name and values as the `account_relationship` carried by every event envelope.\n'}}, 'additionalProperties': False}}, 'required': ['account_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/CreateWebhookSubscriptionRequest'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'Environment': {'enum': ['TEST', 'PROD'], 'type': 'string', 'description': 'Mode a record lives in — its Test/Live twin. It decides where invoices, customers and\nquota are accounted.\n\nFor a company it also decides which AEAT its NIF is registered against: switching a\ncompany on in `PROD` is what registers it with the real AEAT, so `aeat_environment`\nis that same mode and uses this same enum.\n'}}, 'required': ['company_id', 'environment'], 'properties': {'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company being switched 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.'}, 'environment': {'$ref': '#/$defs/Environment', 'description': 'Mode to switch the NIF off in.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'customer_id'], '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.'}, 'customer_id': {'$ref': '#/$defs/UUID', 'description': 'Customer ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'ids'], 'properties': {'ids': {'type': 'string', 'description': 'Comma-separated customer IDs'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'invitation_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, 'invitation_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'invoice_id'], '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'invoice_id'], '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'member_id'], 'properties': {'member_id': {'type': 'string', 'format': 'uuid', 'description': 'Membership unique UUID.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'member_id', 'company_id'], 'properties': {'member_id': {'type': 'string', 'format': 'uuid', 'description': 'Membership unique UUID.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company within the account.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'product_id'], '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.'}, 'product_id': {'type': 'string', 'format': 'uuid', 'description': 'Product unique UUID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'ids'], 'properties': {'ids': {'type': 'string', 'description': 'Comma-separated product IDs (max 100 per request)'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'recurring_invoice_id'], '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'series_id'], 'properties': {'series_id': {'$ref': '#/$defs/UUID', 'description': 'Series ID'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'webhook_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, 'webhook_id': {'type': 'string', 'format': 'uuid', 'description': 'Subscription of the account in the path. A subscription of another account answers `404`, the same as one that does not exist: under the account resolved from `{account_id}` it simply is not there.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'provider'], 'properties': {'provider': {'enum': ['stripe'], 'type': 'string', 'description': 'Payment provider slug in **lowercase**. Currently only `stripe` (Stripe Connect) is\noperative; `woocommerce` and `shopify` are reserved for future providers.\n'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['page'], 'properties': {'page': {'type': 'string', 'minLength': 1, 'description': 'Page title or a distinctive part of it.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['terms'], 'properties': {'limit': {'type': 'integer', 'default': 3, 'maximum': 50, 'minimum': 1, 'description': 'Max sections to return (default 3).'}, 'terms': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 20, 'minItems': 1, 'description': 'Search keywords, e.g. ["recargo", "equivalencia"] or ["corrective", "R5"].'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'provider', 'event_id'], 'properties': {'event_id': {'type': 'string', 'format': 'uuid', 'description': 'Identifier of the payment event, as returned by the list operation.'}, 'provider': {'enum': ['stripe'], 'type': 'string', 'description': 'Payment provider slug in **lowercase**. Currently only `stripe` (Stripe Connect) is\noperative; `woocommerce` and `shopify` are reserved for future providers.\n'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company the events belong to — 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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'recurring_invoice_id'], '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.'}, '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'customer_id'], '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.'}, 'customer_id': {'$ref': '#/$defs/UUID', 'description': 'Customer ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'email_id'], 'properties': {'email_id': {'type': 'string', 'format': 'uuid', 'description': 'Email delivery id'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'related_entity_ids'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, 'related_entity_ids': {'type': 'array', 'items': {'type': 'string', 'format': 'uuid'}, 'description': 'Comma-separated list of related entity ids (e.g. invoice ids)'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], 'properties': {'end_date': {'type': 'string', 'format': 'date', 'description': 'Period end date (inclusive), as `YYYY-MM-DD`. Goes together with `start_date`:\nsupply both or neither. Omitting both defaults to the current month; supplying\nonly one is rejected with `400` (`PERIOD_INCOMPLETE`).\n'}, '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.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'Period start date (inclusive), as `YYYY-MM-DD`. Goes together with `end_date`:\nsupply both or neither. Omitting both defaults to the current month; supplying\nonly one is rejected with `400` (`PERIOD_INCOMPLETE`).\n'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'invitation_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, 'invitation_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'invoice_id'], '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'invoice_id'], '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'invoice_id'], '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'invoice_id'], '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], 'properties': {'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company whose issuing readiness is evaluated — 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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'member_id'], 'properties': {'member_id': {'type': 'string', 'format': 'uuid', 'description': 'Membership unique UUID.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'provider', 'event_id'], 'properties': {'event_id': {'type': 'string', 'format': 'uuid', 'description': 'Identifier of the payment event, as returned by the list operation.'}, 'provider': {'enum': ['stripe'], 'type': 'string', 'description': 'Payment provider slug in **lowercase**. Currently only `stripe` (Stripe Connect) is\noperative; `woocommerce` and `shopify` are reserved for future providers.\n'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company the events belong to — 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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'product_id'], '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.'}, 'product_id': {'type': 'string', 'format': 'uuid', 'description': 'Product unique UUID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'recurring_invoice_id'], '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'recurring_invoice_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'recurring_invoice_id'], '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'request_id'], 'properties': {'timestamp': {'type': 'string', 'format': 'date-time', 'description': 'Log timestamp (the one returned by the list). Narrows the search window around\nthat instant so the detail also works for logs older than the default window.\nIf omitted, the default recent window is searched.\n'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Account the call is authorized against. It does not widen the result set.'}, 'request_id': {'type': 'string', 'description': 'Correlation identifier (X-Request-Id).'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'series_id'], 'properties': {'series_id': {'$ref': '#/$defs/UUID', 'description': 'Series ID'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'properties': {'company_id': {'type': 'string', 'description': 'Optional: restrict the report to a single company, by its company id (a UUID). This is not the NIF; the NIF is reported as a field of each company.'}}}
Schéma de sortie
{'type': 'object', 'required': ['environment', 'account', 'companies', 'next_action'], 'properties': {'error': {'type': 'string', 'description': 'Why the report is incomplete: the company listing failed, a filter matched nothing, or entries were unusable. Present only when something went wrong.'}, 'account': {'type': 'object', 'properties': {'name': {'type': 'string'}, 'email': {'type': 'string'}, 'error': {'type': 'string', 'description': 'Why this section could not be read. Present only on failure.'}, 'account_id': {'type': 'string'}}, 'description': 'The authenticated account, or an error note if identity could not be read.'}, 'companies': {'type': 'array', 'items': {'type': 'object', 'required': ['company_id', 'ready', 'missing', 'next_action'], 'properties': {'nif': {'type': 'string'}, 'error': {'type': 'string', 'description': 'Why this section could not be read. Present only on failure.'}, 'ready': {'type': ['boolean', 'null'], 'description': 'Can issue Live (no blockers). `null` means readiness could not be read — see `error`; it does not mean not ready, and it does not mean ready.'}, 'missing': {'type': 'array', 'items': {'type': 'string'}, 'description': 'Human-readable list of what is missing to issue Live.'}, 'blockers': {'type': 'array', 'items': {'type': 'string'}}, 'verifactu': {'type': 'object', 'properties': {'error': {'type': 'string', 'description': 'Why this section could not be read. Present only on failure.'}, 'enabled': {'type': 'boolean'}, 'apply_by_default': {'type': 'boolean'}}}, 'company_id': {'type': 'string', 'description': 'The company id (a UUID), not the NIF.'}, 'legal_name': {'type': 'string'}, 'next_action': {'type': 'string', 'description': 'Single recommended next action.'}, 'default_series': {'type': 'object', 'properties': {'error': {'type': 'string', 'description': 'Why this section could not be read. Present only on failure.'}, 'missing': {'type': 'array', 'items': {'type': 'string'}}, 'all_configured': {'type': 'boolean'}}}, 'payment_connection': {'type': 'object', 'properties': {'count': {'type': 'integer'}, 'error': {'type': 'string', 'description': 'Why this section could not be read. Present only on failure.'}, 'active': {'type': 'boolean'}}}}}}, 'environment': {'enum': ['test', 'live'], 'type': 'string', 'description': 'Which BeeL environment this session operates on. `live` means every invoice issued is a real fiscal document.'}, 'next_action': {'type': 'string', 'description': 'Single recommended next action across the whole account.'}}}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account id.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'webhook_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, 'webhook_id': {'type': 'string', 'format': 'uuid', 'description': 'Subscription of the account in the path. A subscription of another account answers `404`, the same as one that does not exist: under the account resolved from `{account_id}` it simply is not there.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'InitiatePaymentConnectionRequest': {'type': 'object', 'required': ['provider'], 'properties': {'provider': {'type': 'string', 'description': 'Payment provider slug in **lowercase**. Currently only `stripe` (Stripe Connect) is\noperative; `woocommerce` and `shopify` are reserved for future providers. Any other\nvalue answers `422`.\n'}, 'return_url': {'type': 'string', 'pattern': '^https://.*', 'description': "URL of your portal to redirect the account holder back to after the OAuth callback\ncompletes. Must be an absolute `https://` URL. On **success** BeeL appends\n`status=success`, `provider` (slug), `company_id`, `connection_id` and `account`\n(the provider account id, e.g. `acct_...`). On **error** it appends `status=error`,\n`provider` and `message`, always a stable uppercase error code: `OAUTH_STATE_INVALID`\n(the authorization is unknown, expired or already used), `OAUTH_TOKEN_EXCHANGE_FAILED`\n(the provider rejected the code exchange), `ACCESS_DENIED` (the account holder declined\nat the provider), `OAUTH_ACCOUNT_CONNECTED_TO_OTHER_COMPANY` (the provider account is\nalready connected to another NIF; disconnect it there first),\n`PROVIDER_ERROR` (any other provider-reported failure) or\n`OAUTH_UNEXPECTED`. When omitted, the callback redirects to BeeL's default integrations\nscreen. A `return_url` that is not an absolute `https://` URL with a host is rejected\nup front with `422` `PAYMENT_RETURN_URL_INVALID`, and no authorization is opened.\n"}}, 'description': 'The authorization to open: which provider it is for, and where to send the holder back.\n', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/InitiatePaymentConnectionRequest'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company the authorization is opened for — 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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'invoice_id'], '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}, 'wait_for_pdf': {'type': 'boolean', 'default': False, 'description': 'If `true`, waits for PDF generation and returns the URL in the response. Adds ~1-2s of\nlatency but guarantees the PDF is immediately available.\n'}, '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.'}, 'attach_source_invoices': {'type': 'boolean', 'default': False, 'description': "Only applies when the invoice has automatic email sending enabled. If `true`, the\nemail sent after issuing also attaches a ZIP (`suplidos_<invoice-number>.zip`) with\nthe PDFs of the source invoices referenced by the invoice's SUPLIDO consolidation\nlines. Access to sources owned by managed accounts is re-checked with the same rules\nas issuing, and the request fails synchronously with an actionable error — never a\npartial 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`).\n"}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'ProvisioningStatus': {'enum': ['PROVISIONED', 'CLAIMED', 'ACTIVE'], 'type': 'string', 'description': 'Lifecycle stage of a provisioned account. The claim gates the stage: `PROVISIONED` (created, not yet claimed — the holder has not set a password / taken ownership, even if a NIF was seeded at provisioning or you invoice on their behalf with `OPERATE`); `CLAIMED` (the holder set their password and took ownership, no NIF yet); `ACTIVE` (claimed and has at least one NIF — can operate under their own ownership).'}}, 'properties': {'limit': {'type': 'integer', 'default': 50, 'maximum': 200, 'minimum': 1, 'description': 'Maximum number of accounts to return per page (1–200). Defaults to 50.'}, 'cursor': {'type': 'string', 'description': "Opaque pagination cursor from a previous response's `next_cursor`."}, 'status': {'$ref': '#/$defs/ProvisioningStatus'}, 'external_ref': {'type': 'string', 'description': 'Your own id for the account; returns the 0..1 matching accounts.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'CompanyInclude': {'enum': ['readiness'], 'type': 'string', 'description': 'Derived data to expand on each company of the list.'}}, 'required': ['account_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'search': {'type': 'string', 'description': 'Case-insensitive filter on NIF, legal name or trade name. Blank/omitted returns all.'}, 'include': {'$ref': '#/$defs/CompanyInclude', 'description': "Include derived data. `readiness` adds each company's issuing-readiness status."}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'SortOrder': {'enum': ['asc', 'desc'], 'type': 'string', 'description': 'Sort direction. Shared vocabulary for every `sort_order` query param: declared once so the\ngenerator emits a real enum and an unknown direction is rejected with `400` instead of being\nsilently ignored.\n'}, 'CustomerSortBy': {'enum': ['legal_name', 'nif', 'email', 'phone', 'city', 'province', 'active', 'created_at'], 'type': 'string', 'description': 'Customer field the list is ordered by.'}}, 'required': ['company_id'], 'properties': {'nif': {'type': 'string', 'description': 'Filter by NIF (partial search)'}, 'city': {'type': 'string', 'description': 'Filter by city'}, 'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'email': {'type': 'string', 'description': 'Filter by email (partial search)'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'phone': {'type': 'string', 'description': 'Filter by phone (partial search)'}, 'active': {'type': 'boolean', 'description': 'Filter by active/inactive status. Defaults to `true`, so inactive customers must be\nrequested explicitly with `active=false`. Deleted customers are never returned by\neither value.\n'}, 'search': {'type': 'string', 'description': 'Global search by name, NIF or email'}, 'sort_by': {'allOf': [{'$ref': '#/$defs/CustomerSortBy'}], 'default': 'legal_name', 'description': 'Field to sort by. Results are always tie-broken by a stable internal key, so paging through the collection never repeats or skips a customer.'}, 'province': {'type': 'string', 'description': 'Filter by province'}, '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.'}, 'legal_name': {'type': 'string', 'description': 'Filter by legal name (partial search case-insensitive)'}, 'sort_order': {'allOf': [{'$ref': '#/$defs/SortOrder'}], 'default': 'asc', 'description': 'Sort order direction'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'SortOrder': {'enum': ['asc', 'desc'], 'type': 'string', 'description': 'Sort direction. Shared vocabulary for every `sort_order` query param: declared once so the\ngenerator emits a real enum and an unknown direction is rejected with `400` instead of being\nsilently ignored.\n'}, 'EmailDeliverySortBy': {'enum': ['sent_at', 'status', 'email_type'], 'type': 'string', 'description': 'Email delivery field the list is ordered by.'}, 'EmailDeliveryStatus': {'enum': ['QUEUED', 'REJECTED', 'SENT', 'FAILED', 'DELIVERED', 'BOUNCED', 'OPENED'], 'type': 'string', 'description': "Status of an email.\n\nThe history records every email the system decided to send, not only the ones that\nwent out: an email stopped by policy is listed as REJECTED rather than omitted.\n\n- QUEUED: authorised and recorded, not dispatched yet\n- REJECTED: stopped by policy and never sent (terminal, not retried). In test\n environments invoices may only be emailed to the account owner's own address\n (`+tag` aliases included), so a message addressed elsewhere lands here\n- SENT: successfully sent to the provider\n- FAILED: sending failed\n- DELIVERED / BOUNCED / OPENED: reported by the provider's webhooks\n"}}, 'required': ['account_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'type': {'type': 'string', 'description': 'Filter by email type (e.g. INVOICE_EMITTED)'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'status': {'$ref': '#/$defs/EmailDeliveryStatus', 'description': 'Filter by delivery status'}, 'sort_by': {'allOf': [{'$ref': '#/$defs/EmailDeliverySortBy'}], 'default': 'sent_at', 'description': 'Field to sort by'}, 'recipient': {'type': 'string', 'description': 'Filter to emails where any recipient contains the term (case-insensitive)'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, 'sort_order': {'allOf': [{'$ref': '#/$defs/SortOrder'}], 'default': 'desc', 'description': 'Sort order direction'}, 'related_entity_id': {'type': 'string', 'format': 'uuid', 'description': 'Filter to emails associated with a given related entity (e.g. an invoice id)'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'SortOrder': {'enum': ['asc', 'desc'], 'type': 'string', 'description': 'Sort direction. Shared vocabulary for every `sort_order` query param: declared once so the\ngenerator emits a real enum and an unknown direction is rejected with `400` instead of being\nsilently ignored.\n'}, 'InvoiceType': {'enum': ['STANDARD', 'CORRECTIVE', 'SIMPLIFIED', 'PROFORMA'], 'type': 'string', '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'}, 'InvoiceStatus': {'enum': ['SCHEDULED', 'DRAFT', 'ISSUED', 'SENT', 'PAID', 'OVERDUE', 'RECTIFIED', 'VOIDED', 'CONVERTED', 'ACTIVE', 'EXPIRED'], 'type': 'string', 'description': '- SCHEDULED: Scheduled invoice to be issued automatically on a future date\n- DRAFT: Draft invoice not sent yet (modifiable)\n- ISSUED: Finalized invoice with definitive number but not sent\n- SENT: Invoice sent to customer\n- PAID: Invoice paid\n- OVERDUE: Overdue invoice (not paid after due date)\n- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)\n- VOIDED: Cancelled invoice. Reached either through a direct void request or\n through a TOTAL corrective invoice; `void_cause` tells the two apart.\n- CONVERTED: Proforma converted into an invoice (terminal; the proforma survives\n as the record of the accepted quote, linked to the created invoice)\n- ACTIVE: Active proforma. The single working state of a proforma (non-fiscal\n document): born numbered (PRO-...) and editable, never reaching the fiscal\n statuses. It transitions to CONVERTED when turned into an invoice, or to VOIDED\n when the offer is rejected/withdrawn (POST /v1/invoices/{invoice_id}/void).\n- EXPIRED: Proforma whose offer validity (`valid_until`) has passed. Derived on read\n and never stored; the proforma stays convertible and editable.\n'}, 'VeriFactuSubmissionStatus': {'enum': ['PENDING', 'ACCEPTED', 'VOIDED', 'REJECTED', 'NOT_SUBMITTED'], 'type': 'string', 'description': "Submission status of an invoice's VeriFactu record to AEAT.\n\nSingle vocabulary for the whole axis: the same values are published in\n`verifactu.submission_status` of an invoice and accepted by the `verifactu_status`\nfilter of `GET /v1/invoices`, so a value read from an invoice can be fed straight\nback into the filter.\n\n* `PENDING` — queued, AEAT has not answered yet.\n* `ACCEPTED` — accepted by AEAT (with or without non-blocking warnings).\n* `VOIDED` — a cancellation record was accepted by AEAT.\n* `REJECTED` — rejected by AEAT, or the submission was rejected by the provider\n before reaching AEAT (see `error_code` / `error_message`).\n* `NOT_SUBMITTED` — the invoice is issued with VeriFactu enabled but has no live\n record: the submission fell through (lost event, exhausted retries) and AEAT\n does not know the invoice exists. Transient right after issuing (the async\n submission may still be in flight); if it persists, the registration needs to\n be re-driven.\n\nDrafts and scheduled invoices have no submission to describe yet and omit the\nfield. Invoices with `verifactu.enabled = false` are outside this axis and are\nselected with the `verifactu_enabled` filter.\n"}}, 'required': ['company_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'type': {'$ref': '#/$defs/InvoiceType', 'description': 'Filter by invoice type'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'search': {'type': 'string', 'description': 'Global search across invoice number, recipient name, recipient NIF, and series code (partial, case-insensitive)'}, 'status': {'type': 'array', 'items': {'$ref': '#/$defs/InvoiceStatus'}, 'minItems': 1, 'description': 'Filter by invoice status. Accepts a comma-separated list to match any of several\nstatuses, for example `status=DRAFT,ISSUED`. A single value is also valid.\n'}, 'date_to': {'type': 'string', 'format': 'date', 'description': 'Issue date to (YYYY-MM-DD)'}, 'sort_by': {'type': 'string', 'description': 'Field to sort by (e.g., issue_date, invoice_number, invoice_total)'}, 'metadata': {'type': 'object', 'description': 'Filter by metadata key/value pairs (exact match, AND between keys).\nRepeat the bracket-style param to filter on multiple keys.\nMax 50 pairs per request. Keys must match `^[A-Za-z0-9_\\-.]{1,64}$`.\nExample: `?metadata[external_order_id]=ORD-42&metadata[tenant]=acme`\n', 'maxProperties': 50, 'additionalProperties': {'type': 'string'}}, 'date_from': {'type': 'string', 'format': 'date', 'description': 'Issue date from (YYYY-MM-DD)'}, 'total_max': {'type': 'number', 'format': 'double', 'description': 'Maximum invoice total'}, 'total_min': {'type': 'number', 'format': 'double', 'description': 'Minimum invoice total'}, '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.'}, 'sort_order': {'allOf': [{'$ref': '#/$defs/SortOrder'}], 'default': 'desc', 'description': 'Sort direction'}, 'customer_id': {'$ref': '#/$defs/UUID', 'description': 'Filter by customer UUID'}, 'fiscal_only': {'type': 'boolean', 'default': False, 'description': 'When `true`, returns only fiscal documents (STANDARD, CORRECTIVE, SIMPLIFIED),\nexcluding proformas and any other non-fiscal document. Defaults to `false`\n(the list returns every document type). Ignored when an explicit `type` is given.\n'}, 'series_code': {'type': 'string', 'description': 'Filter by series code (exact match, case-insensitive). Use `search` for partial matching across the invoice number, recipient and series code.'}, 'external_ref': {'type': 'string', 'description': 'Filter by exact external reference (client-supplied order/cart/contract id).'}, 'recipient_nif': {'type': 'string', 'description': "Filter by recipient's NIF (partial search)"}, 'invoice_number': {'type': 'string', 'description': 'Search by invoice number (e.g., 2025/0001)'}, 'recipient_name': {'type': 'string', 'description': "Filter by recipient's fiscal name (partial, case-insensitive search)"}, 'taxable_base_max': {'type': 'number', 'format': 'double', 'description': 'Maximum taxable base'}, 'taxable_base_min': {'type': 'number', 'format': 'double', 'description': 'Minimum taxable base'}, 'verifactu_status': {'$ref': '#/$defs/VeriFactuSubmissionStatus', 'description': 'Filter by the VeriFactu submission status of the invoice, using the very same\nvocabulary that `verifactu.submission_status` publishes on each invoice.\n`NOT_SUBMITTED` selects issued invoices with VeriFactu enabled whose\nregistration never happened (no live record).\n'}, 'verifactu_enabled': {'type': 'boolean', 'description': 'Filter by whether VeriFactu is enabled for the invoice — the same flag published as\n`verifactu.enabled`. `false` returns the invoices that never reach AEAT.\n'}, 'rectified_invoice_id': {'type': 'string', 'format': 'uuid', 'description': 'Return the corrective invoices that correct this invoice. Accepts the id of an\nissued invoice; a single invoice can have several partial correctives.\n'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'member_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'member_id': {'type': 'string', 'format': 'uuid', 'description': 'Membership unique UUID.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id'], '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'provider'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'provider': {'enum': ['stripe'], 'type': 'string', 'description': 'Payment provider slug in **lowercase**. Currently only `stripe` (Stripe Connect) is\noperative; `woocommerce` and `shopify` are reserved for future providers.\n'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company the events belong to — 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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'SortOrder': {'enum': ['asc', 'desc'], 'type': 'string', 'description': 'Sort direction. Shared vocabulary for every `sort_order` query param: declared once so the\ngenerator emits a real enum and an unknown direction is rejected with `400` instead of being\nsilently ignored.\n'}, 'ProductSortBy': {'enum': ['name', 'code', 'category', 'default_price', 'created_at'], 'type': 'string', 'description': 'Product field the list is ordered by.'}, 'ProductCategory': {'enum': ['PRODUCT', 'SERVICE', 'CONSULTING', 'SOFTWARE', 'TRAINING', 'OTHER'], 'type': 'string', 'description': 'Product/service category:\n* PRODUCT - Physical, tangible products\n* SERVICE - General services\n* CONSULTING - Consulting and advisory services\n* SOFTWARE - Development, licenses, SaaS\n* TRAINING - Courses, workshops, training\n* OTHER - Other unclassified types\n'}}, 'required': ['company_id'], 'properties': {'q': {'type': 'string', 'maxLength': 100, 'description': 'Search by name, code or description'}, 'code': {'type': 'string', 'description': 'Filter by code (partial search)'}, 'name': {'type': 'string', 'description': 'Filter by name (partial search case-insensitive)'}, 'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'active': {'type': 'boolean', 'description': 'Filter by active/inactive status'}, 'sort_by': {'allOf': [{'$ref': '#/$defs/ProductSortBy'}], 'default': 'name', 'description': 'Field to sort by'}, 'category': {'$ref': '#/$defs/ProductCategory', 'description': 'Filter by product category'}, 'max_price': {'type': 'number', 'minimum': 0, 'description': 'Maximum price'}, 'min_price': {'type': 'number', 'minimum': 0, 'description': 'Minimum price'}, '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.'}, 'sort_order': {'allOf': [{'$ref': '#/$defs/SortOrder'}], 'default': 'asc', 'description': 'Sort order direction'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'RecurringInvoiceSortBy': {'enum': ['name', 'next_generation', 'status', 'created_at'], 'type': 'string'}, 'RecurringInvoiceStatus': {'enum': ['ACTIVE', 'PAUSED', 'COMPLETED'], 'type': 'string', 'description': 'Lifecycle state of a recurring invoice schedule.'}, 'RecurringInvoiceSortOrder': {'enum': ['asc', 'desc'], 'type': 'string'}}, 'required': ['company_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'status': {'$ref': '#/$defs/RecurringInvoiceStatus'}, 'sort_by': {'$ref': '#/$defs/RecurringInvoiceSortBy', 'description': 'Field to sort by. Defaults to `created_at` when omitted.'}, '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.'}, 'sort_order': {'$ref': '#/$defs/RecurringInvoiceSortOrder', 'description': 'Sort direction. Defaults to `desc` when omitted.'}, 'customer_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'to': {'type': 'string', 'format': 'date-time', 'description': 'Upper bound of the time range (inclusive). Defaults to now.'}, 'from': {'type': 'string', 'format': 'date-time', 'description': 'Lower bound of the time range (inclusive). Defaults to 30 days ago.'}, 'limit': {'type': 'integer', 'default': 25, 'maximum': 100, 'minimum': 1}, 'cursor': {'type': 'string', 'description': 'Opaque cursor returned by a previous response (next_cursor / prev_cursor).'}, 'method': {'type': 'string', 'description': 'Filter by HTTP method.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Account the call is authorized against. It does not widen the result set.'}, 'api_key_id': {'type': 'string', 'format': 'uuid', 'description': 'Narrow the result to one of your API keys. Any key of yours in this environment is accepted, not just the one you authenticate with; a key belonging to someone else simply yields no results.'}, 'http_status': {'type': 'integer', 'maximum': 599, 'minimum': 100, 'description': 'Filter by an exact HTTP status code.'}, 'only_errors': {'type': 'boolean', 'default': False, 'description': 'If true, only requests with status >= 400.'}, 'path_contains': {'type': 'string', 'description': 'Filter by path substring (case-insensitive).'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'DocumentType': {'enum': ['UNASSIGNED', 'STANDARD', 'SIMPLIFIED', 'CORRECTIVE', 'PROFORMA'], 'type': 'string', 'description': 'Document type associated with a series. Values mirror `InvoiceType`,\nso the series a document needs is named exactly like the document:\n- UNASSIGNED: Legacy series, compatible with any invoice type\n- STANDARD: Standard invoice\n- SIMPLIFIED: Simplified invoice\n- CORRECTIVE: Corrects or cancels a previous invoice\n- PROFORMA: Proforma (commercial document, non-fiscal numbering)\n'}}, 'required': ['company_id'], 'properties': {'page': {'type': 'integer', 'minimum': 1, 'description': 'Page number (starts at 1). Omit for the full, unpaginated list.'}, 'limit': {'type': 'integer', 'maximum': 100, 'minimum': 1, 'description': 'Items per page. Omit for the full, unpaginated list.'}, 'active': {'type': 'boolean', 'description': 'Filters by activity: `true` returns only active series, `false` only inactive ones.\nOmit it and you get **all** the series, active and inactive.\n'}, '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.'}, 'document_type': {'$ref': '#/$defs/DocumentType', 'description': 'Filter by document type (UNASSIGNED series are always included)'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'search': {'type': 'string', 'description': 'Case-insensitive filter on NIF, legal name or trade name — the same filter, over the same universe, as the one `GET /v1/accounts/{account_id}/companies` applies. Blank or omitted returns all.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'webhook_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'event_id': {'type': 'string', 'format': 'uuid', 'description': 'Only deliveries of this event. Use it to follow every attempt on one event without paging through the whole history.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, 'event_type': {'type': 'string', 'description': 'Only deliveries of this event type.'}, 'webhook_id': {'type': 'string', 'format': 'uuid', 'description': 'Subscription of the account in the path. A subscription of another account answers `404`, the same as one that does not exist: under the account resolved from `{account_id}` it simply is not there.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id'], 'properties': {'page': {'type': 'integer', 'default': 1, 'minimum': 1, 'description': 'Page number, starting at 1. The response echoes it back as `pagination.current_page`.'}, 'limit': {'type': 'integer', 'default': 20, 'maximum': 100, 'minimum': 1, 'description': 'How many items to return per page. The response echoes it back as `pagination.items_per_page`.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'NIF': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Spanish Tax ID (9 characters, uppercase only). Structural validation:\n- DNI: 8 digits + 1 letter (e.g., 12345678A)\n- NIE: X/Y/Z + 7 digits + 1 letter (e.g., X1234567A)\n- CIF: Organization letter + 7 digits + 1 control digit/letter (e.g., B12345674)\n'}, 'IBAN': {'type': 'string', 'pattern': '^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$', 'maxLength': 34, 'minLength': 15, 'description': 'IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Phone': {'type': 'string', 'pattern': '^[+]?[0-9\\s\\-\\(\\)]+$', 'maxLength': 20, 'minLength': 9, 'description': 'Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +'}, 'SWIFT': {'type': 'string', 'pattern': '^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$', 'maxLength': 11, 'minLength': 8, 'description': 'SWIFT/BIC code'}, 'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'Language': {'enum': ['es', 'en', 'ca'], 'type': 'string', 'description': 'Supported languages'}, 'EntityType': {'enum': ['INDIVIDUAL', 'LEGAL_ENTITY'], 'type': 'string', 'description': 'Taxpayer type.\nINDIVIDUAL: Natural person (individual self-employed).\nLEGAL_ENTITY: Legal entity (company with legal form: SL, SA, etc.).\n'}, 'InvoiceTemplateType': {'enum': ['MODERN_TABLE', 'PROFESSIONAL_SERVICE'], 'type': 'string', 'description': 'Invoice PDF template. `MODERN_TABLE` is a structured table layout for\nproduct/service lines; `PROFESSIONAL_SERVICE` is a text-based layout.\n'}, 'LegalRepresentative': {'type': 'object', 'required': ['full_name', 'nif', 'address'], 'properties': {'nif': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Tax ID of the legal representative (DNI/CIF/NIE)'}, 'address': {'allOf': [{'$ref': '#/$defs/Address'}, {'description': 'Address of the legal representative'}]}, 'full_name': {'type': 'string', 'maxLength': 255, 'minLength': 1, 'description': 'Full name of the legal representative'}}, 'description': 'Legal representative data for a legal entity.\nOnly used when entity_type = LEGAL_ENTITY.\n', 'additionalProperties': False}, 'UpdateCompanyRequest': {'type': 'object', 'properties': {'iae': {'type': ['string', 'null'], 'maxLength': 20, 'minLength': 1, 'description': 'IAE code'}, 'nif': {'allOf': [{'$ref': '#/$defs/NIF'}, {'anyOf': [{'description': 'NIF/CIF. IMMUTABLE once set.'}, {'type': 'null'}]}]}, 'email': {'allOf': [{'$ref': '#/$defs/Email'}, {'anyOf': [{}, {'type': 'null'}]}]}, 'phone': {'allOf': [{'$ref': '#/$defs/Phone'}, {'anyOf': [{}, {'type': 'null'}]}]}, 'address': {'$ref': '#/$defs/Address'}, 'website': {'type': ['string', 'null'], 'maxLength': 500, 'minLength': 1, 'description': 'Website'}, 'logo_url': {'type': ['string', 'null'], 'maxLength': 500, 'minLength': 1, 'description': 'Logo URL'}, 'legal_form': {'type': ['string', 'null'], 'maxLength': 100, 'minLength': 1, 'description': 'Legal form (SL, SA, ...). IMMUTABLE once set. Only for LEGAL_ENTITY.'}, 'legal_name': {'type': ['string', 'null'], 'maxLength': 255, 'minLength': 1, 'description': 'Legal/fiscal name. Changing it triggers AEAT census re-validation of the NIF.\nFor a self-employed individual the census matches NIF and name together, so a\nname it does not recognise is rejected. For a legal entity the name is\n**not verified**: the re-validation only confirms the CIF, and the business\nname held by the census is the only thing to contrast yours against.\n'}, 'trade_name': {'type': ['string', 'null'], 'maxLength': 255, 'minLength': 1, 'description': 'Commercial/trade name for the company'}, 'entity_type': {'allOf': [{'$ref': '#/$defs/EntityType'}, {'anyOf': [{'description': 'Entity type. IMMUTABLE once set.'}, {'type': 'null'}]}]}, 'default_iban': {'allOf': [{'$ref': '#/$defs/IBAN'}, {'anyOf': [{}, {'type': 'null'}]}]}, 'default_swift': {'allOf': [{'$ref': '#/$defs/SWIFT'}, {'anyOf': [{}, {'type': 'null'}]}]}, 'account_holder': {'type': ['string', 'null'], 'maxLength': 255, 'minLength': 1, 'description': 'Bank account holder'}, 'email_language': {'allOf': [{'$ref': '#/$defs/Language'}, {'anyOf': [{'description': 'Language for emails'}, {'type': 'null'}]}]}, 'additional_info': {'type': ['string', 'null'], 'maxLength': 500, 'description': 'Free note printed on the invoice. It is presentation, not fiscal identity, so a\ntest credential may change it even on a company activated in Live. Read it back in\n`CompanyData.additional_info` (`GET /v1/companies/{company_id}`).\n'}, 'invoice_language': {'allOf': [{'$ref': '#/$defs/Language'}, {'anyOf': [{'description': 'Language for invoice PDFs'}, {'type': 'null'}]}]}, 'activity_start_date': {'type': ['string', 'null'], 'format': 'date', 'description': 'Activity start date'}, 'default_payment_term': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, 'description': 'Default payment term in days'}, 'invoice_accent_color': {'type': ['string', 'null'], 'pattern': '^#[0-9A-Fa-f]{6}$', 'description': 'Invoice PDF accent color (#RRGGBB)'}, 'legal_representative': {'$ref': '#/$defs/LegalRepresentative'}, 'invoice_template_type': {'anyOf': [{'allOf': [{'$ref': '#/$defs/InvoiceTemplateType'}], 'description': 'Invoice PDF template type'}, {'type': 'null'}]}}, 'description': 'Editable fields of a company.\n`entity_type`, `nif` and `legal_form` are immutable once set;\n`legal_name` can only be corrected together with a successful\nAEAT census re-validation of the NIF. For a company that\nre-validation checks the CIF only — the name is **not verified**,\nso it can never fail because of the name you send.\n\n**Everything here reads back.** The `200` of the update — and every later\n`GET /v1/companies/{company_id}` — returns `CompanyData`, which carries each of these\nfields under the same name and the same type. No need to keep your own copy to\nreconcile: write it, read it back. Five of them also have a read of their own,\n`logo_url`, `invoice_template_type`, `invoice_accent_color`, `invoice_language` and\n`email_language`, all returned by\n`GET /v1/companies/{company_id}/invoice-customization`.\n\nA field you never set is **absent** from the read, which means "nothing stored" — not\n"hidden from you", and not a default. What varies by caller is what you may *write*\n(see the Test-credential rule below), never what comes back.\n\n**From Test, on a company activated in Live, only six of these fields are writable**:\n`logo_url`, `invoice_accent_color`, `invoice_template_type`, `invoice_language`,\n`email_language` and `additional_info` — what the invoice *looks like* and the free\nnote it carries. Everything else describes the real business and answers\n`422 FISCAL_IDENTITY_LIVE_ONLY` unless the call is made with a live credential.\n', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/UpdateCompanyRequest'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'NIF': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Spanish Tax ID (9 characters, uppercase only). Structural validation:\n- DNI: 8 digits + 1 letter (e.g., 12345678A)\n- NIE: X/Y/Z + 7 digits + 1 letter (e.g., X1234567A)\n- CIF: Organization letter + 7 digits + 1 control digit/letter (e.g., B12345674)\n'}, 'IBAN': {'type': 'string', 'pattern': '^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$', 'maxLength': 34, 'minLength': 15, 'description': 'IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n'}, 'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Phone': {'type': 'string', 'pattern': '^[+]?[0-9\\s\\-\\(\\)]+$', 'maxLength': 20, 'minLength': 9, 'description': 'Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +'}, 'SWIFT': {'type': 'string', 'pattern': '^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$', 'maxLength': 11, 'minLength': 8, 'description': 'SWIFT/BIC code'}, 'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'PaymentInfo': {'type': 'object', 'properties': {'iban': {'$ref': '#/$defs/IBAN'}, 'swift': {'$ref': '#/$defs/SWIFT'}, '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'}, 'payment_term_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, '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}, 'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'PatchCustomerRequest': {'type': 'object', 'properties': {'nif': {'allOf': [{'$ref': '#/$defs/NIF'}], 'description': 'New Spanish Tax ID. Mutually exclusive with `alternative_id`.\nOmit to keep the current identifier; it cannot be cleared.\n'}, 'email': {'type': ['string', 'null'], 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address. Send `null` to clear it.'}, 'notes': {'type': ['string', 'null'], 'description': 'Additional notes. Send `null` to clear it.'}, 'phone': {'anyOf': [{'allOf': [{'$ref': '#/$defs/Phone'}], 'description': 'Phone number. Send `null` to clear it.'}, {'type': 'null'}]}, 'active': {'type': 'boolean', 'description': 'Whether the customer is active or inactive.'}, 'address': {'allOf': [{'$ref': '#/$defs/Address'}], 'description': 'Full address. Replaced as a whole (the address itself is not\npatched field by field) and cannot be cleared.\n'}, 'website': {'type': ['string', 'null'], 'pattern': '^(https?://.+|)$', 'maxLength': 255, 'description': 'Website URL. Send `null` to clear it.'}, 'legal_name': {'type': 'string', 'maxLength': 120, 'minLength': 1, 'description': 'Customer legal name. Cannot be cleared. Matched against the AEAT census only\nfor individuals; for a company the name is **not verified**.\n'}, 'trade_name': {'type': ['string', 'null'], 'maxLength': 120, 'description': 'Customer trade name. Send `null` to clear it.'}, 'alternative_id': {'allOf': [{'$ref': '#/$defs/AlternativeIdentifier'}], 'description': 'New alternative identifier (non-Spanish customers). Mutually\nexclusive with `nif`. Omit to keep the current identifier.\n'}, 'billing_emails': {'type': ['array', 'null'], 'items': {'$ref': '#/$defs/Email'}, 'description': 'Additional emails for invoice delivery. Replaced as a whole;\nsend `null` or `[]` to remove them all.\n'}, 'contact_person': {'type': ['string', 'null'], 'maxLength': 200, 'description': 'Contact person name. Send `null` to clear it.'}, 'general_discount': {'type': ['number', 'null'], 'maximum': 100, 'minimum': 0, 'description': 'General discount percentage. Send `null` to clear it.'}, 'preferred_payment_method': {'allOf': [{'$ref': '#/$defs/PaymentInfo'}], 'description': 'Default payment method. Replaced as a whole; omit it to keep the\ncurrent one.\n'}}, 'description': 'Partial update of a customer (RFC 5789). Only the fields present in the\nbody are touched:\n\n- **field omitted** → the current value is kept;\n- **field sent with a value** → replaced;\n- **field sent as `null`** → cleared (only where documented as nullable\n below).\n\nThe resulting customer goes through the same validation as `PUT`\n(AEAT census check for Spanish NIFs, duplicate identifier check\nexcluding this customer, field formats). The census check matches\n`legal_name` only for individuals; for a company the name is\n**not verified** and only the CIF decides.\n', 'additionalProperties': False}, 'AlternativeIdentifier': {'type': ['object', 'null'], 'required': ['type', 'number'], 'properties': {'type': {'enum': ['NIF_IVA', 'PASSPORT', 'COUNTRY_ID', 'RESIDENCE_CERTIFICATE', 'OTHER_DOCUMENT', 'NOT_REGISTERED', '02', '03', '04', '05', '06', '07'], 'type': 'string', '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', 'maxLength': 20, 'minLength': 1}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code. Constrains the allowed `type` values;\nsee the VeriFactu rules on the parent schema.\n'}}, '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'}}, 'required': ['company_id', 'customer_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/PatchCustomerRequest'}, '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.'}, 'customer_id': {'$ref': '#/$defs/UUID', 'description': 'Customer ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'IBAN': {'type': 'string', 'pattern': '^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$', 'maxLength': 34, 'minLength': 15, 'description': 'IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n'}, 'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Phone': {'type': 'string', 'pattern': '^[+]?[0-9\\s\\-\\(\\)]+$', 'maxLength': 20, 'minLength': 9, 'description': 'Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +'}, 'SWIFT': {'type': 'string', 'pattern': '^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$', 'maxLength': 11, 'minLength': 8, 'description': 'SWIFT/BIC code'}, 'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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"}, 'Recipient': {'type': 'object', 'properties': {'nif': {'type': 'string', 'pattern': '^[A-Za-z0-9]{9}$', 'maxLength': 9, 'minLength': 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'}, 'email': {'$ref': '#/$defs/Email'}, 'phone': {'$ref': '#/$defs/Phone'}, 'address': {'$ref': '#/$defs/Address'}, 'legal_name': {'type': 'string', 'maxLength': 255, 'minLength': 1, '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'], 'maxLength': 255, 'minLength': 1, 'description': 'Recipient trade name (optional)'}, '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"}, 'alternative_id': {'allOf': [{'$ref': '#/$defs/AlternativeIdentifier'}, {'description': 'Alternative identifier for foreign customers (mutually exclusive with nif)'}]}}, 'additionalProperties': False}, 'RegimeKey': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, 'InvoiceType': {'enum': ['STANDARD', 'CORRECTIVE', 'SIMPLIFIED', 'PROFORMA'], 'type': 'string', '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'}, 'PaymentInfo': {'type': 'object', 'properties': {'iban': {'$ref': '#/$defs/IBAN'}, 'swift': {'$ref': '#/$defs/SWIFT'}, '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'}, 'payment_term_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, '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}, 'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'IrpfPercentage': {'enum': [0, 1, 2, 7, 15, 19, 24], 'type': 'integer', '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': {'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'], 'type': 'string', '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': {'enum': ['NORMAL', 'SUPLIDO'], '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'}, 'EmailConfiguration': {'type': 'object', 'required': ['recipients'], 'properties': {'cc': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'description': 'List of CC emails (optional)'}, 'message': {'type': 'string', 'maxLength': 2000, 'minLength': 1, 'description': 'Custom message (optional, added to email body)'}, 'subject': {'type': 'string', 'maxLength': 200, 'minLength': 1, 'description': 'Custom email subject (optional, if not specified uses a default)'}, 'recipients': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'minItems': 1, 'description': 'List of recipient emails (at least 1 required)'}}, 'additionalProperties': False}, 'UpdateInvoiceRequest': {'type': 'object', 'properties': {'type': {'allOf': [{'$ref': '#/$defs/InvoiceType'}], 'description': 'New invoice type. Allowed transitions: `STANDARD` ↔ `SIMPLIFIED`.\nTransitions to/from `CORRECTIVE` are rejected (corrective invoices have a\ndedicated `POST /v1/invoices/{invoice_id}/corrective` endpoint).\nTransitions to/from `PROFORMA` are rejected too — a proforma is converted\ninto an invoice via its dedicated conversion flow, never by editing its type.\n'}, 'lines': {'type': 'array', 'items': {'type': 'object', 'required': ['quantity'], 'properties': {'unit': {'type': 'string'}, 'main_tax': {'$ref': '#/$defs/TaxInfo'}, 'quantity': {'type': 'number'}, '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"}, 'line_type': {'allOf': [{'$ref': '#/$defs/InvoiceLineType'}], 'description': 'Fiscal line type. Omitted, `NORMAL` applies.\nUse `SUPLIDO` for payments on behalf of the final client\n(art. 78.Tres.3 LIVA). Requires `source_invoice_reference`.\n'}, 'unit_price': {'type': 'number', '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).\nFinal amounts are always rounded to 2 decimals.\n', 'exclusiveMinimum': 0}, 'description': {'type': 'string', 'maxLength': 2000, 'description': 'Required for NORMAL lines; optional for SUPLIDO lines.\n'}, 'exemption_reason': {'anyOf': [{'$ref': '#/$defs/ExemptionReason'}, {'type': 'null'}]}, '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'}, 'discount_percentage': {'type': 'number'}, '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'}, 'exemption_reason_text': {'type': ['string', 'null'], 'maxLength': 500}, '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"}, 'equivalence_surcharge_rate': {'$ref': '#/$defs/EquivalenceSurchargePercentage'}}, 'additionalProperties': False}}, 'notes': {'type': 'string'}, 'options': {'type': 'object', 'properties': {'email_config': {'anyOf': [{'allOf': [{'$ref': '#/$defs/EmailConfiguration'}], 'description': 'Email configuration for auto-send. null clears the existing config.'}, {'type': 'null'}]}, 'verifactu_enabled': {'type': 'boolean', 'description': 'Whether VeriFactu submission is enabled at issue time.'}, 'send_automatically': {'type': 'boolean', 'description': 'Whether the invoice should be auto-emailed after issuing.'}}, 'description': 'Processing options for the draft. Fields are optional and follow partial update\nsemantics: omitted fields preserve the existing value.\n', 'additionalProperties': False}, 'due_date': {'type': ['string', 'null'], 'format': 'date', 'description': 'New due date. Must be the same as or after `issue_date`.\nSet to null to clear the due date. If not provided, keeps the existing value.\n'}, 'recipient': {'allOf': [{'$ref': '#/$defs/Recipient'}], 'description': 'Replaces the recipient when present. Provide `customer_id` to switch to a\nregistered client, or inline `legal_name`/`nif`/`address` for an ad-hoc receptor.\nOmit to keep the current recipient.\n'}, 'series_id': {'allOf': [{'$ref': '#/$defs/UUID'}], 'description': 'Series ID. If provided, changes the invoice series (only for DRAFT invoices).\nThe invoice number will be reassigned from the new series when issued.\n'}, 'valid_until': {'type': ['string', 'null'], 'format': 'date', 'description': 'Offer validity date. Only rendered on PROFORMA invoices; on any other\ninvoice type the field is inert. Purely informational.\nSet to null to clear it. If not provided, keeps the existing value.\n'}, 'payment_info': {'allOf': [{'$ref': '#/$defs/PaymentInfo'}], 'description': 'Replaces the payment information when present (sets method/IBAN/SWIFT/term days).\nOmit to keep the current payment info.\n'}, 'operation_date': {'type': ['string', 'null'], 'format': 'date', 'description': 'Date when the operation occurred. **Must be today or a past date.**\nSet to null to clear (operation date = issue date).\nIf not provided, keeps the existing value.\n'}}, 'description': 'Partial update for a DRAFT invoice. Only fields present in the body are applied;\nomitted fields preserve their existing value.\n', 'additionalProperties': False}, 'AlternativeIdentifier': {'type': ['object', 'null'], 'required': ['type', 'number'], 'properties': {'type': {'enum': ['NIF_IVA', 'PASSPORT', 'COUNTRY_ID', 'RESIDENCE_CERTIFICATE', 'OTHER_DOCUMENT', 'NOT_REGISTERED', '02', '03', '04', '05', '06', '07'], 'type': 'string', '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', 'maxLength': 20, 'minLength': 1}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code. Constrains the allowed `type` values;\nsee the VeriFactu rules on the parent schema.\n'}}, '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'}, 'EquivalenceSurchargePercentage': {'enum': [0, 0.5, 0.625, 1.4, 5.2], 'type': 'number', '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'}}, 'required': ['company_id', 'invoice_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/UpdateInvoiceRequest'}, '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'AccountRole': {'enum': ['OWNER', 'ADMIN', 'MEMBER'], 'type': 'string', 'description': "Who administers the account. Independent of `access_level`, which says how much access someone has to a given company.\n\n`OWNER` — full control, including billing, API keys and transferring ownership. Exactly one per account, so it is never an accepted value when you SET a role (inviting a member or changing one's role): both reject it with `422 OWNER_ROLE_NOT_ASSIGNABLE`. Ownership moves only through `PUT /v1/accounts/{account_id}/owner`.\n`ADMIN` — everything an `OWNER` can do, except transferring ownership.\n`MEMBER` — no account administration. Access to each company is granted individually and reported as `access_level`; a member only sees the companies granted to them."}, 'ChangeMemberRoleRequest': {'type': 'object', 'required': ['account_role'], 'properties': {'account_role': {'$ref': '#/$defs/AccountRole'}}, 'additionalProperties': False}}, 'required': ['account_id', 'member_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/ChangeMemberRoleRequest'}, 'member_id': {'type': 'string', 'format': 'uuid', 'description': 'Membership unique UUID.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, 'ProductCategory': {'enum': ['PRODUCT', 'SERVICE', 'CONSULTING', 'SOFTWARE', 'TRAINING', 'OTHER'], 'type': 'string', 'description': 'Product/service category:\n* PRODUCT - Physical, tangible products\n* SERVICE - General services\n* CONSULTING - Consulting and advisory services\n* SOFTWARE - Development, licenses, SaaS\n* TRAINING - Courses, workshops, training\n* OTHER - Other unclassified types\n'}, 'PatchProductRequest': {'type': 'object', 'properties': {'code': {'type': ['string', 'null'], 'pattern': '^[a-zA-Z0-9_-]*$', 'maxLength': 50, 'description': 'Unique alphanumeric product code. Send `null` to clear it.'}, 'name': {'type': 'string', 'maxLength': 255, 'description': 'Product/service name. Cannot be cleared.'}, 'unit': {'type': ['string', 'null'], 'maxLength': 50, 'description': 'Unit of measure. Send `null` to clear it.'}, 'active': {'type': 'boolean', 'description': 'Indicates whether the product is active.'}, 'category': {'allOf': [{'$ref': '#/$defs/ProductCategory'}], 'description': 'Product category. Omit to keep the current one.'}, 'main_tax': {'allOf': [{'$ref': '#/$defs/TaxInfo'}], 'description': 'Main tax. Replaced as a whole (it is not patched field by field);\nomit it to keep the current one. A product always carries a main\ntax, so it cannot be cleared.\n'}, 'irpf_rate': {'type': ['number', 'null'], 'maximum': 100, 'minimum': 0, 'multipleOf': 0.01, 'description': 'IRPF withholding percentage. Send `null` to state that none\napplies (equivalent to `0`).\n'}, 'description': {'type': ['string', 'null'], 'description': 'Detailed description. Send `null` to clear it.'}, 'default_price': {'type': ['number', 'null'], 'minimum': 0, 'multipleOf': 0.0001, 'description': 'Suggested default price. Send `null` to clear it.'}, 'equivalence_surcharge_rate': {'type': ['number', 'null'], 'maximum': 100, 'minimum': 0, 'multipleOf': 0.01, 'description': 'Equivalence surcharge percentage. Send `null` to state that none\napplies (equivalent to `0`).\n\nThe merged result must be coherent with the regime key: if this\nPATCH does not send `main_tax.regime_key`, the stored regime is\nadjusted automatically (`18` when the merged surcharge is > 0,\n`01` when it is not). With an explicit `regime_key` in this PATCH,\nan incoherent combination is rejected with a 422\n(`SURCHARGE_REQUIRES_REGIME` / `REGIME_REQUIRES_SURCHARGE`).\n'}}, 'description': 'Partial update of a product (RFC 5789). Only the fields present in the\nbody are touched:\n\n- **field omitted** → the current value is kept;\n- **field sent with a value** → replaced;\n- **field sent as `null`** → cleared (only where documented as nullable\n below).\n\nThe resulting product goes through the same validation as `PUT`\n(duplicate code check excluding this product, field formats, tax ranges).\n', 'additionalProperties': False}}, 'required': ['company_id', 'product_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/PatchProductRequest'}, '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.'}, 'product_id': {'type': 'string', 'format': 'uuid', 'description': 'Product unique UUID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'ExemptionReason': {'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'], 'type': 'string', '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'}, 'RecurringLineRequest': {'type': 'object', 'required': ['description', 'quantity', 'unit_price', 'vat_rate'], 'properties': {'unit': {'type': 'string', 'maxLength': 20}, 'quantity': {'type': 'number', 'minimum': 0.01}, 'tax_type': {'type': 'string', 'description': 'Tax type. Omitted, `IVA` applies.'}, 'vat_rate': {'type': 'number'}, 'irpf_rate': {'type': ['number', 'null']}, 'regime_key': {'type': 'string', 'description': 'VeriFactu regime key. Omitted, `01` (general regime) applies.'}, 'unit_price': {'type': 'number', 'minimum': 0}, 'description': {'type': 'string', 'maxLength': 2000}, 'exemption_reason': {'anyOf': [{'$ref': '#/$defs/ExemptionReason'}, {'type': 'null'}]}, 'discount_percentage': {'type': 'number', 'maximum': 100, 'minimum': 0}, 'exemption_reason_text': {'type': ['string', 'null'], 'maxLength': 500, 'description': 'Custom exemption text. Only used when `exemption_reason` is `OTRO`.\n\nSame shape as an invoice line: the template declares WHY the operation carries no tax,\nand every invoice it generates inherits it. A 0% line without a reason is rejected on\nwrite — VeriFactu does not accept an exempt line with no explicit motive.\n'}, 'equivalence_surcharge_rate': {'type': ['number', 'null']}}, 'description': 'Recurring-invoice line. Unlike invoice lines (which nest tax data under a `main_tax` object),\nrecurring lines use flat tax fields: `vat_rate`, `tax_type`, `regime_key`,\n`equivalence_surcharge_rate` and `irpf_rate`. Do not send a `main_tax` object here.\n', 'additionalProperties': False}, 'RecurringEmailConfigRequest': {'type': ['object', 'null'], 'properties': {'cc': {'type': 'array', 'items': {'type': 'string'}}, 'message': {'type': ['string', 'null']}, 'subject': {'type': ['string', 'null']}, 'recipients': {'type': 'array', 'items': {'type': 'string'}}}}, 'PatchRecurringInvoiceRequest': {'type': 'object', 'properties': {'name': {'type': 'string', 'maxLength': 255, 'description': 'Template name. Cannot be cleared.'}, 'lines': {'type': ['array', 'null'], 'items': {'$ref': '#/$defs/RecurringLineRequest'}, 'minItems': 1, 'description': 'Template lines, replaced as a whole (they are not patched line by line). Omit\nthem to keep the current ones — a template with no lines invoices nothing, so\nan empty array is rejected.\n'}, 'notes': {'type': ['string', 'null'], 'description': 'Notes printed on the generated invoices. Send `null` to clear them.'}, 'end_date': {'type': ['string', 'null'], 'format': 'date', 'description': 'Date the recurrence stops. Send `null` to make it open-ended.'}, 'frequency': {'enum': ['MONTHLY'], 'type': 'string', 'description': 'Generation cadence. Only `MONTHLY` is supported today; the field exists in the\nrequest so an unsupported cadence is rejected instead of being silently ignored.\n'}, 'series_id': {'type': 'string', 'format': 'uuid', 'description': 'Series the generated invoices are numbered in. Cannot be cleared.'}, 'start_date': {'type': 'string', 'format': 'date', 'description': 'First issue date. Only editable while the template has not generated any invoice yet.\nA past date is accepted and stored as sent, but it never anchors generation in the\npast: `next_generation` moves to the first upcoming `day_of_month`.\n'}, 'customer_id': {'type': ['string', 'null'], 'format': 'uuid', 'description': 'Recipient of the generated invoices. Send `null` to leave the template without\na recipient; omit it to keep the current one.\n'}, 'day_of_month': {'type': 'integer', 'maximum': 31, 'minimum': 1, 'description': 'Day of the month the invoice is issued. Moves the next generation.'}, 'payment_iban': {'type': ['string', 'null']}, 'preview_days': {'type': 'integer', 'maximum': 30, 'minimum': 0, 'description': 'Days before emission date to create a draft for review. 0 means immediate emission.'}, 'payment_swift': {'type': ['string', 'null']}, 'payment_method': {'anyOf': [{'allOf': [{'$ref': '#/$defs/PaymentMethod'}], 'description': 'Payment method. Replaced as a whole together with `payment_iban`,\n`payment_swift` and `payment_term_days`: send them in the same request or they\nare dropped. Send `null` to state that no payment method applies.\n'}, {'type': 'null'}]}, 'payment_term_days': {'type': ['integer', 'null']}, 'verifactu_enabled': {'type': 'boolean'}, 'send_automatically': {'type': 'boolean'}, 'email_configuration': {'anyOf': [{'allOf': [{'$ref': '#/$defs/RecurringEmailConfigRequest'}], 'description': 'Email delivery settings, replaced as a whole. Send `null` to stop sending the\ngenerated invoices by email.\n'}, {'type': 'null'}]}}, 'description': 'Partial update of a recurring invoice (RFC 5789). Only the fields present in the\nbody are touched:\n\n- **field omitted** → the current value is kept;\n- **field sent with a value** → replaced;\n- **field sent as `null`** → cleared (only where documented as nullable below).\n\nIn particular, changing the lines no longer wipes the recipient, and the schedule\n(`day_of_month`, `start_date`) stays put unless you send it.\n', 'additionalProperties': False}}, 'required': ['company_id', 'recurring_invoice_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/PatchRecurringInvoiceRequest'}, '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'SeriesCode': {'type': 'string', 'pattern': '^[A-Z0-9\\-_]{1,50}$', 'maxLength': 50, 'minLength': 1, 'description': 'Alphanumeric series code (used in {CODIGO} variable).\nAllows uppercase letters, numbers, hyphens and underscores.\n'}, 'CounterReset': {'enum': ['NEVER', 'ANNUAL', 'MONTHLY'], 'type': 'string', 'description': 'Counter reset policy:\n- NEVER: Counter never resets (continuous numbering)\n- ANNUAL: Counter resets yearly\n- MONTHLY: Counter resets monthly\n'}, 'DocumentType': {'enum': ['UNASSIGNED', 'STANDARD', 'SIMPLIFIED', 'CORRECTIVE', 'PROFORMA'], 'type': 'string', 'description': 'Document type associated with a series. Values mirror `InvoiceType`,\nso the series a document needs is named exactly like the document:\n- UNASSIGNED: Legacy series, compatible with any invoice type\n- STANDARD: Standard invoice\n- SIMPLIFIED: Simplified invoice\n- CORRECTIVE: Corrects or cancels a previous invoice\n- PROFORMA: Proforma (commercial document, non-fiscal numbering)\n'}, 'SeriesFormat': {'type': 'string', 'pattern': '^[A-Z0-9\\-_/{}:]*$', 'maxLength': 255, 'minLength': 1, 'description': 'Format template with available variables (UPPERCASE ONLY):\n- {CODIGO}: Series code (e.g., "FAC")\n- {YYYY}: Year with 4 digits (e.g., "2025")\n- {YY}: Year with 2 digits (e.g., "25")\n- {MM}: Month with 2 digits (e.g., "01")\n- {NUM}: Sequential number without padding (e.g., "1")\n- {NUM:X}: Sequential number with padding (e.g., {NUM:4} → "0001")\n\n**REQUIRED**: Must contain at least {NUM} or {NUM:X}\n**IMPORTANT**: Only uppercase (rejects {yy}, {mm}, {codigo}, etc.)\n\nValid examples:\n- "{CODIGO}-{YYYY}-{NUM:4}" → "FAC-2025-0001"\n- "{CODIGO}/{NUM:6}" → "FAC/000001"\n- "{YYYY}{MM}-{NUM:3}" → "202501-001"\n'}, 'PatchSeriesRequest': {'type': 'object', 'properties': {'code': {'$ref': '#/$defs/SeriesCode'}, 'name': {'type': 'string', 'maxLength': 100, 'minLength': 1, 'description': 'Descriptive name of the series. Cannot be cleared.'}, 'active': {'type': 'boolean', 'description': 'Whether the series is active.\n\n**Restriction:** A default series cannot be deactivated\n(another must be set as default first).\n'}, 'format': {'$ref': '#/$defs/SeriesFormat'}, 'description': {'type': ['string', 'null'], 'maxLength': 1000, 'description': 'Series description. Send `null` to clear it.'}, 'counter_reset': {'$ref': '#/$defs/CounterReset'}, 'document_type': {'$ref': '#/$defs/DocumentType'}, 'default_series': {'type': 'boolean', 'description': 'Whether this is the default series.\n\n**Restriction:** An inactive series cannot be marked as default.\n'}, 'initial_number': {'type': 'integer', 'format': 'int64', 'maximum': 999999, 'minimum': 1, 'description': 'Initial number for this series counter.\nOnly while the series has no issued invoices.\n'}}, 'description': 'Partial update of an invoice series (RFC 5789). Only the fields present in the\nbody are touched:\n\n- **field omitted** → the current value is kept;\n- **field sent with a value** → replaced;\n- **field sent as `null`** → cleared (only `description`, the one field a series\n can live without).\n\nThe same rules as `PUT` apply: the fields that drive numbering (`code`, `format`,\n`counter_reset`, `initial_number`) are rejected once the series has issued\ninvoices, so renaming a series in production keeps working.\n', 'additionalProperties': False}}, 'required': ['company_id', 'series_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/PatchSeriesRequest'}, 'series_id': {'$ref': '#/$defs/UUID', 'description': 'Series ID'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'WebhookEventTypeEnum': {'enum': ['invoice.issued', 'invoice.email.sent', 'invoice.voided', 'recurring_invoice.paused', 'verifactu.status.updated', 'account.claimed', 'company.created', 'representation.signed'], 'type': 'string', 'description': 'Available webhook event types:\n- `invoice.issued` — Invoice issued and finalized\n- `invoice.email.sent` — Invoice sent by email\n- `invoice.voided` — Invoice voided\n- `recurring_invoice.paused` — A schedule stopped generating on its own (downgrade or a\n permanent generation failure); the invoice it was going to issue will not arrive\n- `verifactu.status.updated` — VeriFactu status changed (see `VeriFactuSubmissionStatus`)\n- `account.claimed` — A provisioned account was claimed by its holder\n- `company.created` — A company was created inside a provisioned account\n- `representation.signed` — Fiscal representation signed for a NIF (production invoicing enabled)\n\nThe `account.*` events are delivered only to the **provisioner** that created the\naccount; a subscription on any other account never receives them.\n'}, 'WebhookAccountRelationship': {'enum': ['own', 'managed', 'all'], 'type': 'string', 'description': 'Which accounts a subscription receives events from — the same vocabulary as the\n`account_relationship` field in every delivered event envelope. One term to ask for\nevents, the same term to route them on arrival.\n\n* `own` (default) — only your own account.\n* `managed` — only accounts you manage (accounts you provisioned). Whether you actually\n receive them also depends on the management relationship granting data visibility; a\n billing-only relationship does not.\n* `all` — both.\n\nA delivered event is always `own` or `managed` (never `all`): its\n`account_relationship`, alongside `account_id` and `account_external_ref`, tells you\nwhich account it belongs to.\n'}, 'UpdateWebhookSubscriptionRequest': {'type': 'object', 'properties': {'url': {'type': ['string', 'null'], 'format': 'uri', 'description': 'New HTTPS endpoint URL.'}, 'active': {'type': ['boolean', 'null'], 'description': 'Enable or disable the webhook subscription.'}, 'events': {'type': ['array', 'null'], 'items': {'$ref': '#/$defs/WebhookEventTypeEnum'}, 'minItems': 1, 'description': 'New list of event types to subscribe to.'}, 'account_relationship': {'anyOf': [{'allOf': [{'$ref': '#/$defs/WebhookAccountRelationship'}], 'description': 'New set of accounts this subscription receives events from. Same field name and values as the `account_relationship` carried by every event envelope.\n'}, {'type': 'null'}]}}, 'additionalProperties': False}}, 'required': ['account_id', 'webhook_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/UpdateWebhookSubscriptionRequest'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, 'webhook_id': {'type': 'string', 'format': 'uuid', 'description': 'Subscription of the account in the path. A subscription of another account answers `404`, the same as one that does not exist: under the account resolved from `{account_id}` it simply is not there.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'Address': {'type': 'object', 'required': ['street', 'number', 'postal_code', 'city', 'province'], 'properties': {'city': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª()]+$", 'maxLength': 100, 'minLength': 1, 'description': 'City or town - Latin characters only'}, 'door': {'type': 'string', 'maxLength': 10, 'description': 'Door or apartment'}, 'floor': {'type': 'string', 'maxLength': 10, 'description': 'Floor or level'}, 'number': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Street number'}, 'street': {'type': 'string', 'pattern': '^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\s\\.,\\-\\/\'ºª°:;"()&#]+$', 'maxLength': 255, 'minLength': 1, 'description': 'Full address (street, number, floor, etc.) - Latin characters only'}, 'country': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Country - Latin characters only.\nOmitted, the address is stored as `España`.\n'}, 'province': {'type': 'string', 'pattern': "^[a-zA-Z0-9À-ÿ\\u0100-\\u017F\\u00B7\\u2018\\u2019\\u0060\\u00B4\\s\\.,\\-\\/'ºª]+$", 'maxLength': 100, 'minLength': 1, 'description': 'Province or state - Latin characters only'}, 'postal_code': {'type': 'string', 'maxLength': 20, 'minLength': 1, 'description': 'Postal code (5 digits for Spain, free format for other countries)'}, 'country_code': {'type': 'string', 'pattern': '^[A-Z]{2}$', 'maxLength': 2, 'minLength': 2, 'description': 'ISO 3166-1 alpha-2 country code.\nOmitted, the address is stored as `ES`.\n'}}, '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', 'additionalProperties': False}, 'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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"}, 'Language': {'enum': ['es', 'en', 'ca'], 'type': 'string', 'description': 'Supported languages'}, 'RegimeKey': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, 'EntityType': {'enum': ['INDIVIDUAL', 'LEGAL_ENTITY'], 'type': 'string', 'description': 'Taxpayer type.\nINDIVIDUAL: Natural person (individual self-employed).\nLEGAL_ENTITY: Legal entity (company with legal form: SL, SA, etc.).\n'}, 'AccessLevel': {'enum': ['NONE', 'VIEW', 'OPERATE'], 'type': 'string', 'description': "How much access an actor has to an account or a company. The same three values are used everywhere access is granted or reported — whether the actor is a member of the account or a provisioner managing it on someone's behalf.\n\n`NONE` — no access to the data.\n`VIEW` — read invoices, customers, products, series and fiscal data.\n`OPERATE` — everything in `VIEW`, plus creating and editing them. Issuing invoices for an account you manage additionally requires a signed fiscal representation from the account holder (see `/v1/accounts/{account_id}/companies/{company_id}/representation`).\n\nAccess level never affects billing: whoever provisioned an account pays for its subscription regardless of the level they keep over it."}, 'LegalRepresentative': {'type': 'object', 'required': ['full_name', 'nif', 'address'], 'properties': {'nif': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Tax ID of the legal representative (DNI/CIF/NIE)'}, 'address': {'allOf': [{'$ref': '#/$defs/Address'}, {'description': 'Address of the legal representative'}]}, 'full_name': {'type': 'string', 'maxLength': 255, 'minLength': 1, 'description': 'Full name of the legal representative'}}, 'description': 'Legal representative data for a legal entity.\nOnly used when entity_type = LEGAL_ENTITY.\n', 'additionalProperties': False}, 'ProvisionTaxProfile': {'type': 'object', 'required': ['nif', 'legal_name', 'entity_type', 'address'], 'properties': {'nif': {'type': 'string', 'description': 'Spanish tax id (NIF/CIF). Validated against the AEAT census; an invalid NIF returns 422.'}, 'address': {'$ref': '#/$defs/Address'}, 'legal_form': {'type': 'string', 'description': 'Legal form (e.g. `SL`). Recommended for `LEGAL_ENTITY`.'}, 'legal_name': {'type': 'string', 'description': 'Registered fiscal name.'}, 'trade_name': {'type': 'string', 'description': 'Commercial/trade name shown on invoices (defaults to `legal_name`).'}, 'entity_type': {'$ref': '#/$defs/EntityType'}, 'default_main_tax': {'$ref': '#/$defs/TaxInfo'}, 'default_irpf_rate': {'type': 'number', 'description': "Default IRPF withholding percentage (use `0` for exempt). Omit it and the company is created with **no withholding at all** — BeeL never assumes a rate nobody declared. You know your account holder's regime; set it explicitly when they do withhold."}, 'legal_representative': {'$ref': '#/$defs/LegalRepresentative'}}, 'description': "The account's fiscal identity, to set it up ready to invoice. Same field vocabulary as `POST /v1/accounts/{account_id}/companies` (`CreateCompanyRequest`). Tax rates fall back to system defaults when omitted; the invoice series is always created with system defaults (the holder edits it later).", 'additionalProperties': False}, 'ProvisionAccountRequest': {'type': 'object', 'required': ['display_name', 'external_ref'], 'properties': {'email': {'type': 'string', 'format': 'email', 'description': 'Optional. Email address of the account holder, used as their login. Omit it to create the account **without a person**: no login, no `person_id` and no `claim_token`. You can add the holder later with `POST /v1/accounts/{account_id}/claim-tokens`. Required when `send_email` is `true` (there is nobody to write to otherwise) — else `422`.'}, 'language': {'allOf': [{'$ref': '#/$defs/Language'}], 'description': 'Preferred language for the account holder. Defaults to `es`.'}, 'send_email': {'type': 'boolean', 'default': False, 'description': 'Optional. When `true`, BeeL emails the account holder a claim link (`/reclamar?token=...`) so they can set their password and take ownership. Defaults to `false`: by default you receive the `claim_token` in the response and deliver it yourself. Requires a deliverable `email`: sending `true` without one returns `422`.'}, 'tax_profile': {'allOf': [{'$ref': '#/$defs/ProvisionTaxProfile'}], 'description': 'Optional fiscal identity. When present, the account is created **ready to invoice** in one call: its company record, a default invoice series and VeriFactu config are set up atomically, and the response returns `company_id` (the value for the `BeeL-Active-Company` header when issuing invoices). Omit it to create an empty account the holder completes on claim. **Required when `access_level` is `OPERATE`** (issuing on their behalf needs a NIF) — else `422`.'}, 'access_level': {'allOf': [{'$ref': '#/$defs/AccessLevel'}], 'description': 'Optional. The access you retain over this account after provisioning. Defaults to `NONE` (you cover their subscription but cannot access their data). Change it later via PATCH /v1/accounts/{account_id}/access-level. This field was previously named `access`; the old name is still accepted as an alias for backwards compatibility and will be withdrawn in a future major version — send `access_level`.', 'x-field-extra-annotation': '@com.fasterxml.jackson.annotation.JsonAlias("access")'}, 'display_name': {'type': 'string', 'maxLength': 255, 'minLength': 1, 'description': 'Human-readable name for the account. Must not be blank.'}, 'external_ref': {'type': 'string', 'description': 'Your own identifier for this account in your system. Used as an idempotency key: re-provisioning with the same `external_ref` returns the existing account (201, not 409).'}}, 'description': 'Request to provision a new account. You retain management access at the level in `access_level` (defaults to `NONE`).\n\nThere are two ways to integrate and both are supported. **With `email`** the account is born with a holder (a person who can log in) and the response carries a `claim_token` / `claim_url` to hand over. **Without `email`** the account and its NIF are created with **no person at all** — for platforms whose self-employed workers will never use BeeL. themselves — and the response carries no token. Inviting someone to claim it is a deferred, optional step: `POST /v1/accounts/{account_id}/claim-tokens`. Nothing is invented: BeeL. never fabricates a placeholder email.', 'additionalProperties': False}}, 'required': ['body'], 'properties': {'body': {'$ref': '#/$defs/ProvisionAccountRequest'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'PutMemberGrantRequest': {'type': 'object', 'required': ['access_level'], 'properties': {'access_level': {'enum': ['VIEW', 'OPERATE'], 'type': 'string', 'description': 'Access the member gets over this company.'}}, 'description': "The access a member gets over ONE company. The company is the one in the path, so it is not repeated in the body, and the member's other grants are untouched.", 'additionalProperties': False}}, 'required': ['account_id', 'member_id', 'company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/PutMemberGrantRequest'}, 'member_id': {'type': 'string', 'format': 'uuid', 'description': 'Membership unique UUID.'}, 'account_id': {'type': 'string', 'format': 'uuid', 'description': 'Your own account, or an account you provisioned. It — not the credential — decides which account the operation acts on; a `403` is returned when you do not reach it, the same response an account that does not exist gets.'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company within the account.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'provider', 'event_id'], 'properties': {'event_id': {'type': 'string', 'format': 'uuid', 'description': 'Identifier of the payment event, as returned by the list operation.'}, 'provider': {'enum': ['stripe'], 'type': 'string', 'description': 'Payment provider slug in **lowercase**. Currently only `stripe` (Stripe Connect) is\noperative; `woocommerce` and `shopify` are reserved for future providers.\n'}, 'company_id': {'type': 'string', 'format': 'uuid', 'description': 'Unique identifier (UUID) of the company the events belong to — 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.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'webhook_id', 'delivery_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, 'webhook_id': {'type': 'string', 'format': 'uuid', 'description': 'Subscription of the account in the path. A subscription of another account answers `404`, the same as one that does not exist: under the account resolved from `{account_id}` it simply is not there.'}, 'delivery_id': {'type': 'string', 'format': 'uuid', 'description': 'Delivery attempt of that subscription to replay.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'webhook_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, 'webhook_id': {'type': 'string', 'format': 'uuid', 'description': 'Subscription of the account in the path. A subscription of another account answers `404`, the same as one that does not exist: under the account resolved from `{account_id}` it simply is not there.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'Email': {'type': 'string', 'format': 'email', 'maxLength': 255, 'minLength': 5, 'description': 'Email address (minimum valid email is 5 chars, e.g. a@b.co)'}, 'Language': {'enum': ['es', 'en', 'ca'], 'type': 'string', 'description': 'Supported languages'}, 'SendEmailRequest': {'type': 'object', 'properties': {'cc': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'description': "CC recipients. Copied addresses count as recipients of the message: they are subject\nto the same sending restrictions and to the same quota as the addresses in `recipients`.\nWhen omitted, the CC addresses configured in the sender's email defaults apply; send an\nempty array to deliver the message without any copy.\n"}, 'message': {'type': 'string', 'maxLength': 2000, 'minLength': 1, 'description': 'Custom message (optional, added before standard message)'}, 'subject': {'type': 'string', 'maxLength': 200, 'minLength': 1, 'description': 'Email subject (optional, if not specified uses a default)'}, 'language': {'allOf': [{'$ref': '#/$defs/Language'}], 'description': "Email language. If not provided, uses the user's language (same fallback as the bulk send). Sin `default:` a propósito: quien resuelve el idioma es el servicio, no el DTO."}, 'attach_pdf': {'type': 'boolean', 'default': True}, 'recipients': {'type': 'array', 'items': {'$ref': '#/$defs/Email'}, 'description': "If not specified, uses the customer's email"}, 'attach_source_invoices': {'type': 'boolean', 'default': False, 'description': "Attach a ZIP archive (`suplidos_<invoice-number>.zip`) containing the PDFs of the source invoices referenced by the invoice's SUPLIDO consolidation lines (`source_invoice_ids`). Each PDF inside the ZIP is named `<invoice-number>_<issuer-tax-id>.pdf`. Requires `attach_pdf: true` (the ZIP accompanies the invoice PDF). Access to sources owned by managed accounts is re-checked at send time with the same rules as issuing; the request fails with an actionable error — never a partial ZIP — if the invoice has no consolidation sources (`ATTACH_SOURCE_INVOICES_NO_SOURCES`), a source is not reachable (`ATTACH_SOURCE_INVOICE_UNAVAILABLE`), a source has no generated PDF (`ATTACH_SOURCE_PDF_MISSING`), or the ZIP exceeds the size limit (`ATTACH_SOURCE_ZIP_TOO_LARGE`)."}}, 'additionalProperties': False}}, 'required': ['company_id', 'invoice_id'], 'properties': {'body': {'$ref': '#/$defs/SendEmailRequest'}, '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}}, 'required': ['company_id', 'series_id'], 'properties': {'series_id': {'$ref': '#/$defs/UUID', 'description': 'Series ID to mark as default'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'GenerationAction': {'enum': ['DRAFT', 'ISSUE_AND_SEND'], 'type': 'string', 'description': 'Action to perform when processing a scheduled invoice:\n- DRAFT: Create as draft for manual review\n- ISSUE_AND_SEND: Issue and send automatically via email\n'}, 'SetInvoiceScheduleRequest': {'type': 'object', 'required': ['scheduled_for', 'generation_mode'], 'properties': {'scheduled_for': {'type': 'string', 'format': 'date', 'description': 'Date on which the invoice should be processed. Today or later.'}, 'generation_mode': {'$ref': '#/$defs/GenerationAction'}}, 'description': 'Full replacement of the scheduling of an invoice (RFC 9110 §9.3.4). Both fields are\nrequired on purpose: `generation_mode` has no default, because silently falling back to\n`DRAFT` would downgrade an `ISSUE_AND_SEND` and the invoice would never be issued.\n', 'additionalProperties': False}}, 'required': ['company_id', 'invoice_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/SetInvoiceScheduleRequest'}, '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'IBAN': {'type': 'string', 'pattern': '^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$', 'maxLength': 34, 'minLength': 15, 'description': 'IBAN (International Bank Account Number).\nRequired when payment method is BANK_TRANSFER.\n'}, 'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'SWIFT': {'type': 'string', 'pattern': '^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$', 'maxLength': 11, 'minLength': 8, 'description': 'SWIFT/BIC code'}, 'PaymentInfo': {'type': 'object', 'properties': {'iban': {'$ref': '#/$defs/IBAN'}, 'swift': {'$ref': '#/$defs/SWIFT'}, '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'}, 'payment_term_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, '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}, 'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'SetInvoiceStatusRequest': {'type': 'object', 'required': ['status'], 'properties': {'status': {'enum': ['ISSUED', 'SENT', 'PAID'], 'type': 'string', 'description': 'Target status.\n\n- **PAID**: from `ISSUED`, `SENT` or `OVERDUE`.\n- **SENT**: from `ISSUED`. Records `sent_at`.\n- **ISSUED**: from `SENT` only. Clears `sent_at`. Use it to undo a `SENT` set by\n mistake; it never un-issues an invoice, which is irreversible.\n'}, 'sent_at': {'type': 'string', 'format': 'date-time', 'description': 'Timestamp for when the invoice was sent. Only read when `status` is `SENT`;\ndefaults to now.\n'}, 'payment_date': {'type': 'string', 'format': 'date', 'description': 'Payment date. Only read when `status` is `PAID`; defaults to today.'}, 'payment_method': {'allOf': [{'$ref': '#/$defs/PaymentInfo'}], 'description': 'Payment details object. Only read when `status` is `PAID`. Example:\n`{ "method": "BANK_TRANSFER", "iban": "ES9121000418450200051332" }`\n'}}, 'description': 'Replaces the status of an invoice. The valid transitions are the same ones the dedicated\nverbs used to expose, and the domain still rejects any transition that is not allowed.\n', 'additionalProperties': False}}, 'required': ['company_id', 'invoice_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/SetInvoiceStatusRequest'}, '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'SetRecurringInvoiceStatusRequest': {'type': 'object', 'required': ['status'], 'properties': {'status': {'enum': ['ACTIVE', 'PAUSED'], 'type': 'string', 'description': 'Target status. `PAUSED` stops automatic generation keeping the schedule; `ACTIVE`\nresumes it and recalculates the next generation date from today.\n'}}, 'additionalProperties': False}}, 'required': ['company_id', 'recurring_invoice_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/SetRecurringInvoiceStatusRequest'}, '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['company_id', 'recurring_invoice_id'], '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.'}, '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.'}, 'recurring_invoice_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', 'required': ['account_id', 'webhook_id'], 'properties': {'account_id': {'type': 'string', 'format': 'uuid', 'description': "Your own account, or an account you provisioned. It — not the credential, and not the `BeeL-Active-Company` header — decides which account the operation acts on. An account you do not reach answers `403`, and so does an account that does not exist, so the existence of somebody else's account is never disclosed."}, 'webhook_id': {'type': 'string', 'format': 'uuid', 'description': 'Subscription of the account in the path. A subscription of another account answers `404`, the same as one that does not exist: under the account resolved from `{account_id}` it simply is not there.'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'Language': {'enum': ['es', 'en', 'ca'], 'type': 'string', 'description': 'Supported languages'}, 'InvoiceTemplateType': {'enum': ['MODERN_TABLE', 'PROFESSIONAL_SERVICE'], 'type': 'string', 'description': 'Invoice PDF template. `MODERN_TABLE` is a structured table layout for\nproduct/service lines; `PROFESSIONAL_SERVICE` is a text-based layout.\n'}, 'UpdateInvoiceCustomizationRequest': {'type': 'object', 'properties': {'email_language': {'allOf': [{'$ref': '#/$defs/Language'}, {'anyOf': [{'description': 'Language used for the emails that deliver the invoice.'}, {'type': 'null'}]}]}, 'invoice_language': {'allOf': [{'$ref': '#/$defs/Language'}, {'anyOf': [{'description': 'Language used to render the invoice PDF.'}, {'type': 'null'}]}]}, 'invoice_accent_color': {'type': 'string', 'pattern': '^#[0-9A-Fa-f]{6}$', 'description': 'Accent colour applied to the invoice PDF, in `#RRGGBB` format.'}, 'invoice_template_type': {'anyOf': [{'allOf': [{'$ref': '#/$defs/InvoiceTemplateType'}], 'description': 'Template used to render the invoice PDF.'}, {'type': 'null'}]}}, 'description': 'Partial update. Properties absent from the body are left unchanged; the logo is managed through the `logo` sub-resource.', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/UpdateInvoiceCustomizationRequest'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'Language': {'enum': ['es', 'en', 'ca'], 'type': 'string', 'description': 'Supported languages'}, 'UpdateMeRequest': {'type': 'object', 'required': ['language'], 'properties': {'language': {'$ref': '#/$defs/Language'}}, 'description': 'Mutable preferences of the authenticated person.', 'additionalProperties': False}}, 'required': ['body'], 'properties': {'body': {'$ref': '#/$defs/UpdateMeRequest'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'TaxInfo': {'type': 'object', 'required': ['type', 'percentage'], 'properties': {'type': {'$ref': '#/$defs/TaxType'}, 'percentage': {'type': 'number', 'maximum': 100, 'minimum': 0, '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}, 'TaxType': {'enum': ['IVA', 'IGIC', 'IPSI', 'OTHER'], 'type': 'string', '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': {'enum': ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '14', '15', '17', '18', '19', '20'], 'type': 'string', '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'}, 'PaymentMethod': {'enum': ['NONE', 'BANK_TRANSFER', 'CARD', 'CASH', 'CHECK', 'DIRECT_DEBIT', 'BIZUM', 'OTHER'], 'type': 'string', 'description': 'Payment method for invoices and recurring invoices.\nNONE means no payment information will be shown.\n'}, 'IrpfPercentage': {'enum': [0, 1, 2, 7, 15, 19, 24], 'type': 'integer', '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': {'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'], 'type': 'string', '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'}, 'UpdateTaxConfigurationRequest': {'type': 'object', 'properties': {'apply_irpf': {'type': 'boolean', 'description': 'Whether IRPF withholding should be applied.\n\nOmit it to leave the current value untouched. On creation, omitting it means `false`:\na withholding nobody declared is not applied.\n'}, 'irpf_exempt': {'type': 'boolean', 'description': 'Whether the freelancer is exempt from IRPF withholding.\n\nOmit it to leave the current value untouched. On creation, omitting it means `false`.\n'}, 'default_main_tax': {'allOf': [{'$ref': '#/$defs/TaxInfo'}], 'description': 'Default main tax configuration.\nIf provided, completely replaces the current configuration.\n\nIt travels together with `default_exemption_reason`: sending the tax without a\nreason clears the stored one (going back from 0% to 21% cannot leave an orphan\n"art. 20 exempt" behind), and sending only the reason applies it to the tax\nalready stored. Sending neither leaves the current declaration untouched.\n'}, 'default_irpf_rate': {'$ref': '#/$defs/IrpfPercentage'}, 'payment_term_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, 'description': 'Default payment term in days (0-365). Omit it to leave the current value untouched;\nsend `null` to clear it.\n'}, 'default_payment_method': {'type': ['string', 'null'], 'allOf': [{'$ref': '#/$defs/PaymentMethod'}], 'description': 'Default payment method for new invoices.\nIf NONE is selected, no payment information will be shown on the invoice.\n'}, 'proforma_validity_days': {'type': ['integer', 'null'], 'maximum': 365, 'minimum': 0, 'description': 'Default validity term in days for new proformas (0-365). Omit it to leave the current\nvalue untouched; send `null` to clear it (proformas stop getting a prefilled expiry date).\n'}, 'default_exemption_reason': {'anyOf': [{'$ref': '#/$defs/ExemptionReason'}, {'type': 'null'}]}, 'apply_equivalence_surcharge': {'type': 'boolean', 'description': 'Whether the freelancer is under the equivalence surcharge regime.\n\nOmit it to leave the current value untouched. On creation, omitting it means `false`.\n'}, 'default_equivalence_surcharge': {'$ref': '#/$defs/EquivalenceSurchargePercentage'}, 'default_exemption_reason_text': {'type': ['string', 'null'], 'maxLength': 500, 'description': 'Custom exemption text, mandatory when `default_exemption_reason` is `OTRO`.\n\nOnly `EXENTA_ART_20` and `OTRO` can be declared as a default — the reasons a\nNIF can verify on its own. The rest depend on the recipient, the operation or\nthe regime, so they are declared per invoice line; sending one returns 422.\nA 0% VAT/IPSI without a reason is also rejected with 422: in those taxes 0% is\nnot a rate, it is the sentinel of an operation carrying no tax.\n'}}, 'additionalProperties': False}, 'EquivalenceSurchargePercentage': {'enum': [0, 0.5, 0.625, 1.4, 5.2], 'type': 'number', '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'}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/UpdateTaxConfigurationRequest'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UpdateVeriFactuConfigurationRequest': {'type': 'object', 'required': ['enabled', 'apply_by_default'], 'properties': {'enabled': {'type': 'boolean', 'description': "Whether VeriFactu is enabled for this user.\nWhen enabled, the user can submit invoices to AEAT.\nFreelancers who don't need to submit invoices to AEAT can leave it disabled.\n"}, 'apply_by_default': {'type': 'boolean', 'description': "Whether VeriFactu should be automatically applied to new invoices.\nRequires 'enabled' to be true.\n"}}, 'description': 'Request body of `PUT /v1/configuration/verifactu`. Carries the **only two writable\nfields**; everything else in `VeriFactuConfiguration` is resolved server-side.\n\nBoth are required and there is **no default**: this PUT replaces the whole state, so\nomitting a field is a client error, not a silent `false`. A `default:` here would be\nmaterialized in the generated DTO and would satisfy the `@NotNull` before validation\ncould tell "not sent" from "sent as false" — which is how `{"apply_by_default": true}`\nused to turn VeriFactu off and answer 200 (BEE-868).\n', 'additionalProperties': False}}, 'required': ['company_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/UpdateVeriFactuConfigurationRequest'}, '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.'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'NIF': {'type': 'string', 'pattern': '^(\\d{8}[A-Z]|[ABCDEFGHJKLMNPQRSUVW]\\d{7}[A-Z0-9]|[XYZ]\\d{7}[A-Z])$', 'maxLength': 9, 'minLength': 9, 'description': 'Spanish Tax ID (9 characters, uppercase only). Structural validation:\n- DNI: 8 digits + 1 letter (e.g., 12345678A)\n- NIE: X/Y/Z + 7 digits + 1 letter (e.g., X1234567A)\n- CIF: Organization letter + 7 digits + 1 control digit/letter (e.g., B12345674)\n'}, 'ValidateNifRequest': {'type': 'object', 'required': ['nif'], 'properties': {'nif': {'allOf': [{'$ref': '#/$defs/NIF'}, {'description': 'NIF/CIF to validate against the AEAT census.\nMust be 9 alphanumeric characters.\n'}]}, 'legal_name': {'type': ['string', 'null'], 'maxLength': 255, 'minLength': 1, 'description': 'Last name and first name (individual) or business name (legal entity).\n\n**Important**:\n- REQUIRED for individuals (NIFs starting with a number)\n- OPTIONAL for legal entities (NIFs starting with a letter)\n\nFor an **individual**, AEAT matches NIF and name together: send a name the\ncensus does not recognise and the person is not identified, so the status\ncomes back `INVALID`.\n\nFor a **legal entity**, the name is **not verified**. AEAT identifies a\ncompany by its CIF alone — there is no census answer meaning "this name is\nwrong", so validation depends only on the CIF and any name you send is\naccepted. Use the `legal_name` of the response to contrast your own.\n'}}, 'additionalProperties': False}}, 'required': ['body'], 'properties': {'body': {'$ref': '#/$defs/ValidateNifRequest'}}, 'additionalProperties': False}
Schéma d’entrée
{'type': 'object', '$defs': {'UUID': {'type': 'string', 'format': 'uuid', 'description': 'Universally Unique Identifier (UUID v4)'}, 'VoidInvoiceRequest': {'type': 'object', 'required': ['reason'], 'properties': {'reason': {'type': 'string', 'maxLength': 500, 'minLength': 10, 'description': 'Void reason (minimum 10 characters)'}, 'void_date': {'type': 'string', 'format': 'date', 'description': '**Deprecated and ignored.** The void is recorded with the instant it actually takes\nplace, returned as `voided_at` on the invoice. A void cannot be dated by the caller,\nso any value sent here has no effect and will be removed in a future version.\n'}}, 'additionalProperties': False}}, 'required': ['company_id', 'invoice_id', 'body'], 'properties': {'body': {'$ref': '#/$defs/VoidInvoiceRequest'}, '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.'}, 'invoice_id': {'$ref': '#/$defs/UUID', 'description': 'Invoice ID'}, '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.'}}, 'additionalProperties': False}
Modifications récentes des outils
Serveurs MCP similaires
corply
Supports company formation and corporate administration including incorporation documents, signatures, cap tables, corporate acti…
RESET Verifica
Verifies Mexican businesses, invoices, payments, identities, tax and labor calculations, legal texts, sanctions and PEP lists, ba…
eu-verify
Verifies European companies, registries, VAT, EORI, LEI, sanctions, insolvency, financial filings, IBANs, emails, addresses, and …
Israel Business Intelligence MCP
Provides Israeli company identity previews, registry-based verification workflows, invoice checks, and payment-risk decision prev…
invowerk
Parses, generates, converts, validates, renders, and explains structured electronic invoices including EN 16931, XRechnung, ZUGFe…
Lovie Company Formation
Supports company formation and business administration with bank accounts, cards, invoicing, bookkeeping, accounting periods, and…
AgentLot Marketplace
Enables agents and users to discover, bid on, purchase, deliver, and settle paid digital services and compute work.
DPX — Institutional Cross-Border Settlement
Provides compliance-gated cross-border crypto settlement, agent registration and spending mandates, stablecoin routing, ESG and s…