Account e integrazioni
Ricevere e verificare un webhook firmato
Quando viene registrata una risposta, Kiosform prepara una richiesta POST JSON al tuo server. Le risposte sincronizzate da un chiosco usano lo stesso meccanismo. I titoli della sezione e il comando di test sono in italiano, ma alcuni campi e il pulsante di aggiunta restano in francese: qui li trovi con una spiegazione in italiano.
Aggiornato il
Prima di iniziare
- Assicurati di avere un endpoint HTTPS accessibile pubblicamente sulla porta 443.
- Prepara un archivio persistente per la deduplicazione e conserva il segreto solo sul server.
Passaggi
Aggiungi il destinatario
Nelle risposte del modulo, trova “Invii automatici ai tuoi strumenti (webhook) e cronologia”. Compila “URL de destination (HTTPS)” (URL di destinazione, HTTPS) e una descrizione, poi usa “Ajouter le webhook signé” (aggiungi il webhook firmato). Il tuo endpoint appare con il relativo segreto.
Controlla la consegna
Usa “Invia un test”. La cronologia distingue le consegne in attesa, i tentativi e i risultati. Lo stato “delivered” (consegnato) significa che il destinatario ha restituito uno stato HTTP 2xx. Controlla anche i tuoi log.
Verifica la firma
Leggi il corpo HTTP grezzo prima di decodificare il JSON. Controlla il timestamp e verifica l'HMAC di timestamp.raw_body usando il segreto del webhook. Questa notazione indica il timestamp seguito da un punto letterale e dal corpo grezzo non modificato. Usa uno degli esempi qui sotto.
Registra ogni consegna senza duplicati
Usa X-Kiosform-Delivery-Id come chiave univoca persistente. Registra questa chiave e l'operazione applicativa nella stessa transazione. La ricezione dello stesso identificatore non deve ripetere l'operazione.

Corpo e intestazioni
L'evento response.created contiene direttamente form_id, form_version_id, workspace_id, response_id, source, device_id, client_created_at, submitted_at, deferred, idempotency_key e answers. Queste proprietà si trovano alla radice del JSON, non in un oggetto response. L'evento webhook.test contiene event, form_id e created_at; non è una risposta di un partecipante.
X-Kiosform-Signature ha la forma t=unix_timestamp,v1=hex_signature, dove unix_timestamp è il timestamp Unix e hex_signature è la firma in esadecimale. X-Kiosform-Delivery-Id resta invariato per una consegna, anche nei tentativi successivi. Il corpo resta invariato; il timestamp e la firma vengono rinnovati.
answers contiene i valori raccolti e può includere dati personali come un nome o un indirizzo email. Scegli un server destinatario autorizzato, proteggine l'archiviazione ed evita di registrare il corpo completo nei log. Conserva i segreti e i contenuti ricevuti sul server, mai in uno script pubblico eseguito nel browser.
{
"event": "response.created",
"form_id": "00000000-0000-4000-8000-000000000001",
"form_version_id": "00000000-0000-4000-8000-000000000002",
"workspace_id": "00000000-0000-4000-8000-000000000003",
"response_id": "00000000-0000-4000-8000-000000000004",
"source": "web",
"device_id": null,
"client_created_at": "2026-10-18T08:00:00.000Z",
"submitted_at": "2026-10-18T08:00:01.000Z",
"deferred": false,
"idempotency_key": "00000000-0000-4000-8000-000000000005",
"answers": {
"prenom": "Camille"
}
}Esempi di verifica
Queste funzioni richiedono i byte del corpo, il segreto e l'intestazione esatta. Tollerano uno scarto dell'orologio di cinque minuti in entrambe le direzioni: mantieni quindi preciso l'orologio del server. Rifiuta la richiesta se la funzione restituisce false. Analizza il JSON e applica la deduplicazione solo dopo la verifica.
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody est un Buffer : ne pas reconstituer le JSON après décodage.
export function verifyKiosformWebhook(secret, rawBody, header, now = Math.floor(Date.now() / 1000)) {
if (!secret || !Buffer.isBuffer(rawBody) || typeof header !== 'string') return false;
const parts = /^t=([1-9][0-9]{0,11}),v1=([a-f0-9]{64})$/.exec(header);
if (!parts || parts[0] !== header || !Number.isFinite(now)) return false;
const timestamp = Number(parts[1]);
if (Math.abs(now - timestamp) > 300) return false;
const expected = createHmac('sha256', secret)
.update(parts[1] + '.', 'utf8').update(rawBody).digest();
const received = Buffer.from(parts[2], 'hex');
return timingSafeEqual(expected, received);
}Python 3
import hashlib
import hmac
import re
import time
def verify_kiosform_webhook(secret, raw_body, header, now=None):
"""raw_body contient les octets HTTP, avant le décodage JSON."""
if not secret or not isinstance(raw_body, bytes) or not isinstance(header, str):
return False
parts = re.fullmatch(r"t=([1-9][0-9]{0,11}),v1=([a-f0-9]{64})", header)
if parts is None:
return False
timestamp = int(parts[1])
if abs((time.time() if now is None else now) - timestamp) > 300:
return False
signed = (parts[1] + ".").encode("ascii") + raw_body
expected = hmac.new(secret.encode("utf-8"), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts[2])PHP
<?php
// $rawBody = file_get_contents('php://input'), avant json_decode.
function verifyKiosformWebhook(string $secret, string $rawBody, string $header, ?int $now = null): bool
{
if ($secret === '' || preg_match('/\At=([1-9][0-9]{0,11}),v1=([a-f0-9]{64})\z/', $header, $parts) !== 1) {
return false;
}
if (abs(($now ?? time()) - (int) $parts[1]) > 300) {
return false;
}
$expected = hash_hmac('sha256', $parts[1] . '.' . $rawBody, $secret);
return hash_equals($expected, $parts[2]);
}Tentativi successivi ed errori
Sono possibili fino a quattro tentativi: la consegna iniziale, poi tre tentativi successivi eseguibili dopo 1, 10 e 60 secondi. Il worker di produzione viene eseguito ogni dieci secondi, quindi questi intervalli non garantiscono una consegna al secondo esatto.
Un errore di rete o uno stato HTTP pari o superiore a 300 conta come un errore di consegna. I reindirizzamenti non vengono seguiti. Le destinazioni locali o private vengono rifiutate. Dopo venti errori consecutivi, l'endpoint viene disabilitato automaticamente. Una risposta 2xx riuscita azzera il contatore.
La consegna avviene almeno una volta, non esattamente una volta. Un arresto anomalo dopo la ricezione può causare un'altra consegna. Rispondi rapidamente dopo aver registrato il lavoro in modo persistente, poi gestisci le operazioni lunghe nella tua coda.
In caso di difficoltà
Una consegna è ancora in attesa
Controlla il certificato HTTPS, la porta 443, l'accessibilità pubblica e la cronologia dei tentativi. Confronta l'identificatore di consegna con quello ricevuto dal tuo server.
La firma viene rifiutata
Controlla di usare il segreto corretto, che l'orologio sia preciso e che tu stia leggendo il corpo grezzo. Riconvertire in testo un JSON già analizzato può modificare gli spazi o l'ordine delle chiavi e invalidare l'HMAC.