Factuarea APIDevelopers

Vistes prèvies i artefactes PDF

Previsualitza una plantilla abans d’usar-la, prepara i renderitza el PDF exacte d’un document, descarrega’l amb ETag i 304, i llegeix pdf_output_state amb un bucle de reintent correcte.

Tot PDF que l’API genera a partir de la biblioteca de plantilles és un artefacte: un PDF exacte i immutable amb el seu propi identificador, el seu estat i la seva suma de comprovació. Hi ha dos tipus.

purposeQuè ésVida útil
documentEl PDF original d’un document: es genera a partir de la presentació amb què es va capturar el document i els seus bytes no canvien mai.Es conserva amb el document.
previewUn esborrany per comprovar com quedarà una plantilla, una marca o un document. No és mai el PDF oficial de res.Caduca 24 hores després de crear-se (expires_at).

Quatre grups d’operacions cobreixen el flux. La gestió de la biblioteca, els valors per defecte i la precedència són a la guia de la biblioteca de plantilles PDF.

OperacióScopesIdempotency-Key
POST /v1/companies/{company}/pdf-template-previewspdfs:read i pdf_templates:readObligatòria
POST /v1/companies/{company}/pdf-artifacts (preparar)pdfs:readObligatòria
POST /v1/companies/{company}/pdf-artifacts/{artifact}/renderpdfs:readObligatòria
GET /v1/companies/{company}/pdf-artifacts/{artifact} (metadades)pdfs:readNo s’aplica
GET /v1/companies/{company}/pdf-artifacts/{artifact}/downloadpdfs:readNo s’aplica
GET /v1/companies/{company}/invoices/{invoice}/pdf i els seus equivalents de pressupost, proforma i albaràpdfs:readNo s’aplica

Totes les rutes d’aquesta guia pengen de /v1/companies/{company}/…: {company} és l’id (UUID v7) del NIF amb què operes, i als exemples curl és $COMPANY_ID. Arribar a un NIF explica com resoldre’l.

Els artefactes necessiten el rol admin o user i la secció de mòdul de la família del document (invoices, quotes, proformas o delivery_notes). Els artefactes de vista prèvia segueixen a més el mòdul pdf_templates i el scope pdf_templates:read, així que llegir-ne un també exigeix aquest scope. Generar un PDF consumeix el mateix pressupost de renderització que els altres endpoints de PDF: el treball nou pot retornar 429 pdf_generation_budget_exceeded amb Retry-After, mentre que les repeticions i els artefactes ja renderitzats no costen res més (vegeu els límits de peticions).

Previsualitzar una plantilla

POST /v1/companies/{company}/pdf-template-previews genera un PDF sense desar res: no publica cap plantilla, no canvia cap valor per defecte ni toca cap document. El cos té cinc camps obligatoris i un source tancat:

CampValor
document_typeinvoice, quote, proforma o delivery-note.
purposeFactures: complete, simplified, corrective, simplified_corrective. Altres tipus: complete.
formata4, ticket_80 o ticket_58 (tiquets només per a factures).
localees, en o ca.
sourceD’on surten les dades, vegeu a sota.

Segons l’origen, altres tres camps descriuen el disseny que es genera: base_preset, layout_version (sempre "1") i configuration (la configuració normalitzada completa, tal com la retorna una revisió de plantilla).

source.kindDades que generaBloc visual
exampleDades d’exemple: scenario és standard, long, simplified, corrective, simplified_corrective, f3 o unvalued_delivery_note. commercial_identity és opcional: { "mode": "inherit" } (per defecte), { "mode": "exact_revision", "identity_id", "revision_id" } o { "mode": "draft", "configuration": { ... } } amb les sis claus de marca i, opcionalment, logo_dark_asset_id, brand_image_dark_asset_id, dark_background_fallback i brand_size.Els tres, obligatoris.
unsaved_formL’objecte form que envies (sèrie, contacte, document, destinatari, línies, condicions de pagament...), sense desar res.Els tres, obligatoris.
persisted_draftUn esborrany de document existent: { "kind": "persisted_draft", "document_id" }.Els tres o cap.
presentation_revisionUn document emès i la seva presentació retinguda: document_id, parent_id, template_id (null per heretar), source_policy (captured o current_legal) i expected_version. Admet un format diferent del conservat per demanar un altre paper del mateix document emès (tiquet o A4), sense crear revisió.Els tres o cap.
invoice_substitutionUna vista prèvia independent de la factura que substituiria factures simplificades: document_id (null si és nova), source_invoice_uuids i line_uuids (mateixa longitud i ordre, fins a 100), client_uuid, notes, prepared_date i template_id (null per heretar). Només amb document_type: invoice, purpose: complete i format: a4; no es desa ni se substitueix res.Cap: omet els tres.

Quan un origen persistit omet el bloc visual, el servidor previsualitza la plantilla que s’aplicaria avui. Enviar només un o dos dels tres camps és un 422 pdf_presentation_invalid, amb el que falta a param. El selector de marca draft exigeix el rol admin i actius que ja hagis pujat.

Amb document_type: invoice, source.form.document.exemption_reason és una causa d’exempció de capçalera opcional (catàleg a GET /v1/tax-catalog): la seva menció legal obre les mencions automàtiques de la vista prèvia, igual que en desar la factura. Omet-lo o envia null per no fer servir causa. Una causa desconeguda, o enviada en un altre tipus de document, es rebutja.

Una bona manera de previsualitzar un disseny que estàs editant és reutilitzar la revisió que has llegit:

curl -s https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-templates/0199f3a2-7c4e-7b1a-9d3e-5a2c8f1b6e40 \
  -H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
  | jq '{
      document_type: "invoice", purpose: "complete", format: "a4", locale: "en",
      base_preset: .current_revision.base_preset,
      layout_version: .current_revision.layout_version,
      configuration: .current_revision.configuration,
      source: { kind: "example", scenario: "standard" }
    }' > preview.json

curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-template-previews \
  -H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  --data-binary @preview.json

La resposta és l’artefacte, embolcallat a data. És 200 quan el PDF està llest i 202 mentre està prepared, queued o processing; en aquest segon cas consulta metadata_url tal com es descriu al bucle de reintent (abreujat):

{
  "data": {
    "id": "0199f405-91ab-7c42-8d6e-2a9f3b5c7e10",
    "purpose": "preview",
    "state": "ready",
    "source_kind": "example",
    "context_authority": "illustrative",
    "sha256": "7a265f5f003866f84e23c7e237301879b7d4a4ecc0ab80d2041a3c980b12310a",
    "size_bytes": 48210,
    "expires_at": "2026-10-15T09:20:00.000000Z",
    "geometry": { "format": "a4", "orientation": "portrait", "width_mm": 210, "height_mm": 297 },
    "metadata_url": "https://api.factuarea.com/v1/companies/0193f1a0-5c2e-7b41-8d06-9a1e2f3c4d5e/pdf-artifacts/0199f405-91ab-7c42-8d6e-2a9f3b5c7e10",
    "download_url": "https://api.factuarea.com/v1/companies/0193f1a0-5c2e-7b41-8d06-9a1e2f3c4d5e/pdf-artifacts/0199f405-91ab-7c42-8d6e-2a9f3b5c7e10/download",
    "retry_after": null,
    "error": null,
    "unavailable_reason": null
  }
}

L’artefacte també informa d’effective_font i warnings de la renderització, de context_fingerprint, d’artifact_fingerprint i dels tokens que es descriuen a continuació.

Autoritat: què pot autoritzar una vista prèvia

context_authority indica fins on et pots refiar de la vista prèvia.

context_authorityOrigenÚs
illustrativeexample, unsaved_form, o un origen persistit amb un altre bloc visual.Només per mirar. No té document_id, source_token ni selection_version.
delivery_preconditionpersisted_draft previsualitzant la plantilla que s’aplica.Retorna source_token, selection_version, template_revision_id, commercial_identity_revision_id i expected_preview_context_fingerprint: els valors de la precondició de presentació de les operacions d’emetre, enviar i acceptar. Vegeu enviament de documents.
revision_preconditionpresentation_revision.Els mateixos valors, vàlids només per a una revisió explícita d’aquest document. No autoritzen mai emetre, enviar, acceptar ni signar.
substitution_preconditioninvoice_substitution.Retorna els mateixos valors que les altres precondicions, propis de la substitució d'aquesta factura. Cap operació v1 no els consumeix (POST /v1/companies/{company}/invoices/substitute-simplified no rep cap precondició) i mai no autoritzen emetre, enviar, acceptar ni signar.
capturedEls artefactes document originals.El PDF retingut d’un document capturat.

Una vista prèvia no es converteix mai en el PDF oficial. Si després de previsualitzar canvia l’origen, la selecció, la marca, la configuració o l’entorn de renderització, la precondició deixa de coincidir i l’acció respon 409; torna a previsualitzar.

Vistes prèvies i l’interruptor de l’empresa

Les vistes prèvies noves i els artefactes de document nous necessiten que la sortida revisionada estigui activa per a la teva empresa: l’interruptor de la plataforma encès i la inicialització de la teva empresa acabada (el render_activation de només lectura dels valors per defecte ho indica). Si no, la crida retorna 422 pdf_presentation_not_ready i no crea res. No es perd res més: reintentar més tard funciona, i les lectures i la renderització clàssica continuen funcionant.

Preparar, renderitzar i llegir el PDF d’un document

L’artefacte official d’un document es crea a partir de la seva presentació retinguda: l’id del bloc presentation que porta el document (vegeu Presentacions de document), juntament amb el seu tipus de document, propòsit i format de paper.

Preparar. POST /v1/companies/{company}/pdf-artifacts amb document_type, document_id, presentation_id, purpose, format i variant. Crea o troba l’artefacte d’exactament aquesta presentació, així que repetir la crida retorna el mateix.

curl -X POST https://api.factuarea.com/v1/companies/$COMPANY_ID/pdf-artifacts \
  -H "Authorization: Bearer fact_test_3pXnR2VbY7TcA9eFmN5z8KqW" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "document_type": "invoice",
    "document_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a42",
    "presentation_id": "0199f401-33de-7a8c-9e15-b7c4d2a60f38",
    "purpose": "complete",
    "format": "a4",
    "variant": "official"
  }'

Renderitzar. POST /v1/companies/{company}/pdf-artifacts/{artifact}/render amb { "mode": "sync" } per esperar el PDF dins la petició, o { "mode": "async" } per posar-lo a la cua i consultar-lo després. Renderitzar un artefacte ready no torna a renderitzar ni a cobrar.

Llegir l’estat. GET /v1/companies/{company}/pdf-artifacts/{artifact} respon sempre 200 amb les metadades, sigui quin sigui l’estat. Aquestes lectures no admeten query string, cos ni If-Match.

Descarregar. GET /v1/companies/{company}/pdf-artifacts/{artifact}/download retorna els bytes quan l’estat és ready.

prepare i render responen 200 amb l’artefacte quan ja està ready, i 202 mentre està prepared, queued o processing. state és un de prepared, queued, processing, ready, failed, unavailable i corrupt. Un artefacte failed porta error amb el code (pdf_generation_failed, pdf_engine_profile_unavailable, pdf_image_resource_unavailable o pdf_payload_resource_unavailable), un indicador retryable i un correlation_id per donar-lo al suport. retry_after és el nombre de segons que cal esperar mentre és pendent.

PDF originals i derivats

  • La variant official és l’original: el PDF de la presentació capturada amb el document, amb una suma de comprovació immutable. És el que informa pdf_output_state. Canviar després una plantilla, un valor per defecte o una marca no l’altera mai.
  • Un aspecte diferent per a un document ja emès és una presentació nova: revises el document de manera explícita i això crea una presentació derivada amb el seu propi artefacte. L’original continua sent llegible.
  • La variant alternative és un altre artefacte de la mateixa presentació en un format de paper autoritzat. No substitueix mai l’original, no canvia mai el que publica el document i no és el que informa pdf_output_state. Un estil diferent sempre necessita una presentació nova.
  • Si els bytes d’un original es perden o no superen la seva suma de comprovació, reps 500 pdf_original_unavailable o 500 pdf_original_corrupt. Res no es regenera en silenci al seu lloc.
  • Una presentació derivada (una signatura, el QR legal o les dades legals actualitzades) conserva el disseny del seu original. Si la versió actual ja no serveix aquest disseny, preparar-la respon 500 pdf_original_layout_unavailable: l’original és íntegre i no es prepara res. Contacta amb el suport; una revisió explícita i autoritzada crea un altre artefacte sense substituir l’original.

Com responen les descàrregues

EstatQuanQuè fer
200El PDF està llest. application/pdf, Content-Disposition: attachment, Cache-Control: private, no-store i un ETag fort: el SHA-256 dels bytes entre cometes.Desa’l; conserva l’ETag.
304Has enviat If-None-Match amb l’ETag actual. Es decideix després de l’autorització, la privacitat i una comprovació dels bytes desats.Fes servir la teva còpia.
202Només GET /v1/companies/{company}/{documents}/{id}/pdf: el PDF encara s’està generant, també quan una renderització ha fallat però es pot reintentar i aquesta petició l’ha tornat a reclamar (una fallada reintentable no es respon mai amb l’error anterior). JSON data amb pdf_url i pdf_output_state, i una capçalera Retry-After.Espera i repeteix la mateixa petició.
503GET .../download d’un artefacte que no està llest: pdf_artifact_not_ready amb Retry-After. Les metadades continuen responent 200. El mateix 503 arriba d’una vista prèvia, de prepare, de render, de GET /v1/companies/{company}/{documents}/{id}/pdf o de GET /v1/companies/{company}/invoices/{invoice}/pdf-link mentre una altra petició encara prepara aquest mateix PDF; aquesta petició no ha creat res.Espera Retry-After segons i repeteix la mateixa petició.
503pdf_generation_failed: els endpoints directes del document no han pogut produir el PDF; el document i les seves dades continuen intactes.Espera i repeteix la mateixa petició.
410pdf_signature_personal_data_forgotten: s’han esborrat les dades de la signatura del document. Terminal.No reintentis; l’artefacte ja no té descàrrega.
404pdf_artifact_not_found: desconegut, d’una altra empresa o una vista prèvia caducada.Crea una vista prèvia nova.
500pdf_original_unavailable, pdf_original_corrupt, pdf_original_layout_unavailable o una renderització que ha fallat de manera definitiva: pdf_engine_profile_unavailable, pdf_payload_resource_unavailable, pdf_image_resource_unavailable. No s’encua res.Contacta amb el suport amb el request_id.

GET /v1/companies/{company}/invoices/{invoice}/pdf, GET /v1/companies/{company}/quotes/{quote}/pdf, GET /v1/companies/{company}/proformas/{proforma}/pdf i GET /v1/companies/{company}/delivery-notes/{delivery_note}/pdf, a nivell de document, retornen el mateix 200 amb els bytes, el 304 amb If-None-Match i el 202 anterior. Accepten download=1 per a una disposició d’adjunt, i les factures també format. Consulta la referència de factures, pressupostos, factures proforma i albarans. Quan l’original no es pot servir responen amb un error en lloc d’un 202: s’apliquen els estats anteriors, més 409 quan la presentació retinguda no es pot lliurar com es demana: pdf_presentation_conflict (ha canviat des que la vas llegir), pdf_presentation_context_changed (per exemple, el format sol·licitat no coincideix amb el retingut) i, en factures, pdf_legal_source_changed (revisa-la amb source_policy: "current_legal"). Torna a llegir la presentació del document abans de demanar el PDF. Mentre un document no té presentació retinguda, o la teva empresa continua renderitzant amb el flux clàssic, el PDF es serveix com abans.

El bloc pdf_output_state

Les factures, els pressupostos, les factures proforma i els albarans porten un objecte pdf_output_state de només lectura que resumeix el seu PDF original. No prepara ni renderitza mai res.

{
  "state": "processing",
  "presentation_id": "0199f401-33de-7a8c-9e15-b7c4d2a60f38",
  "artifact_id": "0199f405-91ab-7c42-8d6e-2a9f3b5c7e10",
  "format": "a4",
  "variant": "official",
  "unavailable_reason": null,
  "error": null,
  "retry_after": 1,
  "download_url": null
}
CampSignificat
stateprepared, queued i processing (pendent), ready, failed, unavailable, corrupt, o null quan el document encara no té un original capturat.
presentation_id, artifact_idLa presentació retinguda i el seu artefacte original; artifact_id és el que passes a /v1/companies/{company}/pdf-artifacts/{artifact}.
format, variantFormat de paper i official.
unavailable_reasonprivacy_erased (estat unavailable, l’original s’ha perdut per sempre) o original_corrupt (estat corrupt).
error{ code, retryable, correlation_id } per a failed, corrupt i originals esborrats.
retry_afterSegons que cal esperar mentre és pendent; en un altre cas null.
download_urlNomés quan està ready: la URL v1 relativa /v1/companies/{company}/pdf-artifacts/{id}/download, mai una ruta d’emmagatzematge. Resol-la contra el host de l’API o construeix la crida a partir d’artifact_id.

Totes les claus hi són sempre; un document sense original capturat les té totes a null. Un esborrat per privacitat es mostra com a state: unavailable amb error.code: pdf_signature_personal_data_forgotten, sense retry_after i sense download_url.

Un bucle de reintent correcte

Consulta la lectura barata, espera el que demana el servidor, limita els intents i para davant les respostes terminals. No regeneris per “anar més de pressa”.

async function downloadOriginal(companyId, artifactId, key) {
  const base = 'https://api.factuarea.com/v1/companies/' + companyId + '/pdf-artifacts/' + artifactId;
  const headers = { Authorization: 'Bearer ' + key };

  for (let attempt = 1; attempt <= 12; attempt++) {
    const res = await fetch(base + '/download', { headers });

    if (res.status === 200) return Buffer.from(await res.arrayBuffer());
    if (res.status === 503) {
      const wait = Number(res.headers.get('Retry-After')) || 2 * attempt;
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }
    const { error } = await res.json();
    // 410 is terminal, 500 needs support, 404 means it expired or never existed.
    throw new Error(error.code + ' (' + res.status + ') ' + error.request_id);
  }
  throw new Error('The PDF is still not ready; check the artifact metadata later.');
}
  • Respecta Retry-After i el camp retry_after. Són segons. Afegeix un petit increment entre intents i un topall al nombre d’intents.
  • Consulta, no tornis a crear. Repeteix el mateix GET. Cridar prepare o render a cada consulta només hi afegeix soroll: ja retornen el mateix artefacte.
  • Reintenta un error a consciència. Quan state és failed i error.retryable és true, torna a cridar render amb una Idempotency-Key nova (la mateixa clau repetiria l’error desat). Si retryable és false, canvia abans la causa: l’actiu, la quantitat de dades o la configuració.
  • Una clau nova és una intenció nova. Reutilitza la mateixa clau només per reintentar la mateixa petició després d’un timeout.
  • Para davant un 410. No canviarà.
  • Fes servir memòria cau amb l’ETag. Envia If-None-Match per obtenir un 304 gratuït.

Idempotència

preview, prepare i render necessiten Idempotency-Key. En aquestes tres l’empremta es calcula sobre el cos cru, així que la mateixa clau amb un cos que difereix en un sol byte (també l’ordre de les claus o els espais) retorna 422 idempotency_key_reused. Una repetició retorna la resposta desada, amb Idempotent-Replayed: true, abans de fer cap feina i encara que les dades vives hagin canviat des d’aleshores; l’autorització de qui crida es comprova abans. Dues claus amb cossos equivalents porten al mateix artefacte. Consulta Idempotència.

Errors

EstatCodiSignificat
403pdf_template_access_deniedEl rol no està permès, o la secció de mòdul del tipus de document no està disponible per a tu.
404pdf_artifact_not_found, pdf_presentation_not_foundNo existeix, és d’una altra empresa o ha caducat.
409pdf_presentation_conflict, pdf_presentation_context_changedHa canviat la selecció, l’origen, la marca o l’entorn després de la vista prèvia. Torna a previsualitzar.
409pdf_legal_source_changedLes dades legals d’una factura emesa han canviat des que es va capturar; l’original continua sent llegible i el lliurament nou queda bloquejat fins que la revisis de manera explícita.
412 / 428pdf_presentation_etag_mismatch, pdf_presentation_precondition_requiredPrecondicions de presentació a les operacions que les fan servir.
410pdf_signature_personal_data_forgottenEsborrat terminal.
422pdf_presentation_invalidUn camp no és vàlid. param porta la ruta, com source.kind.
422pdf_presentation_not_readyLa sortida revisionada encara no està activa per a la teva empresa.
422idempotency_key_requiredFalta la clau.
429pdf_generation_budget_exceededPressupost de renderització; espera Retry-After.
500pdf_original_unavailable, pdf_original_corrupt, pdf_original_layout_unavailable, pdf_engine_profile_unavailable, pdf_image_resource_unavailable, pdf_payload_resource_unavailableL’original, el seu disseny o els recursos de renderització no estan disponibles. Els dos últims no es poden reintentar.
503pdf_artifact_not_readyEncara no està llest; espera Retry-After.
503pdf_generation_failedEls endpoints directes del PDF del document no l’han pogut produir. El document està intacte; repeteix més tard.

Ramifica segons code, no segons message. Consulta el model d’errors.

MCP

Les cinc operacions d’artefacte són les tools preview_pdf_template, prepare_pdf_artifact, render_pdf_artifact, get_pdf_artifact i read_pdf_artifact, que retorna un enllaç de descàrrega autoritzat en lloc dels bytes. Fan servir els mateixos scopes, accepten idempotency_key i segueixen els mateixos estats. Consulta les tools MCP.

En aquesta pàgina

Et donem un cop de mà?Contactar amb suport