# Modèles de transaction - Transfert
API Tiers de Mojaloop
# Table des matières
- Préface
1.1 Conventions utilisées dans ce document
1.2 Informations sur la version du document
1.3 Références - Introduction
2.1 Spécification de l'API Tiers - Transferts
3.1 Découverte
3.2 Accord
3.3 Transfert - Demande de statut de TransactionRequest
- Conditions d’erreur
5.1 Recherche de Bénéficiaire Incorrecte
5.2 Mauvaise demande de transaction tierce
5.3 Échec API FSPIOP aval
5.4 Challenge signé invalide
5.5 Expiration de la demande de transaction tierce - Annexe
6.1 Dérivation du challenge
# 1. Préface
Cette section contient des informations sur l'utilisation de ce document.
# 1.1. Conventions utilisées dans ce document
Les conventions suivantes sont utilisées dans ce document pour identifier les types d'informations spécifiés.
| Type d’information | Convention | Exemple |
|---|---|---|
| Éléments de l’API, comme les ressources | Gras | /authorization |
| Variables | Italique entre chevrons | {ID} |
| Termes du glossaire | Italique à la première occurrence ; défini dans le Glossaire | Le but de l'API est de permettre les transactions financières interopérables entre un Payeur (un payeur de fonds électroniques dans une transaction de paiement) situé dans un FSP (une entité qui fournit un service financier numérique à un utilisateur final) et un Bénéficiaire (un destinataire de fonds électroniques dans une transaction de paiement) situé dans un autre FSP. |
| Documents de référence | Italique | Les informations utilisateur ne devraient, en général, pas être utilisées par les déploiements d'API ; les mesures de sécurité détaillées dans Signature API et Chiffrement API devraient être utilisées à la place. |
# 1.2. Informations sur la version du document
| Version | Date | Description des modifications |
|---|---|---|
| 1.0 | 2021-10-03 | Version initiale |
# 1.3. Références
Les références suivantes sont utilisées dans cette spécification :
| Référence | Description | Version | Lien |
|---|---|---|---|
| Réf. 1 | Open API pour l'interopérabilité FSP | 1.1 | Définition d’API v1.1 (opens new window) |
# 2. Introduction
Ce document présente les modèles de transaction pris en charge par l'API Tiers en lien avec l'initiation d'une demande de transaction (Transaction Request) provenant d’un PISP.
La conception de l’API et le style architectural de cette API sont basés sur la Section 3 (opens new window) de la Réf. 1 ci-dessus.
# 2.1 Spécification de l'API Tiers
La spécification de l’API Tiers Mojaloop inclut les documents suivants:
- Modèles de données
- Modèles de transaction - Liaison
- Modèles de transaction - Transfert
- Définition de l'API ouverte tierce partie – DFSP
- Définition de l'API ouverte tierce partie – PISP
# 3. Transferts
Les transferts sont divisés en sections séparées :
Découverte : Le PISP recherche le bénéficiaire auquel envoyer des fonds
Accord : Le PISP confirme le bénéficiaire, et recherche les conditions de la transaction. Si l'Utilisateur accepte les conditions de la transaction, il signe la transaction avec le justificatif établi lors du flux d’API de liaison
Transfert : Le DFSP du payeur initie la transaction et informe le PISP du résultat de celle-ci.
# 3.1 Découverte
Dans cette phase, un utilisateur saisit l'identifiant de l'utilisateur à qui il souhaite envoyer des fonds. Le PISP exécute un appel GET /parties/{Type}/{ID}** (ou GET /parties/{Type}/{ID}/{SubId}) et attend un callback du switch Mojaloop. Section 6.3 (opens new window) de la Réf. 1 décrit la ressource /parties en détail.
Si la demande GET /parties/{Type}/{ID} réussit, le PISP recevra un callback PUT /parties du switch Mojaloop. Le PISP confirme alors le bénéficiaire avec son utilisateur.
Si le PISP reçoit un callback PUT /parties/{Type}/{ID}/error (ou PUT /parties/{Type}/{ID}/{SubId}/error), il doit afficher l’erreur pertinente à l'utilisateur.
# 3.2 Accord
# 3.2.1 Demande de transaction tierce
Après avoir confirmé les détails du bénéficiaire avec son utilisateur, le PISP demande à l'utilisateur de saisir le montant à envoyer au bénéficiaire, et s’il souhaite que le bénéficiaire reçoive ce montant, ou qu'il souhaite envoyer ce montant (champ amountType).
Si l'utilisateur a associé plus d'un compte avec l'application PISP, le PISP peut lui demander de choisir un compte source pour le virement. Une fois la source de fonds confirmée, le PISP peut déterminer :
- le
FSPIOP-Destinationcomme le DFSP avec lequel le compte de l'utilisateur est associé - Le champ
payerdu corps de la requête POST /thirdpartyRequests/transactions.partyIdTypeestTHIRD_PARTY_LINK,fspIdest le fspId du DFSP qui a émis la liaison, etpartyIdentifierest l’accountIdspécifié dans le corps POST /consents#scopes.
Voir Octroi du consentement pour plus d’informations.
Le PISP génère ensuite un transactionRequestId aléatoire de type UUID (voir RFC 4122 UUID (opens new window)).
Lors de la réception de l'appel POST /thirdpartyRequests/transactions du PISP, le DFSP effectue certaines validations telles que :
- Déterminer que l'identifiant
payerexiste, et a bien été émis par ce DFSP au PISP spécifié dansFSPIOP-Source. - Confirmer que le
Consentementidentifié parpayerexiste et est valide. - Confirmer que le compte de l'utilisateur est actif et a suffisamment de fonds pour effectuer la transaction.
- Toute autre validation que le DFSP souhaite effectuer.
Si cette validation réussit, le DFSP génère un transactionId unique pour la demande, et appelle PUT /thirdpartyRequests/transactions/{ID} avec ce transactionId et l’état transactionRequestState à RECEIVED.
Cet appel informe le PISP que la demande de transaction tierce a été acceptée, et l'informe du transactionId final à suivre ultérieurement.
Si la validation échoue, le DFSP doit envoyer un appel PUT /thirdpartyRequests/transactions/{ID}/error au PISP, contenant un message d’erreur expliquant l’échec. Voir Codes erreurs pour plus d’informations.
# 3.2.2 Demande d’autorisation tierce
Le DFSP payeur (c’est-à-dire, l’institution envoyant des fonds à la demande du PISP) peut alors émettre une demande de devis (POST /quotes) au DFSP bénéficiaire (l’institution recevant les fonds). Après réception du callback PUT /quotes/{ID} du DFSP bénéficiaire, le DFSP payeur doit confirmer les détails de la transaction auprès du PISP.
Il utilise l’appel d’API POST /thirdpartyRequests/authorizations. Le corps de la requête contient les champs suivants :
transactionRequestId– l'identifiant original de POST /thirdpartyRequests/transactions. Utilisé par le PISP pour corréler une demande d’autorisation à une demande de transaction tierce.authorizationRequestId– un UUID aléatoire généré par le DFSP pour identifier cette demande d’autorisation tiercechallenge– le challenge est uneBinaryStringqui sera signé par la clé privée sur l'appareil de l'utilisateur. Bien qu'il puisse s'agir d'une chaîne aléatoire, il est recommandé qu’elle soit dérivée à partir de quelque chose de significatif pour les acteurs de la transaction, qui ne puisse être prédit à l’avance par le PISP. Voir Section 4.1 pour un exemple de dérivation du challenge.transactionType– le champtransactionTypede la demande initiale POST /thirdpartyRequests/transactions
# 3.2.3 Autorisation signée
Une fois la requête POST /thirdpartyRequests/authorizations reçue du DFSP Payeur, le PISP présente les conditions de la transaction à l'utilisateur, et lui demande s'il souhaite la poursuivre.
Les résultats de la demande d'autorisation sont retournés au DFSP via PUT /thirdpartyRequests/authorizations/{ID}, où
{ID} est le authorizationRequestId.
Si l’utilisateur rejette la transaction, la charge utile envoyée dans PUT /thirdpartyRequests/authorizations/{ID} est :
{
"responseType": "REJECTED"
}
Si l’utilisateur accepte la transaction, la charge utile dépend du credentialType du Consent.credential :
Si
FIDO, le PISP demande à l’utilisateur de compléter le flux FIDO Assertion (opens new window) pour signer le challenge. LesignedPayload.fidoSignedPayloadest leFIDOPublicKeyCredentialAssertionrenvoyé suite au processus FIDO. Voir 3.2.3.1 Signature du challenge FIDOSi
GENERIC, la clé privée créée lors du processus d’enregistrement du credential est utilisée pour signer le challenge. Voir 3.2.3.2 Signature du challenge avec un credential GENERIC
# 3.2.3.1 Signature du challenge FIDO
Pour un credentialType FIDO, le PISP demande à l’utilisateur de compléter le flux FIDO Assertion (opens new window) pour signer le challenge. Le champ signedPayload.value est le PublicKeyCredential (opens new window) renvoyé du processus FIDO Assertion, où les ArrayBuffer sont encodés en chaînes base64 utf-8. Le PublicKeyCredential est la réponse aussi bien pour l’attestation que pour l’assertion FIDO, nous définissons l’interface suivante : FIDOPublicKeyCredentialAssertion :
FIDOPublicKeyCredentialAssertion {
"id": "string",
"rawId": "string - base64 encodé utf-8",
"response": {
"authenticatorData": "string - base64 encodé utf-8",
"clientDataJSON": "string - base64 encodé utf-8",
"signature": "string - base64 encodé utf-8",
"userHandle": "string - base64 encodé utf-8"
},
"type": "public-key"
}
Le payload final du PUT /thirdpartyRequests/authorizations/{ID} sera ainsi :
{
"responseType": "ACCEPTED",
"signedPayload": {
"signedPayloadType": "FIDO",
"fidoSignedPayload": FIDOPublicKeyCredentialAssertion
}
}
# 3.2.3.2 Signature du challenge avec un credential GENERIC
Pour un credential GENERIC, le PISP effectue les étapes suivantes :
- Étant donné les entrées :
challenge(authorizationRequest.challenge) sous forme de chaîne base64 encodée utf-8privatekey(stockée par le PISP lors de la création du credential), chaîne base64 encodée utf-8- SHA256() est une fonction de hachage à sens unique, voir RFC6234 (opens new window)
- sign(data, key) est une fonction de signature prenant des données et une clé privée pour produire une signature
- Soit
challengeHashle résultat de la fonction SHA256() appliquée auchallenge - Soit
signaturele résultat de la fonction sign() appliquée àchallengeHashetprivateKey
La réponse du PISP au DFSP utilise alors cette signature comme champ signedPayload.genericSignedPayload :
Le payload final du PUT /thirdpartyRequests/authorizations/{ID} est alors :
{
"responseType": "ACCEPTED",
"signedPayload": {
"signedPayloadType": "GENERIC",
"genericSignedPayload": "signature encodée utf-8 base64"
}
}
# 3.2.4 Validation de l’autorisation
Note : Si le DFSP utilise un service d’autorisation auto-hébergé, cette étape peut être sautée.
Le DFSP doit maintenant vérifier que le challenge a bien été signé, et par la clé privée correspondant à la clé publique attachée à l'objet Consent.
Le DFSP utilise l'appel d’API POST /thirdpartyRequests/verifications, dont le corps est composé de :
verificationRequestId– Un UUID créé par le DFSP pour identifier cette vérification.challenge– Le même challenge envoyé au PISP dans 3.2.2 Demande d’autorisation tierceconsentId– L’identifiant du Consent qui contient la clé publique credential à utiliser pour vérifier cette transaction.signedPayloadType– Le type de SignedPayload, selon le type d’identifiant enregistré par le PISPfidoValueougenericValue– Le champ correspondant du corps de la requête PUT /thirdpartyRequests/authorizations du PISP. Le DFSP doit rechercher leconsentIdd’après les détails dupayerde laThirdpartyTransactionRequest.
# 3.3 Transfert
Après validation du challenge signé, le DFSP peut lancer une transaction Mojaloop standard via l’API FSPIOP.
Après avoir reçu l’appel PUT /transfers/{ID} du switch, le DFSP recherche le ThirdpartyTransactionRequestId du transfert donné puis envoie un appel PATCH /thirdpartyRequests/transactions/{ID} au PISP.
Une fois ce callback reçu, le PISP sait que le transfert est réussi et peut en informer son utilisateur.
# 4. Demander le statut de la TransactionRequest
Un PISP peut effectuer un GET /thirdpartyRequests/transactions/{ID} pour obtenir le statut d’une demande de transaction.
Le PISP effectue un GET /thirdpartyRequests/transactions/{ID}
Le switch valide la demande et répond par
202 AcceptedLe switch recherche l’endpoint pour
dfspapour la transférer à DFSP ADFSPA valide la demande et répond avec
202 AcceptedLe DFSP recherche la demande de transaction via son
transactionRequestId- Si elle est introuvable, il appelle PUT /thirdpartyRequests/transactions/{ID}/error vers le switch, avec un message d’erreur pertinent
Le DFSP vérifie que l'entête
FSPIOP-Sourcecorrespond à celui d’origine du POST /thirdpartyRequests/transactions- Sinon il appelle PUT /thirdpartyRequests/transactions/{ID}/error vers le switch, avec un message d'erreur pertinent
Le DFSP appelle PUT /thirdpartyRequests/transactions/{ID} avec le corps suivant :
{ transactionRequestState: TransactionRequestState }Où
transactionIdest l’identifiant de transaction généré par le DFSP, etTransactionRequestStateestRECEIVED,PENDING,ACCEPTED,REJECTED, comme défini dans 7.5.10 TransactionRequestState (opens new window) de la Définition d’APILe switch valide la demande et répond avec
200 OKLe switch recherche l’endpoint pour
pispaet transmet au PISPLe PISP valide la demande et répond avec
200 OK
# 5. Conditions d’erreur
Après que le PISP a initié la demande de transaction tierce via POST /thirdpartyRequests/transactions, le DFSP doit envoyer soit un PUT /thirdpartyRequests/transactions/{ID}/error soit un callback PATCH /thirdpartyRequests/transactions/{ID} pour informer le PISP du statut final.
- PATCH /thirdpartyRequests/transactions/{ID} est utilisé pour informer le PISP du statut final. Il peut s’agir soit d’un rejet par l’utilisateur, soit d’une approbation ayant abouti à un transfert réussi.
- PUT /thirdpartyRequests/transactions/{ID}/error informe le PISP en cas d’échec de la demande.
- Si le PISP ne reçoit aucun de ces callbacks avant l’expiration
expirationspécifiée dans la requête POST /thirdpartyRequests/transactions, il peut considérer la demande comme échouée et en informer son utilisateur.
# 5.1 Recherche de bénéficiaire infructueuse
Quand le PISP effectue une recherche de bénéficiaire (GET /parties/{Type}/{ID}), il peut recevoir le callback PUT /parties/{Type}/{ID}/error.
Voir 6.3.4 Parties Error Callbacks (opens new window) de la Définition d’API FSPIOP pour plus d’informations sur ce callback d’erreur.
Dans ce cas, le PISP peut vouloir afficher un message d’erreur à l’utilisateur, en l’invitant à essayer avec un autre identifiant ou plus tard.
# 5.2 Mauvaise demande de transaction tierce
Quand le DFSP reçoit le POST /thirdpartyRequests/transactions du PISP, les erreurs suivantes peuvent se produire :
- Le
payer.partyIdTypeoupayer.partyIdentifierest invalide ou pas lié à un consentement valide connu du DFSP - Le compte utilisateur identifié par
payer.partyIdentifiern'a pas assez de fonds - La devise précisée dans
amount.currencyn’est pas prise en charge par le compte de l’utilisateur payee.partyIdInfo.fspIdn’est pas défini — il s’agit d’une propriété optionnelle, mais le fspId bénéficiaire sera requis pour adresser correctement la demande de devis- Tout autre contrôle ou vérification côté DFSP échoue
Dans ce cas, le DFSP doit informer le PISP de l’échec en envoyant un callback PUT /thirdpartyRequests/transactions/{ID}/error.
Le PISP peut alors informer son utilisateur de l’échec, et proposer de relancer une demande s’il le souhaite.
# 5.3 Échec API FSPIOP aval
Le DFSP peut ne pas vouloir, ou ne pas être en mesure, d’exposer des détails sur les échecs API FSPIOP aval au PISP.
Par exemple, avant d’émettre un POST /thirdpartyRequests/authorizations au PISP, si le POST /quotes avec le FSP bénéficiaire échoue, le DFSP envoie un callback PUT /thirdpartyRequests/transactions/{ID}/error au PISP.
Un autre exemple : si la requête POST /transfers échoue :
# 5.4 Challenge signé invalide
Après réception d’un POST /thirdpartyRequests/authorizations du DFSP, le PISP demande à l'utilisateur de signer le challenge via le justificatif enregistré lors du flux de liaison de comptes.
Le challenge signé est retourné au DFSP via PUT /thirdpartyRequest/authorizations/{ID}.
Le DFSP :
- Valide lui-même le challenge signé
- Ou interroge le Auth-Service via thirdpartyRequests/verifications pour vérifier la signature contre la clé publique enregistrée dans le Consent.
Si le challenge signé est invalide, le DFSP appelle alors PUT /thirdpartyRequests/transactions/{ID}/error vers le PISP.
# Cas 1 : DFSP se charge de vérifier le challenge
# Cas 2 : DFSP utilise le Auth-Service hébergé par le hub pour vérifier le challenge signé contre le credential enregistré.
# 5.5 Expiration de la demande de transaction tierce
Si le PISP ne reçoit aucun des callbacks ci-dessus avant la date d’expiration expiration définie dans POST /thirdpartyRequests/transactions, il peut considérer la demande comme échouée et en informer immédiatement l'utilisateur.
# 6. Annexe
# 6.1 Dérivation du challenge
- Soit
quotela valeur du corps de la réponse de l’appel PUT /quotes/{ID}_ - La fonction
CJSON()est l’implémentation du JSON Canonical vers une chaîne, conforme à RFC-8785 - Canonical JSON format (opens new window) - La fonction
SHA256()est la fonction de hachage SHA-256, conforme à RFC-6234 (opens new window) - Le DFSP doit générer la valeur
jsonStringen appliquantCJSON(quote) - Le
challengeest la valeur deSHA256(jsonString)
