Vai al contenuto
Menu della documentazione

Webhook

Eventi dei documenti generati e non riusciti e dei template pubblicati, firmati con HMAC-SHA256 e ritentati.

I webhook informano i tuoi sistemi di ciò che accade in un workspace senza bisogno di polling: un documento generato tramite API, una generazione non riuscita, la pubblicazione di una versione di un template. Prynt invia una POST HTTPS con un corpo JSON al tuo endpoint, la firma e ritenta finché l'endpoint non risponde 2xx.

Come funzionano i webhook

  • Aggiungi un endpoint in Sviluppatori → Webhook (permesso webhooks.manage): un URL https:// su un host pubblico, gli eventi da ricevere e una descrizione facoltativa. Prynt rifiuta gli indirizzi di reti private e localhost.
  • Prynt mostra una sola volta il segreto di firma dell'endpoint (whsec_…). Conservalo insieme alla configurazione dell'endpoint; Ruota il segreto ne crea uno nuovo quando serve (quello vecchio smette subito di firmare).
  • Ogni consegna viene registrata con i tentativi, lo stato HTTP e un estratto della tua risposta. Invia evento di test invia un evento webhook.test per verificare l'endpoint.

Eventi

Eventi dei webhook
CampoTipoDescrizione
document.generatedeventUn documento è stato generato tramite l'API pubblica (in modo sincrono o asincrono).
document.failedeventUna generazione tramite l'API pubblica non è riuscita: errorCode e message spiegano il motivo.
template.publishedeventÈ stata pubblicata una versione di un template nel workspace.
webhook.testeventInviato da Invia evento di test; viene sempre consegnato, qualunque siano gli eventi dell'endpoint.

Payload

Ogni evento ha la stessa struttura: id (l'id dell'evento, un UUID), type, createdAt, workspaceId e i data dell'evento.

document.generated
{  "id": "0199c2f2-0b6e-7f4c-a1d2-6c8e9b0a7f31",  "type": "document.generated",  "createdAt": "2026-10-08T09:12:04.051Z",  "workspaceId": "0199b8a1-0000-7000-8000-00000000abcd",  "data": {    "template": "INVOICE",    "version": 7,    "environment": "production",    "format": "pdf",    "pageCount": 2,    "outputBytes": 48213,    "fileName": "INVOICE_18425.pdf",    "runId": "0199c2f1-5a7e-7b31-9c4d-2f0a8e6b1d23",    "jobId": "0199c2f1-7c10-7d2e-8f61-1b9a4c3e5d77",    "documentUrl": "https://api.prynt.it/api/v1/documents/eyJhbGciOi…",    "documentExpiresAt": "2026-10-09T09:12:04.020Z",    "correlationId": "4bf92f3577b34da6a3ce929d0e0e4736",    "apiKey": { "id": "0199b9c0-…", "prefix": "prynt_live_k3x9a2mq", "name": "ERP production" }  }}

I dati di ogni evento

  • document.generated: template, version, environment, format, pageCount, outputBytes, fileName, runId, jobId, documentUrl (un link firmato di breve durata), documentExpiresAt, correlationId e l'apiKey (id, prefisso, nome) che l'ha richiesto.
  • document.failed: template, version, environment, format, jobId, runId, errorCode, message, correlationId e l'apiKey.
  • template.published: templateId, template, version, previousVersion, format, note e publishedBy.

Header

Una consegna
POST /prynt/webhooks HTTP/1.1Content-Type: application/jsonUser-Agent: Prynt-Webhooks/1.0Prynt-Event: document.generatedPrynt-Event-Id: 0199c2f2-0b6e-7f4c-a1d2-6c8e9b0a7f31Prynt-Delivery: 0199c2f2-0c11-7a05-b3e4-9d1f2a6c8e40Prynt-Signature: t=1760000000, v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
  • Prynt-Event: il tipo di evento; Prynt-Event-Id: l'id dell'evento (lo stesso a ogni nuovo tentativo e riconsegna); Prynt-Delivery: questa consegna.
  • Prynt-Signature: t=<secondi unix>, v1=<firma>.

Verificare le firme

v1 è l'HMAC-SHA256 esadecimale di {t}.{raw body}, calcolato con i byte UTF-8 dell'intero segreto (compreso il prefisso whsec_). Per verificare una consegna:

  • Leggi il corpo grezzo esattamente come ricevuto, prima di qualsiasi parsing JSON (interpretarlo e serializzarlo di nuovo cambia i byte).
  • Calcola l'HMAC di t, un punto e il corpo grezzo, e confrontalo con v1 in tempo costante.
  • Rifiuta le consegne il cui t si discosta di più di 5 minuti dal tuo orologio: una richiesta intercettata non può essere riprodotta in seguito.
1using System.Security.Cryptography;2using System.Text;3 4static bool VerifyPryntSignature(string header, string rawBody, string secret, TimeSpan tolerance)5{6    // header: "t=1760000000, v1=5257a869…"7    string? t = null, v1 = null;8    foreach (var part in header.Split(',', StringSplitOptions.TrimEntries))9    {10        if (part.StartsWith("t=")) t = part[2..];11        else if (part.StartsWith("v1=")) v1 = part[3..];12    }13    if (t is null || v1 is null || !long.TryParse(t, out var seconds)) return false;14    var age = DateTimeOffset.UtcNow - DateTimeOffset.FromUnixTimeSeconds(seconds);15    if (age.Duration() > tolerance) return false;16 17    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)); // l'intera stringa "whsec_…"18    var expected = hmac.ComputeHash(Encoding.UTF8.GetBytes($"{t}.{rawBody}"));19    byte[] received;20    try { received = Convert.FromHexString(v1); } catch (FormatException) { return false; }21    return CryptographicOperations.FixedTimeEquals(expected, received);22}23 24// ASP.NET Core: leggi il corpo grezzo prima di qualsiasi binding JSON.25// var rawBody = await new StreamReader(Request.Body).ReadToEndAsync();26// var ok = VerifyPryntSignature(Request.Headers["Prynt-Signature"]!, rawBody, secret, TimeSpan.FromMinutes(5));

Verifica prima di fidarti del contenuto

Rispondi 400 a una consegna con una firma mancante o errata e non elaborarla. Durante la rotazione del segreto, accetta per un breve periodo sia il vecchio sia il nuovo.

Nuovi tentativi e riconsegna

Una consegna riesce quando il tuo endpoint risponde 2xx entro pochi secondi. In caso contrario (uno stato di errore, un timeout, una connessione fallita) Prynt riprova dopo 1 minuto, 5 minuti, 30 minuti, 2 ore e 12 ore: fino a 6 tentativi. Dopo l'ultimo la consegna risulta abandoned.

  • Il registro delle consegne di ogni webhook mostra lo stato (pending, succeeded, failed, abandoned), il tentativo, il tentativo successivo e la tua risposta.
  • Consegna di nuovo invia di nuovo un evento, come una nuova consegna con lo stesso id evento: utile quando hai sistemato il tuo endpoint.
  • I webhook disattivati non ricevono nulla; la riconsegna e gli eventi di test rispondono 409 WEBHOOK_DISABLED finché non li riattivi.

Buone pratiche

  • Rispondi 2xx rapidamente, poi svolgi il lavoro in modo asincrono (una coda, un job in background). Le risposte lente contano come errori e vengono ritentate.
  • Sii idempotente: lo stesso evento può arrivare più di una volta (nuovi tentativi, riconsegne). Memorizza l'id degli eventi elaborati e ignora le ripetizioni.
  • Gli eventi possono arrivare fuori ordine: basati su createdAt e sugli id di job ed esecuzioni, non sull'ordine di arrivo.
  • Scarica documentUrl subito dopo l'evento: il link ha una durata breve. Rileggi il job (GET /v1/jobs/{jobId}) per ottenere un link nuovo.