Trigger
Riferimento completo di ogni trigger dei Flussi di lavoro automatizzati di Certivant — quando si attiva ciascun evento, il suo contesto dati, esempi di payload, configurazione di soggetto e ambito e schemi di filtro DSL.
Un trigger è il singolo nodo di ingresso di ogni Flusso di lavoro automatizzato. Dichiara quale evento avvia il workflow, a quali oggetti quell'evento deve riferirsi (il soggetto + l'ambito) e un filtro facoltativo che restringe ulteriormente gli eventi idonei. Quando la piattaforma emette un evento corrispondente, viene creata una KycWorkflowRun e il workflow viene eseguito nodo per nodo.
Questa pagina documenta ogni trigger che il motore emette effettivamente, basandosi sui punti di emissione della piattaforma. Ogni voce indica quando si attiva, il context esatto che trasporta, un payload di esempio reale e come limitarlo e filtrarlo.
Il catalogo dei trigger è un enum fisso nel motore (
WorkflowTriggerEvent). Il selettore dell'editor, questa pagina, lo schema di validazione dell'API e il dispatcher leggono tutti dalla stessa lista, quindi ogni trigger che può selezionare è un trigger che la piattaforma emette davvero — nessuno è decorativo. Alcune funzioni che non hanno ancora un punto di emissione sono volutamente escluse dal selettore e riportate in Trigger previsti con l'alternativa funzionante, così non si costruisce mai un workflow che non verrà eseguito in silenzio.
Come si attivano i trigger
I trigger non vengono interrogati periodicamente. Ciascuno corrisponde a un punto reale della piattaforma in cui il codice chiama il dispatcher:
emitter (API route / worker / cron)
└─ enqueueWorkflowDispatch({ organizationId, event, kycRequestId?, …, context })
└─ workflow.worker → dispatchWorkflowEvent(input)
├─ load active workflows whose trigger.event === input.event
├─ narrow by subject + scope (form / applicant / document / check)
├─ evaluate the optional DSL filter (against input.context)
└─ create + run a KycWorkflowRun per match
Per chi integra sono importanti tre proprietà:
- Fire-and-forget. L'invio è racchiuso in modo che un errore non interrompa mai l'azione di origine. Se il caricamento di un documento attiva un workflow e l'invio fallisce, il caricamento va comunque a buon fine. Consideri gli effetti collaterali dei workflow come eseguiti in modo eventuale, non in modo sincrono con la chiamata API.
- Un evento, molte esecuzioni. Un singolo evento può avviare ogni workflow attivo che gli corrisponde. Usi soggetto + ambito (e filtri) per mantenere intenzionale questa diramazione.
- Il contesto viene catturato una sola volta. L'oggetto
contextdell'evento viene salvato nella prima voce di log dell'esecuzione. I nodi Condizione, i modelli delle Azioni e i segnaposto per la stampa unione leggono da quell'istantanea — non interrogano di nuovo lo stato attuale.
La busta dell'invio
Ogni emissione produce un WorkflowEventInput. Oltre a organizationId ed event, i campi sono facoltativi e dipendono dall'evento:
| Campo | Tipo | Presente quando |
|---|---|---|
organizationId | stringa | sempre |
event | WorkflowTriggerEvent | sempre |
kycRequestId | stringa | null | l'evento riguarda una verifica specifica (la maggior parte degli eventi) |
formId | stringa | null | form.submitted |
formKind | "kyc" | "kyb" | null | form.submitted |
applicantId | stringa | null | eventi legati a un richiedente |
documentType | stringa | null | document.* |
checkKind | stringa | null | check.completed, liveness.*, sanctions.* |
context | oggetto | fatti specifici dell'evento (vedi ogni trigger sotto) |
workflowId | stringa | solo in un'invocazione diretta da trigger_workflow |
chainDepth | numero | profondità della catena workflow-a-workflow (massimo 5) |
subject, scope, filter, formIds, schedule, scoreMin e scoreMax sono proprietà del trigger che configura — non dell'evento in esecuzione. Il dispatcher li usa per decidere se un evento in arrivo corrisponde al suo workflow.
La definizione del trigger
Questa è la struttura salvata nel trigger di un workflow (WorkflowTrigger):
interface WorkflowTrigger {
event: WorkflowTriggerEvent; // which event starts the workflow
subject?: "form" | "applicant" // the kind of object it binds to
| "document" | "check"; // (absent → legacy org-wide)
scope?: {
mode: "specific" | "category" | "all";
ids?: string[]; // specific-mode object ids
category?: string; // category-mode key (see below)
};
filter?: string; // optional DSL predicate over context
formIds?: string[]; // legacy form-binding (pre-subject)
schedule?: string; // schedule only — cron expression
scoreMin?: number; // score.threshold convenience bound
scoreMax?: number; // score.threshold convenience bound
}
Soggetto + ambito
Il soggetto è il tipo di oggetto che il trigger osserva; l'ambito lo restringe a oggetti specifici, a una categoria o a tutti. È ciò che impedisce a un trigger di attivarsi per errore su tutta l'organizzazione.
| Soggetto | Eventi validi | Modalità di scope.mode | Significato di category |
|---|---|---|---|
form | form.submitted | specific (id dei moduli) · category · all | "kyc" oppure "kyb" |
applicant | request.*, score.threshold, edd.triggered, verification.expired | specific (id dei richiedenti) · all | — |
document | document.uploaded, document.failed | specific · category · all | un tipo di documento, per esempio "passport" |
check | check.completed, liveness.*, sanctions.* | specific · category · all | un tipo di controllo, per esempio "sanctions" |
| (nessuno) | schedule, inbound.webhook, monitoring.alert, kyb.*, reviewer.decision, conference.completed | — | a livello di organizzazione |
Modalità di ambito:
specific— corrisponde solo agliidselencati (per esempio si attiva solo per questo modulo di onboarding). Se ogni id di un ambitospecificpunta a un oggetto eliminato, il trigger è orfano: il dispatcher si rifiuta di attivarlo (resta inattivo invece di ripiegare silenziosamente su "tutti"), e l'editor mostra un badge "Richiede una nuova associazione".category— corrisponde a una classe di oggetti (tutti i moduli KYC, tutti i passaporti, tutti i controlli sanzioni).all— corrisponde a qualsiasi oggetto del tipo di soggetto nell'organizzazione.
Un trigger senza subject mantiene il comportamento precedente: a livello di organizzazione, eventualmente ristretto da formIds per form.submitted. I nuovi workflow dovrebbero sempre impostare un soggetto + un ambito.
Filtro (DSL)
filter è un predicato booleano facoltativo, con la stessa grammatica delle espressioni del DSL delle politiche decisionali. Viene eseguito sul context dell'evento. Un filtro vuoto si attiva per ogni evento di quel tipo. Vedi Filtrare con il DSL.
Categorie di trigger
| Categoria | Trigger |
|---|---|
| Ingresso | form.submitted, request.created |
| Ciclo di vita / stato | request.status_changed, request.approved, request.rejected, request.escalated, request.resubmitted, request.documents_ready |
| Documenti | document.uploaded, document.failed |
| Segnali di verifica | check.completed, liveness.passed, liveness.failed, face_match.passed, face_match.failed, sanctions.hit, sanctions.cleared, pep.match, kyb.match_found, kyb.match_not_found, kyb.ubo_completed |
| Revisione umana | reviewer.decision, reviewer.assigned, reviewer.comment_added, edd.triggered |
| Rischio / punteggio | score.threshold, score.updated |
| Tempo / monitoraggio | schedule, verification.expired, monitoring.alert |
| Esterni / integrazioni | inbound.webhook, conference.completed |
Riferimento dei trigger
Ogni voce qui sotto usa la stessa struttura: Quando si attiva, Contesto dei dati, Evento di esempio e Esempio di utilizzo nel workflow. Ogni payload è la forma reale dell'invio prodotta dal codice che emette l'evento.
Ingresso
form.submitted
"Un modulo viene inviato" · soggetto form
Quando si attiva. Un modulo di verifica pubblico e ospitato viene inviato da un richiedente. Emesso dalla route dei moduli pubblici nel momento in cui un invio crea il suo KycRequest. L'evento complementare request.created viene emesso insieme ad esso.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
type | stringa | Tipo di richiedente al momento dell'invio, per esempio "INDIVIDUAL" |
Al primo livello: formId, formKind ("kyc"/"kyb"), kycRequestId, applicantId.
Evento di esempio.
{
"organizationId": "org_01H...",
"event": "form.submitted",
"kycRequestId": "req_01J...",
"formId": "form_01H...",
"formKind": "kyc",
"context": { "type": "INDIVIDUAL" }
}
Esempio di utilizzo nel workflow. Colleghi un workflow di email di benvenuto + richiesta documenti a un solo modulo di onboarding specifico:
trigger:
event: form.submitted
subject: form
scope: { mode: specific, ids: ["form_01H..."] }
request.created
"Una verifica viene creata" · soggetto applicant
Quando si attiva. Viene creata una richiesta di verifica — tramite POST /api/v1/kyc/requests (201) oppure come complemento a un form.submitted ospitato. Si attiva prima che venga caricato un documento o che venga eseguito un controllo, quindi usatelo per l'instradamento in ingresso, non per gli esiti.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
applicant.country | stringa | null | ISO-3166 alpha-2, dalla cittadinanza del richiedente |
applicant.type | stringa | "INDIVIDUAL" oppure "BUSINESS" |
type | stringa | Tipo di richiesta (INDIVIDUAL / BUSINESS) |
Evento di esempio.
{
"organizationId": "org_01H...",
"event": "request.created",
"kycRequestId": "req_01J...",
"applicantId": "app_01J...",
"context": {
"applicant": { "country": "CA", "type": "INDIVIDUAL" },
"type": "INDIVIDUAL"
}
}
Esempio di utilizzo nel workflow. Instradi i richiedenti aziendali verso una coda di acquisizione KYB:
trigger:
event: request.created
subject: applicant
scope: { mode: all }
filter: 'applicant.type = "BUSINESS"'
Ciclo di vita / stato
Questi si attivano dopo che l'orchestrazione ha finalizzato un verdetto. Trasportano tutti lo stesso contesto di decisione. Gli eventi specifici (approved/rejected/escalated) si attivano in aggiunta al request.status_changed generico: si ascolti uno dei due — non entrambi — per evitare un'esecuzione doppia.
Contesto dei dati condiviso (request.approved, request.rejected, request.escalated, request.status_changed):
| Campo | Tipo | Note |
|---|---|---|
status | stringa | Nuovo stato, per esempio "APPROVED", "REJECTED", "ESCALATED", "PENDING_SECOND_REVIEW" |
decision | stringa | null | Verdetto del motore di scoring: "approve" / "reject" / "escalate" |
overallScore | numero | null | Punteggio di affidabilità 0–100 (più alto = rischio più basso) |
applicant.country | stringa | null | ISO-3166 alpha-2 |
applicant.type | stringa | INDIVIDUAL / BUSINESS |
request.approved
"Una verifica viene approvata" · soggetto applicant
Quando si attiva. L'orchestrazione finalizza la richiesta come APPROVED.
{
"organizationId": "org_01H...",
"event": "request.approved",
"kycRequestId": "req_01J...",
"applicantId": "app_01J...",
"context": {
"status": "APPROVED",
"decision": "approve",
"overallScore": 88,
"applicant": { "country": "US", "type": "INDIVIDUAL" }
}
}
Esempio di utilizzo nel workflow. Generi e invii via email un report di verifica solo per le approvazioni ad alta affidabilità:
trigger:
event: request.approved
subject: applicant
scope: { mode: all }
filter: 'overallScore >= 80'
request.rejected
"Una verifica viene rifiutata" · soggetto applicant
Quando si attiva. L'orchestrazione finalizza la richiesta come REJECTED. Contesto identico a request.approved, con status: "REJECTED", decision: "reject".
Esempio di utilizzo nel workflow. Avvisi il manager assegnato e marchi il richiedente in caso di rifiuto:
trigger:
event: request.rejected
subject: applicant
scope: { mode: all }
request.escalated
"Una verifica viene inoltrata" · soggetto applicant
Quando si attiva. L'orchestrazione (oppure un'azione escalate di un workflow precedente) sposta la richiesta in ESCALATED / revisione umana. Contesto identico alla forma condivisa, con status: "ESCALATED".
Esempio di utilizzo nel workflow. Pianifichi una conferenza Live ID ogni volta che una richiesta viene inoltrata:
trigger:
event: request.escalated
subject: applicant
scope: { mode: all }
request.status_changed
"Lo stato di una verifica cambia" · soggetto applicant
Quando si attiva. Viene sempre emesso a una variazione di stato finalizzata, insieme a qualsiasi evento di decisione specifico. Lo usi per reagire a stati che non hanno un evento dedicato (per esempio PENDING_SECOND_REVIEW, CANCELLED).
Esempio di utilizzo nel workflow. Reagisca solo al passaggio di consegne tra due revisori:
trigger:
event: request.status_changed
subject: applicant
scope: { mode: all }
filter: 'status = "PENDING_SECOND_REVIEW"'
request.resubmitted
"Una verifica viene reinviata" · soggetto applicant
Quando si attiva. Un revisore rimanda una richiesta per il reinvio dalla dashboard; la richiesta torna in PENDING_UPLOAD.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
status | stringa | "PENDING_UPLOAD" |
kind | stringa | "resubmit" |
{
"organizationId": "org_01H...",
"event": "request.resubmitted",
"kycRequestId": "req_01J...",
"context": { "status": "PENDING_UPLOAD", "kind": "resubmit" }
}
Esempio di utilizzo nel workflow. Reinvii al richiedente il link per il caricamento e avvii un timer di promemoria.
request.documents_ready
"Tutti i documenti richiesti sono caricati" · soggetto applicant
Quando si attiva. Il richiedente ha appena caricato l'ultimo elemento della checklist dei documenti richiesti, quindi la richiesta passa in DOCUMENTS_READY. Emesso da entrambi i percorsi di caricamento — l'API documentale della dashboard e la sessione di verifica ospitata — solo sul caricamento che svuota l'insieme dei documenti in sospeso. È il segnale concreto di "il richiedente ha completato ogni passo richiesto".
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
status | stringa | "DOCUMENTS_READY" |
{
"organizationId": "org_01H...",
"event": "request.documents_ready",
"kycRequestId": "req_01J...",
"context": { "status": "DOCUMENTS_READY" }
}
Esempio di utilizzo nel workflow. Avvisi il revisore assegnato nel momento in cui una pratica è pronta per la revisione:
trigger:
event: request.documents_ready
subject: applicant
scope: { mode: all }
Documenti
document.uploaded
"Un documento viene caricato" · soggetto document
Quando si attiva. Ogni volta che viene caricato un documento — tramite l'API della dashboard oppure una sessione di verifica ospitata. Un evento per ogni documento.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
document.type | stringa | per esempio "passport", "id_card", "drivers_license" |
document.side | stringa | null | "front" / "back" (null quando non applicabile) |
Al primo livello: documentType, kycRequestId.
{
"organizationId": "org_01H...",
"event": "document.uploaded",
"kycRequestId": "req_01J...",
"documentType": "passport",
"context": { "document": { "type": "passport", "side": "front" } }
}
Esempio di utilizzo nel workflow. Si attivi solo sui caricamenti della prova di residenza:
trigger:
event: document.uploaded
subject: document
scope: { mode: category, category: "utility_bill" }
document.failed
"Un documento non supera la validazione" · soggetto document
Quando si attiva. L'orchestrazione segna un documento come failed (l'OCR non è potuto essere eseguito, l'autenticità è stata respinta, ecc.). Un evento per ogni documento non riuscito. La stessa forma di contesto di document.uploaded.
{
"organizationId": "org_01H...",
"event": "document.failed",
"kycRequestId": "req_01J...",
"documentType": "drivers_license",
"context": { "document": { "type": "drivers_license", "side": "back" } }
}
Esempio di utilizzo nel workflow. Richieda automaticamente una nuova acquisizione di ogni documento non riuscito.
Segnali di verifica
check.completed
"Un controllo di verifica si completa" · soggetto check
Quando si attiva. Una volta per ogni singolo controllo che termina durante un'esecuzione dell'orchestrazione (OCR, confronto del volto, vivacità, sanzioni, autenticità del documento, lettura NFC…). È il segnale generico e ad alta frequenza — per un esito chiaro preferisca liveness.* / sanctions.*.
Diramazione protetta. Poiché più controlli terminano per ogni richiesta, la piattaforma chiede prima se l'organizzazione ha almeno un workflow attivo in ascolto di
check.completed. Senza ascoltatori non vengono creati job di invio. Il segno di avanzamento per esecuzione impedisce che una nuova verifica riemetta i controlli di un'esecuzione precedente.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
check.type | stringa | Tipo di controllo, per esempio "sanctions", "face_match", "ocr" |
check.status | stringa | "passed" / "failed" / "error" |
check.provider | stringa | null | Fornitore che ha eseguito il controllo |
check.score | numero | null | Punteggio del fornitore, dove applicabile |
Al primo livello: checkKind, kycRequestId.
{
"organizationId": "org_01H...",
"event": "check.completed",
"kycRequestId": "req_01J...",
"checkKind": "face_match",
"context": {
"check": { "type": "face_match", "status": "passed",
"provider": "azure_face", "score": 0.93 }
}
}
Esempio di utilizzo nel workflow. Reagisca al completamento di qualsiasi controllo sanzioni, indipendentemente dall'esito (per un passa/fallisci netto preferisca gli eventi dedicati sanctions.* / face_match.* qui sotto):
trigger:
event: check.completed
subject: check
scope: { mode: category, category: "sanctions" }
liveness.passed / liveness.failed
"Vivacità superata" / "Vivacità non superata" · soggetto check (
liveness)
Quando si attiva. Dopo l'orchestrazione, quando il controllo di vivacità ha salvato un booleano isLive non ambiguo. passed quando isLive è vero, failed quando è falso. Un controllo di vivacità in errore o ambiguo non emette nessuno dei due.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
liveness.isLive | booleano | Se il richiedente ha superato la vivacità |
liveness.confidence | numero | null | Confidenza 0–1 |
{
"organizationId": "org_01H...",
"event": "liveness.failed",
"kycRequestId": "req_01J...",
"checkKind": "liveness",
"context": { "liveness": { "isLive": false, "confidence": 0.31 } }
}
Esempio di utilizzo nel workflow. Inoltri in caso di mancata vivacità con bassa confidenza:
trigger:
event: liveness.failed
subject: check
scope: { mode: all }
filter: 'liveness.confidence < 0.5'
face_match.passed / face_match.failed
"Confronto del volto superato" / "Confronto del volto non superato" · soggetto check (
face_match)
Quando si attiva. Dopo l'orchestrazione, quando il controllo di confronto del volto (selfie ↔ ritratto del documento) ha salvato un booleano isMatch non ambiguo. passed quando isMatch è vero, failed quando è falso. Un controllo in errore o ambiguo non emette nessuno dei due.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
faceMatch.isMatch | booleano | Se il selfie corrisponde al volto del documento |
faceMatch.confidence | numero | null | Confidenza 0–1 |
{
"organizationId": "org_01H...",
"event": "face_match.failed",
"kycRequestId": "req_01J...",
"checkKind": "face_match",
"context": { "faceMatch": { "isMatch": false, "confidence": 0.42 } }
}
Esempio di utilizzo nel workflow. Inoltri ogni mancato confronto del volto per una revisione manuale:
trigger:
event: face_match.failed
subject: check
scope: { mode: all }
sanctions.hit / sanctions.cleared
"Riscontro nelle sanzioni" / "Sanzioni escluse" · soggetto check (
sanctions)
Quando si attiva. Dopo l'orchestrazione, dal risultato salvato di sanzioni/liste di controllo. hit quando una corrispondenza raggiunge la soglia (oppure quando è presente una corrispondenza qualsiasi); cleared altrimenti. Una corrispondenza che riguarda specificamente una persona politicamente esposta attiva anche l'evento dedicato pep.match, quindi lo ascolti quando le interessa solo l'esposizione PEP.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
sanctions.isMatch | booleano | Vero in caso di riscontro |
sanctions.matchCount | numero | Numero di corrispondenze nelle liste |
sanctions.topScore | numero | null | Punteggio della corrispondenza più forte, 0–1 |
sanctions.listsChecked | stringa[] | Liste verificate (OFAC, OpenSanctions, …) |
{
"organizationId": "org_01H...",
"event": "sanctions.hit",
"kycRequestId": "req_01J...",
"checkKind": "sanctions",
"context": {
"sanctions": { "isMatch": true, "matchCount": 2, "topScore": 0.91,
"listsChecked": ["OFAC", "OpenSanctions"] }
}
}
Esempio di utilizzo nel workflow. Inoltri e avvisi la compliance in caso di riscontro forte nelle sanzioni:
trigger:
event: sanctions.hit
subject: check
scope: { mode: all }
filter: 'sanctions.topScore >= 0.85'
pep.match
"Trovata una corrispondenza PEP" · soggetto check (
sanctions)
Quando si attiva. Dopo l'orchestrazione, quando il risultato di sanzioni/liste di controllo contiene almeno una corrispondenza il cui tipo di entità è una persona politicamente esposta. Si basa sullo stesso screening di sanctions.*, ma si attiva solo quando è presente una voce PEP — un semplice riscontro in lista senza voci PEP non lo attiva.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
pep.isMatch | booleano | Sempre true (l'evento si attiva solo per una corrispondenza PEP) |
pep.matchCount | numero | Numero di corrispondenze PEP |
{
"organizationId": "org_01H...",
"event": "pep.match",
"kycRequestId": "req_01J...",
"checkKind": "sanctions",
"context": { "pep": { "isMatch": true, "matchCount": 1 } }
}
Esempio di utilizzo nel workflow. Avvii automaticamente la Due Diligence Rafforzata (EDD) e instradi alla compliance ogni volta che viene rilevata una PEP:
trigger:
event: pep.match
subject: check
scope: { mode: all }
kyb.match_found / kyb.match_not_found
"Trovata una corrispondenza aziendale KYB" / "Corrispondenza KYB non trovata" · a livello di organizzazione
Quando si attiva. Solo per richieste BUSINESS, dopo che l'orchestrazione scrive il risultato della verifica nel registro delle imprese. verified → kyb.match_found; failed → kyb.match_not_found. Qualsiasi altro stato (in attesa/assente) è ambiguo e non emette nulla.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
kyb.status | stringa | "verified" oppure "failed" |
{
"organizationId": "org_01H...",
"event": "kyb.match_not_found",
"kycRequestId": "req_01J...",
"context": { "kyb": { "status": "failed" } }
}
Esempio di utilizzo nel workflow. Richieda documenti di costituzione aggiuntivi quando non viene trovata alcuna corrispondenza nel registro.
kyb.ubo_completed
"Verifica dei titolari effettivi completata" · a livello di organizzazione
Quando si attiva. Solo per richieste BUSINESS, dopo che l'orchestrazione ha risolto ogni record di titolare effettivo (UBO) dell'azienda (nessuno rimasto pending). Trasporta il numero di UBO sottoposti a screening e quanti hanno fallito, così un workflow può ramificarsi in base al rischio UBO senza interrogare di nuovo. Si attiva solo quando l'azienda ha davvero dei record UBO e la riga KYB è stata toccata in questa esecuzione.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
kyb.uboCount | numero | Numero di titolari effettivi sottoposti a screening |
kyb.failedUboCount | numero | Quanti di questi UBO non hanno superato la verifica |
{
"organizationId": "org_01H...",
"event": "kyb.ubo_completed",
"kycRequestId": "req_01J...",
"context": { "kyb": { "uboCount": 3, "failedUboCount": 1 } }
}
Esempio di utilizzo nel workflow. Inoltri quando un titolare effettivo non supera lo screening:
trigger:
event: kyb.ubo_completed
filter: 'kyb.failedUboCount > 0'
Revisione umana
reviewer.decision
"Un revisore prende una decisione manuale" · a livello di organizzazione
Quando si attiva. Un revisore umano registra una decisione manuale nella dashboard — approvazione singola, una delle due fasi di un flusso a due revisori, oppure un'azione di massa.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
decision | stringa | La scelta del revisore |
reviewerId | stringa | ID del revisore che decide |
stage | stringa | undefined | "first_approval" / "second_approval" nei flussi a due revisori |
via | stringa | undefined | "bulk" quando fa parte di un'azione di massa |
{
"organizationId": "org_01H...",
"event": "reviewer.decision",
"kycRequestId": "req_01J...",
"context": { "decision": "approve", "reviewerId": "usr_01H...",
"stage": "second_approval" }
}
Esempio di utilizzo nel workflow. Registri nel log di audit ogni decisione manuale e avvisi il richiedente dopo un'approvazione finale (la seconda).
reviewer.assigned
"Una richiesta viene assegnata a un revisore" · a livello di organizzazione
Quando si attiva. Una richiesta viene riassegnata a un nuovo titolare/revisore tramite l'azione di riassegnazione della dashboard. Il titolare iniziale impostato alla creazione della richiesta non attiva questo evento — lo attiva solo una riassegnazione esplicita, quindi l'evento segnala un vero cambio di instradamento.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
assignedUserId | stringa | Il nuovo titolare/revisore |
previousUserId | stringa | null | Il titolare precedente |
teamId | stringa | null | Il team a cui la richiesta ora appartiene |
{
"organizationId": "org_01H...",
"event": "reviewer.assigned",
"kycRequestId": "req_01J...",
"context": { "assignedUserId": "usr_new...", "previousUserId": "usr_old...",
"teamId": "team_01H..." }
}
Esempio di utilizzo nel workflow. Invii al revisore appena assegnato una notifica con un link diretto alla pratica.
reviewer.comment_added
"Un revisore aggiunge un commento" · a livello di organizzazione
Quando si attiva. Un revisore pubblica un commento su una pratica (il flusso dei commenti della pratica). Il corpo del commento non viene intenzionalmente inserito nel contesto dell'evento — può contenere note sensibili — quindi l'evento trasporta solo i metadati.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
commentId | stringa | ID del commento creato |
authorId | stringa | Il revisore che ha commentato |
authorName | stringa | Nome visualizzato dell'autore |
{
"organizationId": "org_01H...",
"event": "reviewer.comment_added",
"kycRequestId": "req_01J...",
"context": { "commentId": "cmt_01J...", "authorId": "usr_01H...",
"authorName": "Jordan Lee" }
}
Esempio di utilizzo nel workflow. Ricopi i nuovi commenti della pratica in un canale Slack per il team di compliance.
edd.triggered
"Viene avviata la Due Diligence Rafforzata (EDD)" · soggetto applicant
Quando si attiva. La Due Diligence Rafforzata (EDD) viene avviata per una richiesta (attualmente tramite l'azione EDD manuale).
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
kind | stringa | "edd" |
{
"organizationId": "org_01H...",
"event": "edd.triggered",
"kycRequestId": "req_01J...",
"context": { "kind": "edd" }
}
Esempio di utilizzo nel workflow. All'avvio della EDD, richieda documenti sull'origine dei fondi e assegni la pratica al reparto compliance.
Rischio / punteggio
Entrambi gli eventi di punteggio si attivano dal percorso di decisione, una volta che lo scorer ha scritto un punteggio di affidabilità per l'esecuzione (una richiesta che si finalizza senza punteggio — per esempio annullata prima dello scoring — non emette nessuno dei due). Trasportano l'intero contesto di decisione, quindi overallScore, decision, status e applicant.* sono tutti disponibili per i filtri.
score.updated
"Il punteggio di affidabilità viene aggiornato" · soggetto applicant
Quando si attiva. A ogni finalizzazione con (ri)calcolo del punteggio — inclusa una rianalisi che ricalcola il punteggio. Lo usi per reagire al nuovo punteggio di affidabilità indipendentemente dal verdetto.
Contesto dei dati. Il contesto di decisione condiviso (overallScore, decision, status, applicant.country, applicant.type).
{
"organizationId": "org_01H...",
"event": "score.updated",
"kycRequestId": "req_01J...",
"applicantId": "app_01J...",
"context": {
"status": "APPROVED",
"decision": "approve",
"overallScore": 72,
"applicant": { "country": "CA", "type": "INDIVIDUAL" }
}
}
Esempio di utilizzo nel workflow. Contrassegni ogni richiesta il cui punteggio cade in una fascia di revisione manuale:
trigger:
event: score.updated
subject: applicant
scope: { mode: all }
filter: 'overallScore >= 50 AND overallScore < 70'
score.threshold
"Il punteggio di affidabilità supera una soglia" · soggetto applicant
Quando si attiva. Stesso punto di emissione di score.updated, ma il dispatcher lo restringe in base ai limiti scoreMin / scoreMax del trigger stesso (legge context.overallScore). Imposti i limiti sul trigger e il workflow viene eseguito solo quando il punteggio rientra in essi — una comodità rispetto a scrivere a mano un filtro su overallScore.
Contesto dei dati. Identico a score.updated.
{
"organizationId": "org_01H...",
"event": "score.threshold",
"kycRequestId": "req_01J...",
"applicantId": "app_01J...",
"context": {
"status": "REJECTED",
"decision": "reject",
"overallScore": 38,
"applicant": { "country": "US", "type": "INDIVIDUAL" }
}
}
Esempio di utilizzo nel workflow. Si esegua solo per i punteggi bassi impostando un limite superiore sul trigger:
trigger:
event: score.threshold
subject: applicant
scope: { mode: all }
scoreMax: 50 # fire only when overallScore <= 50
scoreMin/scoreMaxsono inclusivi. Ne imposti uno o entrambi. Se non ne imposta nessuno,score.thresholdsi comporta comescore.updated.
Tempo / monitoraggio
schedule
"Secondo una pianificazione" · a livello di organizzazione, non legato a una richiesta
Quando si attiva. Secondo l'espressione cron del workflow stesso (impostata nel campo schedule del trigger). L'esecuzione è a livello di organizzazione — kycRequestId è null — quindi lo usi per lavori batch o di manutenzione, non per una logica per singolo richiedente.
Il cron è un'espressione standard a 5 campi (minuto ora giorno mese giorno-della-settimana) valutata in UTC e non può attivarsi più spesso di ogni 5 minuti: la pubblicazione rifiuta * * * * * o */2 * * * *.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
firedAt | stringa | Momento di attivazione in ISO-8601 |
cron | stringa | L'espressione cron che si è attivata |
{
"organizationId": "org_01H...",
"event": "schedule",
"kycRequestId": null,
"context": { "firedAt": "2026-05-31T09:00:00.000Z", "cron": "0 9 * * 1" }
}
Esempio di utilizzo nel workflow. Ogni lunedì alle 09:00 genera un riepilogo settimanale delle verifiche e lo pubblica su Slack:
trigger:
event: schedule
schedule: "0 9 * * 1"
verification.expired
"Una verifica scade" · soggetto applicant
Quando si attiva. Dal cron di scadenza, quando una richiesta supera la propria finestra di validità.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
status | stringa | "EXPIRED" |
{
"organizationId": "org_01H...",
"event": "verification.expired",
"kycRequestId": "req_01J...",
"context": { "status": "EXPIRED" }
}
Esempio di utilizzo nel workflow. Invii al richiedente un nuovo link via email e avvisi il titolare quando una verifica scade.
monitoring.alert
"Scatta un avviso di monitoraggio" · a livello di organizzazione
Quando si attiva. Dal nuovo screening continuo delle sanzioni, quando un soggetto già escluso trova una nuova corrispondenza in una lista di controllo (monitoraggio continuo).
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
alertType | stringa | Il tipo di avviso di monitoraggio |
severity | stringa | Gravità dell'avviso |
topScore | numero | null | Punteggio della nuova corrispondenza più forte |
{
"organizationId": "org_01H...",
"event": "monitoring.alert",
"kycRequestId": "req_01J...",
"context": { "alertType": "sanctions_rescreen", "severity": "high",
"topScore": 0.88 }
}
Esempio di utilizzo nel workflow. Su un avviso di monitoraggio di gravità alta, inoltri la richiesta e apra una pratica di compliance.
Esterni / integrazioni
inbound.webhook
"Arriva un webhook in ingresso" · a livello di organizzazione, payload arbitrario
Quando si attiva. Il Suo sistema invia una POST all'endpoint dei webhook in ingresso del workflow. Il context è il JSON che invia, quindi controlla interamente la sua forma. Non è legato a una richiesta, a meno che il payload non fornisca un ID che il workflow usa.
Endpoint. POST /api/v1/kyc/workflows/inbound, autenticato con una chiave API che ha lo scope workflows:trigger. Nessuno scope kyc:* lo include: selezioni Workflow di automazione → Attivare quando crea o modifica la chiave. Il Suo piano deve includere i workflow di automazione (altrimenti 402). Invii context (il Suo oggetto JSON, massimo 64 KB) e, facoltativamente, eventId (il Suo ID: un nuovo tentativo con lo stesso eventId non avvia mai due volte lo stesso workflow). La chiamata risponde 202 e le esecuzioni avvengono in background. Una chiave limitata a determinati workflow avvia solo quelli.
curl -X POST https://app.certivant.com/api/v1/kyc/workflows/inbound \
-H "Authorization: Bearer ck_live_..." \
-H "Content-Type: application/json" \
-d '{"eventId":"crm-9281-1","context":{"externalRef":"user-9281","tier":"vip"}}'
Contesto dei dati. Arbitrario — il corpo JSON inviato, così com'è.
{
"organizationId": "org_01H...",
"event": "inbound.webhook",
"context": { "externalRef": "user-9281", "tier": "vip", "source": "crm" }
}
Esempio di utilizzo nel workflow. Lasci che il Suo CRM avvii un batch di nuova verifica per i clienti segnalati; filtri su un campo che ha inviato:
trigger:
event: inbound.webhook
filter: 'tier = "vip"'
conference.completed
"Una conferenza dal vivo si completa" · a livello di organizzazione
Quando si attiva. Una conferenza web di verifica dell'identità dal vivo termina e il conduttore (notaio/revisore) registra una decisione. Emesso una sola volta, con una protezione che impedisce a una decisione concorrente di attivarlo due volte.
Contesto dei dati.
| Campo | Tipo | Note |
|---|---|---|
decision | stringa | La decisione registrata dal conduttore |
status | stringa | Lo stato risultante della richiesta |
{
"organizationId": "org_01H...",
"event": "conference.completed",
"kycRequestId": "req_01J...",
"context": { "decision": "approve", "status": "APPROVED" }
}
Esempio di utilizzo nel workflow. Dopo una conferenza, generi il Certificato di verifica firmato e lo invii via email al richiedente.
Filtrare con il DSL
Il filtro del trigger (e ogni nodo Condizione) usa la grammatica delle espressioni delle politiche — un solo predicato booleano, senza chiamate di funzione:
- Campi: il contesto dell'evento appiattito (i campi mostrati nella tabella Contesto dei dati di ogni trigger).
- Operatori:
=!=>>=<<=,IN/NOT IN. - Combinatori:
ANDORNOT, con raggruppamento( ). - Letterali: numeri,
"stringhe",true/false/null, e liste[...].
L'operatore di uguaglianza è un singolo
=(non==). I campi mancanti sono a prova di errore: un campo assente vale falso invece di generare un'eccezione — quindi un filtro che fa riferimento asanctions.topScoresu un evento non legato alle sanzioni semplicemente non corrisponde.
Quali campi sono valorizzati dipende dall'evento: un evento sanctions.* trasporta sanctions.*, un evento liveness.* trasporta liveness.*, e gli eventi di decisione trasportano overallScore / decision / status / applicant.*.
| Campo | Tipo | Disponibile su |
|---|---|---|
overallScore | numero | eventi di decisione / stato |
decision | stringa | eventi di decisione / stato |
status | stringa | eventi di decisione / stato / ciclo di vita |
applicant.country | stringa | eventi di ingresso / decisione |
applicant.type | stringa | eventi di ingresso / decisione |
document.type | stringa | document.* |
document.side | stringa | document.* |
liveness.isLive | booleano | liveness.* |
liveness.confidence | numero | liveness.* |
faceMatch.isMatch | booleano | face_match.* |
faceMatch.confidence | numero | face_match.* |
sanctions.isMatch | booleano | sanctions.* |
sanctions.topScore | numero | sanctions.* |
sanctions.matchCount | numero | sanctions.* |
pep.isMatch | booleano | pep.match |
pep.matchCount | numero | pep.match |
kyb.status | stringa | kyb.match_* |
kyb.uboCount | numero | kyb.ubo_completed |
kyb.failedUboCount | numero | kyb.ubo_completed |
reviewerId | stringa | reviewer.decision |
Esempi di predicati:
overallScore >= 75
decision = "reject"
applicant.country IN ["CA","US"]
document.type = "passport"
sanctions.isMatch = true AND sanctions.topScore >= 0.85
overallScore < 50 OR sanctions.isMatch = true
Nell'editor, prema Ctrl+Space in qualsiasi campo di espressione per il completamento automatico in base al contesto e un popover di aiuto con campi, operatori ed esempi pronti.
Tabella di confronto
| Trigger | Categoria | Soggetto | Legato alla richiesta | Frequenza | Note |
|---|---|---|---|---|---|
form.submitted | Ingresso | form | sì | per invio | Solo moduli ospitati |
request.created | Ingresso | applicant | sì | per richiesta | Prima di qualsiasi controllo |
request.status_changed | Ciclo di vita | applicant | sì | per cambio di stato | Generico; affianca eventi specifici |
request.approved | Ciclo di vita | applicant | sì | per finalizzazione | |
request.rejected | Ciclo di vita | applicant | sì | per finalizzazione | |
request.escalated | Ciclo di vita | applicant | sì | per finalizzazione | |
request.resubmitted | Ciclo di vita | applicant | sì | per reinvio | |
request.documents_ready | Ciclo di vita | applicant | sì | per completamento della checklist | Tutti i documenti richiesti caricati |
document.uploaded | Documenti | document | sì | per documento | |
document.failed | Documenti | document | sì | per documento non riuscito | |
check.completed | Segnali | check | sì | per controllo (alta) | Protetto; uno per controllo |
liveness.passed | Segnali | check | sì | per richiesta | Solo esiti non ambigui |
liveness.failed | Segnali | check | sì | per richiesta | Solo esiti non ambigui |
face_match.passed | Segnali | check | sì | per richiesta | Solo esiti non ambigui |
face_match.failed | Segnali | check | sì | per richiesta | Solo esiti non ambigui |
sanctions.hit | Segnali | check | sì | per richiesta | Corrispondenza in lista |
sanctions.cleared | Segnali | check | sì | per richiesta | |
pep.match | Segnali | check | sì | per richiesta | Solo voci PEP |
kyb.match_found | Segnali | — | sì | per richiesta aziendale | Solo BUSINESS |
kyb.match_not_found | Segnali | — | sì | per richiesta aziendale | Solo BUSINESS |
kyb.ubo_completed | Segnali | — | sì | per richiesta aziendale | Solo BUSINESS; UBO risolti |
reviewer.decision | Revisione | — | sì | per decisione manuale | Fasi + azione di massa |
reviewer.assigned | Revisione | — | sì | per riassegnazione | Solo riassegnazione esplicita |
reviewer.comment_added | Revisione | — | sì | per commento | Corpo non nel contesto |
edd.triggered | Revisione | applicant | sì | per avvio EDD | |
score.updated | Rischio | applicant | sì | per (ri)calcolo | Si attiva con la decisione |
score.threshold | Rischio | applicant | sì | per (ri)calcolo | Ristretto da scoreMin/scoreMax |
schedule | Tempo | — | no | cron | Esecuzione a livello di organizzazione |
verification.expired | Tempo | applicant | sì | per scadenza | Dal cron di scadenza |
monitoring.alert | Monitoraggio | — | sì | per avviso | Screening continuo |
inbound.webhook | Esterno | — | facoltativo | per POST | Payload arbitrario |
conference.completed | Esterno | — | sì | per conferenza | Sessioni Live ID |
Trigger previsti
Alcuni trigger richiesti di frequente non sono nel selettore, perché la piattaforma non ha ancora un segnale da cui emetterli — renderli selezionabili creerebbe trigger che non si attivano mai. Sono elencati qui con l'alternativa funzionante, così il divario è esplicito. (Tutto ciò che è nel selettore, al contrario, è davvero emesso — incluso score.threshold, il confronto del volto, PEP, UBO e gli eventi di revisione, che sono stati collegati in questa release.)
| Trigger richiesto | Perché non viene emesso | Cosa usare al suo posto |
|---|---|---|
| Frode rilevata | Non esiste ancora un tipo di controllo autonomo di analisi forense/autenticità (la analisi forense è oggi un fattore di scoring del rischio, non un controllo discreto che emette un risultato). | Ramificarsi su document.failed, oppure sugli eventi di decisione / score.threshold per il rischio risultante. |
| Dati del registro delle imprese aggiornati | La KYB è una verifica una tantum; non esiste un job continuo di ri-recupero/monitoraggio del registro da cui emettere. | Ripetere la verifica secondo una schedule e ramificarsi su kyb.match_* / kyb.ubo_completed. |
| Link di email / SMS cliccato | Non esiste un'infrastruttura di tracciamento di apertura email o clic sui link. | Usare form.submitted / document.uploaded come segnali concreti che "il richiedente ha agito". |
Queste sono vere voci di roadmap, non lacune della documentazione — l'enum dei trigger del motore è l'unica fonte di verità, e questa tabella riflette ciò che non contiene ancora.
Buone pratiche
- Imposti sempre un soggetto + un ambito. Un trigger senza soggetto è a livello di organizzazione e si attiva per ogni oggetto corrispondente nell'organizzazione. Preferisca l'ambito
specificocategory; riserviallalle automazioni davvero a livello di organizzazione. - Ascolti gli eventi specifici, non quello generico, quando possibile. Usi
liveness.failed/sanctions.hitinvece di analizzarecheck.completed, e un unico evento di decisione invece direquest.status_changed— a meno che non le serva specificamente uno stato senza un evento dedicato. - Non ascolti sia l'evento di stato specifico sia quello generico.
request.approvederequest.status_changedsi attivano entrambi all'approvazione; collegare due workflow (o due trigger) allo stesso esito esegue due volte gli effetti collaterali. - Consideri il contesto come un'istantanea. Il contesto dell'evento viene catturato all'invio. Se il workflow attende (un nodo
wait, un lungo ritardo), rilegga lo stato attuale all'interno di un'Azione invece di fidarsi di un contesto obsoleto per una decisione critica. - Mantenga snelli i workflow di
check.completed. È il trigger a più alta frequenza; lo limiti a una categoria e filtri presto, così da non diramarsi su ogni controllo di ogni richiesta. - Attenzione agli ambiti orfani. Eliminare un modulo/richiedente referenziato da un ambito
specificrende il trigger inattivo (non si attiva e mostra il badge "Richiede una nuova associazione"). Lo riassocii a un oggetto attivo per riattivarlo. - I workflow inoltrano, non decidono. Se l'esito di un trigger dovrebbe cambiare il verdetto, passi da
escalateper la revisione umana — non esiste volutamente alcuna azione di approvazione/rifiuto. - Si aspetti un'esecuzione almeno una volta, in modo eventuale. L'invio è asincrono e fire-and-forget; renda idempotenti gli effetti collaterali delle Azioni dove conta (per esempio includendo un riferimento esterno, così un nuovo attivarsi non duplica i record a valle).
Domande frequenti
Un workflow può approvare o rifiutare una verifica?
No. Il set di Azioni non ha approve/reject. Il controllo più forte sull'esito è escalate, che sposta la richiesta in revisione umana tramite la macchina a stati esistente, con blocco ottimistico e tracciata. Il verdetto appartiene alla politica decisionale e ai revisori umani.
Si sono attivati sia un evento di decisione specifico sia request.status_changed — è un bug?
No. Il request.status_changed generico viene sempre emesso insieme all'evento specifico, così può reagire a stati che non hanno un evento dedicato. Ne ascolti uno, non entrambi.
Perché il mio workflow check.completed non è stato eseguito?
La diramazione per controllo è protetta: invia solo quando un workflow attivo è in ascolto di check.completed. Verifichi che il workflow sia attivo e che ambito/filtro corrispondano al controllo. Tenga presente anche che i controlli in errore senza un dato booleano utilizzabile non emettono i segnali specifici liveness.* / sanctions.*.
Perché il mio trigger score.threshold non si attiva?
Si attiva a ogni finalizzazione con punteggio, poi il dispatcher lo restringe in base ai limiti scoreMin / scoreMax del trigger. Se non viene mai eseguito, verifichi che il punteggio rientri davvero nei limiti, e che la richiesta abbia raggiunto un esito con punteggio (una richiesta annullata prima dello scoring non emette alcun evento di punteggio). Senza limiti impostati, si comporta come score.updated.
Qual è la differenza tra score.updated e score.threshold?
Stesso punto di emissione e stesso contesto. score.updated si esegue sempre; score.threshold si esegue solo quando overallScore rientra nei limiti scoreMin / scoreMax del trigger — una comodità integrata, così non deve scrivere lei stessa il filtro su overallScore.
Come si attiva su un esito di confronto del volto o PEP?
Usi gli eventi dedicati face_match.passed / face_match.failed e pep.match. Un riscontro PEP attiva anche sanctions.hit (lo screening PEP si basa sullo screening delle liste di controllo), quindi ascolti pep.match quando le interessa solo l'esposizione PEP.
Eliminare un modulo disattiva i suoi workflow?
Un workflow il cui trigger è limitato per ambito specific solo a quel modulo diventa orfano: resta inattivo (non si attiva) e mostra il badge "Richiede una nuova associazione". Lo riassocii a un oggetto attivo per riattivarlo. Non ripiega mai silenziosamente sull'attivazione a livello di organizzazione.
L'invio è sincrono con la mia chiamata API? No. L'invio è fire-and-forget ed è eseguito fuori banda. L'azione di origine (caricamento, cambio di stato) va a buon fine indipendentemente dal successo dell'invio o dell'esecuzione del workflow.
Un workflow può attivarne un altro?
Sì — l'azione trigger_workflow esegue direttamente un workflow salvato scelto, con una profondità massima di catena pari a 5 per evitare cicli.
Appendice
Glossario
- Trigger — il singolo nodo di ingresso che dichiara evento, soggetto, ambito e filtro che avviano un workflow.
- Evento — un
WorkflowTriggerEventche la piattaforma emette in un punto reale del ciclo di vita della verifica. - Soggetto — il tipo di oggetto a cui un trigger si lega:
form,applicant,documentoppurecheck. - Ambito — come viene ristretto il soggetto:
specific(id),categoryoppureall. - Contesto — i fatti specifici dell'evento catturati all'invio e letti dai filtri e dai modelli delle Azioni.
- Filtro — un predicato DSL facoltativo che restringe ulteriormente quali eventi corrispondono.
- Trigger orfano — un trigger con ambito
specifici cui oggetti sono stati eliminati; inattivo finché non viene riassociato. - Esecuzione — una
KycWorkflowRun: un'esecuzione di un workflow, con unlogin sola aggiunta.
Enum completo degli eventi
type WorkflowTriggerEvent =
| "form.submitted" | "request.created"
| "request.status_changed" | "request.approved" | "request.rejected"
| "request.escalated" | "request.resubmitted" | "request.documents_ready"
| "document.uploaded" | "document.failed" | "check.completed"
| "liveness.passed" | "liveness.failed"
| "face_match.passed" | "face_match.failed"
| "sanctions.hit" | "sanctions.cleared" | "pep.match"
| "kyb.match_found" | "kyb.match_not_found" | "kyb.ubo_completed"
| "reviewer.decision" | "reviewer.assigned" | "reviewer.comment_added"
| "score.threshold" | "score.updated" | "edd.triggered"
| "monitoring.alert" | "verification.expired" | "schedule"
| "inbound.webhook" | "conference.completed";
Ciclo di vita di un invio
1. Something happens (form submit, check finishes, cron, webhook…)
2. Emitter calls enqueueWorkflowDispatch({ event, …, context })
3. workflow.worker picks it up → dispatchWorkflowEvent(input)
4. Match active workflows trigger.event === input.event
5. Narrow by subject + scope specific ids / category / all (orphans excluded)
6. Evaluate filter (DSL) against input.context (missing fields = false)
7. Create KycWorkflowRun context stashed on the first log entry
8. Execute nodes Condition → Action → Wait → … → End
Esempio completo
Un'automazione di onboarding completa, collegata a un solo modulo KYC:
trigger:
event: form.submitted
subject: form
scope: { mode: specific, ids: ["form_onboarding_01H..."] }
# graph (conceptual):
# ▸ Trigger: form.submitted
# → Action: email applicant "We received your submission"
# → Wait: until check.completed (or 24h timeout)
# → Condition: sanctions.isMatch = true
# true → Action: escalate + Action: notify compliance (Slack)
# false → Condition: overallScore >= 80
# true → Action: generate_pdf_report → email applicant
# false → Action: assign_department "manual-review"
# → End
Questo non imposta mai il verdetto: l'unico passo che incide sull'esito è escalate, che instrada alla revisione umana. Tutto il resto è notifica, raccolta dati e reportistica attorno alla decisione di cui sono responsabili la politica e i revisori.
Flussi di lavoro automatizzati
Flussi eseguibili attivati da eventi, che instradano, notificano e orchestrano attorno a una verifica — senza mai impostare il verdetto.
Web SDK
Mostri una verifica Certivant all'interno del Suo sito web con un solo tag script — modale o incorporata, con eventi ready, step, complete, cancel ed error, controlli rigorosi sull'origine e supporto della fotocamera.