Biblioteca de plantillas PDF
Gestiona las plantillas PDF, las identidades de marca y los valores por defecto de tu empresa — revisiones, impacto, valores por defecto por contacto, subida de activos, precedencia, concurrencia con ETag e idempotencia.
La biblioteca de plantillas PDF es donde tu empresa guarda los diseños y las marcas que dan forma al PDF de cada documento que genera la API. Creas una plantilla (maquetación, preajuste, columnas, textos), le asignas una identidad comercial (logotipo y marca) y decides dónde se aplica: como valor por defecto de la empresa, por tipo de documento, por serie o por contacto.
Todo lo que hay en la biblioteca está versionado. Una plantilla o una identidad es una
cabecera (nombre, estado, version) que apunta a su revisión actual; una revisión es
una instantánea inmutable del diseño o de la marca. Publicar nunca edita una revisión: añade
la siguiente. Un documento conserva el PDF con el que se capturó: cambiar, archivar o
restaurar recursos de la biblioteca solo afecta a los documentos que crees o revises después.
| Recurso | Qué es | Ruta |
|---|---|---|
| Plantilla | Diseño del PDF: preajuste base, columnas, títulos, secciones, página. | /v1/companies/{company}/pdf-templates |
| Revisión de plantilla | Instantánea inmutable de una plantilla, numerada desde 1. | /v1/companies/{company}/pdf-templates/{template}/revisions/{revision} |
| Identidad comercial | Marca: nombre comercial, logotipo, imagen de marca, modo de marca, correo y teléfono. | /v1/companies/{company}/pdf-commercial-identities |
| Activo | Logotipo o imagen de marca que subes; privado e inmutable. | /v1/companies/{company}/pdf-templates/assets |
| Valores por defecto de la empresa | Plantilla e identidad que se usan cuando no hay nada más específico. | /v1/companies/{company}/pdf-templates/defaults |
| Valores por defecto por contacto | Plantilla preferida por un contacto para un tipo de documento y un propósito. | /v1/companies/{company}/pdf-templates/contact-defaults/{contact}/{document_type}/{purpose} |
Todas las rutas de esta guía cuelgan de /v1/companies/{company}/…: {company} es el id (UUID v7)
del NIF con el que operas, y en los ejemplos curl es $COMPANY_ID.
Alcanzar un NIF explica cómo resolverlo.
Una identidad comercial nunca sustituye a la identidad fiscal del emisor. La razón social,
el NIF, los datos de impuestos y las cuentas bancarias salen de tu empresa y de cada
documento; la biblioteca solo guarda su aspecto. Una plantilla o una identidad que intente
llevar datos fiscales o bancarios, HTML, CSS, scripts o URLs se rechaza con 422.
Los recursos de la biblioteca se devuelven como objeto plano (sin envoltorio data) y los
listados como { "items": [...], "meta": { "page", "per_page", "total" } }. Todos los
identificadores son UUID v7 y se exponen como id.
Acceso: módulo, plan, scopes y roles
| Operación | Scope |
|---|---|
| Leer plantillas, identidades, revisiones, activos, impacto y valores por defecto | pdf_templates:read |
| Crear, renombrar, publicar, duplicar, archivar, restaurar, subir y cambiar valores por defecto | pdf_templates:write |
| Previsualizar una plantilla (véase Vistas previas y artefactos PDF) | pdfs:read y pdf_templates:read |
- Roles. Las lecturas están abiertas a los roles
adminyuserde la empresa; las escrituras y la lectura del impacto exigenadmin. Unemployeerecibe403 pdf_template_access_denied. Una API key actúa con el rol del usuario al que pertenece, y el rol y las restricciones de módulo se comprueban de nuevo en cada petición. - Módulo y plan. La biblioteca es el módulo
pdf_templates, disponible en Esencial, Profesional, Avanzado y Enterprise. El editor avanzado (tipografía, colores, columnas, maquetación de página y los preajustescorporativeypremium) es el módulopdf_templates_editor, incluido desde Profesional. Sin él puedes seguir gestionando plantillas que solo cambian la marca sobre los preajustesclassic,modernyminimal; cualquier otro cambio devuelve403 feature_not_available_in_plan. Leepdf_capabilitiesen personalización de la cuenta para saberlo de antemano. Un downgrade conserva lo que ya guardaste; solo los cambios avanzados nuevos necesitan el editor. - Modo de prueba. La biblioteca funciona igual con claves
fact_test_yfact_live_.
Plantillas
Crear una plantilla
POST /v1/companies/{company}/pdf-templates crea una plantilla con su primera revisión. Solo name es obligatorio;
el resto tiene valores por defecto.
| Campo | Significado |
|---|---|
name | De 1 a 120 caracteres. |
description | Opcional, hasta 500 caracteres. |
base_preset | classic, modern (por defecto), minimal, corporative o premium. |
supported_types | Tipos de documento que puede generar: invoice, quote, proforma, delivery-note. Por defecto, los cuatro. |
supported_purposes | Propósitos por tipo. Facturas: complete, simplified, corrective, simplified_corrective; los demás tipos solo complete. Por defecto, todos. |
supported_formats | a4 (por defecto), ticket_80, ticket_58. Los formatos de ticket solo valen para plantillas exclusivas de factura. |
commercial_identity_id | Marca que usa por defecto, o null para heredar la identidad por defecto de la empresa. |
configuration | Diseño parcial, combinado sobre los valores del preajuste (véase abajo). |
id, revision_id | UUID v7 opcionales si quieres elegir tú los identificadores. |
configuration es un objeto cerrado con los grupos branding (mode: logo, imago o none;
size: small, medium, large o inherit, consulta el tamaño de la marca), typography, colors, page, watermark, titles, columns, company_fields,
client_fields, custom_field_definitions y sections. Una clave desconocida, un tipo incorrecto
o un valor fuera de rango se rechaza con 422 invalid_pdf_template_configuration y el param
señala la ruta exacta, por ejemplo configuration.typography.font_size. Cuando branding.mode es
logo o imago, la plantilla necesita una marca efectiva: su propio commercial_identity_id o
una identidad por defecto de la empresa que esté activa. Sin ella, la petición devuelve 422 pdf_commercial_identity_required.
curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-templates \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Invoices with logo",
"base_preset": "modern",
"supported_types": ["invoice"],
"commercial_identity_id": "0199f39e-1a20-7f6b-a2c8-3d5e9b0c4a71",
"configuration": { "branding": { "mode": "logo", "size": "medium" } }
}'La respuesta es 201 con la plantilla y una cabecera ETag (abreviada aquí):
{
"id": "0199f3a2-7c4e-7b1a-9d3e-5a2c8f1b6e40",
"name": "Invoices with logo",
"description": null,
"state": "active",
"version": 1,
"availability": { "selectable": true, "reason": null },
"supported_types": ["invoice"],
"supported_purposes": { "invoice": ["complete", "simplified", "corrective", "simplified_corrective"] },
"supported_formats": ["a4"],
"commercial_identity_id": "0199f39e-1a20-7f6b-a2c8-3d5e9b0c4a71",
"current_revision": {
"id": "0199f3a2-7c52-7d03-8a41-6b9e0c2d7f15",
"template_id": "0199f3a2-7c4e-7b1a-9d3e-5a2c8f1b6e40",
"number": 1,
"base_preset": "modern",
"layout_version": "1",
"schema_version": 1,
"configuration": { "...": "complete normalized configuration" }
},
"created_at": "2026-10-14T09:12:41.000000Z",
"updated_at": "2026-10-14T09:12:41.000000Z"
}Listar y leer
GET /v1/companies/{company}/pdf-templatesaceptaq(búsqueda por nombre),state(activepor defecto,archivedoall),document_type,purpose,format,pageyper_page(de 1 a 100, por defecto 25). Los resultados salen ordenados por nombre. Un filtro no válido devuelve422con el filtro enparam; nunca se ignora en silencio.GET /v1/companies/{company}/pdf-templates/{template}devuelve la plantilla con su revisión actual y elETagque necesitas para el siguientePATCH.GET /v1/companies/{company}/pdf-templates/{template}/revisions/{revision}devuelve una revisión exacta, también las archivadas.
Renombrar: solo metadatos
PATCH /v1/companies/{company}/pdf-templates/{template} cambia únicamente name y description (description: null
la borra). Nunca toca el diseño: enviar configuration aquí es un 422. Una petición que no
cambia nada no crea versión nueva. La precondición es obligatoria, véase
concurrencia.
curl -X PATCH https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-templates/0199f3a2-7c4e-7b1a-9d3e-5a2c8f1b6e40 \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Content-Type: application/json" \
-H 'If-Match: "00295d3c3bb1b0b0ce5187e46fc6af39f41f507558608c8d14312fba4a710dc6"' \
-d '{ "name": "Invoices with logo (2026)" }'Publicar una revisión
Cambiar el diseño significa publicar una revisión nueva, en dos pasos.
- Pide el impacto:
GET /v1/companies/{company}/pdf-templates/{template}/impact?action=publish. La respuesta enumera las asociaciones que apuntan a la plantilla (company_default,type_default,contact_default,seriesyrecurring), losretained_countsde presentaciones, salidas preparadas y anclajes que quedan intactos, loswarningssi los hay, y unimpact_fingerprint. - Publica con
POST /v1/companies/{company}/pdf-templates/{template}/revisions, enviando elexpected_versionde la plantilla, eseexpected_impact_fingerprinty al menos un cambio entrebase_preset,commercial_identity_id,supported_types,supported_purposes,supported_formatsyconfiguration.
Los objetos de configuration se combinan en profundidad sobre la revisión actual; las listas
como columns o custom_field_definitions se sustituyen por completo. La respuesta es 201 con
la revisión nueva, y la version de la plantilla sube una unidad. Si las asociaciones cambiaron
entre las dos llamadas, la huella ya no coincide y recibes 409 pdf_library_impact_conflict:
vuelve a leer el impacto y decide.
curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-templates/0199f3a2-7c4e-7b1a-9d3e-5a2c8f1b6e40/revisions \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"expected_version": 2,
"expected_impact_fingerprint": "b8a9f15005a46cf651f5652419b2edba941b3090090a1934a96f37c9cd0b973f",
"configuration": { "page": { "show_page_numbers": true }, "sections": { "footer_text": "Thank you for your business" } }
}'Los documentos nuevos se resuelven con la revisión nueva. Los documentos ya capturados, las salidas preparadas y los anclajes de las facturas recurrentes conservan la revisión que tenían.
Duplicar
POST /v1/companies/{company}/pdf-templates/{template}/duplicate con name y el expected_version de la origen crea
una plantilla nueva (version 1, revisión 1, active) con la configuración actual de la origen.
La origen puede estar archivada; la copia siempre nace activa. La copia no hereda valores por
defecto, asignaciones de series ni preferencias de contacto, y necesita la marca que la origen
necesitaría hoy (las capacidades del plan se comprueban en el momento de copiar).
Archivar y restaurar
Una plantilla archivada sigue siendo legible y conserva sus revisiones y activos, pero ya no se
puede seleccionar (availability.selectable es false).
-
GET /v1/companies/{company}/pdf-templates/{template}/impact?action=archivedevuelve las asociaciones que dependen de ella y una huella. -
POST /v1/companies/{company}/pdf-templates/{template}/archiveconexpected_version,expected_impact_fingerprintyreplacements, una lista (puede ir vacía) con una decisión por cada asociación cuyaactionseareplace_or_clearopause:Decisión Campos Sustituir por otra plantilla { "key", "expected_version", "action": "replace", "replacement_id" }Quitar el vínculo { "key", "expected_version", "action": "clear", "replacement_id": null }Pausar (facturas recurrentes que siguen la última plantilla) { "key", "expected_version", "action": "pause", "replacement_id": null }Copia
keyyversionde la asociación tal como las devolvió el impacto;keyes opaca. Las asociaciones marcadasretainedno necesitan decisión.
Cada decisión y cada asociación se validan antes de cambiar nada, y el archivado se aplica como
un único cambio atómico. Si falta una decisión se devuelve
422 pdf_template_default_replacement_required. POST /v1/companies/{company}/pdf-templates/{template}/restore
(solo expected_version) vuelve a activar la plantilla; no reinstala los valores por defecto, los
vínculos de serie ni las preferencias de contacto que el archivado sustituyó o quitó.
Identidades comerciales
Una identidad comercial es la marca que muestra una plantilla. Tiene el mismo ciclo de vida que una
plantilla, con las mismas operaciones bajo /v1/companies/{company}/pdf-commercial-identities: GET (listado, con
q, state, page, per_page), POST (crear), GET /{identity}, PATCH /{identity} (nombre y
descripción), GET /{identity}/impact, POST /{identity}/revisions, POST /{identity}/archive,
POST /{identity}/restore y GET /{identity}/revisions/{revision}.
La marca vive en configuration, que acepta exactamente estas claves:
| Clave | Notas |
|---|---|
commercial_name | Hasta 120 caracteres. |
logo_asset_id | Un activo que subiste con kind: logo. |
brand_image_asset_id | Un activo que subiste con kind: imago. |
brand_mode | logo, imago o none. |
contact_email, contact_phone | Hasta 254 y 50 caracteres. Cuando la plantilla muestra el correo o el teléfono de la empresa, el de la marca lo sustituye en la línea de contacto del emisor; cuando la plantilla lo oculta, no sale ninguno. No hay un bloque aparte de contacto comercial. |
logo_dark_asset_id | Opcional. Versión del logo para fondos oscuros, un activo con kind: logo. Necesita logo_asset_id: al quitar logo_asset_id, envía también null aquí o la petición responde 422 invalid_pdf_template_configuration. |
brand_image_dark_asset_id | Opcional. Versión de la imagen de marca para fondos oscuros, un activo con kind: imago. Necesita brand_image_asset_id. |
dark_background_fallback | silhouette (por defecto) o plate. Consulta los fondos oscuros. |
brand_size | small, medium (por defecto) o large. Consulta el tamaño de la marca. |
Todas las claves admiten null salvo dark_background_fallback y brand_size. Una marca no tiene dirección: el domicilio del emisor en el PDF es siempre el de la empresa, un dato legal que la marca no puede sustituir.
Los activos deben ser de tu empresa y del tipo correcto; si no, la petición falla
(404 pdf_template_asset_not_found o 422). Publicar una revisión pide expected_version,
expected_impact_fingerprint y una configuration parcial con al menos una clave. El impacto de
una marca también enumera las plantillas que la usan (asociaciones template), y archivarla pide
una decisión por asociación, exactamente igual que archivar una plantilla (la decisión sobre una asociación template también puede llevar revision_id).
curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-commercial-identities \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Main brand",
"configuration": {
"commercial_name": "Acme Studio",
"logo_asset_id": "0199f39d-52b1-7e34-9c07-1f6a8d3b2e90",
"logo_dark_asset_id": "0199f39d-6a14-7c52-8e31-2b7c9e4d1f05",
"brand_mode": "logo",
"contact_email": "hello@acme.example"
}
}'La marca sobre fondos oscuros
Algunos diseños ponen la marca sobre un fondo oscuro, como el marco del preajuste
corporative o la banda de la cabecera del documento de control. En cada captura nueva,
la imagen que muestra la plantilla (la de brand_mode) se pinta en este orden:
- La versión para fondo oscuro, si la marca la tiene. Sobre un fondo oscuro,
logo_dark_asset_id(obrand_image_dark_asset_idpara la imagen de marca) se pinta tal cual. Sobre el papel no se usa. - La imagen tal cual, si se lee. Una imagen con fondo propio (un JPEG, o un PNG sin transparencia) se pinta tal cual, y también una cuya tinta contrasta con el fondo.
- Si no, una silueta o la placa. Sobre un fondo oscuro decide
dark_background_fallback:silhouette(por defecto) pinta la forma de la marca en blanco, yplatela pone sobre una placa clara, siempre que se lea sobre ella (si no, la silueta blanca). - Sobre un fondo claro, como el papel, una imagen que desaparecería (un logo blanco, por ejemplo) se pinta como una silueta negra.
La silueta conserva la forma y la transparencia de la imagen; solo cambia el color de su
tinta. En la práctica: sube tu logo en color como logo_asset_id y su versión blanca
como logo_dark_asset_id. Los documentos capturados antes de esta regla conservan el
aspecto con el que se capturaron.
El tamaño de la marca
brand_size es el tamaño por defecto de la marca: small, medium (por defecto) o
large. Una plantilla fija el suyo en configuration.branding.size, o usa inherit, el
valor de las plantillas nuevas, para tomar el tamaño de su marca; sin marca, medium. Las
plantillas que ya guardaban un tamaño lo conservan. Cada tamaño es una superficie óptica de
la tinta, no una caja máxima: un logo apaisado baja de alto y gana ancho, uno vertical
crece algo de alto, y el margen transparente que rodea la imagen no cuenta. El mismo
tamaño se aplica a todos los diseños, al ticket y al documento de control.
Subir activos
POST /v1/companies/{company}/pdf-templates/assets sube un logotipo o una imagen de marca como multipart/form-data.
Idempotency-Key es obligatoria en esta operación.
| Parte | Reglas |
|---|---|
kind | logo o imago. |
file | JPEG, PNG o WebP, hasta 2 MiB, hasta 6000 px por lado y 24 megapíxeles. El tipo y el tamaño reales se comprueban sobre los bytes, no sobre la extensión. |
id | UUID v7 opcional. |
curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-templates/assets \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Idempotency-Key: $(uuidgen)" \
-F kind=logo \
-F file=@logo.png{
"id": "0199f39d-52b1-7e34-9c07-1f6a8d3b2e90",
"kind": "logo",
"mime": "image/png",
"sha256": "7a265f5f003866f84e23c7e237301879b7d4a4ecc0ab80d2041a3c980b12310a",
"size_bytes": 18342,
"created_at": "2026-10-14T09:05:12.000000Z"
}Los activos son privados e inmutables; GET /v1/companies/{company}/pdf-templates/assets/{asset} devuelve estos metadatos en JSON, nunca una ruta de almacenamiento. Con una cabecera Accept image/* devuelve los bytes guardados en línea, con Cache-Control: private, no-store. En JPEG y PNG se eliminan los metadatos
EXIF, GPS y de texto. Archivar una plantilla o una marca no borra sus activos, y cada activo cuenta
una sola vez para tu espacio de almacenamiento aunque lo compartan varias marcas.
Por MCP, upload_pdf_template_asset recibe la imagen como image_base64 (hasta 2048 KiB ya
descodificada), el mime declarado (image/jpeg, image/png o image/webp) y un filename.
Valores por defecto de la empresa
GET /v1/companies/{company}/pdf-templates/defaults devuelve el registro único de tu empresa:
{
"id": "0199e0aa-4b10-7c33-9a52-6d8e1f3b7a24",
"version": 1,
"company_template_id": null,
"company_commercial_identity_id": null,
"type_defaults": [],
"render_activation": "legacy"
}| Campo | Significado |
|---|---|
company_template_id | Plantilla que se usa cuando no hay nada más específico. Debe poder generar todos los tipos de documento y propósitos. |
company_commercial_identity_id | Marca que usan las plantillas que no tienen una propia. |
type_defaults | Lista de { "document_type", "purpose", "template_id" }: la plantilla para un tipo de documento y un propósito. |
render_activation | Solo lectura. legacy o revisioned: indica si la salida revisionada que se apoya en esta biblioteca está efectivamente activa para tu empresa. |
Mientras no escribas nada, la lectura es virtual: id es el UUID de tu empresa, version es 1 y
no hay nada guardado. El primer PATCH /v1/companies/{company}/pdf-templates/defaults lo guarda en version 2.
- Un campo omitido conserva su valor y
nulllo borra. type_defaultssustituye la lista entera: envía todas las entradas que quieras conservar. El formato de papel no forma parte de la clave.render_activationnunca se acepta: enviarlo, incluso comonull, es un422. Forma parte de la representación, así que cuando cambia también cambia elETagy unIf-Matchcaducado responde412como corresponde.
curl -X PATCH https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-templates/defaults \
-H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"expected_version": 1,
"company_template_id": "0199f3a2-7c4e-7b1a-9d3e-5a2c8f1b6e40",
"type_defaults": [
{ "document_type": "quote", "purpose": "complete", "template_id": "0199f3b0-2a41-7c88-9e02-d4f6a8b1c3e5" }
]
}'Una plantilla archivada no puede ser valor por defecto (422 pdf_template_archived), y una
plantilla que no admite el tipo de documento o el propósito se rechaza con 422.
El ajuste clásico pdf_template de la personalización de la cuenta
es otra capa, anterior. Estos valores por defecto no la sustituyen: véase
qué plantilla usa un documento.
Valores por defecto por contacto
Un contacto puede preferir una plantilla para cada tipo de documento y propósito:
GET /v1/companies/{company}/pdf-templates/contact-defaults/{contact}/{document_type}/{purpose}PATCH /v1/companies/{company}/pdf-templates/contact-defaults/{contact}/{document_type}/{purpose}
document_type es invoice, quote, proforma o delivery-note, y purpose debe pertenecer a
ese tipo (en facturas complete, simplified, corrective o simplified_corrective; en los
demás tipos complete).
{
"id": "0199f2c1-8d10-7a55-8b3e-4c7d2e9f1a06",
"document_type": "invoice",
"purpose": "complete",
"template_id": null,
"version": 1,
"persisted": false
}id es el contacto. Si el contacto se fusionó con otro, configura el contacto resultante: la
preferencia del fusionado no se hereda. El contacto debe ser un cliente de tu empresa. Sin
preferencia guardada la lectura es virtual (version 1, persisted: false); la primera escritura
la guarda en version 2. PATCH recibe template_id (null la borra) y la precondición. Un
contacto desconocido o de otra empresa devuelve 404, idéntico al de un contacto inexistente.
Qué plantilla usa un documento
Cuando se crea, se emite o se envía un documento, Factuarea elige su plantilla con este orden, y gana el primer nivel que tenga una plantilla disponible para el tipo de documento, el propósito y el formato de papel:
- Selección manual en el documento (
selection_mode: manual). Es exclusiva: si esa plantilla ya no está disponible la operación falla, nunca recurre al siguiente nivel. - Valor por defecto de la serie, con
GETyPATCH /v1/companies/{company}/series/{series}/pdf-template. - Valor por defecto del contacto canónico.
- Valor por defecto de la empresa para el tipo de documento y el propósito (
type_defaults). - Plantilla por defecto de la empresa (
company_template_id). - Legacy: la personalización de la cuenta (
pdf_template,accent_color, logotipo) y el renderizador clásico.
Si un nivel heredado apunta a una plantilla archivada o incompatible, se pasa al siguiente nivel y
el documento informa de un aviso en presentation.warnings: pdf_series_template_unavailable
cuando era la serie y pdf_inherited_candidate_unavailable para cualquier otro nivel heredado. La
marca se resuelve aparte: el commercial_identity_id propio de la plantilla y, si no tiene, la
identidad por defecto de la empresa. Cómo lee y cambia un documento concreto su selección está en
Presentaciones de documento.
Concurrencia: versiones, ETag e If-Match
Todo recurso mutable de la biblioteca tiene una version, y toda representación que luego puedes
cambiar lleva un ETag fuerte: el SHA-256 de su JSON completo, de modo que también cambia cuando
cambian availability o render_activation. Las mismas reglas valen para plantillas, identidades,
valores por defecto de la empresa y valores por defecto por contacto.
| Operación | Precondición |
|---|---|
PATCH sobre un recurso | If-Match con el ETag, o expected_version en el cuerpo. Al menos una es obligatoria. |
Acciones POST (revisions, duplicate, archive, restore) | expected_version en el cuerpo. If-Match no se acepta como sustituto. |
Si envías las dos en un PATCH, primero se evalúa la etiqueta y después la versión. If-Match
acepta una o varias etiquetas de entidad, las débiles (W/"...") y *.
| Estado | Código | Significado y recuperación |
|---|---|---|
412 | pdf_template_precondition_failed | El ETag no coincide con la representación actual. Vuelve a leer el recurso y reintenta con la etiqueta nueva. |
409 | pdf_template_version_conflict | expected_version es antigua. error.details trae current_version y recovery: reload_or_keep_local: recarga y vuelve a aplicar tu cambio, o conserva tu copia local y decide. |
428 | pdf_template_precondition_required | No enviaste ninguna. Añade If-Match o expected_version. |
409 | pdf_library_impact_conflict | La huella del impacto ha caducado. Vuelve a leer el impacto. |
Un conflicto nunca cambia el recurso, y current_version solo sale del recurso de tu propia
empresa. Las series usan el mismo patrón con sus propios códigos:
series_template_precondition_failed, series_template_version_conflict y
series_template_precondition_required.
Idempotencia
Idempotency-Key es obligatoria en POST /v1/companies/{company}/pdf-templates/assets y opcional, pero
recomendada, en el resto de escrituras de la biblioteca. Una repetición con la misma clave y el
mismo cuerpo devuelve la respuesta guardada con Idempotent-Replayed: true antes de la
comprobación de versión, de modo que un reintento tras un timeout no falla con 409 porque tu
propio primer intento ya avanzó la versión. La autorización se comprueba de nuevo antes de repetir:
si perdiste el rol o el acceso, recibes el error de autorización, no la respuesta guardada. Reutilizar
una clave con otro cuerpo devuelve 422 idempotency_key_reused. Consulta
Idempotencia para la ventana y el formato.
Errores
| Estado | Código | Cuándo |
|---|---|---|
403 | pdf_template_access_denied | El rol, el módulo o una restricción del usuario no lo permiten. |
403 | feature_not_available_in_plan | El cambio necesita el editor avanzado. |
404 | pdf_template_not_found, pdf_commercial_identity_not_found, pdf_template_asset_not_found | No existe o es de otra empresa, con la misma respuesta. |
409 | pdf_template_version_conflict, pdf_library_impact_conflict | Véase concurrencia. |
409 | pdf_template_asset_conflict | El id que elegiste para la subida del activo ya existe. |
409 | resource_conflict | Al crear o duplicar una plantilla, otra petición estaba reservando identificadores en ese momento. No se escribió nada; vuelve a enviarla tras unos segundos. |
412 / 428 | pdf_template_precondition_failed, pdf_template_precondition_required | Véase concurrencia. |
422 | invalid_pdf_template_configuration | Clave desconocida, tipo incorrecto, fuera de rango, filtro no válido, contenido prohibido o render_activation en el cuerpo. param trae la ruta. |
422 | pdf_commercial_identity_required | La plantilla necesita una marca (branding.mode logo o imago) y ni ella ni la empresa tienen una activa por defecto. |
422 | pdf_template_archived, pdf_commercial_identity_unavailable | La plantilla o la marca está archivada o no se puede seleccionar. |
422 | pdf_template_default_replacement_required | Al archivado le falta una decisión para una asociación. |
422 | idempotency_key_required | Falta Idempotency-Key en la subida del activo. |
500 | pdf_library_association_coverage_incomplete | El servidor no pudo inspeccionar todas las asociaciones; no se cambió nada. Reintenta más tarde. |
Ramifica según code, nunca según message. Consulta el modelo de errores.
MCP
La biblioteca tiene una tool MCP por operación: list_pdf_templates, get_pdf_template,
create_pdf_template, update_pdf_template, publish_pdf_template_revision,
duplicate_pdf_template, archive_pdf_template, restore_pdf_template,
get_pdf_template_impact, get_pdf_template_revision, los equivalentes de las marcas sin
duplicación (list_pdf_commercial_identities, get_pdf_commercial_identity,
create_pdf_commercial_identity, update_pdf_commercial_identity,
publish_pdf_commercial_identity_revision, archive_pdf_commercial_identity,
restore_pdf_commercial_identity, get_pdf_commercial_identity_impact y
get_pdf_commercial_identity_revision), get_pdf_template_defaults,
set_pdf_template_defaults, get_pdf_template_contact_default,
set_pdf_template_contact_default, upload_pdf_template_asset y get_pdf_template_asset.
Necesitan los mismos scopes y roles, reciben la versión como expected_version en los argumentos
(en MCP no hay cabeceras) y aceptan idempotency_key. Consulta las tools MCP.