Passa al contenuto principale

Webhooks

I webhook permettono di ricevere notifiche automatiche sull'avanzamento delle pratiche di firma. Attraverso i webhook, il vostro sistema viene informato in tempo reale quando una pratica viene firmata, rifiutata, scade o cambia stato, senza dover eseguire polling continuo.

Come Funzionano

Quando un evento significativo si verifica su una pratica (firma, rifiuto, scadenza, ecc.), Askme Sign invia una richiesta HTTP POST all'URL da voi configurato. Il corpo della richiesta contiene un payload JSON con le informazioni sull'evento.

[Firmatario firma] → [Askme Sign aggiorna stato] → [POST al vostro endpoint]

Configurazione del Webhook

I webhook si configurano al momento della creazione della pratica, specificando il campo webhook (singolo endpoint) o webhooks (più endpoint) nel body della richiesta POST /api/v2/files/send.

Campi di configurazione

CampoTipoObbligatorioDescrizione
urlstringURL del vostro endpoint. Supporta placeholder: {{idFile}}, {{tenantCode}}, {{signerEmail}}, {{status}}, {{action}}.
authModestringNoModalità di autenticazione: basic, header, oauth2.
authConfigstringNoChiave di configurazione per le credenziali (per tenant).
usernamestringNoUsername per Basic Auth (se authMode = basic).
passwordstringNoPassword per Basic Auth (se authMode = basic).

Esempio: webhook nella creazione pratica

{
"documents": [{ "filename": "contratto.pdf", "base64content": "..." }],
"name": "Contratto con webhook",
"sendNotifications": true,
"webhook": {
"url": "https://your-server.com/webhooks/askmesign",
"authMode": "basic",
"username": "webhook_user",
"password": "webhook_secret"
},
"signers": [
{
"email": "[email protected]",
"firstName": "Mario",
"lastName": "Rossi",
"action": "S",
"signatureCoordinates": [
{ "document": 0, "page": 1, "signatureType": "S", "positionX": 0.6, "positionY": 0.8, "width": 0.2, "height": 0.08 }
]
}
]
}

Webhook multipli

Per notificare più endpoint, usare il campo webhooks (array):

{
"webhooks": [
{
"url": "https://server-a.com/webhook",
"authMode": "basic",
"username": "user_a",
"password": "pass_a"
},
{
"url": "https://server-b.com/webhook?idFile={{idFile}}&status={{status}}",
"authMode": "header"
}
]
}

Webhook per firmatario

Ogni firmatario può avere un webhook dedicato, utile per notificare sistemi diversi in base al firmatario:

{
"signers": [
{
"email": "[email protected]",
"action": "S",
"webhook": {
"url": "https://crm.example.com/webhook/firma-cliente",
"authMode": "basic",
"username": "crm_user",
"password": "crm_pass"
}
}
]
}

Payload della Notifica

Struttura JSON

Quando un evento si verifica, il sistema invia il seguente payload al vostro endpoint:

{
"idFile": 12345,
"tenantCode": "TENANT01",
"name": "Contratto Cliente Rossi",
"status": "F",
"action": "S",
"signerEmail": "[email protected]",
"notes": null,
"protocol": "PROT-2024-001",
"externalId": "CRM-98765",
"time": "2024-10-23T10:09:00.000+0200"
}

Descrizione dei campi

CampoTipoDescrizione
idFilenumberID univoco della pratica in Askme Sign.
tenantCodestringCodice del tenant a cui appartiene la pratica.
namestringNome della pratica.
statuscharStato corrente della pratica dopo l'evento.
actioncharTipo di azione che ha generato l'evento.
signerEmailstringEmail del firmatario che ha eseguito l'azione.
notesstringNote associate all'azione (es. motivazione del rifiuto). null per azioni di sottomissione e rimozione.
protocolstringNumero di protocollo della pratica (se configurato).
externalIdstringID esterno della pratica nel vostro sistema (se specificato in fase di creazione).
timestringData/ora dell'evento in formato ISO 8601 (es. 2024-10-23T10:09:00.000+0200).

Eventi e Codici

Codici di stato (status)

CodiceDescrizioneQuando si verifica
LIn lavorazioneLa pratica è in corso: un firmatario ha firmato ma ce ne sono altri in attesa.
FFirmatoTutti i firmatari hanno completato le azioni richieste. La pratica è chiusa con successo.
RRifiutatoUn firmatario ha rifiutato la pratica.
ACompletatoLa pratica è stata approvata (in workflow con approvazione).
EScadutoLa data di scadenza è stata superata senza completamento.
VAnnullatoLa pratica è stata annullata.

Codici di azione (action)

CodiceDescrizione
ISottomissione (pratica creata e inviata)
SFirma elettronica semplice
EFES (Firma Elettronica Semplice conforme eIDAS)
TFES con OTP
VFEA (Firma Elettronica Avanzata)
QFEQ (Firma Elettronica Qualificata)
OFEQ One-Shot
JFirma IO
PVisto
WApprovazione
DRifiuto
NAnnullamento

Scenari comuni

ScenariostatusactionDescrizione
Pratica creataLIIl processo di firma è stato avviato.
Firma intermediaLS/E/T/V/QUn firmatario ha firmato, ma altri devono ancora firmare.
Ultima firmaFS/E/T/V/QL'ultimo firmatario ha firmato. Pratica completata.
RifiutoRDUn firmatario ha rifiutato. Il campo notes può contenere la motivazione.
ScadenzaELa pratica è scaduta automaticamente.
AnnullamentoVNLa pratica è stata annullata manualmente.

Autenticazione del Webhook

Basic Auth

POST https://your-server.com/webhooks/askmesign
Authorization: Basic base64(username:password)
Content-Type: application/json

Header personalizzato

Con authMode: "header", il sistema invia un header di autenticazione configurato a livello di tenant (nome e valore dell'header sono definiti nella configurazione server).

OAuth 2.0

Con authMode: "oauth2", il sistema ottiene un Bearer token dalla configurazione del tenant e lo include nell'header Authorization.


Retry e Affidabilità

Il sistema gestisce automaticamente i retry in caso di fallimento della chiamata:

  • Se il vostro endpoint non risponde o restituisce un errore (status >= 400), il sistema ripianifica l'invio
  • Ogni esecuzione registra: numero di tentativi, codice di risposta, timestamp dell'ultimo tentativo e del prossimo pianificato
  • I retry continuano fino al raggiungimento del limite configurato
Risposta rapida

Il vostro endpoint deve rispondere con HTTP 200 entro pochi secondi. Se l'elaborazione richiede tempo, accodare il lavoro in una coda asincrona e rispondere immediatamente.


Personalizzazione del Payload

Il payload può essere personalizzato a livello di tenant tramite un template nella configurazione del sistema. Le variabili disponibili sono:

VariabileDescrizione
$idFileID della pratica
$tenantCodeCodice tenant
$nameNome della pratica
$statusStato corrente
$actionAzione eseguita
$externalIdID esterno
$timeTimestamp dell'evento

La personalizzazione viene configurata tramite la chiave webhook.body.[authConfig].content nelle impostazioni del tenant. Se non configurato, viene usato il payload JSON standard.


Implementazione dell'Endpoint

Checklist

  1. Endpoint HTTPS accessibile da Internet che accetti richieste POST
  2. Autenticazione: implementare il meccanismo scelto (Basic Auth, API Key, OAuth)
  3. Risposta rapida: restituire HTTP 200 entro pochi secondi
  4. Idempotenza: gestire eventuali notifiche duplicate (stesso evento ricevuto più volte)
  5. Logging: registrare tutti i webhook ricevuti per debugging e auditing

Esempio: Node.js/Express

const express = require('express');
const app = express();
app.use(express.json());

// Middleware autenticazione Basic
const authenticate = (req, res, next) => {
const auth = req.headers.authorization;
if (!auth || !auth.startsWith('Basic ')) {
return res.status(401).json({ error: 'Unauthorized' });
}
const credentials = Buffer.from(auth.slice(6), 'base64').toString();
const [username, password] = credentials.split(':');
if (username !== process.env.WEBHOOK_USER || password !== process.env.WEBHOOK_PASS) {
return res.status(401).json({ error: 'Invalid credentials' });
}
next();
};

app.post('/webhooks/askmesign', authenticate, (req, res) => {
const { idFile, status, action, signerEmail, time } = req.body;
console.log(`[${time}] Pratica ${idFile}: status=${status}, action=${action}, signer=${signerEmail}`);

// Elaborazione asincrona
processWebhookAsync(req.body).catch(console.error);

// Risposta immediata
res.status(200).json({ success: true });
});

app.listen(3000, () => console.log('Webhook server avviato sulla porta 3000'));

Esempio: Python/Flask

from flask import Flask, request, jsonify
import base64
import os

app = Flask(__name__)

def verify_basic_auth():
auth = request.headers.get("Authorization", "")
if not auth.startswith("Basic "):
return False
credentials = base64.b64decode(auth[6:]).decode()
username, password = credentials.split(":", 1)
return (username == os.environ["WEBHOOK_USER"] and
password == os.environ["WEBHOOK_PASS"])

@app.route("/webhooks/askmesign", methods=["POST"])
def handle_webhook():
if not verify_basic_auth():
return jsonify({"error": "Unauthorized"}), 401

data = request.get_json()
print(f"[{data['time']}] Pratica {data['idFile']}: "
f"status={data['status']}, action={data['action']}, "
f"signer={data['signerEmail']}")

# Elaborazione asincrona consigliata in produzione
return jsonify({"success": True}), 200

if __name__ == "__main__":
app.run(port=3000)

Best Practices

  1. Preferire i webhook al polling: i webhook sono più efficienti e forniscono aggiornamenti in tempo reale
  2. Implementare idempotenza: il vostro endpoint potrebbe ricevere lo stesso evento più volte in caso di retry
  3. Rispondere velocemente: restituire HTTP 200 entro pochi secondi, elaborare in modo asincrono
  4. Usare HTTPS: proteggere sempre l'endpoint con HTTPS
  5. Autenticazione: implementare sempre Basic Auth, API Key o OAuth per proteggere l'endpoint
  6. Logging: registrare ogni webhook per debugging e auditing
  7. Gestire tutti gli stati: implementare la logica per tutti i codici di stato possibili, non solo F (firmato)
  8. Monitorare i fallimenti: configurare alerting se il vostro endpoint smette di ricevere webhook