Factuarea APIDevelopers

Recurring invoices

Skip a cycle, create a recurrence from an invoice, choose whether each run issues or emails the invoice, fix or follow the PDF template, generate an invoice now, configure auto-delivery, preview the next document and set per-line fiscal fields.

A recurring invoice is a template plus a cadence: Factuarea generates a real invoice on every scheduled run. This guide covers the controls that go beyond basic create/update — skipping a cycle, bootstrapping a recurrence from an existing invoice, automatic email delivery, previewing the computed document and the per-line fiscal fields that VeriFactu requires.

All endpoints below live under https://api.factuarea.com/v1 and use the same error envelope, cursor pagination and scopes as the rest of the API. They hang off /v1/companies/{company}/…: {company} is the id (UUID v7) of the tax ID you operate on, and in the curl examples it is $COMPANY_ID. Reach a tax ID explains how to resolve it.

Skip the next generation

POST /v1/companies/{company}/recurring-invoices/{recurring_invoice}/skip

Advances next_run_at by exactly one period without generating an invoice for the current cycle. The skipped occurrence is not counted against max_occurrences — the generated-invoice counter does not move. Use it to jump over a billing period (holidays, a paused client) while keeping the schedule intact.

Requires the recurring_invoices:write scope. Returns 200 with the recurring-invoice resource (note the advanced next_run_at). A cancelled or completed recurrence responds 422; a recurring invoice that belongs to another company responds 404.

curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/recurring-invoices/01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0b/skip \
  -H "Authorization: Bearer $FACTUAREA_API_KEY"

Skipping logs a skipped entry in the recurring-invoice activity — the history shows the cycle was deliberately omitted, not missed.

Create a recurrence from an existing invoice

POST /v1/companies/{company}/invoices/{invoice}/create-recurring

Copies the lines, client and series of a source invoice into a brand-new recurring invoice (its own UUID v7) and applies the cadence supplied in the body. The source invoice is untouched. Requires the recurring_invoices:write scope.

FieldTypeRequiredNotes
frequencystringyesdaily, weekly, biweekly, monthly, quarterly, semiannual, yearly.
start_onstring (YYYY-MM-DD)yesFirst scheduled run.
end_onstring (YYYY-MM-DD)noLast allowed run.
namestringnoLabel for the recurrence (≤255).
descriptionstringno
notesstringno
metadataobjectnoYour key/value pairs.
holiday_handlingstringnoHow to shift a run that falls on a holiday.
days_before_dueintegernoDue date offset for each generated invoice.
max_occurrencesintegernoStop after N generated invoices.
auto_deliveryobjectnoSee Auto-delivery.
generation_modestringnodraft, issue or issue_and_send. See Generation mode.
presentation_policyobjectnoWhich PDF template each run uses. See Presentation policy.
payment_terms_templatearraynoRelative instalments for every generated invoice. See Payment schedule template.

Returns 201 with the new recurring invoice and a Location header pointing to it. A source invoice that belongs to another company responds 404.

curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/invoices/01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a42/create-recurring \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "frequency": "monthly",
    "start_on": "2026-07-01",
    "max_occurrences": 12,
    "generation_mode": "issue_and_send",
    "auto_delivery": {
      "recipients": ["billing@acme.example"]
    }
  }'

Generation mode

generation_mode decides what each run does with the invoice it generates. It is available on POST /v1/companies/{company}/recurring-invoices, PATCH /v1/companies/{company}/recurring-invoices/{recurring_invoice} and POST /v1/companies/{company}/invoices/{invoice}/create-recurring, in every API version, and every recurring invoice response returns it.

generation_modeEach runDelivery
draftLeaves the invoice as a draft, without a definitive number.None.
issueIssues the invoice: definitive number, VeriFactu record, stock movements.None: the invoice stays is_sent: false.
issue_and_sendIssues the invoice and emails it to the auto-delivery recipients.Marked as sent when the mail server accepts the email.

In issue_and_send, a failed delivery does not undo the run: the invoice stays issued and not sent, and you can email it later with POST /v1/companies/{company}/invoices/{invoice}/send. Any other value answers 422. On PATCH, omitting generation_mode keeps the current mode.

send_automatically remains as a compatibility field derived from the mode: true only with issue_and_send. Without generation_mode, true still selects issue_and_send and false selects draft; sending both with contradictory values answers 422. Recurring invoices created before the mode existed keep their behavior: the ones that emailed their invoices are issue_and_send and the rest draft.

Presentation policy

Every invoice a recurrence generates needs a PDF template. The presentation policy says which one. It is available on POST /v1/companies/{company}/recurring-invoices, PATCH /v1/companies/{company}/recurring-invoices/{recurring_invoice} and POST /v1/companies/{company}/invoices/{invoice}/create-recurring, and the recurring-invoice resource returns presentation_policy, presentation_policy_version and presentation_pause_reason.

The policy is an object with exactly five keys, all required:

Keylatestpinned
mode"latest""pinned"
template_idA template UUID, or null to follow the selection each document would normally get (series, customer, company).Required.
revision_idnullRequired: the exact revision of the template.
commercial_identity_id, commercial_identity_revision_idnullBoth set, or both null when the template has no brand.
  • latest follows the template: each run uses the revision that is published at that moment, so editing the template changes the next invoices.
  • pinned freezes it: every run uses exactly that revision (and brand revision), however the template changes later. A pin that can no longer be used never degrades to latest.
curl -X PATCH https://api.factuarea.com/v1/companies/$COMPANY_ID/recurring-invoices/0197c6a0-5e14-7b29-8d73-4a1f9c2e6b35 \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "presentation_policy": {
      "mode": "pinned",
      "template_id": "0197c4a1-02aa-7c31-9e5b-6d2f8a4c1b73",
      "revision_id": "0197c4a1-02ab-7e08-8a14-3b7c9d5e2f40",
      "commercial_identity_id": null,
      "commercial_identity_revision_id": null
    },
    "expected_presentation_policy_version": 1
  }'

On update, omitting presentation_policy keeps the current one and null resets it to a latest policy that follows the usual selection. {}, extra keys and partial combinations are rejected with 422 invalid_recurring_presentation_policy (error.param points at the offending key); a pinned brand revision without its brand, for example.

Version. The policy has its own counter, presentation_policy_version, which a new recurrence starts at 1. To edit an existing recurrence you must send expected_presentation_policy_version (an integer of 1 or more) whenever the request carries the policy, the payment schedule template, the client or the series, even if the value is null or does not change. Without it: 428 recurring_presentation_policy_precondition_required. With a stale one: 409 recurring_presentation_policy_version_conflict, and nothing is written. Read the recurrence again and retry on the new version. Changing only labels does not need it, a new recurrence does not accept it, and saving never reactivates a paused recurrence.

If the revisioned presentation is not active for your company, presentation_policy, payment_terms_template and expected_presentation_policy_version are ignored (even as null): the request behaves as before and never answers pdf_presentation_not_ready because of them. Once it is active they are validated.

When the template is no longer available

Between runs a template can be archived, lose compatibility or stop being included in your plan. What happens depends on the mode:

  • latest: the run is rolled back (no invoice is created), the recurrence moves to paused and presentation_pause_reason says why — template_archived, template_blocked, template_incompatible, commercial_identity_archived, commercial_identity_blocked, entitlement_unavailable or configuration_invalid. The company receives a single notification asking for an available template.
  • pinned: the recurrence is not paused or changed. The failed run is recorded in the logs and the pin keeps pointing at its revision.

Restoring the template or editing the recurrence does not resume it. Resume explicitly with POST /v1/companies/{company}/recurring-invoices/{id}/resume; it checks the policy again and, if the template is still unavailable, answers 422 recurring_presentation_unavailable and leaves the pause reason in place. Failures that are not visual (transport, tax data, bank data) are never turned into a pause.

Payment schedule template

payment_terms_template gives every generated invoice its payment schedule, with offsets instead of dates. Each row has offset_days (an integer, 0 or more, not decreasing along the list), amount (a string with exactly two decimals, not zero, all rows with the same sign), payment_means ("01" to "19") and account (an { "iban", "bic" } object or null; only for 02 and 04). On update, omitting it keeps the template, null means unknown and [] means "no instalments".

{
  "payment_terms_template": [
    { "offset_days": 0, "amount": "50.00", "payment_means": "01", "account": null },
    { "offset_days": 30, "amount": "50.00", "payment_means": "01", "account": null }
  ]
}

The due date of each instalment is the date of that invoice plus its offset, and each invoice gets its own instalment identities. The amounts must add up to the total to pay of the generated invoice: if they do not, that run fails with the error of the invoice (see Invoice business data), not with a visual pause. A bad row answers 422 invalid_recurring_payment_terms_template.

Generate an invoice now

POST /v1/companies/{company}/recurring-invoices/{recurring_invoice}/generate

Forces the generation of today's invoice outside the cycle (reference, scope recurring_invoices:write). It follows the same rules as a scheduled run: the generation mode decides whether the invoice stays a draft, is issued or is emailed, and the presentation policy decides the template. It answers 200:

{
  "data": {
    "object": "recurring_invoice.generate_result",
    "invoice_id": "0197c6b3-2a48-7d15-9e60-5c8b1f3a7d92",
    "invoice_number": "F-2026-0048"
  }
}

A recurrence generates one invoice per day: repeating the call the same day returns the invoice already generated. A recurrence that cannot run in its current state answers 422 recurring_invoice_cannot_run, and a latest policy whose template is unavailable answers 422 recurring_presentation_unavailable. If the company switches its presentation system on or off twice in a row while the invoice is generated, the call answers a retryable 409 recurring_presentation_activation_changed: nothing was written, so repeat the request (it is not stored for replay, and the same Idempotency-Key does not duplicate the invoice). The MCP server offers the same operation as the tool generate_recurring_invoice.

If the company switches its presentation system on or off twice in a row while the invoice is generated, the call answers a retryable 409 recurring_presentation_activation_changed. Nothing was written: repeat the request, and the same Idempotency-Key does not duplicate the invoice.

Auto-delivery

The auto_delivery object — available on recurring create, update and create-recurring — emails every generated invoice automatically.

FieldTypeNotes
send_automaticallybooleanDerived from generation_mode: true only with issue_and_send. Prefer sending the mode.
recipientsstring[]Primary recipients (email).
ccstring[]Carbon-copy recipients (email).
subjectstringCustom subject (≤255). null uses the default.
bodystringCustom body (≤5000). null uses the default.

With generation_mode: "issue_and_send", each generated invoice is emailed to recipients (with optional cc) using subject/body. draft and issue send nothing. With issue_and_send, an auto_delivery object needs at least one recipient: an empty recipients list answers 422 auto_delivery_recipients_required — there is no one to send to.

{
  "generation_mode": "issue_and_send",
  "auto_delivery": {
    "recipients": ["billing@acme.example"],
    "cc": ["copy@acme.example"],
    "subject": "Your monthly invoice",
    "body": "Hi, here is your invoice for this period."
  }
}

Preview the computed document

GET /v1/companies/{company}/recurring-invoices/{recurring_invoice}/preview

Without expand, preview returns only the date forecast — the upcoming run dates (use count to control how many).

Pass expand=document to also compute the next document as a dry-run: the response adds a next_invoice block with the resolved lines and totals (subtotal, tax, total), built from template_data without persisting anything. Use it to show the customer exactly what the next invoice will contain before it is issued.

curl -G https://api.factuarea.com/v1/companies/$COMPANY_ID/recurring-invoices/01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0b/preview \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  --data-urlencode "expand=document" \
  --data-urlencode "count=2"
{
  "data": [
    {
      "date": "2026-04-01",
      "due_date": "2026-05-01",
      "occurrence_number": 4,
      "estimated_total": 242,
      "will_be_sent": true
    },
    {
      "date": "2026-05-01",
      "due_date": "2026-05-31",
      "occurrence_number": 5,
      "estimated_total": 242,
      "will_be_sent": true
    }
  ],
  "next_invoice": {
    "lines": [
      {
        "description": "Cuota soporte mensual",
        "quantity": 1,
        "unit_price": 200,
        "tax_rate": 21,
        "retention_rate": 0,
        "surcharge_rate": 0,
        "commercial_quantity": 1,
        "commercial_unit_code": "MON",
        "base_unit_code": "MON",
        "conversion_factor": "1.000000",
        "base_quantity": "1.0000",
        "price_list_uuid": null,
        "price_list_name": null,
        "price_source": "manual",
        "price_unit_code": "MON",
        "configuration_uuid": null,
        "configuration_name": null,
        "configuration_signature": null,
        "option_labels": [],
        "price_semantics": "per_commercial_unit",
        "price_adjustment_total": "0.0000",
        "option_adjustments_absorbed": false,
        "subtotal": 200,
        "tax": 42,
        "line_total": 242
      }
    ],
    "totals": {
      "subtotal": 200,
      "tax": 42,
      "total": 242
    }
  }
}

preview never creates an invoice. It is a pure read — the dry-run totals are computed in memory from template_data.

Per-line fiscal fields

Each line of template_data accepts the fiscal fields VeriFactu and the Spanish tax model need. They flow into every generated invoice.

FieldTypeNotes
exemption_reasonstringLIVA exemption / non-subjection cause. One of E1–E6, N1, N2. null if not informed.
regime_keystringVeriFactu regime key (ClaveRegimen, AEAT list L8.1). null if not informed.
retentionnumberIRPF withholding percentage (0–100).
retention_rate_idstring (UUID v7)Catalog tax applied as IRPF withholding. Opaque — does not change the taxes/total computation (the flat retention percentage does).
surchargenumberEquivalence surcharge percentage (0–100).
surcharge_rate_idstring (UUID v7)Catalog tax applied as equivalence surcharge. Opaque — the flat surcharge percentage drives the maths.

The equivalence surcharge is tied to the line VAT by law. The only legal tax_rate → surcharge pairs are:

VAT (tax_rate)Surcharge (surcharge)
215.2
101.4
40.5

Sending an exemption_reason, regime_key, retention_rate_id or surcharge_rate_id outside its catalog responds 422 with an allowed_values list in the error. An illegal VAT↔surcharge pair (e.g. 21 with 1.4) is also rejected with 422.

{
  "template_data": {
    "lines": [
      {
        "description": "Consulting",
        "quantity": 1,
        "unit_price": 1000,
        "tax_rate": 21,
        "surcharge": 5.2,
        "retention": 15,
        "regime_key": "01",
        "exemption_reason": null
      }
    ]
  }
}

Catalog price-list snapshots

Recurring templates accept price_list_id and reprice_strategy, just like a sales-document draft. Catalog-backed template_data.lines can store product_id, variant_id, presentation_id, confirmed_base_quantity and the resolved snapshot fields (item_kind, units, conversion factor, base quantity, price_source, price-list id/name and price unit). Generated invoices inherit that snapshot deterministically; later catalog edits do not silently rewrite the template. Use existing_catalog_lines to re-resolve catalog-priced lines or future_lines_only to preserve them. Manual, supplier-offer and pack prices are never silently repriced. See Price lists.

Forecasts, logs and monthly estimates

preview returns an array of forecast dates under data; count is capped at 36. expand=document adds the next computed document. Execution logs use limit (up to 100) and cursor. estimated_revenue_this_month estimates the remaining scheduled template amounts from today through month end. It is not issued revenue, collections or guaranteed cash. Per-line additional_description is retained in templates.

On this page

Need a hand?Contact support