API Reference

Tutti gli endpoint sono REST/JSON, accettano e restituiscono application/json (con eccezione dei download PDF, binari). Le date sono in formato ISO 8601 UTC. Gli ID di risorsa sono UUID v4.

Base URL

https://api.ezysign.net/api/v1

Autenticazione

Tutti gli endpoint sotto /dossiers richiedono l'header X-API-Key. Le chiavi sono associate al tenant: ogni dossier creato eredita automaticamente l'identità del chiamante.

X-API-Key: esf_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Rate limiting

  • /api/v1/dossiers/*: 120 richieste / minuto per chiave API
  • /verify/*: 20 richieste / minuto per IP

Quando il limite viene superato il server risponde con 429 Too Many Requests. Riprova con backoff esponenziale.

Codici di stato HTTP

CodiceSignificato
200 OKRichiesta riuscita
400 Bad RequestPayload mancante o non valido (vedi message)
401 UnauthorizedHeader X-API-Key mancante o chiave non valida
403 ForbiddenOperazione non consentita sullo stato corrente del dossier
404 Not FoundRisorsa inesistente o non appartenente al tenant chiamante
413 Payload Too LargeBody oltre 25 MB
429 Too Many RequestsRate limit superato
500 Internal Server ErrorErrore inatteso, riportare al supporto allegando il request-id

Formato errori

{
  "statusCode": 400,
  "message": "Documento non e' un PDF valido",
  "error":   "Bad Request"
}

POST /dossiers

Crea un nuovo dossier di firma e invia immediatamente l'OTP al firmatario.

Body

CampoTipoObbl.Descrizione
signer.firstNamestring (1-100)Nome del firmatario
signer.lastNamestring (1-100)Cognome del firmatario
signer.emailstring (email)Email del firmatario (sempre richiesta, anche con OTP via SMS)
signer.phonestringcond.Telefono in formato E.164. Obbligatorio se otpChannel = sms
signer.taxCodestring (max 32)noCodice fiscale, riportato nel report di evidenze
otpChannel"email" | "sms"Canale di invio del codice OTP
document.namestring (1-200)Nome file mostrato al firmatario
document.contentBase64string (base64)Contenuto del PDF codificato in base64
signPointsarray (max 20)noCoordinate dei riquadri di firma (vedi sotto)
callbackUrlstring (URL https)noEndpoint per la ricezione di webhook eventi
metadataobjectnoCoppie chiave/valore di tua scelta, ritornate nei webhook
expiresInHoursinteger (1-720)noValidità del link firma. Default: 168 (7 giorni)

Schema signPoint

Le coordinate sono percentuali rispetto a larghezza/altezza della pagina (origine in basso a sinistra), così non dipendono dal formato (A4, Letter, custom):

{
  "page":   3,                    // 1-based
  "x":      60,                   // 0-100 (% larghezza)
  "y":      10,                   // 0-100 (% altezza, dal basso)
  "width":  35,                   // 1-100 (% larghezza)
  "height": 10,                   // 1-30  (% altezza)
  "label":  "Firma Cliente"       // opzionale, max 120 char
}

Risposta 200

{
  "id":                "8c1e4f2a-...",
  "status":            "sent",
  "signerUrl":         "https://ezysign.net/sign/abc123...",
  "signedDocumentUrl": null,
  "evidenceUrl":       null,
  "createdAt":         "2026-04-27T10:00:00.000Z",
  "sentAt":            "2026-04-27T10:00:00.000Z",
  "viewedAt":          null,
  "signedAt":          null,
  "expiresAt":         "2026-05-04T10:00:00.000Z"
}

Errori

  • 400 — payload non valido, PDF non valido, telefono mancante con SMS
  • 401 — chiave API non valida
  • 413 — payload > 25 MB

GET /dossiers

Elenca i dossier del tenant chiamante, ordinati per data di creazione (più recenti prima).

Query params

  • limit (integer, default 50, max 200) — numero di elementi da restituire.

Risposta 200

[
  {
    "id":                "8c1e4f2a-...",
    "status":            "signed",
    "signerFirstName":   "Mario",
    "signerLastName":    "Rossi",
    "signerEmail":       "[email protected]",
    "otpChannel":        "email",
    "documentName":      "Contratto.pdf",
    "createdAt":         "2026-04-27T10:00:00.000Z",
    "signedAt":          "2026-04-27T10:05:12.000Z",
    "expiresAt":         "2026-05-04T10:00:00.000Z"
  },
  ...
]

GET /dossiers/:id

Restituisce il dossier indicato. Tipico uso: polling lato integratore quando non si è configurato un callbackUrl.

Risposta 200

Stesso schema di POST /dossiers.

Errori

  • 404 — dossier inesistente o non appartenente al tuo tenant

POST /dossiers/:id/resend

Reinvia un nuovo OTP al firmatario sullo stesso canale del dossier. Utile se il primo codice non è stato ricevuto.

Risposta 200

{ "ok": true }

Errori

  • 403 — il dossier è in stato terminale (signed, expired, cancelled)
  • 404 — dossier inesistente

DELETE /dossiers/:id

Annulla un dossier in corso. Il link firma viene invalidato. Operazione irreversibile.

Risposta 200

{ "ok": true }

Errori

  • 403 — il dossier è già firmato
  • 404 — dossier inesistente

GET /verify/:id (pubblico)

Endpoint pubblico (no API key) per verificare la validità di una firma da parte di terzi. Ritorna solo informazioni minime (nome firmatario mascherato, hash documento, marca temporale, link al PDF firmato e alla prova OpenTimestamps). Usato dalla pagina pubblica https://ezysign.net/verify/{id}.

Risposta 200 (firmato)

{
  "id":        "8c1e4f2a-...",
  "status":    "signed",
  "brandName": "Acme Srl",
  "signer":    { "name": "M. Rossi", "email": "m***@example.com" },
  "document":  { "name": "Contratto.pdf", "hash": "sha256:f3a1...c0" },
  "signedAt":  "2026-04-27T10:05:12.000Z",
  "expiresAt": "2026-05-04T10:00:00.000Z",
  "files":     {
    "signed": "https://...presigned...",
    "ots":    "https://...presigned..."
  }
}

Stati del dossier

StatoDescrizione
pendingCreato, OTP non ancora inviato (transitorio)
sentOTP inviato al firmatario, in attesa di apertura
viewedIl firmatario ha aperto il link
signedOTP verificato, PDF sigillato e marcato temporalmente
expiredLink scaduto senza completamento
cancelledDossier annullato dall'integratore
failedErrore irreversibile (es. invio OTP impossibile)

URL firmati per i file

I campi signedDocumentUrl e evidenceUrl sono URL pre-firmati con validità 2 ore. Per uso prolungato, scarica il file e archivialo nel tuo sistema oppure interroga di nuovo l'endpoint per ottenere un URL fresco.