> ## Documentation Index
> Fetch the complete documentation index at: https://verifner.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Flux

> Décidez vous-même de ce qui suit chaque vérification : règles métier, revue par une équipe, notifications vers vos outils.

Un **flux** est une suite de blocs que vous construisez dans la console, page **Flux**, pour une [application](https://verifner.mintlify.site/console/applications.md). Il s'exécute à chaque vérification de cette application et peut :

* **rendre le verdict plus sévère** selon vos propres règles : un montant élevé, un document qui expire bientôt, une personne mineure ;
* **envoyer la vérification à une équipe** de relecteurs ;
* **prévenir vos outils** : un e-mail, un webhook, une requête HTTP vers votre CRM.

> [!NOTE]
>
> Les flux font partie de l'offre **Grands comptes**. Si votre organisation quitte cette offre, la version active continue de tourner telle quelle, en lecture seule : vous pouvez seulement la désactiver.

## Un exemple

Kaïna Pay ouvre des portefeuilles. Au-delà de 500 000 FCFA, son équipe conformité veut relire chaque dossier ; en dessous, le CRM est prévenu dès que le client est vérifié.

```
Vérification terminée
  └─ Donnée de session : amount_xof > 500 000 ?
       ├─ oui → Envoyer en revue (équipe « Conformité », raison « Montant élevé »)
       └─ non → Selon le verdict
                  └─ vérifiée → Webhook « CRM »
```

Le montant vient des [`metadata`](https://verifner.mintlify.site/guides/web-sdk#1-ouvrez-une-session-depuis-votre-serveur) que votre serveur passe à l'ouverture de la session :

```json theme={"dark"}
{ "reference": "user_8812", "metadata": { "amount_xof": 750000, "product": "wallet_l2" } }
```

## Construire un flux

Chaque application a **un flux**, fait d'autant de **règles** que vous voulez (vingt au plus). Une règle commence par un déclencheur (« Vérification terminée », « Revue tranchée » ou « Session expirée ») ; vous pouvez la nommer (« Gros montants », « Mineurs »), la **mettre en pause** sans la supprimer, la replier et changer son ordre avec ↑↓. Toutes les règles actives s'appliquent, de haut en bas, à chaque vérification : un verdict ne fait que se durcir, donc le plus sévère l'emporte, et chaque règle fait ses propres envois. Un seul flux par application garde une seule réponse à « pourquoi cette vérification est-elle en revue ? » ; pour des parcours vraiment séparés, utilisez des [applications](https://verifner.mintlify.site/console/applications.md) distinctes.

Un flux vide, comme le bouton **Nouvelle règle**, propose trois départs :

* **Décrivez votre règle** en une phrase, par exemple « au-delà de 500 000 FCFA, envoyer en revue à l'équipe Conformité ». Un modèle d'IA en propose un brouillon, que vous relisez, testez et publiez vous-même : rien n'est publié sans vous. N'y écrivez pas de données personnelles ; la phrase n'est pas conservée.
* **Partir d'un modèle** : gros montants en revue, mineurs refusés, document qui expire bientôt, prévenir mon CRM, relance des abandons, passeport avec puce obligatoire.
* **Une page blanche**, ou, depuis **Nouvelle règle**, une règle vide qui commence par le déclencheur de votre choix.

La vue **Étapes** se lit de haut en bas : chaque condition se sépare en colonnes, une par réponse (oui, non, vérifiée…). Le bouton **+** entre deux étapes ou au bout d'une branche ouvre la liste des blocs, avec une recherche (↑↓ pour choisir, Entrée pour ajouter) ; les décisions n'y figurent que là où elles sont permises. Cliquez une étape pour la régler à droite. Supprimer une étape relie ce qui était avant à ce qui suit ; supprimer une condition retire aussi ses branches (⌘Z / Ctrl+Z annule). Le bandeau **En clair** redit le flux en une phrase. La vue **Schéma** montre le même flux en blocs libres, pour ceux qui préfèrent le dessiner ; **Ranger les blocs** les remet en ordre.

**Tester** ouvre un panneau à gauche : choisissez une des vingt dernières vérifications de l'application, ou inventez un cas (verdict, document, une donnée de session). Le chemin suivi s'allume, chaque condition affiche ce qu'elle a lu (`amount_xof 750000 > 500000`) et le panneau donne le verdict publié et ce qui serait envoyé. Le test se refait à chaque modification. Rien n'est envoyé ni enregistré ; soixante tests par minute au plus.

## Intégrer le flux à votre application

Le flux s'exécute chez VerifNer, à chaque vérification de l'application, quel que soit le SDK : votre code n'appelle rien de plus. L'onglet **Intégrer** de l'éditeur montre ce qu'il doit faire, en trois étapes, avec du code prêt à copier pour votre application (Web, React Native, Flutter, ou un simple lien envoyé par SMS ou e-mail) et votre serveur (Node.js, Python, PHP, cURL) :

1. **Ouvrir la session avec les données que vos règles lisent.** Si une règle teste `amount_xof`, votre serveur passe `metadata: { "amount_xof": … }` à `POST /v1/sessions` ; le code d'exemple contient déjà les clés de votre flux.
2. **Lancer la capture** : le [SDK Web](https://verifner.mintlify.site/guides/web-sdk.md), le SDK React Native, ou, pour Flutter et sans application, la page de capture hébergée dont la session renvoie l'adresse (`url`). Le SDK Flutter natif est en bêta et appelle encore l'API avec la clé secrète : ne l'embarquez pas en production.
3. **Recevoir la décision** sur votre [webhook](https://verifner.mintlify.site/guides/webhooks.md) : `data.verdict` après vos règles, `data.workflow` (équipe, raison) quand c'est une revue, puis `data.final_verdict` quand un relecteur tranche.

Au-dessus du code, **Ce que nous voyons** vérifie l'intégration sur les vérifications des 30 derniers jours : une clé API pour l'application, du trafic, chaque clé de `metadata` que lisent vos règles (reçue dans combien de vérifications), un webhook actif, une version publiée. Une clé **jamais reçue** est aussi signalée sur le bloc qui la lit : votre serveur ne l'envoie pas, et la règle ne se déclenchera jamais.

## Brouillon, versions et test

* Chaque application a **un flux** : un **brouillon** que vous modifiez librement, et des **versions publiées**, numérotées 1, 2, 3… Une version publiée ne change plus jamais.
* **Publier** fait du brouillon la version active. Une seule version est active à la fois, pour le mode test comme pour le mode live.
* Vous pouvez **revenir à une version précédente** ou **désactiver** le flux à tout moment.
* **Brouillon en test** : activé, les vérifications de **test** passent par le brouillon au lieu de la version active ; le live n'est pas touché. Si le brouillon contient une erreur, c'est la version active qui tourne.

| Action | Rôles |
| - | - |
| Voir le flux, ses versions, simuler | tous les membres |
| Modifier le brouillon, gérer les secrets, brouillon en test | développeur, admin, propriétaire |
| Publier, revenir à une version, désactiver | admin, propriétaire |

Chaque publication, retour arrière, désactivation, simulation et envoi est inscrit dans le [journal d'audit](https://verifner.mintlify.site/console/logs.md).

## Les déclencheurs

| Déclencheur | Quand | Peut changer le verdict ? |
| - | - | - |
| **Vérification terminée** | Juste après le verdict des contrôles, avant la réponse de l'API | Oui, seulement pour le rendre plus sévère |
| **Revue tranchée** | Après la décision d'un relecteur dans la console | Non : envois seulement. « Selon le verdict » lit la décision du relecteur |
| **Session expirée** | Une session ouverte n'a abouti à aucune vérification avant son expiration. Vérifié toutes les 5 minutes, une seule fois par session | Non : envois seulement |

Un flux peut contenir les trois déclencheurs, chacun au plus une fois.

## Les blocs

### Conditions

Chaque condition a plusieurs sorties. Une condition qui ne peut pas répondre (date non lue, donnée absente) sort par **inconnu** quand elle en a une, sinon par **non**.

| Bloc | Réglages | Sorties |
| - | - | - |
| **Selon le verdict** | — | vérifiée, revue, rejetée |
| **Score** | inférieur, inférieur ou égal, supérieur, supérieur ou égal à une valeur de 0 à 1 | oui, non |
| **Contrôle** | un [contrôle](https://verifner.mintlify.site/concepts/checks.md) et un ou plusieurs statuts (`pass`, `warn`, `fail`, `skipped`) | oui, non |
| **Type de document** | — | passeport, CNI, inconnu |
| **Âge** | moins de, ou au moins, N ans (0 à 120) | oui, non, inconnu |
| **Expiration proche** | expire dans N jours ou moins (1 à 3 650) ; un document déjà expiré répond oui | oui, non, inconnu |
| **Mode** | — | test, live |
| **Donnée de session** | une clé de `metadata`, un opérateur (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `exists`) et une valeur. `gt` à `lte` comparent des nombres ; `in` prend une liste de 50 valeurs au plus | oui, non |

L'âge et l'expiration sont calculés au jour de la vérification, heure de Niamey : une simulation donne la même réponse des mois plus tard. Pour la carte d'identité papier, l'expiration est celle que déduisent les contrôles, 5 ans après la délivrance.

### Décisions

Seulement sous **Vérification terminée**, et toujours **avant** tout envoi ou attente sur leur chemin.

| Bloc | Réglages | Effet |
| - | - | - |
| **Définir le verdict** | `review` ou `rejected`, une raison (200 caractères au plus) | Rend le verdict plus sévère |
| **Envoyer en revue** | une équipe (60 caractères au plus) ou un relecteur (e-mail d'un membre), une raison | Passe le verdict en `review` ; l'équipe ou le relecteur s'affichent dans la File de revue |

### Envois et attente

| Bloc | Réglages |
| - | - |
| **E-mail** | 1 à 5 destinataires, un objet (120 caractères au plus), les champs à inclure |
| **Webhook** | un de vos [webhooks](https://verifner.mintlify.site/guides/webhooks.md) de cette application, un libellé (60 caractères au plus), les champs à inclure |
| **Requête HTTP** | une adresse `https` (500 caractères au plus), une clé de signature et un en-tête d'authentification facultatifs, jusqu'à 5 en-têtes `X-…`, les champs à inclure |
| **Attendre** | 1 à 10 080 minutes (7 jours) avant les envois qui suivent |

Les branches d'une même sortie s'exécutent dans l'ordre des blocs ; un bloc atteint par deux branches ne s'exécute qu'une fois.

## Garde-fous

* **Un flux ne rend jamais un verdict moins sévère.** Ordre : `verified`, puis `review`, puis `rejected`. Un document rejeté par les contrôles reste rejeté ; aucun bloc ne propose « vérifiée ».
* **Le score ne change jamais.** Il reste celui des [contrôles](https://verifner.mintlify.site/concepts/verdict.md#comment-le-score-est-calcule).
* **Une erreur dans le flux ne bloque jamais une vérification** : le verdict des contrôles est publié et l'erreur apparaît dans le bloc `workflow`.
* **Pas de boucle**, et au plus **50 blocs**, **100 liens**, **10 envois ou attentes sur un même chemin** et **20 envois** dans un flux.
* **Adresses publiques uniquement** : `localhost` et les adresses privées sont refusées à la publication, puis vérifiées à nouveau à chaque envoi. Les redirections ne sont pas suivies.
* **Rien n'est envoyé par défaut** au-delà de l'identifiant de la vérification : vous cochez chaque champ.

### Les champs envoyables

| Champs | Contenu |
| - | - |
| `verification_id`, `session_id`, `reference`, `mode`, `app_id` | Identifiants |
| `verdict`, `rules_verdict`, `score`, `document_type`, `checks` | Le résultat ; `checks` donne le nom et le statut de chaque contrôle, sans preuve |
| `workflow.reason`, `workflow.team` | La décision du flux |
| `metadata.<clé>` | Une donnée de session |
| `document.surname`, `document.given_names`, `document.date_of_birth`, `document.nationality`, `document.sex`, `document.document_number`, `document.date_of_expiry` | **Données personnelles** lues sur le document |

Les champs `document.*` demandent une confirmation explicite dans le bloc : vous attestez que ce destinataire peut les recevoir. Jamais d'image, de ligne MRZ ni de similarité de visage. Le journal d'audit note chaque envoi avec sa destination et la liste des champs, jamais leurs valeurs.

## Les envois

Ils partent **après** la réponse de l'API et le webhook `verification.completed`, dans l'ordre du chemin. Un envoi qui échoue n'empêche pas les suivants.

### E-mail

Un message par destinataire : personne ne voit les autres adresses. Il contient les champs choisis, sous forme de tableau.

### Webhook

Un événement `workflow.notification` vers l'endpoint choisi, signé comme tous les webhooks. Il apparaît dans **Dernières livraisons** et suit les mêmes [relances](https://verifner.mintlify.site/guides/webhooks.md#repondre-et-reessayer).

```json theme={"dark"}
{
  "id": "evt_7d1z0p4x9c2r8k2m1q5v",
  "type": "workflow.notification",
  "created_at": "2026-10-07T09:12:04.000Z",
  "data": {
    "label": "CRM",
    "run_id": "wfr_4h6j2n9t3k7m5c9x3r1q",
    "step_id": "wfs_2q8w4e6r8t0y2u4i6o8p",
    "version": 4,
    "mode": "live",
    "fields": {
      "verification_id": "vrf_8k2m1qz7x4c9v2b5n3m1",
      "verdict": "verified",
      "metadata.amount_xof": 20000
    }
  }
}
```

`version` vaut `null` quand c'est le brouillon qui a tourné, en test.

### Requête HTTP

Un `POST` JSON avec la même enveloppe `workflow.notification` (`data.label` est le nom d'hôte), vers une adresse `https` publique, avec ces en-têtes :

| En-tête | Valeur |
| - | - |
| `Idempotency-Key`, `VerifNer-Delivery` | L'identifiant de l'envoi (`wfs_…`), le même à chaque tentative : ignorez un doublon |
| `VerifNer-Event` | `workflow.notification` |
| `VerifNer-Signature` | Avec une clé de signature : `t=<secondes>,v1=<HMAC-SHA256>`, calculée exactement comme pour les [webhooks](https://verifner.mintlify.site/guides/webhooks.md#verifier-la-signature) |
| Votre en-tête d'authentification | Avec un secret d'en-tête : par exemple `Authorization: Bearer …` |
| Vos en-têtes `X-…` | Jusqu'à 5, non secrets |

Réponses :

* **2xx** : envoyé ;
* **408, 429, 5xx**, délai de 10 secondes dépassé ou serveur injoignable : nouvelle tentative, avec un délai qui double à partir de 60 secondes, **5 tentatives** au total ;
* **toute autre réponse 4xx** : échec définitif, sans nouvelle tentative ;
* **secret révoqué** : échec avant tout envoi.

La réponse n'est pas lue.

### Secrets

Créés dans la console, chiffrés, jamais réaffichés :

* **Clé de signature** : générée par VerifNer (`wsec_…`) et montrée **une seule fois** ; vous la gardez sur votre serveur pour vérifier `VerifNer-Signature`. Vous pouvez aussi fournir la vôtre (16 caractères au moins).
* **En-tête d'authentification** : un nom (`Authorization`, `X-Api-Key` ou un autre `X-…`) et la valeur que vous collez, par exemple la clé d'API de votre CRM. Elle n'est jamais renvoyée.

Révoquer un secret fait échouer les envois qui l'utilisent.

## Ce que vous recevez

Le `verdict` de la réponse de `POST /v1/verify`, de `GET /v1/verifications/{id}` et du webhook `verification.completed` est toujours le **verdict publié**, celui du flux. Votre code ne change pas : `verified` on poursuit, `review` on attend la décision humaine, `rejected` on refuse.

Deux champs vous disent ce qu'a fait le flux :

```json theme={"dark"}
{
  "id": "vrf_8k2m1qz7x4c9v2b5n3m1",
  "verdict": "review",
  "rules_verdict": "verified",
  "score": 0.97,
  "workflow": {
    "version": 4,
    "draft": false,
    "run_id": "wfr_4h6j2n9t3k7m5c9x3r1q",
    "decided": true,
    "reason": "Montant élevé",
    "team": "Conformité",
    "status": "completed"
  },
  "metadata": { "amount_xof": 750000, "product": "wallet_l2" }
}
```

| Champ | Contenu |
| - | - |
| `rules_verdict` | Le verdict des contrôles, **seulement** quand le flux l'a changé ; `null` sinon |
| `workflow` | `null` quand aucun flux n'a tourné |
| `workflow.version` | La version publiée qui a décidé ; `null` pour le brouillon en test |
| `workflow.decided` | `true` quand le flux a changé le verdict |
| `workflow.reason`, `workflow.team` | La raison et l'équipe données par le bloc de décision |
| `workflow.status` | `running` tant que des envois sont en cours, puis `completed` ; `error` si le flux a échoué (le verdict des contrôles est alors publié) |

## Simuler avant de publier

Le bouton **Simuler** rejoue le brouillon sur les dernières vérifications de l'application, de 50 à 500 (200 par défaut), et le compare à ce qui a été réellement publié : combien de décisions changeraient, dans quel sens, quels envois seraient partis. Rien n'est envoyé ni enregistré, et aucune image n'est relue. Dix simulations par minute au plus.

Les vérifications déjà faites gardent leur décision : une nouvelle version ne s'applique qu'aux suivantes.

## Conservation

Le détail de chaque exécution (chemin suivi, envois, tentatives) est gardé 90 jours. Les versions publiées ne sont jamais supprimées : vous pouvez toujours retrouver le flux exact qui a décidé d'une vérification.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.