Comment intégrer Canonical
Découvrez comment le pilote PSS Canonical vous permet de connecter un fournisseur de services de paiement à B2CORE en implémentant un contrat d’API de dépôt standard, y compris la configuration côté B2CORE, les webhooks, le polling et le cycle de vie du statut des dépôts.
Le pilote Canonical vous permet de connecter un fournisseur de services de paiement (PSP) de votre choix à B2CORE via PSS, même lorsque B2CORE ne propose pas encore de pilote dédié pour ce fournisseur.
Pourquoi utiliser le pilote Canonical
La plupart des systèmes de paiement dans B2CORE reposent sur un pilote dédié conçu spécifiquement pour un fournisseur. Le pilote Canonical adopte une approche différente : il définit un contrat d’API unique et standard — l’API Canonical Deposit — que tout fournisseur peut implémenter. B2CORE gère alors l’authentification, le flux de démarrage du dépôt, le polling, les webhooks et le cycle de vie des statuts de manière uniforme, quel que soit le fournisseur derrière le contrat.
Le pilote Canonical est utile lorsque vous souhaitez :
- Connecter un PSP privilégié ou interne qui ne dispose pas de pilote B2CORE dédié, sans attendre un développement personnalisé.
- Réduire le délai de mise sur le marché en demandant à votre fournisseur d’implémenter un contrat documenté et stable plutôt qu’une intégration sur mesure.
- Conserver un contrôle total sur la partie fournisseur, tandis que B2CORE gère le flux de travail des dépôts de son côté.
Le pilote Canonical prend actuellement en charge les flux de dépôt. Pour proposer des dépôts via votre fournisseur, celui-ci doit implémenter l’API Canonical Deposit décrite dans la spécification OpenAPI ci-dessous et respecter les exigences comportementales de cette page.
Spécification OpenAPI
L’API Canonical Deposit est définie dans la spécification OpenAPI suivante, qui couvre l’authentification, les schémas de requête et de réponse, les points de terminaison et les codes de statut. Téléchargez-la pour examiner le contrat complet que votre fournisseur doit implémenter :
canonical-deposit-api.yaml
Le reste de cette page décrit les exigences comportementales, la configuration côté B2CORE et les décisions de conception que la spécification ne peut pas exprimer. Lisez les deux ensemble pour obtenir une vue complète de l’intégration.
Identifiants du pilote B2CORE
Ces champs sont configurés côté B2CORE (Back Office) et utilisés pour s’authentifier auprès de l’API du PSP. Consultez la spécification OpenAPI pour connaître tous les détails relatifs à la génération et à la vérification des jetons JWT.
| Champ | Description |
|---|---|
| URL de base de l’API | URL HTTPS de base de l’API du PSP. |
| ID d’application | Identifiant marchand unique. Utilisé comme revendication sub dans le JWT. |
| Secret de l’application | Clé secrète pour la signature HMAC-SHA256. Encodée en Base64 URL, 32 octets (43 caractères). Jamais envoyée dans les requêtes — utilisée uniquement pour signer les jetons. |
Champs de configuration du pilote B2CORE
Ces champs sont configurés côté B2CORE (Back Office) et contrôlent le comportement du pilote. Ils ne font pas partie de l’API destinée au PSP.
Paramètres globaux (globalParam1, globalParam2, globalParam3)
Trois champs de chaîne au niveau de la configuration, envoyés avec chaque requête authentifiée au PSP.
- Pour les points de terminaison
POST, ils sont inclus dans le corps de requête JSON. - Pour les points de terminaison
GET, ils sont inclus comme paramètres de requête.
Ils représentent des valeurs spécifiques au PSP telles que l’ID marchand, le canal ou l’ID de projet. La sémantique exacte dépend de l’implémentation du PSP. L’administrateur B2CORE les renseigne lors de la configuration.
Champs obligatoires (lecture seule)
Type : Sélection multiple
Sélectionne les champs d’informations utilisateur affichés dans le formulaire de paiement en lecture seule (non modifiables).
Les champs sélectionnés doivent déjà être configurés et enregistrés dans le profil B2CORE de l’utilisateur. Si un champ sélectionné est absent du profil, la génération du formulaire de paiement échoue avec une erreur de champs manquants — l’utilisateur ne peut pas continuer tant que les données ne sont pas renseignées dans son profil B2CORE.
Les champs sélectionnés, ainsi que les champs provenant des Champs obligatoires (modifiables), déterminent quelles données utilisateur sont réellement renseignées dans l’objet startDepositUserInfo envoyé au PSP dans la requête POST /api/v1/deposits. Les champs qui ne sont sélectionnés dans aucune des deux listes sont masqués dans le formulaire et peuvent être envoyés avec des valeurs vides.
Champs obligatoires (modifiables)
Type : Sélection multiple
Sélectionne les champs d’informations utilisateur affichés dans le formulaire de paiement comme modifiables. L’utilisateur peut renseigner ou modifier ces champs directement dans le formulaire de paiement. Contrairement aux Champs obligatoires (lecture seule), ces champs n’ont pas besoin d’être préconfigurés dans le profil B2CORE de l’utilisateur.
Règle de priorité : Si un champ est sélectionné à la fois dans Champs obligatoires (lecture seule) et Champs obligatoires (modifiables), il est affiché en lecture seule. Le paramètre lecture seule est toujours prioritaire.
Comportement de l’e-mail : L’e-mail est toujours affiché dans le formulaire de paiement et toujours envoyé dans startDepositUserInfo, qu’il soit ou non sélectionné dans l’une des listes. La configuration contrôle uniquement son affichage :
| E-mail sélectionné dans | Comportement |
|---|---|
| Aucune des listes | Affiché comme champ modifiable |
| Champs obligatoires (modifiables) | Affiché comme champ modifiable |
| Champs obligatoires (lecture seule) | Affiché comme champ en lecture seule (valeur du profil B2CORE) |
| Les deux listes | Affiché comme champ en lecture seule (la lecture seule est prioritaire) |
Délai de synchronisation par défaut
Type : Sélection
Par défaut : 4h
Durée maximale après la création d’un dépôt pendant laquelle B2CORE interroge le statut du dépôt. Après ce délai :
StatusSyncInProgress→ le dépôt passe àunexpected.StatusSyncUnexpected→ le dépôt passe àunexpected.
Le statut unexpected nécessite une investigation manuelle de l’administrateur via LifecycleService.
Échec autorisé au démarrage
Type : Booléen (actuellement codé en dur sur yes, aucun choix)
Détermine s’il est sûr de marquer un dépôt comme failed (terminal) lorsque la requête de démarrage rencontre une erreur inattendue.
yes— si le PSP renvoie une erreur lors du démarrage du dépôt et que B2CORE est certain que le dépôt n’a pas été créé côté PSP (par exemple, B2CORE n’a jamais reçu d’URL de redirection), le dépôt peut être passé en toute sécurité àfailed. Le client n’a perdu aucun argent.no— même en cas d’erreur, le dépôt passe àin_progressavec un ID externe non vérifié et est interrogé, car le PSP pourrait avoir créé le dépôt malgré l’erreur.
Actuellement, toujours yes. Dans le cas typique, sans URL de redirection, le client ne peut pas finaliser la page de paiement du PSP ; le dépôt ne peut donc pas réussir.
Attendre le webhook avant le polling
Type : Booléen (actuellement codé en dur sur yes, aucun choix)
Contrôle si B2CORE attend une notification webhook avant de commencer à interroger GET /api/v1/deposits/{externalID}.
| Valeur | Comportement |
|---|---|
yes | Après le démarrage du dépôt, B2CORE attend jusqu’à 5 minutes un webhook avant de commencer le polling. Si aucun webhook n’arrive dans les 5 minutes, B2CORE passe au polling standard. |
no | B2CORE commence le polling immédiatement selon la planification standard de backoff. |
Justification : De nombreux PSP envoient rapidement une notification webhook lorsque le statut du dépôt change. Attendre le webhook avant le polling réduit le nombre d’appels API inutiles, ce qui aide à respecter les limites de débit. Le délai d’expiration de 5 minutes garantit la progression même si le webhook est retardé ou perdu.
Flux de test de la configuration
Lorsqu’un administrateur clique sur Tester la configuration dans B2CORE :
1. B2CORE generates a one-time JWT signed with appSecret
2. B2CORE → POST /api/v1/configuration/test (with Bearer JWT + globalParams)
3. If response status = "available" → test result: "available"
4. If response status = "failed" → test result: "failed" (with error from PSP)
5. If unexpected error (5xx, timeout, and similar) → test result: "unexpected"La méthode de test de la configuration est la seule méthode pour laquelle tout problème d’identifiants doit renvoyer non pas 401 Unauthorized, mais 200 OK avec un corps de réponse.
Les valeurs code et description sont affichées à l’administrateur B2CORE ; renvoyez donc des données propres et non sensibles.
Conception du système de webhooks
Deux canaux de webhook
B2CORE prend en charge deux canaux de webhook par dépôt :
| Canal | Enregistrement | Description |
|---|---|---|
| Automatique | Via notificationURL dans la requête POST /api/v1/deposits | Toujours actif. B2CORE génère l’URL et la transmet au PSP. |
| Configurable par l’administrateur | Défini par l’administrateur dans le Back Office B2CORE | Facultatif. L’administrateur peut configurer une URL de webhook distincte vers laquelle le PSP envoie les notifications (par exemple, enregistrée dans le panneau d’administration du PSP). |
Les deux canaux alimentent le même gestionnaire de webhooks B2CORE → magasin driver_transit → pipeline d’optimisation du poller.
Webhook comme optimisation du polling
Le webhook n’est pas la source de vérité. C’est une optimisation qui réduit les requêtes de polling inutiles.
PSP → B2CORE webhook handler → driver_transit (key-value store) → pollerFonctionnement :
- Lorsqu’un webhook arrive, B2CORE enregistre un indicateur dans
driver_transitassocié àexternalID. - Le poller vérifie
driver_transitavant d’effectuer un appel API :- Si un indicateur webhook existe pour
externalID, B2CORE appelle immédiatementGET /api/v1/deposits/{externalID}. - Si aucun indicateur n’existe et que moins de 5 minutes se sont écoulées, B2CORE attend (voir Attendre le webhook avant le polling).
- Si aucun indicateur n’existe et que plus de 5 minutes se sont écoulées, B2CORE poursuit avec le polling standard.
- Si un indicateur webhook existe pour
- Lorsque le dépôt atteint un statut terminal (succès ou échec), l’entrée
driver_transitest supprimée.
Charge utile du webhook
La charge utile du webhook est minimale (voir le rappel webhook sous POST /api/v1/deposits dans la spécification OpenAPI) :
{
"externalID": "550e8400-e29b-41d4-a716-446655440000",
"status": "success"
}La charge utile contient les champs suivants :
externalID— correspond à l’UUID de la requêtePOST /api/v1/deposits.status— l’une des valeurs"success","failed"ou"unprocessable".
Le webhook doit être envoyé uniquement lorsque le dépôt passe à un statut terminal.
Flux de démarrage du dépôt
Requête de démarrage
B2CORE initie un dépôt en appelant POST /api/v1/deposits.
La requête inclut un champ returnURL — une URL de page frontend B2CORE vers laquelle rediriger l’utilisateur après son interaction avec la page du PSP. Il ne s’agit pas d’un webhook — c’est uniquement une redirection du navigateur.
Pour tous les autres détails, consultez la spécification OpenAPI.
Correspondance des résultats de démarrage
La réponse du PSP correspond à une action B2CORE comme suit :
| Réponse du PSP | Action B2CORE |
|---|---|
| Le PSP renvoie une URL de redirection | Passer à in_progress |
| 2xx avec une violation de la spécification (par exemple, aucune URL de redirection) | Passer à failed |
| HTTP 4xx / 5xx / délai d’expiration / erreur réseau | Passer à failed |
Tous les scénarios d’échec aboutissent à failed (et non à unexpected) car Échec autorisé au démarrage est défini sur yes (voir Échec autorisé au démarrage) : sans URL de redirection valide, l’utilisateur final ne peut pas interagir avec la page de paiement du PSP ; aucun argent ne peut donc être perdu.
Flux de redirection
Lors d’un démarrage réussi, B2CORE reçoit une URL de redirection et envoie l’utilisateur final vers la page de paiement du PSP :
sequenceDiagram
participant B as B2CORE
participant P as PSP
participant U as End user
B->>P: POST /api/v1/deposits
P-->>B: 200 OK<br/>action.type: "redirect"<br/>action.redirect.url: "..."
B->>U: Redirect end user to PSP payment page
U->>P: Open PSP payment page
U->>P: Complete payment
P-->>U: Redirect to returnURL
U->>B: Land on B2CORE "in progress" page- Le
returnURLramène l’utilisateur vers une page frontend B2CORE indiquant que le dépôt est en cours de traitement. - Après le démarrage, B2CORE lance le flux de polling et de webhook (voir Polling et synchronisation des statuts).
- Actuellement,
"redirect"est le seul type d’action pris en charge.
Polling et synchronisation des statuts
Planification du backoff de polling
B2CORE utilise un backoff progressif pour interroger GET /api/v1/deposits/{externalID} :
| Temps écoulé depuis le démarrage du dépôt | Intervalle de polling |
|---|---|
| 0–15 minutes | Toutes les 1 minute |
| 15–60 minutes | Toutes les 3 minutes |
| 1–3 heures | Toutes les 5 minutes |
| 3–5 heures | Toutes les 10 minutes |
| 5+ heures | Toutes les 15 minutes |
Gestion du délai
Délai par défaut : 4 heures après la création du dépôt (configurable, voir Délai de synchronisation par défaut).
Lorsque le délai est dépassé, les statuts intermédiaires sont résolus comme suit :
| Dernier résultat du polling | Action B2CORE |
|---|---|
inProgress | Passer à unexpected |
| Erreur réseau, 5xx, erreur d’analyse et similaire | Passer à unexpected |
Le statut unexpected arrête le polling automatique et nécessite une action manuelle de l’administrateur via LifecycleService de B2CORE.
Logique d’attente du webhook
Lorsque Attendre le webhook avant le polling est défini sur yes (valeur par défaut actuelle, voir Attendre le webhook avant le polling) :
flowchart TD
A["t=0min: deposit created, redirect URL returned<br/>Poller scheduled but WAITS for webhook"] --> B{Webhook received<br/>before t=5min?}
B -- yes --> C["Immediately poll<br/>GET /api/v1/deposits/{externalID}"]
B -- "no (t=5min elapsed)" --> D["Begin standard polling<br/>(1-minute intervals initially)"]
C --> E[Continue with standard<br/>polling backoff]
D --> E
E --> F[Continue until terminal status<br/>or deadline]Correspondance des résultats du polling
Chaque résultat de polling provenant de GET /api/v1/deposits/{externalID} correspond à une action interne B2CORE :
| Statut de réponse du PSP | Action B2CORE |
|---|---|
"inProgress" + délai non dépassé | Continuer le polling (nouvelle tentative) |
"inProgress" + délai dépassé | Passer à unexpected |
"success" | Passer à success, arrêter le polling. Enregistrer finalAmount et finalCurrencyCode |
"failed" | Passer à failed, arrêter le polling. Enregistrer reason |
"unprocessable" | Passer à unexpected, arrêter le polling. Enregistrer reason. Nécessite une investigation de l’administrateur |
| HTTP 5xx / délai d’expiration / erreur d’analyse | Traiter comme une tentative de polling unexpected. Continuer le polling si le délai n’est pas dépassé |
HTTP 404 avec X-Safe-To-Fail-After-Seconds | Continuer le polling. Après la durée indiquée plus une marge de sécurité (5 minutes), si toujours 404, passer à failed avec la raison "deposit redirect URL is expired" |
| HTTP 404 sans l’en-tête | Continuer le polling. Attendre que le dépôt apparaisse côté PSP ou que le délai de synchronisation soit dépassé |
Cycle de vie des statuts de dépôt
Cette section décrit les statuts de dépôt B2CORE. Pour la correspondance entre les statuts de réponse du PSP et les statuts B2CORE, consultez Correspondance des résultats de démarrage et Correspondance des résultats du polling.
Diagramme complet des statuts
flowchart TD
created[created]
post["POST /api/v1/deposits"]
failed1[failed]
inProgress1[in_progress]
unexpected1[unexpected]
poll["GET /api/v1/deposits/{externalID}<br/>(polling)"]
retryIP["(in_progress)<br/>(retry)"]
retryUX["(unexpected)<br/>(retry)"]
success[success]
failed2[failed]
unprocessable["(unprocessable)<br/>(stop polling)"]
inProgress2[in_progress]
created --> post
post --> failed1
post --> inProgress1
inProgress1 --> poll
poll --> retryIP
poll --> retryUX
poll --> success
poll --> failed2
poll --> unprocessable
retryIP --> inProgress2
retryUX --> inProgress2
unprocessable --> unexpected1
unexpected1 -->|Manual recovery| inProgress2Récupération depuis le statut unexpected
Un administrateur peut effectuer ces transitions manuelles via LifecycleService :
| Transition | Quand l’utiliser |
|---|---|
unexpected → in_progress | Réessayer le polling (par exemple, après la résolution d’une panne du PSP) |
unexpected → success | Uniquement si la dernière tentative de polling était unprocessable et que l’administrateur confirme le succès |
unexpected → failed | L’administrateur confirme que le dépôt a échoué |
Définitions des statuts de dépôt
Le tableau suivant définit chaque statut de dépôt B2CORE :
| Statut | Signification métier |
|---|---|
in_progress | Le dépôt est en cours de traitement. Couvre tous les états intermédiaires : virement bancaire en attente, vérification 3DS en cours, attente d’un examen manuel côté PSP, client interagissant avec la page de paiement du PSP et situations similaires. Il s’agit d’un statut non terminal — B2CORE continue le polling. |
success | Le courtier a reçu l’argent du client. Le PSP a confirmé que les fonds ont été crédités. Les champs finalAmount et finalCurrencyCode reflètent le montant et la devise réellement reçus, qui peuvent différer de la demande initiale en raison de frais ou d’une conversion. |
failed | Le dépôt n’a pas abouti. Le client n’a pas perdu d’argent et le courtier n’a pas reçu de fonds. Exemples : carte refusée, virement bancaire rejeté, utilisateur ayant annulé sur la page du PSP ou lien de redirection expiré. |
unexpected | Le dépôt n’a pas pu être résolu automatiquement et nécessite une action manuelle de l’administrateur via B2CORE (voir Récupération depuis le statut unexpected) ; le polling automatique a été arrêté. Ce statut est utilisé lors d’un dépassement de délai pendant in_progress, ou lorsque le PSP signale unprocessable. |
Moment de création du dépôt
Les PSP suivent l’un des deux modèles de création de dépôt :
| Modèle | Comportement | Impact sur le polling |
|---|---|---|
| Création immédiate | Le PSP crée l’enregistrement du dépôt lors de POST /api/v1/deposits. | GET /api/v1/deposits/{externalID} renvoie un résultat immédiatement après le démarrage. |
| Création différée | Le PSP crée l’enregistrement du dépôt uniquement après que l’utilisateur final a terminé la page de paiement du PSP. | GET /api/v1/deposits/{externalID} renvoie 404 Not Found tant que l’utilisateur n’a pas terminé la page. |
Pour la création différée, le PSP devrait renvoyer l’en-tête X-Safe-To-Fail-After-Seconds avec la réponse 404. Cet en-tête indique à B2CORE combien de temps le lien de redirection est valide. Après redirect_time + header_value + safety_margin, si le dépôt est toujours en 404, B2CORE le marque comme failed avec la raison "deposit redirect URL is expired".
Si l’en-tête est absent, B2CORE continue le polling jusqu’à ce que le dépôt apparaisse ou que le délai de synchronisation (4 heures par défaut) soit dépassé, auquel cas le dépôt passe à unexpected.
Exigences comportementales
Traçage distribué
Toutes les requêtes HTTP de B2CORE vers le PSP incluent des en-têtes de traçage standard conformément à la spécification W3C Trace Context :
traceparent— contient l’ID de trace, l’ID de span parent et les indicateurs de trace.tracestate— données de trace spécifiques au fournisseur.
Les implémentations PSP devraient propager ces en-têtes à leurs services en aval afin de permettre une observabilité de bout en bout.
Verrouillage de la devise sur la page de paiement PSP
Lorsque la réponse de démarrage du dépôt inclut une redirection vers une page de paiement PSP :
- La page PSP ne doit pas permettre à l’utilisateur final de modifier le
currencyCodevers une devise analogue, équivalente ou alternative. - La devise affichée sur la page PSP doit correspondre exactement à celle envoyée dans la requête de démarrage du dépôt.
- Si la page PSP permet la sélection de devise, la devise doit être présélectionnée et verrouillée.
Recommandation de liste blanche d’IP
Bien que cela ne soit pas exigé par la spécification API, il est fortement recommandé aux implémentations PSP de configurer une liste blanche d’IP de leur côté. Cela fournit une couche de sécurité supplémentaire au-delà de l’authentification JWT, en limitant l’accès API aux adresses IP B2CORE connues.
Pour rendre le pilote Canonical disponible dans votre environnement, veuillez contacter votre gestionnaire de compte. Indiquez précisément comment et à quelles fins vous prévoyez d’utiliser le pilote Canonical afin que nous puissions organiser l’accès en conséquence.
Dernière mise à jour le