Make
Ricevere webhook Blu Pantheon in Make, gestire i limiti della verifica HMAC e chiamare le API con il modulo HTTP.
Make (ex Integromat) è adatto a scenari di orchestrazione rapidi. Ha però un limite importante sulla verifica della firma HMAC che va affrontato esplicitamente prima di andare in produzione.
Prima di iniziare
- Un account Make con piano che consenta i Custom webhook
- La chiave API bp_live_xxxxxxxxxxxxxxxx
- Il segreto whsec_xxxxxxxxxxxxxxxx
- Per la verifica firma: un gateway intermedio oppure il modulo Tools con funzione sha256
Parte 1 — Custom webhook
Crea lo scenario
In Make scegli Create a new scenario. Come primo modulo cerca Webhooks e seleziona Custom webhook.
Configura il webhook
Clicca Add e compila:
| Campo | Valore |
|---|---|
| Webhook name | Blu Pantheon eventi |
| IP restrictions | lascia vuoto salvo indicazioni specifiche |
| Data structure | lascia vuoto per ora |
| JSON pass-through | attivo |
JSON pass-through obbligatorio
Con JSON pass-through attivo Make espone il corpo come stringa nel campo Body, senza
riordinare i campi. È l'unico modo per avere qualcosa di simile al corpo grezzo. Senza questa
opzione la verifica HMAC è impossibile.
Registra l'endpoint in Console
Incolla l'URL nel campo URL, seleziona gli eventi e salva.
Determina la struttura dati
Torna sul modulo webhook e clicca Re-determine data structure. Dalla Console invia un evento
di prova webhook.test. Make analizza il payload e crea la mappatura dei campi.
Ripeti l'operazione per ogni tipo di evento che intendi gestire, perché la struttura di data
varia.
Parte 2 — Verifica della firma
Il limite di Make
Make non dispone di una funzione HMAC nativa. Le funzioni crittografiche disponibili nel
modulo Tools e nelle espressioni si limitano a sha256, md5 e base64. Con sha256
puoi implementare HMAC manualmente, ma il risultato è fragile: gestione dei padding a blocchi,
XOR byte a byte e conversioni esadecimali non sono operazioni pratiche nel motore di espressioni
di Make.
Non saltare la verifica
Non esiste una scorciatoia accettabile. Un endpoint Make senza verifica accetta richieste da chiunque conosca l'URL, che è visibile nella configurazione dello scenario e nei log.
Opzione consigliata: gateway intermedio
Anteponi un piccolo servizio che verifica la firma e inoltra a Make solo le richieste autentiche. È la soluzione più robusta e riutilizzabile.
Blu Pantheon ──► Gateway (Cloudflare Worker) ──► Custom webhook Make
verifica HMAC + 202 elaboraexport default {
async fetch(request, env) {
if (request.method !== 'POST') {
return new Response('Metodo non consentito', { status: 405 });
}
const rawBody = await request.text();
const signatureHeader = request.headers.get('X-BP-Signature') ?? '';
const deliveryId = request.headers.get('X-BP-Delivery') ?? '';
const eventType = request.headers.get('X-BP-Event') ?? '';
let timestamp = null;
const signatures = [];
for (const segment of signatureHeader.split(',')) {
const index = segment.indexOf('=');
if (index === -1) continue;
const key = segment.slice(0, index).trim();
const value = segment.slice(index + 1).trim();
if (key === 't') timestamp = Number(value);
if (key === 'v1') signatures.push(value);
}
if (!Number.isFinite(timestamp)) {
return new Response('timestamp non valido', { status: 400 });
}
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - timestamp) > 300) {
return new Response('timestamp fuori tolleranza', { status: 400 });
}
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(env.BP_WEBHOOK_SECRET),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign'],
);
const signatureBytes = await crypto.subtle.sign(
'HMAC',
key,
new TextEncoder().encode(`${timestamp}.${rawBody}`),
);
const expected = [...new Uint8Array(signatureBytes)]
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('');
const valid = signatures.some((candidate) => {
if (candidate.length !== expected.length) return false;
let diff = 0;
for (let i = 0; i < candidate.length; i += 1) {
diff |= candidate.charCodeAt(i) ^ expected.charCodeAt(i);
}
return diff === 0;
});
if (!valid) {
return new Response('firma non valida', { status: 401 });
}
// Inoltro a Make senza attendere la risposta dello scenario.
const forward = fetch(env.MAKE_WEBHOOK_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-BP-Delivery': deliveryId,
'X-BP-Event': eventType,
},
body: rawBody,
});
request.waitUntil?.(forward);
return new Response(JSON.stringify({ status: 'accettato' }), {
status: 202,
headers: { 'Content-Type': 'application/json' },
});
},
};Configura la variabile BP_WEBHOOK_SECRET come Secret del Worker e MAKE_WEBHOOK_URL come
variabile d'ambiente.
Opzione alternativa: verifica con Tools e sha256
Se non puoi introdurre un gateway, implementa la verifica con moduli Tools → Set variable
usando la costruzione HMAC su due passaggi di sha256. Richiede che il segreto sia lungo al
massimo 64 byte, condizione soddisfatta dai segreti whsec_.
| Ordine | Modulo | Nome variabile | Valore |
|---|---|---|---|
| 1 | Tools → Set variable | rawBody | {{1.Body}} |
| 2 | Tools → Set variable | timestamp | {{split(split(1.Headers.x-bp-signature; ","); "=")}} da normalizzare |
| 3 | Tools → Set variable | signedPayload | {{timestamp}}.{{rawBody}} |
| 4 | Text parser | expected | funzione sha256 applicata secondo lo schema HMAC |
| 5 | Router + Filter | — | prosegue solo se expected coincide con il valore v1 |
Verifica il risultato con un caso noto
Se scegli questa strada, valida l'implementazione con un payload e una firma calcolati
offline tramite openssl dgst -sha256 -hmac. Se i due valori non coincidono esattamente, la
verifica è inutile. Vedi la pagina cURL.
Parte 3 — Controllo del timestamp
Anche con il gateway, aggiungi in Make un Filter anti-replay tra il webhook e il resto dello scenario.
| Campo | Valore |
|---|---|
| Label | Timestamp entro tolleranza |
| Condition | {{abs(timestamp - parseNumber(1.Headers.x-bp-timestamp))}} |
| Operator | Numeric: less than |
| Value | 300 |
Parte 4 — Chiamare le API
Aggiungi il modulo HTTP → Make a request.
| Campo | Valore |
|---|---|
| URL | https://api.blupantheon.com/identity/v1/sessions/{{1.data.sessionId}}/notes |
| Method | POST |
| Headers | vedi tabella |
| Body type | Raw |
| Content type | JSON (application/json) |
| Request content | vedi JSON |
| Parse response | attivo |
| Timeout | 30 |
Headers:
| Name | Value |
|---|---|
Authorization | Bearer bp_live_xxxxxxxxxxxxxxxx |
X-BP-Project | bp_proj_7f3a9c21 |
Idempotency-Key | {{1.Headers.x-bp-delivery}} |
Request content:
{
"body": "Pratica creata nel gestionale: {{5.numeroPratica}}",
"visibility": "internal",
"author": "make"
}Non incollare la chiave nel modulo
Il valore dell'header è visibile a chiunque possa aprire lo scenario. Crea una Connection
di tipo API Key Auth in Connections oppure usa una Custom variable a livello di team
con visibilità ristretta.
Parte 5 — Gestione degli errori
Aggiungi un error handler
Fai clic destro sul modulo HTTP e scegli Add error handler. Make mostra le direttive disponibili.
Scegli la direttiva corretta
| Direttiva | Comportamento | Quando usarla |
|---|---|---|
| Resume | Sostituisce l'output con un valore predefinito e prosegue | Errore non bloccante |
| Ignore | Scarta il bundle e prosegue con il successivo | Evento non rilevante |
| Break | Sposta il bundle in coda incompleta per ritentativo | Errore temporaneo del sistema a valle |
| Rollback | Annulla le operazioni transazionali dello scenario | Scrittura parziale non accettabile |
| Commit | Conferma e chiude l'esecuzione | Raro |
Configura Break con ritentativi
Per gli errori 429 e 5xx usa Break:
| Campo | Valore |
|---|---|
| Number of attempts | 5 |
| Interval (minutes) | 10 |
I bundle finiscono in Incomplete executions e vengono ripresi automaticamente.
Attiva le notifiche
In Scenario settings attiva Allow storing of incomplete executions e imposta le notifiche email su errore in Profile → Notifications.
| Codice ricevuto | Direttiva consigliata |
|---|---|
401 / 403 | Ignore con notifica: è un problema di configurazione, il ritentativo non serve |
409 | Resume leggendo la risorsa esistente |
422 | Ignore con notifica: dato non valido |
429 | Break con intervallo di 10 minuti |
5xx | Break con 5 tentativi |
Procedura di test
Test del gateway
TIMESTAMP="$(date +%s)"
BODY='{"id":"evt_test","event":"webhook.test","apiVersion":"2026-09-01","createdAt":"2026-09-04T09:00:00.000Z","tenantId":"bp_ten_4a91c0e5","projectId":"bp_proj_7f3a9c21","data":{}}'
SIGNATURE="$(printf '%s.%s' "$TIMESTAMP" "$BODY" | openssl dgst -sha256 -hmac "whsec_xxxxxxxxxxxxxxxx" -r | cut -d' ' -f1)"
curl -sS -i -X POST "https://gateway.acme.it/blupantheon" \
-H "Content-Type: application/json" \
-H "X-BP-Event: webhook.test" \
-H "X-BP-Delivery: 11111111-2222-4333-8444-555555555555" \
-H "X-BP-Timestamp: $TIMESTAMP" \
-H "X-BP-Signature: t=$TIMESTAMP,v1=$SIGNATURE" \
--data-raw "$BODY"Attendi 202. Con una firma alterata deve restituire 401.
Test dello scenario
Clicca Run once in Make e invia l'evento di prova dalla Console. Ispeziona i bundle di ogni modulo.
Attiva lo scenario
Imposta lo Scheduling su Immediately as data arrives e attiva lo scenario.
Verifica end-to-end
Genera un evento reale e controlla che la nota compaia in Console e che il conteggio delle operazioni consumate sia coerente con le attese.