PDF template library and structured invoices
Manage PDF templates and brand identities, choose the presentation of each document, prepare exact PDF artifacts, and carry payment schedules, references and DIR3 centres on invoices. Fifty new operations, the pdf_templates scopes and a pdf_output_state block on every document.
19 October 2026 (provisional: the final date is the day this release is published) — The API now exposes the PDF template library of the app, the presentation each document retains, the exact PDF artifacts, and the structured business data of an invoice. Four guides explain the whole model: PDF template library, Document presentations, PDF previews and artifacts and Invoice business data.
Every operation of this release hangs off the company axis,
/v1/companies/{company}/…, where {company} is the id (UUID v7) of the tax ID you
operate on; reach a tax ID explains it. None of the new
operations was ever published at the root of /v1: they are new, not moved, so there
is no old path to migrate from.
Operations are written as METHOD /path. The tables at the end of this page link
every new and updated operation to its API Reference page.
New operations
None of these operations is marked x-irreversible. All 27 writes accept
Idempotency-Key; it is required on the preview, the artifact preparation,
the artifact render and the asset upload, and optional on the rest.
- Template library (
pdf_templates:read/pdf_templates:write) —GET|POST /v1/companies/{company}/pdf-templates,GET|PATCH /v1/companies/{company}/pdf-templates/{template},POST /v1/companies/{company}/pdf-templates/{template}/revisions,/duplicate,/archiveand/restore,GET /v1/companies/{company}/pdf-templates/{template}/impactandGET /v1/companies/{company}/pdf-templates/{template}/revisions/{revision}. Company defaults live inGET|PATCH /v1/companies/{company}/pdf-templates/defaults, per-contact defaults inGET|PATCH /v1/companies/{company}/pdf-templates/contact-defaults/{contact}/{document_type}/{purpose}, and logos and images inPOST /v1/companies/{company}/pdf-templates/assetsandGET /v1/companies/{company}/pdf-templates/assets/{asset}(16 in all). The list usespageandper_pageand answers{ "items", "meta" }. - Commercial identities (same scopes) —
GET|POST /v1/companies/{company}/pdf-commercial-identities,GET|PATCH /v1/companies/{company}/pdf-commercial-identities/{identity},POST .../{identity}/revisions,/archiveand/restore,GET .../{identity}/impactandGET .../{identity}/revisions/{revision}(9 in all). - Preview (
pdfs:readandpdf_templates:read) —POST /v1/companies/{company}/pdf-template-previewsrenders a template before you use it, from an example, an unsaved form, a saved draft, a presentation revision or an invoice substitution (thesourcefield). It returns the metadata of a preview artifact and answers200, or202while the render is queued. - PDF artifacts (
pdfs:read) —POST /v1/companies/{company}/pdf-artifactsprepares the PDF of a retained presentation,POST /v1/companies/{company}/pdf-artifacts/{artifact}/renderrenders it,GET /v1/companies/{company}/pdf-artifacts/{artifact}reads its state andGET /v1/companies/{company}/pdf-artifacts/{artifact}/downloadreturns the bytes withETag,304forIf-None-Matchand503withRetry-Afterwhile it is pending. - Presentation of each document — for invoices, quotes, proformas and
delivery notes (scope
{document}:read|write):GET|PATCH /v1/companies/{company}/{documents}/{id}/presentation,GET /v1/companies/{company}/{documents}/{id}/presentation-history(paginated withpageandper_page) andPOST /v1/companies/{company}/{documents}/{id}/presentation-revisions(16 in all). - Template of a series (
series:read|write) —GET|PATCH /v1/companies/{company}/series/{series}/pdf-template. - Administrative revisions of an invoice (
invoices:read|write) —GET|POST /v1/companies/{company}/invoices/{invoice}/administrative-revisionsrevise the DIR3 routing of an issued or overdue invoice with a version check in the body.
The nine PATCH operations of this list (templates, identities, company defaults,
contact defaults, the four document presentations and the series template) accept
If-Match, and the operations that return a single resource answer with an ETag.
MCP tools
The MCP server publishes 51 new tools: one for each of these operations and
generate_recurring_invoice for the existing generate operation. The company comes
from the MCP session, so the tools take no company argument. See the
tool catalog.
| Group | Tools | Scope |
|---|---|---|
| PDF templates | 14 writes (create_pdf_template, update_pdf_template, publish_pdf_template_revision, duplicate_pdf_template, archive_pdf_template, restore_pdf_template, the five equivalents for commercial identities, set_pdf_template_defaults, set_pdf_template_contact_default and upload_pdf_template_asset) and 11 reads (list_pdf_templates, get_pdf_template, its revision, impact, asset, defaults and contact default, and the commercial identity reads) | pdf_templates:write / pdf_templates:read |
| Document presentation | get_*_presentation, list_*_presentations, assign_*_presentation and revise_*_presentation for invoices, quotes, proformas and delivery notes (16) | The scope of the document, read or write |
| Series template | get_series_pdf_template and assign_series_pdf_template | series:read / series:write |
| Administrative revisions | list_invoice_administrative_revisions and revise_invoice_administrative_routing | invoices:read / invoices:write |
| PDF artifacts | prepare_pdf_artifact and render_pdf_artifact (category generate), get_pdf_artifact and read_pdf_artifact, which returns a short signed link and never base64 | pdfs:read |
| Preview | preview_pdf_template (category generate) | pdfs:read and pdf_templates:read |
| Recurring invoices | generate_recurring_invoice | recurring_invoices:transition |
- Retries. The 14 library writes,
assign_*_presentation,revise_*_presentation,assign_series_pdf_template,prepare_pdf_artifact,render_pdf_artifact,preview_pdf_templateandgenerate_recurring_invoiceacceptidempotency_key: reuse the same key when you retry a call so that it is not applied twice. - Errors. A rejection raised while one of these tools runs (for example
pdf_presentation_not_ready,pdf_template_version_conflictor a404) comes back as a normal result withisError: true, and_meta["com.factuarea/error"]carries the samehttp_status,codeandparamas the REST error. Branch oncode; MCP errors has the full shape. - Existing tools.
accept_quoteandaccept_proformafollow the acceptance rule of the REST operations (optionalexpected_presentation_uuid, precondition only for the first capture), andget_invoice_pdf,get_quote_pdf,get_proforma_pdfandget_delivery_note_pdfclaim a retryable failed render again instead of returning the earlier failure.create_invoiceandupdate_invoicedescribe thedue_onrule of invoices with a payment schedule, and every tool that issues an invoice answersinvoice_due_date_not_last_instalmentwhen it is not met; so doschedule_invoiceandreschedule_invoice, andduplicate_invoicemoves the instalments with the issue date.
Scopes
Two new scopes, pdf_templates:read and pdf_templates:write, cover the library
and the identities. No scope macro includes them. The preview needs both
pdfs:read and pdf_templates:read. Document presentations reuse the scope of
their document. The library is the pdf_templates module and the advanced editor
needs pdf_templates_editor; see Access.
POST /v1/accounts/{account}/api-keys accepts the new scopes in its scopes list.
Changes to existing operations
137 existing operations change their contract. They are listed in the tables at the end of the page; these are the groups. The transport control document operations that also change are listed in their own release.
- Template on write — create and update of quotes, proformas and delivery
notes, create, update and corrective of invoices, and
POST /v1/companies/{company}/invoices/substitute-simplifiedacceptpdf_template_id, withexpected_selection_versionwherever there is an earlier selection to compare (not on corrective orsubstitute-simplified). Series acceptpdf_template_idon create and update, pluspdf_template_expected_versionon update, and now returnpdf_template_idandpdf_template_version. - Presentation in responses — invoices, quotes, proformas and delivery notes
carry
presentationandpdf_output_statein every response that returns the document (list, show, create, update, transitions, lookups and duplicates). - Revisioned presentation inactive or active — with it inactive the
presentation fields (
presentation_precondition,presentation_preconditions,pdf_template_uuid,expected_presentation_uuid,expected_selection_versionand the otherexpected_*) are ignored and the behaviour is the one before this release. With it active they are validated, and a template named withoutexpected_selection_version, or a delivery without its precondition, answers428. Clients that do not use templates are not affected. - Delivery precondition — invoice
issueandsendtake the sevenexpected_*,purposeandformatfields flat; quotesendandaccept, proformasendandaccept, and delivery notesendtakepresentation_precondition; thebulk-sendandbulk-statusoperations of the four documents takepresentation_preconditions. The conversion operations declare these fields as not accepted. See the delivery precondition. - Accepting quotes and pro-formas —
POST /v1/companies/{company}/quotes/{quote}/acceptandPOST /v1/companies/{company}/proformas/{proforma}/acceptneedpresentation_preconditiononly for the first capture: when the document has no retained capture yet or its draft was edited or re-templated after it was captured (without it,428 pdf_presentation_precondition_requiredand nothing is written). A document that already has a retained capture is accepted without the object; the optionalexpected_presentation_uuid(new on quotes) cites that capture and answers409 pdf_presentation_conflictif it is no longer the current one. Accepting a draft numbers it, also a pro-forma, and captures what was reviewed. The request examples arefirst_captureandretained_capture. pdf_presentation_not_readyis422— it is a business rule, not a permission. Branch oncode.- Conflicts (
409) — every409of this release changes nothing: read again, review and repeat. Document writes, transitions, conversions, duplicates, signatures and downloads declarepdf_presentation_conflict(the presentation changed since you read it) andpdf_presentation_context_changed(what you reviewed no longer matches the document). Invoice operations that deliver or register a fiscal fact (create,issue,send,annul,void,corrective,substitute-simplified,mark-paid,mark-sent, payments and their reversal,send-reminder, the quarterly ZIP and email, and the generation of a recurring invoice) also declarepdf_legal_source_changed. In the library, the writes withexpected_versiondeclarepdf_template_version_conflict(details.current_versionandrecovery: reload_or_keep_local), publishing and archiving declarepdf_library_impact_conflict, the asset uploadpdf_template_asset_conflictand create and duplicateresource_conflict. The series template, the presentation policy of a recurring invoice and the payment schedule declare their own version conflict. - Public links —
PATCH {document}/public-linkacceptsaction: "publish"withpublication_context(presentation_idandexpected_binding_version), and bothGETandPATCHreturn apublicationblock. Opened without a version selector, theurlof the link now shows the last version you shared withpublish, not the one bound to the current presentation;publication.public_urlalways names its exact version, and an unknown or private selector answers404instead of falling back to another version. See Sending documents. - Delivery note signature —
signed_atinPOST /v1/companies/{company}/delivery-notes/{id}/signis deprecated and ignored: the server sets the date.signed_byaccepts up to 120 characters. The operation also takes theexpected_*identifiers of the presentation the signer saw. - Invoices — responses carry
payment_terms(instalments), header and linebusiness_references,legal_literals, the invoicing period and theadministrative_*routing. Writes accept them with the omit /null/[]semantics of Invoice business data, andexpected_payment_terms_versionprotects the schedule of an existing invoice. With a schedule, the invoice falls due on the day of its last instalment: issuing it with a missing or differentdue_onanswers422 invoice_due_date_not_last_instalment, a draft keeps the date you send, and an update that replacespayment_termswithoutdue_onmoves it to the last instalment. A corrective without a schedule falls due 30 days after it is issued. Scheduling or rescheduling an invoice (POST /v1/companies/{company}/invoices/{invoice}/scheduleandPATCH /v1/companies/{company}/invoices/{invoice}/reschedule) checks the same rule and answers422 invoice_due_date_not_last_instalment(param: due_on), with the invoice keeping its status and date. Duplicating an invoice issues the draft today: each instalment keeps its amount and moves by the days between both issue dates, anddue_onis the last moved instalment. The422of create, update, corrective and issue starts with the general text of invoice validation and lists the schedule codes after it. The extended invoice also travels insideGET /v1/companies/{company}/events,GET /v1/companies/{company}/events/{event}and the webhook deliveries (list and show), so their payloads change. With revisioned templates, thepdfblock ofPOST /v1/companies/{company}/invoicesis the output retained for the presentation captured at issuance, in that presentation's paper (a simplified invoice may be an 80 mm ticket), and while it ispendingitsurlanswers503 pdf_artifact_not_readywithRetry-After. - Contacts — the customer profile accepts and returns the optional
dir3_proponent(role 04), so every operation that returns a contact changes. - FacturaE and FACe —
GET /v1/companies/{company}/invoices/{id}/facturaeacceptssubmission_id, returnsETagandX-Facturae-Sha256when the artifact is retained, and rejects a draft or scheduled invoice with422.POST /v1/companies/{company}/invoices/{id}/face-submissionsacceptssubmission_idand answers201(new attempt),200(continuation or replay) or409(for exampleface_transmission_uncertain).POST /v1/companies/{company}/invoices/{id}/sendtakesattach_facturaeandsubmission_id. See FACe invoicing. - PDF downloads and render —
GET /v1/companies/{company}/{documents}/{id}/pdfandGET /v1/companies/{company}/invoices/{id}/pdf-linkcan answer202while the PDF is being prepared, and409or410when the source changed or was erased. A render that failed but can be retried is never answered with that earlier failure: the download claims it again and answers202, so retrying makes progress. A render that failed terminally answers500with its code (pdf_engine_profile_unavailable,pdf_payload_resource_unavailable,pdf_image_resource_unavailable) and nothing is enqueued.POST /v1/companies/{company}/pdf-artifacts/{artifact}/renderandPOST /v1/companies/{company}/pdf-template-previewsanswer200only with a ready artifact: one that no render can complete answers500with its code. See how downloads answer. The fourbulk-pdfoperations declareX-Bulk-Total,X-Bulk-SuccessfulandX-Bulk-Failed, andPOST /v1/companies/{company}/invoices/quarterly/download-zipdeclares itsX-Quarterly-*headers. - Recurring and correctives — a recurring invoice carries a presentation
policy (
presentation_policy,presentation_policy_version,presentation_pause_reason) andpayment_terms_template; a corrective invoice inherits what Corrective invoices lists. See also Recurring invoices. - Other declarations —
GET /v1/tax-catalogdeclaresIf-None-Match;POST /v1/companies/{company}/employeesandPOST /v1/companies/{company}/employees/{employee}/reactivatedeclare the correlation headerX-Request-Idon their503;POST /v1/companies/{company}/contacts/importand its preview declare the limit of themappingfield;POST /v1/companies/{company}/contactsand the customer profile declare409 idempotency_key_in_use(a request with the same key is still running);PATCH /v1/companies/{company}/delivery-notes/{delivery_note}no longer declaresresource_conflict, because editing a delivery note does not number it.
Brand on dark backgrounds and brand size
A commercial identity revision has four more keys, which POST /v1/companies/{company}/pdf-commercial-identities
and POST /v1/companies/{company}/pdf-commercial-identities/{identity}/revisions accept and every identity
response returns:
logo_dark_asset_idandbrand_image_dark_asset_id: optional versions of the logo and of the brand image for dark backgrounds. Each needs its base image.dark_background_fallback:silhouette(default) orplate.brand_size:small,medium(default) orlarge.
A brand has no address: contact_address is not part of its configuration, and the
issuer address on the PDF is always the company's. There is no separate commercial
contact block either: when the template shows the company's email or phone, the
brand's contact_email or contact_phone replaces it in the issuer's contact line,
and when the template hides it, neither is printed. The unsaved brand of a preview
therefore takes six required keys.
On a dark background (the frame of the corporative preset, the header band of the
control document), the brand is painted in this order: its dark version, if it has
one; the image as it is, if it reads; otherwise a white silhouette, or the light plate
if the brand prefers plate. On a light background, an image that would disappear,
such as a white logo, is painted as a black silhouette. In practice, upload the colour
logo as the base and the white one as the dark version.
A template's configuration.branding.size also accepts inherit, the value of new
templates, which takes the brand_size of its brand (medium without one). The
preview accepts the four keys in an unsaved brand (commercial_identity with
mode: draft), and the MCP tools create_pdf_commercial_identity,
publish_pdf_commercial_identity_revision and preview_pdf_template take them as
well. Documents captured before keep their look. See
dark backgrounds and
brand size.
Section texts per language
footer_text, conditions_text and commercial_register_text of the sections block
of PdfTemplateConfiguration are now objects with one text per language:
{ "es": "…", "en": "…", "ca": "…" }. Each language is a string or null, with the same
limits as before for each one (500, 5,000 and 5,000 characters), and an empty string is
stored as null.
- Reading. Every response returns the object, always. A text stored in the earlier
form, a plain string, is returned as
{ "es": text, "en": null, "ca": null }. Published revisions, captures and artifacts are not rewritten, so their fingerprint does not change. - Writing. Create and publish accept a plain string or the object. A string replaces
the text of all three languages with that text under
es. A partial object only changes the languages you send. An unknown key, such asfr, returns422 invalid_pdf_template_configurationwithparamconfiguration.sections.footer_text(or the field you sent). - Rendering. The PDF uses the text in the language of the document. If it is empty, it uses the Spanish one, and if that is empty too, the block is not printed. A plain string is printed the same in the three languages.
Operations affected: POST /v1/companies/{company}/pdf-templates and POST /v1/companies/{company}/pdf-templates/{template}/revisions
(they accept both forms), and GET /v1/companies/{company}/pdf-templates, GET /v1/companies/{company}/pdf-templates/{template},
PATCH /v1/companies/{company}/pdf-templates/{template}, GET /v1/companies/{company}/pdf-templates/{template}/revisions/{revision},
/duplicate, /archive, /restore and POST /v1/companies/{company}/pdf-template-previews (they return or
take the template configuration). The MCP tools of the library follow the same contract.
sections.notes_mode keeps its three values: auto prints the notes of the document
when it has them, no hides them, and yes is still accepted and behaves exactly
like auto.
pdf_output_state on every document
Invoice, Quote, Proforma and DeliveryNote responses include pdf_output_state, a
summary of the retained PDF output that never exposes snapshots, proofs or storage
paths. GET /v1/companies/{company}/{documents}/{id}/pdf also answers 202 while the PDF is being
prepared.
| Field | Contract |
|---|---|
state | prepared, queued, processing, ready, failed, unavailable, corrupt, or null when the document has no retained output state. |
presentation_id, artifact_id | UUID or null. |
format | PDF format captured for this output, or null when unavailable. |
variant | official, alternative, or null. |
unavailable_reason | Stable reason when output is unavailable, or null; privacy_erased is one example. |
error | Object or null. When present, it contains code, retryable and correlation_id; the correlation ID may be null. |
retry_after | Suggested retry delay in seconds (integer ≥ 1), or null when no retry is scheduled. |
download_url | Relative path /v1/companies/{company}/pdf-artifacts/{id}/download, or null. It is non-null only when state is ready, and is never an internal storage path. |
The key is always present. The example of the field is the all-null state:
{
"state": null,
"presentation_id": null,
"artifact_id": null,
"format": null,
"variant": null,
"unavailable_reason": null,
"error": null,
"retry_after": null,
"download_url": null
}Error codes
61 codes are new; none changes the status of an existing code. The most relevant ones:
| Status | Code | Meaning |
|---|---|---|
404 | pdf_template_not_found, pdf_commercial_identity_not_found, pdf_artifact_not_found | Missing, or from another company. |
409 | pdf_template_version_conflict, pdf_library_impact_conflict, pdf_presentation_conflict, pdf_presentation_context_changed, pdf_legal_source_changed | A version, an impact or a context changed. Read again. |
409 | invoice_payment_terms_version_conflict, invoice_administrative_version_conflict, face_transmission_uncertain | Stale schedule or routing version; FACe outcome unknown. |
410 | pdf_signature_personal_data_forgotten | Terminal privacy erasure of the original. |
412 | pdf_template_precondition_failed, pdf_presentation_etag_mismatch | If-Match does not match. |
422 | invalid_pdf_template_configuration, pdf_template_archived, pdf_presentation_invalid, pdf_presentation_not_ready | Invalid field (see param), archived template, or revisioned output not active. |
422 | invalid_invoice_business_data, invalid_invoice_payment_terms, invalid_facturae_structured_data | Invalid structured data. |
422 | invoice_due_date_not_last_instalment | The invoice has a payment schedule and is issued with a due_on that is missing or is not the date of the last instalment. |
428 | pdf_template_precondition_required, pdf_presentation_precondition_required, invoice_payment_terms_precondition_required, invoice_administrative_precondition_required | A required version or precondition is missing. |
403 | pdf_template_access_denied, series_template_access_denied, facturae_operation_forbidden | Role, module or issuer authority. |
500 | pdf_original_unavailable, pdf_original_corrupt, pdf_original_layout_unavailable | The original PDF is lost, fails its checksum, or is intact but its layout is no longer served by this release (preparing a derived presentation: signature, legal QR or refreshed legal data). Nothing is regenerated in its place; contact support. |
503 | pdf_artifact_not_ready | Not ready; wait Retry-After. |
idempotency_key_reused is still 422: reusing an Idempotency-Key with
another body, also on the preview and on the artifact operations, which compare the
raw body byte for byte. Resending an unattended checkout whose external_id was
already issued with another type or total is a different error,
409 unattended_replay_mismatch.
Branch on code, never on message. The error catalog has
all of them. Over MCP the same codes arrive in _meta["com.factuarea/error"] of a
result with isError: true.