Demo gratuita Inizia gratis

API reference

Reference API completa.

Gli endpoint, i payload e i codici di errore che ti servono per integrare DataPDFEngine.

Base URL https://api.datapdfengine.com/api/v1

Autenticazione

Tutte le richieste si autenticano con una API key Bearer. Le chiavi appartengono a una singola organizzazione, sono mostrate in chiaro una sola volta, alla creazione, e si possono revocare in qualsiasi momento: la richiesta successiva con una chiave revocata restituisce 401. L'accesso API richiede un piano con la REST API (da Pro in su).

I token sono `pdf_` seguito da 40 caratteri. La dashboard ne mostra solo un breve prefisso, per distinguere le chiavi.

Authorization: Bearer pdf_X8s3...e2Qa
  • ›Solo lato server — mai includere una API key in un bundle browser o in un binario mobile.
  • ›Le chiavi si creano dalla dashboard; il token viene mostrato solo in quel momento. L'ultimo utilizzo è registrato (al massimo una volta al minuto) e visibile lì.
  • ›Revochi una chiave dalla dashboard o con `DELETE /api-keys/{id}/`; effetto dalla richiesta successiva.
  • ›Dopo 20 chiavi non valide in un minuto dallo stesso indirizzo IP, ogni richiesta con una chiave da quell'indirizzo riceve `429 throttled` fino alla fine del minuto, anche con una chiave valida.
Templates

Templates — il PDF che il motore compila

Un template è il tuo PDF sorgente più i campi (le label dell'API: rettangoli con nome e coordinate) che indicano dove disegnare i valori. I campi si disegnano nell'editor visuale o si inviano con `POST /labels/bulk-upsert/`; `POST /templates/{id}/detect-fields/` legge il PDF e te li propone, senza salvare nulla.

GET /templates/

Elenca i template della tua organizzazione.

Paginazione a cursore, 25 per pagina (`page_size` fino a 200), dai più recenti. `?search=` cerca in nome e descrizione.

POST /templates/ multipart/form-data

Carica un nuovo PDF come template.

Fields

  • name string · obbligatorio Nome mostrato in dashboard.
  • description string · opzionale Nota interna per il tuo team.
  • file file · obbligatorio File PDF, fino a 25 MB e 200 pagine.

Le anteprime delle pagine vengono generate in background. `previews_ready` passa a `true` quando sono pronte.

GET /templates/{id}/

Recupera un template con le sue label e le anteprime delle pagine.

POST /templates/{id}/detect-fields/

Propone i campi che il PDF sembra chiedere, senza salvarli.

Legge i campi modulo che il PDF ha già, le caselle, le celle e le righe che disegna, e i tratteggi come `Nome ______`. Restituisce `{ fields, pages, complete }`: ogni campo ha `page`, `x`, `y`, `width`, `height`, `field_type`, `layout`, `box_count`, `line_count`, `font_size`, `description` e `source`. Tieni quelli giusti e salvali con `bulk-upsert`. `complete` è `false` se la lettura si è fermata prima dell'ultima pagina. Al massimo 30 chiamate l'ora.

DELETE /templates/{id}/

Elimina il template e i suoi file.

Rifiutato con `409 template_in_use` finché compilazioni, batch o link share lo usano.

POST /labels/bulk-upsert/ application/json

Sostituisce in una chiamata i campi, le sezioni e i firmatari di un template, e gli allegati e i consensi richiesti quando li invii.

Fields

  • template uuid · obbligatorio Template da aggiornare.
  • labels array · obbligatorio L'insieme completo dei campi: nome, titolo (`description`), testo di aiuto (`help_text`, fino a 500 caratteri, mostrato sotto il campo), tipo di campo, pagina (da 0), coordinate (`x`, `y`, `width`, `height` come frazioni della pagina, da 0 a 1, dall'angolo in alto a sinistra), `form_order` (posizione nell'ordine di compilazione della sua sezione, da 1; 0 segue la pagina) e, solo per i campi di testo, un `format` (`email`, `phone`, `codice_fiscale`, `partita_iva`, `iban`, `cap`) oppure `options`, l'elenco da cui si sceglie il valore (fino a 50 opzioni di 100 caratteri al massimo, senza doppioni). I campi non inclusi vengono eliminati.
  • groups array · opzionale Sezioni del modulo: `name`, `title`, `description`, `order`, `before_ungrouped` (si compila prima dei campi senza sezione), una condizione opzionale su una casella (`show_if`, `show_if_checked`) e `min_checked` / `max_checked`, quante sue caselle si possono spuntare insieme (0 = nessun limite: `max_checked` 1 rende la scelta singola). Se omesso, le sezioni attuali vengono eliminate.
  • signers array · opzionale Chi firma i documenti del template: `name`, `title`, `order` (l'ordine di firma). Ogni campo firma indica poi il suo firmatario in `signer_role`. Se omesso, i firmatari attuali vengono eliminati.
  • attachments array · opzionale Gli allegati da chiedere: `name`, `title`, `description`, `required`, `formats` (`pdf`, `jpg`, `png`, `heic`), `max_size_mb` (fino a 10), `signer_role` (il firmatario che lo carica) e `order`. Se omesso, restano quelli attuali.
  • consents array · opzionale I consensi da chiedere fuori dal PDF: `name`, `text` (fino a 1.000 caratteri), `required`, `document` (id di un documento caricato con `consent-documents`), `signer_role` (vuoto = ogni firmatario) e `order`. Se omesso, restano quelli attuali.

Gli allegati obbligatori o assegnati a un firmatario richiedono Pro o superiore; il numero di allegati per firmatario dipende dal piano (3 su Starter, 10 da Pro).

POST /templates/{id}/consent-documents/ multipart/form-data

Carica il PDF a cui un consenso rimanda, per esempio le condizioni generali.

Fields

  • file file · obbligatorio PDF fino a 10 MB.

Il documento non si modifica più: una nuova versione è un nuovo documento, con la sua impronta. Restituisce `id`, `file_name`, `size`, `sha256`.

Compilations

Compilations — un singolo PDF renderizzato

Invii una mappa di valori per un template e ricevi il PDF finito nella stessa richiesta: la risposta porta `status: done` e un `download_url` firmato. Se il motore fallisce per un altro motivo, `status` è `failed` con un messaggio in `error`, e non viene consumata quota.

POST /compilations/ application/json

Crea una compilazione e la renderizza.

Fields

  • template uuid · obbligatorio Template da renderizzare.
  • name string · opzionale Nome leggibile, fino a 200 caratteri.
  • values object · obbligatorio Mappa `label_name → valore`. Accetta stringhe, numeri, booleani e null — coercion server-side per tipo di campo. Un campo con `format` o `options` accetta solo un valore di quel formato o dell'elenco, altrimenti `400 invalid` con l'errore sotto il suo nome in `extra.fields`; codice fiscale, partita IVA e IBAN si salvano senza spazi e in maiuscolo.
  • store_values bool · default true Se false, i valori vengono cancellati appena il PDF è prodotto.

Request body

{
  "template": "3f0e4b2a-21c2-4d34-9c8d-9b0a5d6b3f11",
  "name": "NDA — Acme S.r.l.",
  "values": {
    "nome_completo": "Giulia Rossi",
    "data_efficacia": "2026-06-01",
    "accetta_condizioni": true
  }
}

Response

HTTP/1.1 201 Created
{
  "id": "c2a1...e9",
  "name": "NDA — Acme S.r.l.",
  "template": "3f0e4b2a-21c2-4d34-9c8d-9b0a5d6b3f11",
  "values": { "nome_completo": "Giulia Rossi", "data_efficacia": "2026-06-01", "accetta_condizioni": true },
  "store_values": true,
  "status": "done",
  "download_url": "https://…",
  "output_sha256": "9b1c…4e",
  "is_signed": false,
  "signature_request": null,
  "attachments_count": 0,
  "consents_count": 0,
  "error": "",
  "expires_at": null,
  "created_at": "2026-09-30T10:13:51Z",
  "updated_at": "2026-09-30T10:13:52Z"
}

Status: `done`, `failed`, `pending` (solo mentre viene renderizzato l'invio di un link share) ed `expired` quando la retention ha cancellato il PDF. `download_url` è un link pre-firmato valido fino a 30 minuti: se ti serve dopo, prendine uno nuovo con `GET`. `GET` riporta anche `expires_at`, quando la retention cancellerà il PDF (`null` se non succede mai). `signature_request` è `{ id, status, signed, total }` per un documento inviato a più firmatari. I valori che non si possono stampare nel loro campo restituiscono `400` con codice `unprintable` o `does_not_fit`.

GET /compilations/

Elenca le compilazioni.

Filtri: `?status=`, `?template=`, `?search=` (nome), `?expiring=1` (PDF che la retention cancella entro 14 giorni).

GET /compilations/{id}/

Recupera una compilazione, con un `download_url` nuovo.

PATCH /compilations/{id}/

Ri-renderizza con nuovi valori, o rinomina la compilazione.

Inviare `values` ri-renderizza dentro la richiesta, restituisce `200` e consuma un PDF di quota. Inviare solo `name` è gratuito. `store_values` può accompagnare l'uno o l'altro; se omesso, la scelta attuale resta. Una compilazione firmata non si può modificare (`409 signed`), e nemmeno una con consensi (`409 has_consents`).

POST /compilations/preview/ application/json

Renderizza un'anteprima PNG di una pagina con i tuoi valori, senza consumare quota.

Fields

  • template uuid · obbligatorio Template da mostrare.
  • page int · obbligatorio Numero di pagina, a partire da 0.
  • values object · obbligatorio Valori da disegnare, anche parziali.
  • dpi int 60–220 · default 110 Risoluzione dell'immagine.
DELETE /compilations/{id}/

Elimina definitivamente la compilazione, il PDF renderizzato e i suoi allegati.

Una compilazione firmata, o con consensi, non si può eliminare con una API key: `403 admin_required`. La elimina il titolare o un amministratore dalla dashboard, confermando con `confirm=ELIMINA` (altrimenti `400 confirmation_required`). Di un documento firmato restano le impronte, il nome di chi l'ha emesso e le date, così la pagina di verifica lo indica come firmato e poi eliminato.

Batches

Batches — migliaia di PDF in una sola chiamata

Due entry point: `/batches/json/` per le righe nel body della richiesta, `/batches/upload/` per un file CSV o XLSX. Il batch gira in background: la chiamata risponde subito `202`, e alla fine ottieni un unico `result.zip` con un PDF per riga (le righe fallite compaiono come file `.error.txt`). I batch richiedono un piano con l'elaborazione massiva (da Pro in su).

POST /batches/json/ application/json

Invia fino a 5.000 righe di valori inline.

Fields

  • template uuid · obbligatorio Template di riferimento.
  • rows array · obbligatorio 1–5.000 oggetti `label_name → valore`. Una chiave `__filename` dà il nome a ogni PDF nello zip.
  • completion_webhook_endpoint uuid · opzionale Endpoint salvato da notificare al completamento.
  • completion_webhook_url url · opzionale URL webhook usa e getta. La risposta contiene il suo `completion_webhook_secret`, mostrato una sola volta.
  • store_source bool · default true Se false, le righe inviate vengono cancellate a batch concluso; lo zip resta.

Response

HTTP/1.1 202 Accepted
{
  "id": "b1f2...77",
  "source": "json",
  "status": "pending",
  "total": 0,
  "expected_total": 2,
  "succeeded": 0,
  "failed": 0
}

Precedenza webhook: endpoint salvato → URL inline → endpoint di default dell'org. Senza configurazione, il batch parte comunque senza notifica.

POST /batches/upload/ multipart/form-data

Invia un file CSV o XLSX (fino a 20 MB).

Fields

  • template uuid · obbligatorio Template di riferimento.
  • file file · obbligatorio .csv o .xlsx, ≤ 20 MB.
  • sheet string · opzionale Foglio XLSX da leggere.
  • column_mapping JSON string · opzionale Mappa `label_name → nome colonna`. Le colonne che si chiamano come una label vengono abbinate da sole.
  • store_source bool · default true Se false, il file caricato viene cancellato a batch concluso; lo zip resta.
GET /batches/{id}/

Polling su un batch.

Status: `pending → running → done | failed`, poi `expired` dopo la retention. A `done`, `succeeded + failed` sono pari a `expected_total` e `download_url` punta allo zip. Un batch che fallisce per intero finisce `failed`, senza zip.

Share requests

Share requests — fai compilare al destinatario

Genera un link protetto da token verso un form hostato. Il destinatario lo apre da qualsiasi dispositivo, opzionalmente verifica l'email con un codice, compila e invia. Se il template chiede allegati, li carica dallo stesso form. Se ha campi firma, rivede il PDF renderizzato e lo firma prima di inviarlo. Un link arriva a una persona sola: un template con più firmatari viene rifiutato (`400 several_signers`), invialo con una richiesta di firma. Via API i link share richiedono Pro o superiore; dalla dashboard i link singoli sono inclusi da Starter.

POST /share-requests/ application/json

Crea una share request singola.

Fields

  • template uuid · obbligatorio Template da esporre.
  • recipient_email email · opzionale Se valorizzato, consegniamo il link via email. Obbligatorio con `verify_email` e quando il template chiede un consenso obbligatorio (`400 recipient_required`).
  • verify_email bool · default false Blocca l'invio dietro a un codice via email. Sempre attivo se il template chiede un consenso obbligatorio.
  • require_review bool · default false Mostra il PDF renderizzato da rivedere prima dell'invio. Sempre attivo se il template ha campi firma.
  • signature_otp bool · default true Conferma la firma con un codice inviato via email.
  • send_copy_to_recipient bool · default false Invia per email il PDF finale al destinatario; su un link senza destinatario, all'indirizzo verificato con il codice di firma.
  • notify_sender_on_complete bool · default false Ti mandiamo una email quando il destinatario invia.
  • prefill_values object · opzionale Valori che già conosci.
  • expires_in_days int 1–90 · default 7 Durata del link.
  • invitation_language string · opzionale Lingua dell'email di invito, es. `it` o `en`.
  • reminders bool · default false Promemoria automatici al destinatario. Serve `recipient_email`: senza, `reminders_enabled` torna false.

Promemoria automatici (`reminders: true`): lo stesso link, con lo stesso token, al massimo due volte per destinatario. Il primo parte 3 giorni dopo l'invito, se mancano più di 24 ore alla scadenza; l'ultimo nelle 24 ore prima della scadenza, saltato se quella persona ha ricevuto un messaggio nelle 24 ore precedenti. Partono solo dal lunedì al sabato, 09:00–18:59 ora italiana, e mai dopo che il link è stato completato, revocato o è scaduto. Ogni link riporta `reminders_enabled`, `reminder_count` (promemoria automatici inviati), `last_reminded_at` (l'ultimo messaggio dopo l'invito, automatico o reinviato da te), `resend_count` e `first_opened_at`, la prima volta che il destinatario ha aperto il link.

POST /share-requests/bulk/ application/json

Crea un batch di link da una lista di destinatari.

Fields

  • template uuid · obbligatorio Template condiviso.
  • name string · obbligatorio Nome del batch, 2–200 caratteri.
  • requests array · obbligatorio Un oggetto per destinatario: `email` (obbligatorio), `verify_email`, `send_copy`, `notify_sender`, `prefill`.
  • expires_in_days int 1–90 · default 7 Applicato a ogni link del batch.
  • invitation_language string · opzionale Lingua di tutti gli inviti.
  • reminders bool · default false Promemoria automatici a ogni destinatario del batch.

Le righe con un'email non valida vengono saltate e contate in `failed`.

POST /share-requests/bulk-upload/ multipart/form-data

Crea un batch di link da un file.

Fields

  • template uuid · obbligatorio Template condiviso.
  • name string · obbligatorio Nome del batch.
  • file file · obbligatorio .csv, .xlsx o .json, fino a 20 MB e 5.000 righe. Colonne: `email`, opzionali `verify_email` e `send_copy`; ogni colonna che si chiama come una label la precompila.
  • expires_in_days int 1–90 · default 7 Applicato a ogni link.
  • reminders bool · default false Promemoria automatici a ogni destinatario: `true` o `1` li attiva.
GET /share-requests/

Elenca le share request.

Filtri: `?status=pending|completed|expired|revoked`, `?batch=`, `?q=` (email del destinatario). Senza `?batch=` tornano solo i link creati uno per uno; quelli di un batch con `?batch=<id>`. I link completati riportano la `compilation` e il suo `compilation_download_url`. Per sapere cosa seguire: `?expiring_within=N` restituisce i link ancora aperti che scadono entro N giorni, `?expired_within=N` quelli scaduti senza risposta negli ultimi N giorni (completati e revocati esclusi); N da 1 a 90, altrimenti `400`. Senza `?batch=` questi due comprendono anche i link dei batch.

GET /share-requests/batches/

Elenca i batch di link.

Filtri: `?q=` (nome del batch o del template), `?status=open|done`. Ogni batch riporta `id`, `name`, `source`, `template`, `template_name`, `total`, `sent`, `completed`, `failed` e `created_at`; `GET /share-requests/batches/{id}/` ne legge uno, con `open_links` (link ancora aperti), `open_with_recipient` (quelli con un destinatario) e `remindable_links` (quelli che un promemoria raggiunge adesso), che nella lista restano `null`.

POST /share-requests/batches/{id}/remind/

Invia di nuovo l'invito a ogni destinatario di un batch che non ha ancora risposto.

Nessun body. Ogni link aperto con un destinatario riceve di nuovo lo stesso link, con le regole di `resend`: una volta ogni 24 ore (contando anche i promemoria automatici) e al massimo 5 volte per link. Risponde `200` con `{"sent": n, "skipped": n, "reasons": {"no_recipient": n, "cooldown": n, "limit": n}}`. I link completati, revocati o scaduti restano esclusi. Stessi permessi degli altri endpoint dei batch.

POST /share-requests/batches/{id}/revoke-pending/

Revoca tutti i link di un batch ancora aperti.

Nessun body. Risponde `200` con `{"revoked": n}`; con i link smettono di funzionare anche i loro codici e le bozze di firma. I link completati, scaduti o già revocati restano come sono.

GET /share-requests/batches/{id}/export/

Scarica i link di un batch in CSV.

UTF-8 con BOM e `;` come separatore, così Excel lo apre in colonne; date in ora italiana. Colonne: destinatario (chi ha firmato, se noto), email, stato, invito inviato, prima apertura, completamento, scadenza, promemoria inviati (automatici e a mano). Le celle che iniziano con `=`, `+`, `-`, `@`, una tabulazione o un ritorno a capo sono precedute da `'`, così nessun foglio di calcolo le esegue come formule. Le intestazioni seguono `Accept-Language`.

POST /share-requests/{id}/revoke/

Revoca un link: smette di funzionare subito.

POST /share-requests/{id}/recreate/

Emette un nuovo link con le stesse impostazioni e invia un nuovo invito.

POST /share-requests/{id}/resend/

Reinvia l'invito, con lo stesso link.

Senza corpo. Restituisce `200` con il link. `409 not_pending` se il link non è più aperto, `409 no_recipient` se non ha un destinatario. `429 resend_cooldown` entro 24 ore dall'ultimo messaggio a quella persona (promemoria o reinvio), con `Retry-After`, oppure dopo 5 reinvii in tutto.

POST /share-requests/{id}/extend/ application/json

Proroga la scadenza di un link aperto.

Fields

  • days int 1–90 · obbligatorio Giorni aggiunti alla scadenza attuale.

Restituisce `200` con il link aggiornato; `400` se `days` non è valido. `409 not_open` se il link è completato, revocato o scaduto: uno scaduto si emette di nuovo con `recreate`. Dopo una proroga l'ultimo promemoria può ripartire prima della nuova scadenza. Stessi permessi della revoca.

Firma

Firma — fai firmare un documento via API

Una bozza di firma è il PDF compilato, congelato: chi firma rivede esattamente quei byte e le firme vengono apposte su di essi. La firma si completa sul dispositivo del firmatario, con un link che gli mandi, oppure la raccoglie la tua integrazione e la invia con la sua API key. In entrambi i casi il PDF firmato si chiude con una pagina di registro, e il registro riporta la API key usata. Firma elettronica semplice (FES) ai sensi dell'art. 3 del regolamento eIDAS.

POST /signing-drafts/ application/json

Compila e congela il documento da firmare.

Fields

  • template uuid · obbligatorio Un template con campi firma.
  • values object · obbligatorio Mappa `label_name → valore`, come per una compilazione.
  • name string · opzionale Nome della compilazione risultante.
  • compilation uuid · opzionale Firma una compilazione esistente non ancora firmata.
  • store_values bool · default true Se false, i valori vengono cancellati dopo la firma.

La risposta contiene `id`, `sha256`, `pdf_url` e `pages` per mostrare il documento, `signature_labels` e `consent_text`, la dichiarazione che il firmatario accetta. La bozza vale 24 ore.

POST /signing-drafts/{id}/handoff/

Ottieni un link per il dispositivo del firmatario.

Restituisce `{ url, expires_at }`: un link valido 30 minuti. Il firmatario lo apre, rivede il documento e firma lì; il registro riporta il metodo `handoff` con la tua API key.

GET /signing-drafts/{id}/

Controlla se la bozza è stata firmata.

Restituisce `{ id, finalized, compilation }`. Oppure ascolta `compilation.signed`.

POST /signing-drafts/{id}/finalize/ application/json

Invia una firma raccolta dalla tua integrazione.

Fields

  • document_sha256 string · obbligatorio Lo `sha256` della bozza: rifiutata se il documento è cambiato.
  • signer_name string · obbligatorio Nome e cognome del firmatario.
  • consent bool · obbligatorio Il firmatario ha accettato `consent_text`.
  • signatures object · obbligatorio Mappa `campo firma → PNG in data URL`, fino a 512 KB ciascuna.

Request body

{
  "document_sha256": "<sha256>",
  "signer_name": "Mario Rossi",
  "consent": true,
  "signatures": { "signature": "data:image/png;base64,iVBORw0KGgo..." }
}

Restituisce la compilazione firmata. Il registro riporta il metodo `api` con il nome della tua API key, e così la pagina di registro.

GET /compilations/{id}/signatures/

Leggi il registro firme di una compilazione.

Metodo (`remote`, `in_person`, `handoff`, `api`), firmatario, email e verifica del codice, IP, dispositivo, `api_key_label` e impronte SHA-256 del documento e di ogni firma.

Richieste di firma

Richieste di firma — più firmatari, un documento

Una richiesta di firma fa firmare un documento a più persone, ognuna sui propri campi firma. I firmatari si definiscono sul template, nell'ordine di firma (il pannello Firmatari dell'editor, o `signers` in `bulk-upsert`), e ogni campo firma indica chi lo firma. Ogni firmatario riceve via email un link personale, rivede il documento, conferma con un codice e firma. In sequenza, ognuno viene invitato quando il precedente ha firmato e vede le firme già apposte; in parallelo, tutti vengono invitati subito. Se il template assegna degli allegati a un firmatario, li carica dal suo link prima di firmare. L'ultima firma chiude il PDF con una pagina di registro che elenca tutti i firmatari. Da Pro in su.

POST /signature-requests/ application/json

Crea una richiesta e invita chi firma per primo.

Fields

  • template uuid · obbligatorio Un template con campi firma.
  • signers array · obbligatorio Un `{ role, name, email }` per ogni firmatario del template, dove `role` è il `name` del firmatario. Un template senza firmatari ne vuole uno solo, con `role` vuoto.
  • order sequential | parallel · default sequential Un firmatario alla volta, o tutti insieme.
  • fill_mode sender | first_signer · default sender Chi compila il documento: tu con `values`, o il primo firmatario dal suo link.
  • values object · opzionale I dati del documento; con `first_signer`, quello che il primo firmatario trova già compilato.
  • signature_otp bool · default true Ogni firmatario conferma con un codice inviato via email.
  • notify_sender_on_complete bool · default false Ti invia per email il PDF firmato quando hanno firmato tutti.
  • send_copy_to_signers bool · default false Invia a ogni firmatario la sua copia alla fine.
  • expires_in_days int 1–90 · default 14 Durata dei link.
  • invitation_language string · opzionale Lingua degli inviti, es. `it` o `en`.
  • reminders bool · default false Promemoria automatici al firmatario di turno.

Request body

{
  "template": "3f0e4b2a-21c2-4d34-9c8d-9b0a5d6b3f11",
  "order": "sequential",
  "fill_mode": "sender",
  "values": { "full_name": "Jordan Rivera" },
  "signers": [
    { "role": "cliente", "name": "Jordan Rivera", "email": "[email protected]" },
    { "role": "garante", "name": "Sasha Park", "email": "[email protected]" }
  ]
}

Restituisce `201` con lo `status` di ogni firmatario (`waiting`, `invited`, `signed`) e il suo `url` personale finché può firmare. Con `sender` il documento viene renderizzato e un PDF di quota consumato subito; con `first_signer`, quando il primo firmatario invia. Creare la richiesta conta anche un documento firmato del piano, restituito se la richiesta si chiude senza nessuna firma. Con `reminders: true` i promemoria seguono le regole dei link share e, in sequenza, vanno solo al firmatario di turno; in parallelo, a chi deve ancora firmare. La richiesta riporta `reminders_enabled`; ogni firmatario `reminder_count`, `last_reminded_at` e `first_opened_at`.

GET /signature-requests/

Elenca le richieste di firma.

Filtri: `?status=open|completed|expired|revoked`, `?template=`, `?q=` (email del firmatario), `?expiring_within=N` (richieste aperte che scadono entro N giorni), `?expired_within=N` (scadute senza firma negli ultimi N giorni); N da 1 a 90.

GET /signature-requests/{id}/

A che punto è la richiesta: firmatari, compilazione e, a completamento, `download_url`.

POST /signature-requests/{id}/revoke/

Chiude la richiesta: i link smettono di funzionare e la compilazione risulta fallita.

POST /signature-requests/{id}/signers/{signer_id}/resend/

Reinvia l'invito a un firmatario di turno (al massimo una volta al minuto).

POST /signature-requests/{id}/extend/ application/json

Proroga la scadenza di una richiesta aperta.

Fields

  • days int 1–90 · obbligatorio Giorni aggiunti alla scadenza attuale.

Restituisce `200` con la richiesta aggiornata; `400` se `days` non è valido, `409 not_open` se è completata, revocata o scaduta. Dopo una proroga l'ultimo promemoria può ripartire prima della nuova scadenza. Stessi permessi della revoca.

Allegati

Allegati — i documenti caricati dal cliente

Gli allegati richiesti si definiscono sul template (`attachments` in `bulk-upsert`). Il cliente li carica dal link o dal QR code, e restano legati alla compilazione, al link share o alla richiesta di firma. Sono in uno storage privato: non hanno mai un URL pubblico, si scaricano solo con la tua API key, sempre come file da salvare e mai in anteprima, e vengono cancellati insieme ai PDF, con la retention del piano. Il tipo di file è controllato dai suoi byte, non dall'estensione.

GET /attachments/

Elenca gli allegati della tua organizzazione.

Filtri: `?compilation=`, `?share_request=`, `?signature_request=`. Ogni allegato riporta `id`, `requirement`, `title`, `signer_role`, `file_name`, `content_type`, `size`, `sha256`, `uploaded_at` e `download_url`.

GET /compilations/{id}/attachments/

Gli allegati di una compilazione.

GET /attachments/{id}/download/

Scarica il file di un allegato.

È il `download_url` degli allegati: richiede la tua API key e restituisce il file come allegato, con il suo nome.

GET /compilations/{id}/package/

Scarica la pratica completa: uno ZIP con il PDF e i suoi allegati.

Consensi

Consensi — cosa ha accettato il cliente

I consensi si definiscono sul template (`consents` in `bulk-upsert`). Chi compila o firma li spunta dalla pagina del link, dal telefono o dalla firma in app; le caselle partono vuote e ogni risposta viene registrata con testo esatto, impronta del documento collegato, esito, data e ora, IP e browser. Un consenso obbligatorio non accettato blocca invio e firma; uno mai spuntato risulta rifiutato. Se il template chiede un consenso obbligatorio, i link richiedono la verifica dell'email e le richieste di firma il codice via email. Una compilazione con consensi non si può più modificare (`409 has_consents`).

GET /consents/

Elenca le risposte ai consensi della tua organizzazione.

Filtri: `?compilation=`, `?share_request=`, `?signature_request=`. Ogni risposta riporta `requirement`, `text`, `required`, `signer_role`, `accepted`, `answered_at`, `document_name`, `document_sha256`, `ip` e `user_agent`.

GET /compilations/{id}/consents/

Le risposte ai consensi di una compilazione.

Webhooks

Webhooks — eventi consegnati al tuo endpoint

Registri un endpoint HTTPS e DataPDFEngine firma ogni richiesta con HMAC-SHA256, usando il secret dell'endpoint. `batch.completed` va all'endpoint scelto per il batch, o a quello di default; gli altri eventi vanno all'endpoint di default dell'organizzazione. Ogni richiesta porta un ID di consegna univoco, così il tuo handler la elabora una sola volta. Gli eventi di firma e di completamento portano un array `attachments`: `{ id, requirement, title, signer_role, file_name, content_type, size, sha256, uploaded_at, download_url }`, dove `download_url` richiede la tua API key. Portano anche un array `consents`: `{ requirement, text, required, signer_role, accepted, answered_at, document_name, document_sha256, ip, user_agent }`. I webhook richiedono Pro o superiore.

Verifica firma (HMAC-SHA256)

Ogni richiesta porta questi header. Verifica la firma prima di fidarti del payload, e calcola sempre l'HMAC sul body grezzo della richiesta, prima di qualsiasi parsing JSON.

  • X-DataPdfEngine-Event Nome dell'evento, es. `batch.completed`.
  • X-DataPdfEngine-Delivery ID univoco della consegna: salvalo per ignorare i duplicati.
  • X-DataPdfEngine-Timestamp Tempo Unix, in secondi, in cui la richiesta è stata firmata.
  • X-DataPdfEngine-Signature `t=<unix>,v1=<hex>`: `<hex>` è l'HMAC-SHA256 di `"<unix>." + body grezzo`, con il secret del tuo endpoint come chiave. Rifiuta i timestamp a più di 5 minuti dal tuo orologio.
import crypto from "node:crypto";

// header: "t=<unix>,v1=<hex>"
export function verify(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(
    (header ?? "").split(",").map((part) => part.split("=", 2))
  );
  const t = Number(parts.t);
  if (!parts.v1 || !Number.isInteger(t)) return false;
  if (Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.`)
    .update(rawBody)
    .digest("hex");
  const a = Buffer.from(parts.v1, "hex");
  const b = Buffer.from(expected, "hex");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
POST /webhooks/endpoints/

Registra un nuovo endpoint. La risposta include il `secret` una sola volta — conservalo.

GET /webhooks/endpoints/

Elenca i tuoi endpoint.

PATCH /webhooks/endpoints/{id}/

Aggiorna un endpoint, lo disattiva (`is_active`) o lo rende quello di default per i batch (`is_default`).

POST /webhooks/endpoints/{id}/rotate-secret/

Emette un nuovo secret, restituito una sola volta. Il vecchio smette di funzionare subito.

POST /webhooks/endpoints/{id}/test/

Invia un `test.ping` e restituisce la risposta del target: `{ ok, response_status, delivery }`.

GET /webhooks/deliveries/

Ispeziona le consegne recenti: status code, numero di tentativi, response body.

Errori di rete, `5xx` e `429` vengono ritentati, fino a 6 tentativi, aspettando 30 s e raddoppiando ogni volta. I redirect non vengono seguiti e gli indirizzi privati sono rifiutati.

Events

  • batch.completed Inviato quando un batch finisce `done`. Payload: `{ event, batch_id, organization_id, template_id, totals: { total, succeeded, failed }, download_url }`.
  • compilation.signed Inviato a ogni firma raccolta in presenza, via API, sul dispositivo del firmatario (`handoff`) o tramite link share. I firmatari di una richiesta di firma generano invece `signature_request.signed`. Payload: `{ event, compilation_id, organization_id, template_id, share_request_id, method, signer: { name, email, email_verified }, api_key, signed_at, document_sha256, signed_document_sha256, download_url, attachments, consents }`.
  • share_request.completed Inviato quando un link share è stato compilato e il suo PDF è pronto (firmato, se aveva campi firma). Payload: `{ event, share_request_id, share_batch_id, organization_id, template_id, compilation_id, recipient_email, completed_at, signed, download_url, attachments, consents }`.
  • signature_request.signed Inviato quando un firmatario di una richiesta ha firmato. Payload: `{ event, signature_request_id, organization_id, template_id, compilation_id, signer: { id, role, role_title, name, email, position, signed_at }, email_verified, document_sha256, remaining, attachments, consents }`.
  • signature_request.completed Inviato quando hanno firmato tutti. Payload: `{ event, signature_request_id, organization_id, template_id, compilation_id, completed_at, signers, signed_document_sha256, download_url, attachments, consents }`, dove ogni elemento di `signers` ha gli stessi campi di `signer` qui sopra.
  • test.ping Inviato quando testi un endpoint, dalla dashboard o con `POST /webhooks/endpoints/{id}/test/`. Payload: `{ event, endpoint_id, organization_id, sent_at }`. Usalo per verificare la firma e la raggiungibilità prima del go-live.

Modello di errore

Gli errori arrivano come JSON: `{ code, detail, extra? }`. `code` è stabile, `detail` è un messaggio leggibile, ed `extra` porta dettagli come i campi non validi o la feature mancante.

HTTP Code Detail
400 invalid Payload non valido. `detail` indica il primo problema; `extra.fields` li elenca tutti.
400 unprintable · does_not_fit Un valore non si può stampare nel suo campo, o non ci sta. Dettagli in `extra.fields.values`.
400 target_not_allowed L'URL del webhook punta a un indirizzo privato.
400 document_changed · signature_missing · signature_blank Firma rifiutata: il documento è cambiato dopo la revisione, manca una firma obbligatoria o è vuota.
400 signer_name_required · consent_required · signature_invalid · signature_too_large Firma rifiutata: manca il nome del firmatario, `consent` non è true, oppure una firma non è un data URL PNG o supera 512 KB o 2.048 pixel per lato.
400 draft_unusable La bozza di firma è scaduta o già usata: creane una nuova.
400 no_signature_fields Il template non ha campi firma.
400 several_signers Il template ha più firmatari: invialo con una richiesta di firma, non con un link share.
400 recipient_required · invalid_email Serve un indirizzo email valido: per un link share con `verify_email` o con un consenso obbligatorio, o per ogni firmatario di una richiesta.
400 confirmation_required Per eliminare una compilazione firmata, o con consensi, serve `confirm=ELIMINA`.
400 pdf_unreadable · pdf_encrypted · pdf_damaged · pdf_empty · pdf_too_many_pages · pdf_page_too_large Il PDF caricato non può diventare un template: illeggibile, protetto da password, danneggiato, senza pagine, oltre 200 pagine o con pagine troppo grandi.
401 authentication_failed API key non valida o revocata.
401 not_authenticated Header `Authorization` mancante, o schema diverso da `Bearer`.
403 feature_required Il tuo piano non include questa feature; `extra.feature` la indica.
403 admin_required Una compilazione firmata, o con consensi, la elimina solo il titolare o un amministratore dalla dashboard, non una API key.
404 not_found Risorsa inesistente, o appartiene a un'altra organizzazione.
409 signed La compilazione è firmata e non si può modificare.
409 already_signed La compilazione è già firmata.
409 signing_in_progress · not_your_turn Il documento è in attesa di firme e non si può modificare, oppure non è ancora il turno di un firmatario.
409 has_consents La compilazione ha consensi registrati e non si può modificare (`400` da `POST /signing-drafts/` con quella `compilation`).
409 already_submitted Il documento è già stato inviato.
409 template_in_use Il template è ancora usato da compilazioni, batch o link.
409 endpoint_inactive L'endpoint webhook è disattivato.
429 quota_exceeded Quota mensile esaurita su un piano senza overage, o raggiunto il tuo tetto di overage. `extra.limit` riporta la quota.
429 throttled Troppe richieste (240 al minuto per organizzazione), oppure 20 API key non valide in un minuto dal tuo indirizzo IP, che bloccano fino alla fine del minuto anche le chiavi valide. Riprova dopo `Retry-After` secondi.
429 invite_cooldown Un invito è stato rinviato meno di un minuto fa. Riprova dopo `Retry-After` secondi.
500 server_error Errore inatteso da parte nostra.
502 delivery_failed Solo dal test dell'endpoint: il target non è raggiungibile.