Configura i webhook per gli eventi dell'agente
Ricevi una POST firmata sul tuo endpoint https quando il lavoro di un agente termina o fallisce, un agente è in attesa di approvazione o un sito di documentazione viene pubblicato. Eventi, payload, verifica della firma, tentativi e disattivazione automatica.
Un webhook invia una POST firmata al tuo endpoint nel momento in cui accade qualcosa, come il termine del lavoro di un agente o un agente in attesa di approvazione, così i tuoi sistemi non devono eseguire il polling. Questo articolo spiega come aggiungere un endpoint, gli eventi, il payload, la verifica della firma e cosa succede quando gli invii falliscono.
Prima di iniziare
- I webhook sono disponibili nei piani Pro, Business e Custom ("I webhook sono disponibili dal piano Pro in su.").
- Solo il proprietario dello spazio di lavoro e gli amministratori possono gestire i webhook. Gli altri membri visualizzano "Solo i proprietari e gli amministratori possono gestire i webhook".
- Hai bisogno di un indirizzo https pubblico che risponda con uno stato
2xxentro 10 secondi. - Uno spazio di lavoro può avere fino a 10 webhook.
Aggiungi un webhook
Apri la scheda Webhook
Apri il menu dello spazio di lavoro, scegli AI agents & API, quindi apri Webhooks. Clicca su Nuovo webhook.

Ogni webhook mostra i suoi eventi, quando ha inviato l'ultima volta e la fine del suo segreto. Inserisci l'endpoint
- URL endpoint: "Un indirizzo HTTPS pubblico." Ad esempio
https://example.com/clevera/webhooks. - Descrizione: facoltativa, fino a 200 caratteri, ad esempio "Relay Slack".
- URL endpoint: "Un indirizzo HTTPS pubblico." Ad esempio
Scegli gli eventi
Seleziona gli eventi da ricevere, oppure Tutti gli eventi, inclusi quelli nuovi. Gli eventi contrassegnati come Presto sono accettati ma "Nessun evento invia ancora questo tipo di notifica."

Gli eventi contrassegnati come Presto sono accettati ma non ancora inviati. Crealo e salva il segreto
Clicca su Crea webhook. Il Segreto di firma (inizia con
whsec_) viene mostrato una sola volta: "Copialo ora: non lo vedrai più. Usalo per controllare l'intestazione Clevera-Signature." Salvalo come una password, quindi clicca su L'ho salvato.Invia un evento di test
Apri il menu ⋯ del webhook e scegli Invia evento di test. Clevera invia un evento
pingfirmato una volta (senza tentativi). "Evento di test inviato" significa che è partito da Clevera; controlla Invii per vedere la risposta del tuo endpoint.
Eventi
| Evento | Inviato quando |
|---|---|
job.started |
Un lavoro avviato da un agente inizia l'esecuzione. |
job.needs_input |
Un lavoro è in attesa di una persona, ad esempio un'approvazione. Include il link e la scadenza della richiesta. |
job.succeeded |
Il lavoro è terminato. |
job.failed |
Il lavoro è fallito. Include il codice di errore. |
job.canceled |
Il lavoro è stato annullato, oppure la sua approvazione è stata negata o è scaduta. |
approval.requested |
Un agente ha richiesto l'approvazione su Richieste dell'agente. |
approval.decided |
Qualcuno ha approvato o negato la richiesta, o questa è scaduta. |
site.published |
Un sito di documentazione è stato pubblicato. |
site.build_failed |
La pubblicazione di un sito di documentazione è fallita. |
ping |
Hai cliccato su Invia evento di test. Non richiede iscrizione. |
Questi eventi sono elencati come Presto e non ancora inviati: job.progress, video.ready, article.ready, research.completed, insights.weekly.
Gli eventi di lavoro riguardano i lavori avviati dagli agenti (tramite un token API o un'app connessa), non i video avviati dalle persone nell'app.
Cosa invia Clevera
Ogni invio è una POST con un corpo JSON e queste intestazioni:
| Intestazione | Valore |
|---|---|
Content-Type |
application/json |
User-Agent |
Clevera-Webhooks/1.0 |
Clevera-Event |
Il nome dell'evento, come job.succeeded |
Clevera-Delivery |
L'id univoco dell'invio. Un re-invio ripete lo stesso id, quindi usalo per ignorare i duplicati. |
Clevera-Signature |
t=<unix time>,v1=<signature> |
I payload trasportano id, link, stati e numeri, mai il contenuto stesso. Per leggere un video o un articolo terminato, chiama l'API con un token.
{
"id": "6f1c2d3e-4b5a-4c6d-8e9f-0a1b2c3d4e5f",
"event": "job.succeeded",
"created_at": "2026-10-20T14:03:11Z",
"data": {
"job": {
"id": "job_8k2m4n6p8r0t2v4x",
"kind": "video.create",
"status": "succeeded",
"error_code": null,
"subject": { "type": "video", "id": "vid_example" },
"credits_spent": 64
},
"needs_input": null,
"workspace": { "id": "tm_example" }
}
}
{
"id": "0b9a8c7d-6e5f-4a3b-9c2d-1e0f9a8b7c6d",
"event": "approval.requested",
"created_at": "2026-10-20T14:01:02Z",
"data": {
"approval": {
"id": "apr_example",
"kind": "spend",
"status": "pending",
"credits_high": 80,
"expires_at": "2026-10-21T14:01:02Z",
"decided_at": null,
"url": "https://app.clevera.ai/agents?tab=requests&team=tm_example"
},
"job": { "id": "job_8k2m4n6p8r0t2v4x", "kind": "video.create" },
"workspace": { "id": "tm_example" }
}
}
Verifica la firma
Controlla ogni invio prima di considerarlo attendibile. La firma è un HMAC-SHA256, codificato con il tuo segreto di firma, del timestamp, un punto e il corpo della richiesta raw: <t>.<body>.
- Leggi
tev1dall'intestazioneClevera-Signature. - Calcola
HMAC-SHA256(secret, t + "." + rawBody)come esadecimale. - Confrontalo con
v1in tempo costante. - Rifiuta gli invii il cui
tha più di 5 minuti, in modo che una richiesta catturata non possa essere riprodotta.
import crypto from 'node:crypto';
export function verifyClevera(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')));
const t = Number(parts.t);
if (!parts.v1 || !Number.isInteger(t)) return false;
if (Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return expected.length === parts.v1.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
import hashlib, hmac, time
def verify_clevera(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.strip().split("=", 1) for p in header.split(","))
t, v1 = parts.get("t", ""), parts.get("v1", "")
if not t.isdigit() or not v1 or abs(time.time() - int(t)) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, v1)
function verifyClevera(string $rawBody, string $header, string $secret, int $tolerance = 300): bool
{
parse_str(str_replace(',', '&', $header), $parts);
$t = $parts['t'] ?? '';
$v1 = $parts['v1'] ?? '';
if (! ctype_digit($t) || $v1 === '' || abs(time() - (int) $t) > $tolerance) {
return false;
}
return hash_equals(hash_hmac('sha256', $t.'.'.$rawBody, $secret), $v1);
}
Usa il corpo esattamente come ricevuto. Analizzare e ricodificare il JSON prima cambia i byte e la firma non corrisponderà.
Tentativi e fallimenti
Un invio viene considerato consegnato quando il tuo endpoint risponde con uno stato 2xx. Qualsiasi altra risposta fa fallire il tentativo:
- qualsiasi altro stato, inclusi i reindirizzamenti (i
3xxnon vengono seguiti); - nessuna risposta entro 10 secondi (5 secondi per connettersi);
- un indirizzo che non viene più risolto su internet pubblico.
Clevera riprova un invio fallito 5 volte, dopo 1 minuto, 5 minuti, 30 minuti, 2 ore e 6 ore. Il corpo della risposta del tuo endpoint non viene mai letto.
Quando 15 invii consecutivi falliscono ogni tentativo, il webhook viene disattivato: "Disattivato dopo 15 invii falliti consecutivi. Correggi l'endpoint, quindi attivalo." Il proprietario e gli amministratori ricevono una notifica "Webhook verso host disattivato": "I suoi invii continuavano a fallire. Correggi l'endpoint, quindi riattivalo." Gli eventi che si verificano mentre è disattivato non vengono inviati. Gli eventi di test non contano ai fini di questo limite.
Gestisci un webhook
Clicca su Invii su un webhook per vedere il suo log, o apri il suo menu ⋯ per le altre opzioni:
| Opzione | Cosa fa |
|---|---|
| Modifica | Cambia l'URL, gli eventi o la descrizione. |
| Invii | Gli ultimi 100 invii con il loro stato (Consegnato, Non riuscito, In invio), Tentativi e il codice HTTP. Re-invia ne invia uno di nuovo. Gli invii vengono conservati per 30 giorni. |
| Invia evento di test | Invia un ping firmato. |
| Rigenera segreto | "Gli invii vengono firmati subito con il nuovo segreto. Aggiorna il tuo endpoint per verificarlo." Non c'è sovrapposizione, quindi aggiorna il tuo endpoint subito dopo. |
| Disattiva / Attiva | Mette in pausa e riprende gli invii. |
| Elimina | "Smettiamo di inviare eventi e eliminiamo il log degli invii. Questa operazione non può essere annullata." |
Se lo spazio di lavoro lascia il piano Pro
I webhook rimangono elencati e possono ancora essere modificati ed eliminati, ma non viene inviato nulla. Gli invii in attesa di un nuovo tentativo terminano come falliti con plan_locked, e Invia evento di test e Re-invia indicano "I webhook non sono inclusi nel tuo piano." L'aggiornamento al piano Pro riprende l'invio; nulla viene eliminato.
Risoluzione dei problemi
| Messaggio | Causa | Soluzione |
|---|---|---|
| "I webhook non sono inclusi nel tuo piano." | Lo spazio di lavoro non è nel piano Pro, Business o Custom. | Esegui l'upgrade a Pro. |
| "Usa un indirizzo https://." | L'URL inizia con http://. |
Servi l'endpoint tramite HTTPS. |
| "Usa un nome host, non un indirizzo IP." | L'URL usa un indirizzo IP. | Usa un nome di dominio. |
| "Questo indirizzo non è raggiungibile su internet pubblico." | L'host risolve in un indirizzo privato o locale. | Usa un endpoint pubblico o un relay. |
| "Rimuovi il nome utente e la password dall'indirizzo." | L'URL ha user:password@. |
Rimuovili; controlla invece la firma. |
| "Inserisci un indirizzo web valido." | L'URL non è valido. | Controlla eventuali errori di battitura. |
| "Scegli almeno un evento." | Nessun evento selezionato. | Seleziona almeno un evento. |
| "Questo spazio di lavoro ha già 10 webhook." | Il limite dello spazio di lavoro. | Elimina quello che non usi. |
| "Attiva prima il webhook." | Hai provato a re-inviare su un webhook disattivato. | Attivalo, quindi re-invia. |
| "Questo invio è ancora in fase di invio." | L'invio sta ancora riprovando. | Attendi che finisca. |
| Gli invii falliscono con un codice HTTP | Il tuo endpoint ha risposto con un errore. | Controlla i log del tuo endpoint e assicurati che restituisca 2xx rapidamente; esegui operazioni lente dopo aver risposto. |
| Le firme non corrispondono mai | Il corpo è stato modificato prima del controllo, o il segreto è vecchio. | Verifica rispetto al corpo raw; rigenera il segreto se non sei sicuro. |