DoConure

Gestire i template da uno script

Tutto quello che fa la pagina Templates della console è anche una chiamata dell'API, tranne la rinomina, così un'integrazione può configurarsi da sola — caricare un template, portare avanti una nuova versione, attivarla — senza che nessuno apra la console. Un template si rinomina in console (la pagina del template, Name): cambia solo il nome che le persone leggono, il templateId che il tuo codice chiama resta lo stesso. Il file viaggia in base64 dentro il corpo JSON, la stessa forma di ogni altro endpoint, invece che in multipart: più comodo per chiamanti come Salesforce Apex, che con il multipart non hanno vita facile.

MetodoPercorsoCosa fa
POST/api/v1/compose/templatesCrea un template e la versione 1, attiva subito.
GET/api/v1/compose/templatesElenca i template di questa organizzazione.
GET/api/v1/compose/templates/{templateId}Un template, con ogni versione.
POST/api/v1/compose/templates/{templateId}/versionsAggiunge una versione. Arriva inattiva — la stessa regola della console.
POST/api/v1/compose/templates/{templateId}/versions/{n}/activateAttiva la versione n. Le altre restano come sono.
POST/api/v1/compose/templates/{templateId}/versions/{n}/deactivateSpegne la versione n; le altre continuano a funzionare.
POST/api/v1/compose/templates/{templateId}/deactivateSpegne tutto il template, con ogni sua versione.
POST /api/v1/compose/templates
{
  "name": "Invoice",
  "templateType": "docx",
  "fileName": "invoice.docx",
  "fileBase64": "UEsDBBQAAAAIA...",
  "errorOnMissingFields": false
}

Ognuna di queste chiamate risponde con lo stato attuale completo del template:

{
  "templateId": "invoice-a1b2c3",
  "name": "Invoice",
  "templateType": "docx",
  "active": true,
  "errorOnMissingFields": false,
  "payloadValidation": "warn",
  "activeVersions": [1],
  "versions": [
    { "versionNumber": 1, "active": true,
      "originalFilename": "invoice.docx",
      "checksum": "9f8c...", "createdAt": "2026-09-14T10:00:00+00:00",
      "hasJsonSchema": false }
  ]
}

Controllato al caricamento, non alla prima generazione. Questi endpoint controllano il file subito — lo stesso controllo che fa la console quando vi si carica un file — e rispondono TEMPLATE_FILE_REJECTED o TEMPLATE_FILE_INVALID nella chiamata di caricamento stessa: un'integrazione che gira da sola non ha una pagina su cui accorgersi del problema più tardi.

templateType si fissa alla creazione (docx, html o xlsx); ogni versione successiva di quel template deve avere lo stesso formato. Gli id dei template li assegna il servizio, con lo stesso schema slug più suffisso dell'admin: non provare a sceglierne uno.

Controllare i dati: JSON Schema

Una versione può portare uno jsonSchema (nel caricamento qui sopra, su una nuova versione, o incollato in console). Ogni chiamata di composizione che usa quella versione misura il suo data rispetto allo schema. Cosa succede a una violazione lo decide il payloadValidation del template:

ModalitàCosa succede
warn (predefinita)Il documento viene prodotto e addebitato come sempre. output.warnings porta PAYLOAD_SCHEMA_VIOLATIONS (2106) con le prime 20 violazioni.
rejectLa chiamata è rifiutata con PAYLOAD_SCHEMA_VIOLATION (1403, 422) prima di prendere credito, elementi di prova o posti di rendering: non costa nulla e non viene mai registrata come risultato di una Idempotency-Key. In un batch bulk l'elemento fallisce con quel codice e non si paga; gli altri proseguono. In un flusso non si compone e non si invia nulla.
offLo schema è ignorato.

Imposta la modalità con payloadValidation quando crei il template, o su una nuova versione insieme al suo schema, così un job di CI può pubblicare entrambi in una chiamata e passare a reject:

POST /api/v1/compose/templates/{templateId}/versions
{
  "fileName": "invoice.docx",
  "fileBase64": "UEsDBBQAAAAIA...",
  "jsonSchema": {
    "type": "object",
    "required": ["cliente"],
    "properties": {
      "cliente": { "type": "string", "maxLength": 40 },
      "importo": { "type": "number", "minimum": 0 }
    },
    "additionalProperties": false
  },
  "payloadValidation": "reject"
}

Una violazione è {path, keyword, message}: path è un JSON pointer dentro il tuo data (/righe/1/qta; vuoto vuol dire tutto il payload), keyword la parola chiave dello schema che non è stata rispettata, message una frase fatta con le parole dello schema stesso e il tipo trovato. Il valore che hai inviato non c'è mai, così l'avviso è lo stesso per un'organizzazione dataless. Anche il nome di una chiave che viene dai tuoi dati (sotto additionalProperties) lì è nascosto.

Lo schema è input del cliente ed è trattato come un template: è codice. Il servizio applica un sottoinsieme limitato della draft 2020-12 e rifiuta il resto al caricamento con JSON_SCHEMA_INVALID (1303), così uno schema o fa quello che dice o non viene accettato.

  • Supportati: type, enum, const, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minLength, maxLength, pattern, minItems, maxItems, uniqueItems, items (un solo schema), required, properties, additionalProperties, minProperties, maxProperties, allOf, anyOf, oneOf, not, e $ref verso # o #/$defs/name.
  • Accettati e ignorati: $schema, $id, $comment, title, description, default, examples, deprecated, readOnly, writeOnly e format (mai verificato).
  • Rifiutati: tutto il resto (patternProperties, prefixItems, if/then/else, dependentRequired, unevaluated*), e ogni $ref che non sia locale: non si scarica mai nulla.
  • Limiti: 64 KB di schema, 24 livelli, 1.000 sotto-schemi, 500 valori di enum; un pattern di al massimo 128 caratteri, senza riferimenti all'indietro né look-around, senza gruppi ripetuti che a loro volta si ripetono, al massimo due ripetizioni illimitate, e una stringa oltre i 2.048 caratteri non viene confrontata con un pattern. Il controllo ha un budget di passi e di tempo; se si esaurisce la risposta è una violazione con keyword $budget, mai "valido".

Ritentare un caricamento

Ogni POST di questa pagina accetta l'header Idempotency-Key, e nessuna ti addebita nulla. Non è quello il motivo per mandarlo. Un caricamento andato in timeout e ritentato senza chiave ti lascia con due template con lo stesso nome e due id, e la tua integrazione punta poi a quello tornato per ultimo mentre qualcuno in console sceglie l'altro.

POST /api/v1/compose/templates
Authorization: Bearer lpdc_…
Idempotency-Key: invoice-template-v3

Le regole sono quelle di comporre un documento, invariate: la stessa chiave con lo stesso corpo ripete la prima risposta con Idempotent-Replay: true, la stessa chiave con un corpo diverso è rifiutata, e un tentativo fallito non viene mai registrato, così il successivo gira davvero.