PatchRecurringInvoiceRequest
Partial update of a recurring invoice (RFC 5789). Only the fields present in the body are touched: - **field omitted** → the current value is kept; - **field sent with a value** → replaced; - **field sent as `null`** → cleared (only where documented as nullable below). In particular, changing the lines no longer wipes the recipient, and the schedule (`day_of_month`, `start_date`) stays put unless you send it.
Properties
| Name | Type | Description |
|---|---|---|
| name | string | Template name. Cannot be cleared. |
| frequency | string | Generation cadence: `MONTHLY` every month, `QUARTERLY` every 3 months, `YEARLY` every 12 months. Omitted, the current one is kept — it is never reset to `MONTHLY`. **Changing it reschedules the templa |
| day_of_month | integer | Day of the month the invoices are issued. Moves the next generation immediately, on an `ACTIVE` template and on a `PAUSED` one alike: the response to this very call already carries the new `next_gener |
| start_date | string | First issue date. Only **changeable** while the template has not generated any invoice yet: once it has issued, a *different* date is rejected with a 422 `RECURRING_START_DATE_NOT_EDITABLE`. Sending t |
| draft_in_advance | boolean | Whether the template prepares a draft for review before emitting. The window is fixed at 5 days and both options emit on the scheduled day. Generating manually a period whose scheduled date is today o |
| preview_days | integer | **Deprecated.** Superseded by `draft_in_advance`. Any value greater than `0` means the same as `draft_in_advance: true`, and `0` the same as `false`. When both are sent, `draft_in_advance` wins. It wi |
| end_date | stringnull | Date the recurrence stops. Send `null` to make it open-ended. |
| max_invoices | integernull | Total number of invoices this template will generate before ending on its own, between 2 and 600. Send `null` to stop capping the recurrence by number. Editing it MOVES THE GOAL, it does not add turns |
| series_id | string | Series the generated invoices are numbered in. Cannot be cleared. |
| invoice_type | object | Type of the invoices the template generates. Omitted, the current type is kept; it cannot be cleared. A change is judged on the resulting template, with the rules of the new type: its series must acce |
| customer_id | stringnull | Recipient of the generated invoices. Send `null` to leave the template without a recipient; omit it to keep the current one. |
| lines | arraynull | Template lines, replaced as a whole (they are not patched line by line). Omit them to keep the current ones — a template with no lines invoices nothing, so an empty array is rejected. |
| payment_method | object | Payment method. Replaced as a whole together with `payment_iban`, `payment_swift` and `payment_term_days`: send them in the same request or they are dropped. Send `null` to state that no payment metho |
| payment_iban | stringnull | |
| payment_swift | stringnull | |
| payment_term_days | integernull | |
| notes | stringnull | Notes printed on the generated invoices. Send `null` to clear them. |
| custom_fields | arraynull | Replaces the custom fields of the template as a whole: the list sent becomes the new list. Omit it to keep the current ones; send `null` or `[]` to remove them all. The same rules as on an invoice app |
| send_automatically | boolean | |
| email_configuration | object | Email delivery settings, replaced as a whole. Send `null` to stop sending the generated invoices by email. |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/beel-es/json-schema/beel-es-patch-recurring-invoice-request-schema.json",
"title": "PatchRecurringInvoiceRequest",
"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",
"x-generated": "2026-10-30",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/beel-es-openapi.json#/components/schemas/PatchRecurringInvoiceRequest",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"pattern": "^\\S.*$",
"description": "Template name. Cannot be cleared."
},
"frequency": {
"type": "string",
"enum": [
"MONTHLY",
"QUARTERLY",
"YEARLY"
],
"description": "Generation cadence: `MONTHLY` every month, `QUARTERLY` every 3 months, `YEARLY` every 12 months. Omitted, the current one is kept — it is\nnever reset to `MONTHLY`.\n\n**Changing it reschedules the template.** The next generation is recalculated on the new\ngrid — the `day_of_month` dates anchored at `start_date`, one every cadence — so it can\nland months later than the one you saw before the call. **If the template has already\nissued invoices, the landing respects that**: it is never a period that was already\nbilled, and never before today either — the first point of the new grid strictly after\nthe last invoiced one. It also **discards a pending skip**: the skipped period only\nexisted as a point of the old grid, and that grid is gone. Send the same cadence and\nnothing is rescheduled.\n"
},
"day_of_month": {
"type": "integer",
"minimum": 1,
"maximum": 31,
"description": "Day of the month the invoices are issued. Moves the next generation immediately, on an\n`ACTIVE` template and on a `PAUSED` one alike: the response to this very call already\ncarries the new `next_generation`. On a paused template the new day rules from the edit,\nnot from the day you resume — resuming keeps the date this call left, so editing the day\nof a paused schedule is never ignored for a round.\n\nA month that does not have that day falls back to its last day: a template on `31`\nissues on 28 February (29 in a leap year) and on 30 April. So `31` is how you ask for\nthe last day of the month it generates in — there is no separate flag for it, and the\naccepted range stays 1–31.\n\nThe adjustment does not stick and the schedule does not drift: every generation is\nrecalculated from the `day_of_month` you sent, never from the date it was adjusted\nto (31 Jan → 28 Feb → 31 Mar).\n"
},
"start_date": {
"type": "string",
"format": "date",
"description": "First issue date. Only **changeable** while the template has not generated any invoice\nyet: once it has issued, a *different* date is rejected with a 422\n`RECURRING_START_DATE_NOT_EDITABLE`. Sending the value it already has is a no-op and\nsucceeds, so a read-modify-write cycle never has to strip the field out of the body.\n\nA past date is accepted and stored as sent, but it never anchors generation in the\npast: `next_generation` becomes the first date of the template's own calendar on or\nafter today (today included) — the grid of `day_of_month` dates anchored at\n`start_date`, one every `frequency` — which on a quarterly or yearly template can be\nmonths from now. Creating and updating apply the same rule. If today's period was\nalready invoiced in the system you are migrating from, send a `start_date` of tomorrow\n(or of the next period) so it is not invoiced twice.\n"
},
"draft_in_advance": {
"type": "boolean",
"description": "Whether the template prepares a draft for review before emitting. The window is fixed at\n5 days and both options emit on the scheduled day. Generating manually a period whose\nscheduled date is today or earlier emits it on the spot. Omitted, the current value is\nkept.\n"
},
"preview_days": {
"type": "integer",
"minimum": 0,
"maximum": 30,
"deprecated": true,
"description": "**Deprecated.** Superseded by `draft_in_advance`. Any value greater than `0` means the\nsame as `draft_in_advance: true`, and `0` the same as `false`. When both are sent,\n`draft_in_advance` wins. It will be removed in a future version.\n"
},
"end_date": {
"type": [
"string",
"null"
],
"format": "date",
"description": "Date the recurrence stops. Send `null` to make it open-ended."
},
"max_invoices": {
"type": [
"integer",
"null"
],
"description": "Total number of invoices this template will generate before ending on its own, between\n2 and 600. Send `null` to stop capping the recurrence by number.\n\nEditing it MOVES THE GOAL, it does not add turns: above the invoices already generated the\ntemplate stays active; exactly equal ends it in this very call (with\n`completion.reason = MAX_INVOICES_REACHED`); below it the call is rejected — issued invoices\nare fiscal facts, and someone typing a lower number is asking to stop now, which is what\nending the recurrence is for.\n\nA recurrence ends in ONE way, and the conflict is judged on the RESULTING state, not on the\nbody: sending `max_invoices` to a template that already has an `end_date` is rejected with\n`RECURRING_END_MODE_CONFLICT` even though the body only mentions one of them. Switching mode\nis a single call that says both things — the new field with a value and the old one as\n`null`. Nothing is cleared silently.\n"
},
"series_id": {
"type": "string",
"format": "uuid",
"description": "Series the generated invoices are numbered in. Cannot be cleared."
},
"invoice_type": {
"allOf": [
{
"$ref": "#/$defs/RecurringInvoiceType"
}
],
"description": "Type of the invoices the template generates. Omitted, the current type is kept; it cannot be cleared.\nA change is judged on the resulting template, with the rules of the new type: its series\nmust accept it (`SERIES_INCOMPATIBLE_DOC_TYPE` otherwise), a `SIMPLIFIED` template\ncannot keep an identified recipient (`SIMPLIFIED_INVOICE_FORBIDS_IDENTIFIED_RECIPIENT`)\nnor lines a simplified invoice does not admit. Send the new `series_id`, and\n`customer_id: null` when moving to `SIMPLIFIED`, in the same call.\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"
},
"lines": {
"type": [
"array",
"null"
],
"minItems": 1,
"items": {
"$ref": "#/$defs/RecurringLineRequest"
},
"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"
},
"payment_method": {
"allOf": [
{
"$ref": "#/$defs/PaymentMethod"
}
],
"nullable": true,
"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\n`payment_iban`, `payment_swift` and `payment_term_days` are detail of this\nmethod, not standalone fields: sending any of them without a `payment_method`\nthat is present, non-null and different from `NONE` is rejected with `422`\n(`PAYMENT_DETAILS_REQUIRE_METHOD`).\n"
},
"payment_iban": {
"type": [
"string",
"null"
]
},
"payment_swift": {
"type": [
"string",
"null"
]
},
"payment_term_days": {
"type": [
"integer",
"null"
]
},
"notes": {
"type": [
"string",
"null"
],
"description": "Notes printed on the generated invoices. Send `null` to clear them."
},
"custom_fields": {
"type": [
"array",
"null"
],
"maxItems": 20,
"description": "Replaces the custom fields of the template as a whole: the list sent becomes the new\nlist. Omit it to keep the current ones; send `null` or `[]` to remove them all. The same\nrules as on an invoice apply: at most one value per `key` (a repeated `key` answers\n`422 VALIDATION_ERROR`), a `key` the company does not have answers\n`422 CUSTOM_FIELD_UNKNOWN` and an archived field answers `409 CUSTOM_FIELD_ARCHIVED`,\neven when the template already carries it; in every case nothing is written. Every field\nin the list is saved again with the label it has now, and each value follows the same\nrules as on an invoice, with the template's `customer_id` as the customer.\n\nWhen the request changes `customer_id` and omits `custom_fields`, the saved fields are\ncarried over to the new customer; one archived since is left out, with no error.\n\nInvoices already generated keep the fields they were created with; the change applies\nfrom the next generation. They are informational: they are not part of the VeriFactu\nrecord sent to the AEAT and do not enter its hash.\n",
"items": {
"$ref": "#/$defs/InvoiceCustomFieldInput"
}
},
"send_automatically": {
"type": "boolean"
},
"email_configuration": {
"allOf": [
{
"$ref": "#/$defs/RecurringEmailConfigRequest"
}
],
"nullable": true,
"description": "Email delivery settings, replaced as a whole. Send `null` to stop sending the\ngenerated invoices by email.\n"
}
},
"$defs": {
"CustomFieldKey": {
"type": "string",
"minLength": 1,
"maxLength": 64,
"pattern": "^[a-z0-9_]{1,64}$",
"description": "Identifier of the custom field within the company, chosen when the field is created: lowercase letters, digits and `_`, up to 64 characters. It never changes. BeeL. gives it no meaning of its own."
},
"Email": {
"type": "string",
"format": "email",
"minLength": 5,
"maxLength": 255,
"description": "Email address (minimum valid email is 5 chars, e.g. a@b.co)"
},
"ExemptionReason": {
"type": "string",
"enum": [
"EXENTA_ART_20",
"EXENTA_ART_21",
"EXENTA_ART_22",
"EXENTA_ART_24",
"EXENTA_ART_25",
"EXENTA_ART_26",
"EXENTA_ART_140",
"NO_SUJETA_ART_7_9",
"NO_SUJETA_LOCALIZACION",
"ISP_ART_84_2_A",
"ISP_ART_84_2_B",
"ISP_ART_84_2_C",
"ISP_ART_84_2_D",
"ISP_ART_84_2_E",
"ISP_ART_84_2_F",
"ISP_ART_84_2_G",
"REGIMEN_ART_129",
"REGIMEN_ART_135",
"REGIMEN_ART_141",
"REGIMEN_ART_154",
"REGIMEN_ART_163_DECIES",
"OTRO"
],
"description": "Tax exemption reason code per the Spanish VAT Law (Ley 37/1992, LIVA), with the\nVeriFactu code each one is reported as.\n\n- `EXENTA_ART_20`: exempt, art. 20 (domestic operations such as medical, educational,\n cultural and financial services, or housing rentals). E1.\n- `EXENTA_ART_21`: exempt, art. 21 (exports of goods). E2.\n- `EXENTA_ART_22`: exempt, art. 22 (operations treated as exports). E3.\n- `EXENTA_ART_24`: exempt, art. 24 (free zones, warehouses and customs regimes). E4.\n- `EXENTA_ART_25`: exempt, art. 25 (intra-community supplies of goods). E5.\n- `EXENTA_ART_26`: exempt, art. 26 (intra-community acquisitions of goods). It exempts the\n buyer's acquisition, not a supply the seller invoices, so an invoice line that carries it\n is rejected with `EXEMPTION_NOT_FOR_ISSUED_INVOICE`; a supply to another Member State is\n `EXENTA_ART_25`.\n- `NO_SUJETA_ART_7_9`: not subject under art. 7 (such as the transfer of a business as\n a going concern, art. 7.1º). N1.\n- `NO_SUJETA_LOCALIZACION`: not subject by the place-of-supply rules (intra-community\n or non-EU services, arts. 69 and 70). N2.\n- `ISP_ART_84_2_A` … `ISP_ART_84_2_F`: reverse charge (the invoice states «inversión del\n sujeto pasivo»), art. 84.Uno.2.º letters a) (supplier not established in Spain), b) (unwrought\n or semi-finished gold), c) (scrap, waste and recovery materials, plastic, paper, cardboard, glass and textile waste, and semi-finished non-ferrous metal products), d) (greenhouse gas emission\n allowances), e) (certain real estate supplies: in insolvency proceedings, with the exemption\n waived, or enforcing a security) and f) (construction or renovation works). S2.\n- `ISP_ART_84_2_G`: reverse charge of letter g) (silver, platinum, palladium, mobile phones,\n consoles, laptops and tablets). The law requires these supplies to be invoiced in a special\n series, so an invoice line that carries it is rejected with\n `REVERSE_CHARGE_CASE_NOT_SUPPORTED`.\n- `EXENTA_ART_140`: investment gold exemption, art. 140 bis (usually with `regime_key`\n `04`). E6.\n- `REGIMEN_ART_129` (agriculture,\n livestock and fishing, arts. 124 to 134 bis), `REGIMEN_ART_135` (second-hand goods,\n art and antiques), `REGIMEN_ART_141` (travel agencies), `REGIMEN_ART_154` (equivalence\n surcharge) and `REGIMEN_ART_163_DECIES` (cash basis, arts. 163 decies to 163\n sexiesdecies): operations of special regimes, which VeriFactu identifies by the regime\n key rather than by an exemption code. An\n invoice line that carries one is rejected with `EXEMPTION_REGIME_NOT_SUPPORTED_IN_VERIFACTU`;\n declare the regime with `regime_key` instead.\n- `OTRO`: any other provision. Requires the text in `exemption_reason_text`. E6.\n"
},
"InvoiceCustomFieldInput": {
"type": "object",
"description": "The value of one custom field of the company on an invoice. The field must exist in the company and be active; the label is taken from it when the invoice is saved.",
"required": [
"key",
"value"
],
"properties": {
"key": {
"$ref": "#/$defs/CustomFieldKey"
},
"value": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Text of the value. Leading and trailing spaces are removed; a value that is empty after that answers `422`. When an option of the field is equivalent (it matches ignoring case, accents and repeated spaces), the invoice stores the text of that option, archived options included. Otherwise the text is stored as sent and, when the invoice has a registered customer (`recipient.customer_id`), it is added as an option of that customer; with recipient data sent inline, no option is created. On a field with `suggest_values: false` the value is never compared with the options and never creates one: the invoice stores the text as sent, without the leading and trailing spaces."
}
}
},
"PaymentMethod": {
"type": "string",
"description": "Payment method shown on invoices and recurring invoices.\n\n- `NONE`: no payment information is shown.\n- `BANK_TRANSFER`: bank transfer to the IBAN of the payment details; the only method\n that requires an IBAN.\n- `CARD`: card payment.\n- `CASH`: cash payment.\n- `CHECK`: payment by cheque.\n- `DIRECT_DEBIT`: direct debit from the customer's bank account.\n- `BIZUM`: payment through Bizum.\n- `OTHER`: any other method.\n",
"enum": [
"NONE",
"BANK_TRANSFER",
"CARD",
"CASH",
"CHECK",
"DIRECT_DEBIT",
"BIZUM",
"OTHER"
]
},
"RecurringEmailConfigRequest": {
"type": [
"object",
"null"
],
"properties": {
"recipients": {
"type": "array",
"items": {
"$ref": "#/$defs/Email"
}
},
"cc": {
"type": "array",
"items": {
"$ref": "#/$defs/Email"
}
},
"subject": {
"type": [
"string",
"null"
]
},
"message": {
"type": [
"string",
"null"
]
}
}
},
"RecurringInvoiceType": {
"type": "string",
"enum": [
"STANDARD",
"SIMPLIFIED"
],
"description": "Type of the invoices a recurring template generates: `STANDARD` for an identified recipient,\n`SIMPLIFIED` for a recipient that is not identified.\n"
},
"RecurringLineRequest": {
"type": "object",
"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\n**Line amount**: send **exactly one** of `unit_price`, `total_excluding_tax` or\n`total_including_tax` — same contract as an invoice line. Sending none, or more than\none, is rejected with `LINE_UNIT_PRICE_XOR_DECLARED_TOTAL`; a declared total together\nwith an explicit `discount_percentage` is rejected with\n`LINE_DECLARED_TOTAL_FORBIDS_DISCOUNT` (the discount, if any, already lives inside\nthe total).\n\nThe mode is what the template promises, and it is re-applied on **every** generation:\na line declared as `total_including_tax: 1.00` over 300 units invoices 1,00 € on every\ngeneration, not 300 × 0,0033 = 0,99 €. Because `PATCH` replaces the lines as a whole,\nresending a line with a different amount field switches its mode.\n",
"required": [
"description",
"quantity",
"vat_rate"
],
"properties": {
"description": {
"type": "string",
"maxLength": 2000
},
"quantity": {
"type": "number",
"minimum": 0.01,
"multipleOf": 0.0001
},
"unit": {
"type": "string",
"maxLength": 20
},
"unit_price": {
"type": "number",
"minimum": 0,
"maximum": 999999.9999,
"description": "Unit price before taxes. Supports up to 4 decimal places for micro-pricing\n(e.g. €0.0897/unit for labels, packaging); the generated invoices always round\ntheir amounts to 2 decimals. Mutually exclusive with `total_excluding_tax` and\n`total_including_tax`.\n\nThe upper bound is the same one the invoice line declares, and so is the\nacceptance of `0` (a discount granted before or simultaneously with the sale,\ne.g. a free introductory month). A price outside the range is rejected with\n`422 VALIDATION_ERROR` and the offending field in `details`.\n\nNegative prices are NOT accepted, unlike an invoice line of a corrective invoice:\na recurring template only issues `STANDARD` or `SIMPLIFIED` invoices, and a\ncorrective is created through its own endpoint over an already issued invoice —\nnever generated by a template.\n"
},
"total_excluding_tax": {
"type": "number",
"minimum": 0,
"maximum": 99999999.99,
"description": "Declared line total excluding taxes: this amount IS the taxable base, exactly,\nwith no recalculation. The stored `unit_price` becomes derived and informational\n(`total / quantity`, 4 decimals). Mutually exclusive with `unit_price` and\n`total_including_tax`.\n\nNegative totals are NOT accepted, for the same reason `unit_price` does not accept\nnegative prices: a template only issues `STANDARD` or `SIMPLIFIED` invoices, and only\na corrective invoice — created through its own endpoint over an already issued\ninvoice — carries a negative amount. A total outside the range is rejected with\n`422 VALIDATION_ERROR` and the offending field in `details`.\n\nThe upper bound is the same one `POST /v1/invoices` declares for a line total: a\ntemplate is a promise to issue an invoice, and it cannot accept less than the\ninvoice it will generate does. The derived `unit_price` (`total / quantity`) can\nstill exceed the `maximum` this contract accepts for `unit_price` itself — what\nactually bounds it then is the domain's price ceiling, not this field's contract.\n"
},
"total_including_tax": {
"type": "number",
"minimum": 0,
"maximum": 99999999.99,
"description": "Declared line total including taxes — what the customer pays. The engine works\nthe breakdown backwards so that taxable base + VAT + equivalence surcharge equals\nthis amount exactly on every generated invoice. IRPF withholding is never part of\nthe decomposition: it is a retention, not a price. Mutually exclusive with\n`unit_price` and `total_excluding_tax`.\n\nNegative totals are NOT accepted, same as `total_excluding_tax`.\n\nThe upper bound is the same one `POST /v1/invoices` declares for a line total, for\nthe same reason: the template cannot promise more than the invoice it generates\ncould ever accept. The derived `unit_price` (`total / quantity`) can still exceed\nthe `maximum` this contract accepts for `unit_price` itself — what actually bounds\nit then is the domain's price ceiling, not this field's contract.\n"
},
"discount_percentage": {
"type": "number",
"minimum": 0,
"maximum": 100
},
"tax_type": {
"type": "string",
"description": "Tax type. Omitted, `IVA` applies."
},
"vat_rate": {
"type": "number"
},
"regime_key": {
"type": "string",
"description": "VeriFactu regime key. Omitted, `01` (general regime) applies."
},
"equivalence_surcharge_rate": {
"type": [
"number",
"null"
]
},
"irpf_rate": {
"type": [
"number",
"null"
]
},
"exemption_reason": {
"$ref": "#/$defs/ExemptionReason",
"nullable": true
},
"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"
}
}
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
curl "https://apis.io/api/v1/json-schemas/beel-es-patch-recurring-invoice-request"
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.