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

# API Travel Rule : actions sur les transferts

> Avec Didit, clôturez un transfert Travel Rule avec son hash on-chain, annulez-le ou renvoyez-le, ou enregistrez le portefeuille d'origine.



Prompt pour l'API des actions de transfert Travel Rule
        Copier le prompt dans le presse-papiers



      
      

\<pre>

\`Act on an existing Travel Rule transfer: report the on-chain hash to finish it, cancel it, re-run counterparty routing, replace a refused compliance email, or record the wallet the funds left from.

Endpoint:
PATCH https://verification.didit.me/v3/transactions/{transaction_id}/travel-rule/

Authentication:
Use the x-api-key header with my Didit API key. {transaction_id} is the Didit transaction uuid.

Four mutually exclusive bodies:

1\. Finish (close out after broadcasting on-chain):
\{"payment_txn_id": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"}
\- Requires an OUTBOUND transfer in COMPLETED status - otherwise 409.
\- Moves the transfer (and its INTERNAL-rail counterpart, if any) to FINISHED and stores the hash on the transaction.
\- Over GTR, VerifyVASP or Sygna Bridge, the network learns the hash after the response, with retries (see delivery below).
\- On the TRP rail, Didit also posts the hash to the counterparty's confirmation callback.

2\. Cancel:
\{"action": "cancel"}
\- Allowed from any non-terminal status; moves the transfer (and its INTERNAL-rail counterpart, if any) to CANCELLED.
\- From a terminal status (FINISHED, CANCELLED, EXPIRED) it returns 409.
\- On an outbound TRP transfer, Didit also sends a cancellation to the counterparty.
\- Over GTR, VerifyVASP or Sygna Bridge, the network is told after the response, with retries.

3\. Resend (re-run the routing ladder):
\{"action": "resend"}
\- Allowed only on an OUTBOUND transfer in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA - otherwise 409.
\- Resets the deadline and re-runs routing; a transfer whose destination wallet was declared unhosted moves to UNCONFIRMED_OWNERSHIP.
\- First give Didit a route, for example by registering the destination wallet in your address book (same chain as the transfer, or a blank chain) with the counterparty's travel_address (TRP carries BTC, ETH, and USDC on a named network), or by adding a compliance contact for the counterparty's directory entry with POST /v3/travel-rule/counterparty-contacts/, then resend.
\- Resend reuses the transfer's beneficiary_data, which you cannot change after creation except for the compliance email (body 4), so submit a new transaction to send different beneficiary data.
\- A previously recorded blockchain-analytics attribution is reused - no new lookup, no new charge.
\- Discovery runs again from the first step (internal address book, wallet attribution, network lookup, your VASP hint, then the end user); the transfer's "discovery" list shows what each step found.
\- Queued, not run inside the request: the response shows the transfer back in AWAITING_COUNTERPARTY with a "resend queued" timeline entry, and the outcome arrives as a travel_rule.status.updated webhook. A resend sent while an earlier attempt is still running is sent once that attempt settles.
\- If routing still resolves nothing, the transfer lands back in COUNTERPARTY_VASP_NOT_FOUND.

4\. Update the compliance email (the fix for reason email_undeliverable):
\{"action": "update_compliance_email", "compliance_email": "desk@bene-casp.example"}
\- Allowed only on an OUTBOUND transfer in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA - otherwise 409.
\- A missing or malformed compliance_email returns 400.
\- Stores the address as this transfer's beneficiary_data.counterparty_vasp_email; it belongs to this transfer only and joins no directory entry or contact list.
\- The status does not change and the timeline gains "compliance email updated". The transfer keeps reason email_undeliverable until you send {"action": "resend"}, which sends the request to the new address.

4\. Update the originator wallet (the wallet the funds actually left from):
\{"action": "update_originator_wallet", "wallet_address": "bc1q...", "memo": ""}
\- Outbound transfers only (an inbound transfer -> 409), and never a CANCELLED or EXPIRED one (-> 409).
\- Use it when a withdrawal is broadcast from another address than the one declared, typically a UTXO withdrawal spending whichever addresses held the coins. When the transfer's UTXO inputs are known, wallet_address must be one of them (-> 400 otherwise).
\- Changes the record only: nothing is sent to the counterparty again and the status stays. chain_details.originator becomes the new wallet with source "updated", the timeline records the previous and the new wallet, and the INTERNAL-rail counterpart is updated the same way.

5\. Name the counterparty (when discovery could not):
\{"action": "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"}
\- The id comes from GET /v3/travel-rule/vasps/.
\- Allowed only for an outbound transfer in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA - otherwise 409.
\- Routes the transfer to that VASP and sends it again; automatic discovery never overrides your choice.
\- 400 if beneficiary_vasp is missing or not a valid id, 404 if no directory entry has that id.

What to read from the response:
\- The full transfer object: status, rail, direction, ownership_confirmed, deadline_at, timeline, counterparty_vasp, delivery, discovery, reason, next_actions.
\- delivery: the latest message the transfer owes the other side - kind (SEND, ANSWER, TXID, CANCEL, POLL), status (QUEUED, SENDING, RETRYING, DELIVERED, FAILED), rail, attempts, last_error, next_attempt_at, delivered_at. Failures a network may recover from are retried after 30 s, 2, 10, 30 and 60 minutes; when a first message fails for good the transfer moves to COUNTERPARTY_VASP_NOT_REACHABLE. null when the transfer never owed a message.
\- reason and next_actions say why a COUNTERPARTY_VASP_NOT_FOUND or COUNTERPARTY_VASP_NOT_REACHABLE transfer is stuck and what moves it on: email_undeliverable offers update_compliance_email then resend, delivery_failed offers resend, and a discovery reason offers select_counterparty_vasp, declare_self_hosted, add_vasp_hint and resend. Both are empty for any other status, so they clear once a resend moves the transfer on.

Order of operations for outbound transfers:
submit transaction -> wait for travel_rule.status == "COMPLETED" -> broadcast on-chain -> PATCH with payment_txn_id -> FINISHED.
Never broadcast before COMPLETED.
A transfer sent over TRUST cannot reach COMPLETED, because TRUST sends back nothing Didit can read; it stays AWAITING_COUNTERPARTY until it expires. Over GTR, VerifyVASP and Sygna Bridge, Didit reads the counterparty's answer from the network.
If the message cannot be delivered, the transfer moves to COUNTERPARTY_VASP_NOT_REACHABLE instead.

Failure modes:
\- 400 - the body has none of payment_txn_id or a supported action, update_compliance_email has a missing or malformed compliance_email, or a wallet_address or memo the transfer's chain cannot carry.
\- 409 - action not allowed from the transfer's current status or direction (see the per-action rules above).
\- 400 - action=beneficiary_vasp without a valid beneficiary_vasp.
\- 404 - unknown transaction, no Travel Rule transfer attached, or (action=beneficiary_vasp) no directory entry has that id.

Full guide: /transaction-monitoring/travel-rule#sending-a-transfer and /transaction-monitoring/travel-rule#why-a-transfer-is-stuck.`

\</pre>



      
      

Coller dans



## OpenAPI

````yaml fr/openapi-25.json PATCH /v3/transactions/{transaction_id}/travel-rule/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: API de vérification d'identité. Authentifiez-vous avec l'en-tête x-api-key.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/transactions/{transaction_id}/travel-rule/:
    patch:
      tags:
        - Travel Rule
      summary: >-
        Terminer, annuler, renvoyer ou mettre à jour le portefeuille du donneur
        d'ordre d'un transfert Travel Rule
      description: >-
        Fournissez `payment_txn_id` pour signaler le hash on-chain et passer un
        transfert sortant COMPLETED à FINISHED (son homologue sur le rail
        INTERNAL passe également à FINISHED), `{"action": "cancel"}` pour
        annuler un transfert non terminal, ou `{"action": "resend"}` pour router
        à nouveau un transfert sortant bloqué dans COUNTERPARTY_VASP_NOT_FOUND,
        COUNTERPARTY_VASP_NOT_REACHABLE ou NOT_ENOUGH_COUNTERPARTY_DATA
        (améliorez d'abord les données de la contrepartie, par ex. en ajoutant
        une travel_address à l'entrée du portefeuille de destination). resend
        s'applique uniquement aux transferts sortants. `{"action":
        "update_compliance_email", "compliance_email": "desk@example.com"}`
        remplace l'e-mail de conformité d'un transfert sortant se trouvant dans
        l'un de ces trois statuts, la solution pour `reason:
        email_undeliverable` : le statut ne change pas, et le prochain `resend`
        envoie la requête à cette adresse. Un renvoi est mis en file d'attente
        et ne s'exécute pas au sein de la requête : la réponse montre le
        transfert de retour dans AWAITING_COUNTERPARTY avec une entrée
        d'historique `resend queued` et une `delivery` en file d'attente, et sa
        destination arrive via un webhook `travel_rule.status.updated`. Lorsque
        le transfert est passé par GTR, VerifyVASP ou Sygna Bridge, le réseau
        est informé du hash on-chain ou de l'annulation après la réponse, avec
        des réessais ; `delivery` indique où en est ce message. `{"action":
        "update_originator_wallet", "wallet_address": "..."}` enregistre le
        portefeuille depuis lequel les fonds sont réellement partis sur un
        transfert sortant, par exemple l'adresse depuis laquelle un retrait UTXO
        a été diffusé plutôt que le portefeuille principal que vous aviez
        déclaré. Cela modifie uniquement l'enregistrement : rien n'est renvoyé à
        la contrepartie et le statut reste le même. Le donneur d'ordre devient
        `chain_details.originator` avec `source: updated`, la modification est
        ajoutée à la `timeline` avec l'ancien et le nouveau portefeuille, et
        l'homologue sur le rail INTERNAL du transfert est mis à jour de la même
        manière. `{"action": "beneficiary_vasp", "beneficiary_vasp": "<directory
        VASP id>"}` désigne vous-même la contrepartie lorsque la découverte a
        échoué, sur un transfert sortant dans COUNTERPARTY_VASP_NOT_FOUND,
        COUNTERPARTY_VASP_NOT_REACHABLE ou NOT_ENOUGH_COUNTERPARTY_DATA : le
        transfert est routé vers ce VASP et envoyé à nouveau.
      operationId: patchTravelRuleTransfer
      parameters:
        - name: transaction_id
          in: path
          required: true
          description: >-
            UUID de transaction stable attribué par Didit propriétaire du
            transfert.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TravelRuleTransferPatchRequest'
            examples:
              Finish:
                value:
                  payment_txn_id: 0xchainhash
              Cancel:
                value:
                  action: cancel
              Resend:
                value:
                  action: resend
              Update compliance email:
                value:
                  action: update_compliance_email
                  compliance_email: desk@example.com
              Update originator wallet:
                value:
                  action: update_originator_wallet
                  wallet_address: bc1qOriginatorInputAddress01
              Name the counterparty:
                value:
                  action: beneficiary_vasp
                  beneficiary_vasp: 9f1c2b34-5d6e-4f70-8a91-b2c3d4e5f607
      responses:
        '200':
          description: >-
            Le transfert mis à jour. Après `update_compliance_email`, son statut
            reste inchangé et conserve `reason: email_undeliverable` jusqu'au
            prochain `resend`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleTransferDetail'
        '400':
          description: >-
            Ni payment_txn_id ni une action prise en charge n'ont été fournis,
            `compliance_email` est manquant ou n'est pas une adresse e-mail lors
            de `update_compliance_email`, ou, pour `update_originator_wallet`,
            aucun wallet_address, un portefeuille ou memo que la blockchain du
            transfert ne peut pas acheminer, ou un portefeuille qui ne fait pas
            partie des entrées UTXO du transfert, ou `beneficiary_vasp` est
            manquant ou n'est pas un identifiant de VASP valide dans l'annuaire.
          content:
            application/json:
              examples:
                No action:
                  value:
                    detail:
                      - >-
                        Provide payment_txn_id, action=cancel, action=resend,
                        action=beneficiary_vasp, action=update_originator_wallet
                        or action=update_compliance_email.
                Invalid compliance email:
                  value:
                    compliance_email:
                      - Enter a valid email address.
        '404':
          description: >-
            Transaction inconnue, la transaction n'a aucun transfert Travel
            Rule, ou (action `beneficiary_vasp`) aucune entrée de l'annuaire ne
            possède cet identifiant.
        '409':
          description: >-
            Le transfert n'est pas dans un état permettant cette opération (par
            exemple, pas COMPLETED/sortant pour finish, déjà terminal pour
            cancel, ou pas un transfert sortant dans un statut réexpédiable pour
            resend). `update_compliance_email` renvoie `409` pour un transfert
            entrant, ainsi que pour un transfert sortant en dehors de
            COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE et
            NOT_ENOUGH_COUNTERPARTY_DATA. `update_originator_wallet` renvoie
            `409` pour un transfert entrant, annulé ou expiré.
            `beneficiary_vasp` renvoie `409` sauf si le transfert est sortant et
            dans l'état COUNTERPARTY_VASP_NOT_FOUND,
            COUNTERPARTY_VASP_NOT_REACHABLE ou NOT_ENOUGH_COUNTERPARTY_DATA.
          content:
            application/json:
              examples:
                Cancel from a terminal status:
                  value:
                    detail: Transfer is already in a terminal state.
                Resend not allowed:
                  value:
                    detail: Transfer cannot be resent from its current state.
                Finish not allowed:
                  value:
                    detail: >-
                      Transfer must be an outbound transfer in COMPLETED status
                      to finish.
                Compliance email cannot change:
                  value:
                    detail: >-
                      The compliance email of this transfer cannot change from
                      its current state.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: >-
            curl -X PATCH
            https://verification.didit.me/v3/transactions/{transaction_id}/travel-rule/
            \
              -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \
              -d '{"payment_txn_id": "0xchainhash"}'
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.transactions.travel_rule.update_transfer(
                "11111111-2222-3333-4444-555555555555",
                payment_txn_id="0xchainhash",
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: >-
            import Didit from "@didit-protocol/sdk-node";


            // Reads DIDIT_API_KEY.

            const didit = new Didit();


            const result = await
            didit.transactions.travelRule.updateTransfer("11111111-2222-3333-4444-555555555555",
            {
              payment_txn_id: "0xchainhash",
            });

            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.Transactions.TravelRule.UpdateTransfer(ctx, \"11111111-2222-3333-4444-555555555555\", didit.TravelRuleTransferPatchRequest{\n\tPaymentTxnID: didit.String(\"0xchainhash\"),\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: >-
            import me.didit.Didit;

            import me.didit.types.TravelRuleTransferPatchRequest;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.transactions().travelRule().updateTransfer("11111111-2222-3333-4444-555555555555",
            TravelRuleTransferPatchRequest.builder()
                    .paymentTxnId("0xchainhash")
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: >-
            <?php


            require 'vendor/autoload.php';


            use Didit\DiditClient;


            // Reads DIDIT_API_KEY.

            $didit = new DiditClient();


            $result =
            $didit->transactions->travelRule->updateTransfer('11111111-2222-3333-4444-555555555555',
            [
                'payment_txn_id' => '0xchainhash',
            ]);

            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

            # Reads DIDIT_API_KEY.
            didit = Didit::Client.new

            result = didit.transactions.travel_rule.update_transfer(
              "11111111-2222-3333-4444-555555555555",
              payment_txn_id: "0xchainhash"
            )
            puts result.to_h
        - lang: csharp
          label: .NET
          source: >-
            using System;

            using System.Text.Json;

            using Didit;


            // Reads DIDIT_API_KEY.

            using var client = new DiditClient();


            var result = await
            client.Transactions.TravelRule.UpdateTransferAsync("11111111-2222-3333-4444-555555555555",
            new TravelRuleTransferPatchRequest

            {
                PaymentTxnId = "0xchainhash",
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    TravelRuleTransferPatchRequest:
      type: object
      description: >-
        Fournissez exactement un des éléments suivants : payment_txn_id
        (finish), action=cancel, action=resend, action=update_compliance_email
        avec compliance_email, action=update_originator_wallet avec
        wallet_address, ou action=beneficiary_vasp avec beneficiary_vasp.
      properties:
        payment_txn_id:
          type: string
          description: >-
            Le hash de la transaction on-chain. Nécessite que le transfert soit
            un transfert sortant au statut COMPLETED.
        action:
          type: string
          enum:
            - cancel
            - resend
            - update_compliance_email
            - update_originator_wallet
            - beneficiary_vasp
          description: "\"cancel\" annule un transfert non terminal. \"resend\" réexécute le routage pour un transfert sortant bloqué dans COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE ou NOT_ENOUGH_COUNTERPARTY_DATA. \"update_compliance_email\" remplace l'e-mail de conformité auquel la requête est envoyée, sur un transfert sortant dans l'un de ces trois statuts\_; envoyez \"resend\" par la suite. \"update_originator_wallet\" enregistre le portefeuille depuis lequel les fonds sont réellement partis (`wallet_address`, `memo`). \"beneficiary_vasp\" vous permet d'indiquer vous-même le VASP de contrepartie (requiert `beneficiary_vasp`) pour un transfert sortant dans l'un de ces statuts\_: il est routé vers ce VASP et envoyé à nouveau."
        compliance_email:
          type: string
          format: email
          maxLength: 254
          description: "Requis avec `action: update_compliance_email`. Conservé comme `beneficiary_data.counterparty_vasp_email` de ce transfert\_: il appartient uniquement à ce transfert et n'est associé à aucune entrée d'annuaire ni à aucune liste de contacts."
        wallet_address:
          type: string
          maxLength: 128
          description: >-
            Avec `action: update_originator_wallet` : le portefeuille depuis
            lequel les fonds sont partis. Lorsque les entrées UTXO du transfert
            sont connues, il doit s'agir de l'une d'entre elles.
        memo:
          type: string
          maxLength: 256
          description: >-
            Avec `action: update_originator_wallet` : le mémo ou tag du
            portefeuille sur un réseau à mémos. Facultatif.
        beneficiary_vasp:
          type: string
          format: uuid
          description: >-
            Requis avec action=beneficiary_vasp : l'`id` d'un VASP de
            l'annuaire, issu de `GET /v3/travel-rule/vasps/`. Votre choix
            prévaut sur chaque étape de découverte automatique, qui ne l'écrase
            jamais.
    TravelRuleTransferDetail:
      type: object
      description: >-
        Objet de transfert complet renvoyé par les endpoints de confirmation
        d'actionnariat et de finalisation/annulation. Tant que l'actionnariat du
        portefeuille d'un transfert entrant n'est pas confirmé, les champs
        `originator_data` et `beneficiary_data` de la contrepartie sont renvoyés
        masqués (la première lettre de chaque mot est conservée ; le
        portefeuille, la blockchain et le routage VASP restent lisibles) et
        `data_masked` est à true.
      properties:
        uuid:
          type: string
          format: uuid
        status:
          type: string
          enum:
            - AWAITING_COUNTERPARTY
            - ON_HOLD
            - COMPLETED
            - FINISHED
            - CANCELLED
            - EXPIRED
            - COUNTERPARTY_MISMATCHED_DATA
            - COUNTERPARTY_VASP_NOT_FOUND
            - COUNTERPARTY_VASP_NOT_REACHABLE
            - UNCONFIRMED_OWNERSHIP
            - COUNTERPARTY_VASP_GENERAL_DECLINE
            - NOT_ENOUGH_COUNTERPARTY_DATA
            - NOT_APPLICABLE
        direction:
          type: string
          enum:
            - INBOUND
            - OUTBOUND
        rail:
          type: string
          nullable: true
          enum:
            - INTERNAL
            - TRP
            - GTR
            - TRUST
            - VERIFYVASP
            - SYGNA
            - EMAIL
            - TEST_VASP
            - null
          description: >-
            Le réseau sur lequel le transfert a été acheminé, ou null
            lorsqu'aucun réseau n'a été sélectionné (par exemple en dessous du
            seuil, un portefeuille de contrepartie auto-hébergé, un
            enregistrement après dépôt ou aucune contrepartie joignable).
            INTERNAL signifie que les deux parties sont des applications Didit ;
            EMAIL signifie que la contrepartie a été jointe via un lien de
            récupération envoyé par e-mail. TEST_VASP signifie que le VASP de
            test Didit a répondu au transfert sandbox. Sur GTR, VERIFYVASP et
            SYGNA, Didit lit la réponse de la contrepartie à partir de la
            réponse du réseau ou en l'interrogeant toutes les 5 minutes. TRUST
            effectue uniquement des envois, de sorte qu'un transfert TRUST reste
            à l'état AWAITING_COUNTERPARTY jusqu'à son expiration. Un canal de
            réseau n'est utilisé que si vous avez connecté votre propre adhésion
            à ce réseau. Il est choisi après le retour de la création de la
            transaction, il est donc null dans cette réponse.
        protocol:
          type: string
          nullable: true
        ivms_version:
          type: string
          example: ivms101.2023
        required:
          type: boolean
        ownership_confirmed:
          type: boolean
          nullable: true
        deadline_at:
          type: string
          format: date-time
          nullable: true
        timeline:
          type: array
          items:
            type: object
            properties:
              status:
                type: string
              at:
                type: string
                format: date-time
              detail:
                type: string
              name_match:
                allOf:
                  - $ref: '#/components/schemas/TravelRuleNameMatch'
                nullable: true
                description: >-
                  La comparaison de noms déterminée par cette entrée, à côté de
                  `detail`. Absente pour les entrées qui n'ont comparé aucun
                  nom.
              reason:
                type: string
                description: >-
                  Présent uniquement sur l'entrée d'une transition provoquée par
                  un échec de livraison : `email_undeliverable` ou
                  `delivery_failed`, la valeur indiquée par le `reason` du
                  transfert.
        counterparty_vasp:
          type: object
          nullable: true
          properties:
            name:
              type: string
            lei:
              type: string
            dd_score:
              type: integer
              description: >-
                Score de due diligence de 0 à 100, où une valeur plus élevée est
                meilleure. Même échelle que dans l'annuaire des VASP.
            dd_score_breakdown:
              type: object
              description: >-
                Contributions par composant au dd_score, un objet par composant
                comme dans le répertoire VASP (jurisdiction, verification,
                protocol, lei, history, essentials, responsiveness), chacun
                comprenant {points, max, reason, detail}. {} jusqu'à ce que la
                contrepartie ait été évaluée.
              additionalProperties:
                type: object
                properties:
                  points:
                    type: number
                    description: Points attribués pour ce composant.
                  max:
                    type: integer
                    description: Nombre maximal de points que ce composant peut attribuer.
                  reason:
                    type: string
                    description: Code lisible par machine du verdict du composant.
                  detail:
                    type: string
                    description: >-
                      Raison lisible par l'utilisateur pour les points
                      attribués.
            dd_assessed_at:
              type: string
              format: date-time
              nullable: true
              description: >-
                Date et heure de la dernière évaluation de diligence
                raisonnable. Null tant que la contrepartie n'a pas été évaluée.
        originator_data:
          type: object
          description: >-
            Partie du donneur d'ordre. Pour un transfert entrant, les valeurs de
            la contrepartie sont masquées jusqu'à ce que l'actionnariat soit
            confirmé.
        beneficiary_data:
          type: object
          description: >-
            Partie bénéficiaire. Pour un transfert entrant, les valeurs de la
            contrepartie sont masquées jusqu'à confirmation de la propriété.
        name_match:
          allOf:
            - $ref: '#/components/schemas/TravelRuleNameMatch'
          nullable: true
          description: "La comparaison de noms qui a déterminé le transfert, ou null tant qu'aucune n'a été exécutée. Lorsque les parties sont masquées, ainsi que sur la copie de l'autre client d'un échange INTERNAL, `transfer_name`, `compared_name`, `matched_names` et `mismatched_names` sont masqués. `score` et `matched` peuvent différer\_: `matched` suit le niveau d'exigence, `score` correspond à la similarité entre les deux noms complets."
        data_match:
          $ref: '#/components/schemas/TravelRuleDataMatch'
        mismatched_fields:
          type: array
          items:
            type: string
          description: >-
            Raccourci pour `data_match.mismatched_fields`. Vide lorsque rien ne
            diffère.
        data_unmasked:
          $ref: '#/components/schemas/TravelRuleDataUnmasked'
        data_masked:
          type: boolean
          description: >-
            Vrai tant que les données personnelles de la contrepartie sont
            masquées dans cette réponse.
        created_at:
          type: string
          format: date-time
        delivery:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/TravelRuleDelivery'
          description: >-
            État d'acheminement du dernier message que ce transfert doit à
            l'autre partie. Vaut null lorsque le transfert n'a jamais dû en
            envoyer un (par exemple en dessous de `threshold_amount`, pour un
            portefeuille auto-hébergé déclaré ou un enregistrement sunrise).
        discovery:
          type: array
          description: >-
            Manière dont Didit a recherché la contrepartie, une entrée par étape
            exécutée. Vide lorsqu'aucune recherche n'a été effectuée, par
            exemple lors d'un transfert entrant.
          items:
            $ref: '#/components/schemas/TravelRuleDiscoveryStep'
        reason:
          type: string
          description: "Raison pour laquelle un transfert `COUNTERPARTY_VASP_NOT_FOUND` ou `COUNTERPARTY_VASP_NOT_REACHABLE` est bloqué\_; `\"\"` pour tout autre statut. Un échec de livraison la détermine en premier, sur `COUNTERPARTY_VASP_NOT_REACHABLE` uniquement\_: `email_undeliverable` (le fournisseur de messagerie a refusé l'e-mail de conformité et il ne reste aucune adresse à essayer\_: lors de son envoi, lors d'un rappel ou sous la forme d'un rejet permanent signalé ultérieurement) ou `delivery_failed` (le canal assurant la livraison a définitivement échoué\_: un canal réseau a refusé le message ou a épuisé ses tentatives, un hôte d'identité `TRP` n'a pas répondu, ou l'hôte `TRP` de la contrepartie n'a pas accepté la demande). Sinon, la trace `discovery` la détermine\_: `awaiting_end_user` (aucune étape n'a désigné de contrepartie que Didit peut joindre), `directory_match_no_route` (une étape a désigné un VASP de l'annuaire qui ne dispose d'aucun routage), `picked_member_without_proven_wallet` (l'utilisateur final a choisi un client Didit qui n'a pas prouvé le contrôle du portefeuille) ou `no_directory_match` lorsque la trace ne donne aucune autre raison. Un nouvel envoi fait progresser le transfert, ce qui efface le motif. Voir [Pourquoi un transfert est bloqué](/fr/transaction-monitoring/travel-rule#pourquoi-un-transfert-est-bloqué)."
        next_actions:
          type: array
          description: >-
            Ce qui permet de faire avancer le transfert ; `[]` pour tout statut
            autre que `COUNTERPARTY_VASP_NOT_FOUND` ou
            `COUNTERPARTY_VASP_NOT_REACHABLE`. `email_undeliverable` propose
            `update_compliance_email`, puis `resend`. `delivery_failed` propose
            `resend`. Un motif lié à la découverte propose
            `select_counterparty_vasp`, `declare_self_hosted`, `add_vasp_hint`
            et `resend`.
          items:
            $ref: '#/components/schemas/TravelRuleNextAction'
        chain_details:
          $ref: '#/components/schemas/TravelRuleChainDetails'
    TravelRuleNameMatch:
      type: object
      nullable: true
      description: "La comparaison de noms qui a déterminé le transfert, ou null tant qu'aucune n'a été exécutée. Lorsque les parties sont masquées, ainsi que sur la copie de l'autre client d'un échange INTERNAL, `transfer_name`, `compared_name`, `matched_names` et `mismatched_names` sont masqués. `score` et `matched` peuvent différer\_: `matched` suit le niveau d'exigence, `score` correspond à la similarité entre les deux noms complets."
      properties:
        score:
          type: integer
          minimum: 0
          maximum: 100
          description: >-
            Similarité des deux noms complets, de 0 à 100. 0 si l'un des deux
            noms est vide.
        matched:
          type: boolean
          description: >-
            Indique si les noms satisfont à `strictness`. L'issue du transfert
            dépend de `data_match`, qui compare chaque champ ; un transfert peut
            donc être COUNTERPARTY_MISMATCHED_DATA alors que cette valeur est
            vraie.
        method:
          type: string
          enum:
            - none
            - exact_token
            - token_subset
            - token_containment
            - sequence_ratio
          description: >-
            Manière dont `matched` a été déterminé : none (`NONE`), exact_token
            (`STRICT`), token_subset (`DEFAULT`), token_containment (`CONTAINS`)
            ou sequence_ratio (`FUZZY`).
        strictness:
          type: string
          enum:
            - NONE
            - STRICT
            - CONTAINS
            - DEFAULT
            - FUZZY
        compared_with:
          type: string
          enum:
            - wallet_holder
            - counterparty_vasp
          description: >-
            wallet_holder : le titulaire enregistré pour le portefeuille.
            counterparty_vasp : le nom fourni par la contrepartie sur la page de
            réponse par e-mail, ou la réponse du VASP de test Didit dans le
            sandbox.
        transfer_name:
          type: string
          description: Le nom figurant sur le transfert.
        compared_name:
          type: string
          description: Le nom avec lequel il a été comparé.
        matched_names:
          type: array
          items:
            type: string
          description: Mots de `transfer_name` trouvés dans `compared_name`.
        mismatched_names:
          type: array
          items:
            type: string
          description: >-
            Mots de `transfer_name` absents de `compared_name`, puis mots de
            `compared_name` absents de `transfer_name`.
    TravelRuleDataMatch:
      type: object
      nullable: true
      description: >-
        Comparaison champ par champ des données des parties au transfert avec ce
        que l'autre partie sait du détenteur du portefeuille. Elle nomme les
        champs et les résultats, jamais les valeurs, afin de rester lisible
        pendant que les données de la contrepartie sont masquées. Null jusqu'à
        ce qu'une comparaison ait été exécutée.
      properties:
        matched:
          type: boolean
          description: Vrai lorsqu'aucun champ comparé ne diffère.
        mismatched_fields:
          type: array
          items:
            type: string
            enum:
              - name
              - date_of_birth
              - address
              - account
          description: Les champs qui diffèrent.
        fields:
          type: object
          description: >-
            Une entrée par champ comparé pour le type d'entité de la partie
            (`name`, `date_of_birth`, `address`, `account` ; une entreprise n'a
            pas de `date_of_birth`).
          additionalProperties:
            type: object
            properties:
              result:
                type: string
                enum:
                  - matched
                  - mismatched
                  - not_compared
                description: >-
                  `not_compared` lorsque la règle est `NONE` ou que l'un des
                  deux côtés ne comporte aucune valeur pour le champ.
              strictness:
                type: string
                enum:
                  - NONE
                  - STRICT
                  - CONTAINS
                  - DEFAULT
                  - FUZZY
    TravelRuleDataUnmasked:
      type: object
      nullable: true
      description: >-
        Enregistrement d'audit du moment où les données de la contrepartie ont
        été démasquées. Null tant que les données sont encore masquées, ainsi
        que pour les transferts sortants.
      properties:
        at:
          type: string
          format: date-time
        reason:
          type: string
          enum:
            - ownership_confirmed
            - wallet_proof
            - address_book_match
            - own_verified_wallet
            - inquiry_approved
            - known_payment_method
            - travel_address
          description: >-
            Ce qui a confirmé la propriété : ownership_confirmed (votre
            confirmation via la console ou l'API), wallet_proof (une preuve de
            portefeuille dans le widget, ou un transfert entrant INTERNAL,
            défini lors de sa création), address_book_match (un portefeuille
            vérifié du carnet d'adresses), own_verified_wallet (le portefeuille
            vérifié propre à votre utilisateur), inquiry_approved (votre
            approbation d'une demande TRP entrante ou d'un message GTR ou
            Sygna), known_payment_method (un portefeuille avec lequel votre
            utilisateur a déjà payé) ou travel_address (la Travel Address par
            portefeuille qui a nommé le portefeuille).
        actor:
          type: string
          description: >-
            Qui l'a confirmé : l'e-mail de l'utilisateur de la console ou le
            libellé de la clé API. Laissé vide pour une décision automatique.
    TravelRuleDelivery:
      type: object
      description: >-
        État d'acheminement du dernier message que le transfert doit à l'autre
        partie. Didit contacte la contrepartie après le retour de la requête
        ayant créé ou modifié le transfert ; cet objet indique donc si ce
        message a abouti : en file d'attente, en cours d'envoi, en attente de
        nouvelle tentative après une erreur, livré ou échoué. Une défaillance
        dont le réseau peut encore se remettre (absence de réponse dans les
        délais, échec de connexion, HTTP `408`, `429` ou `5xx`) fait l'objet
        d'une nouvelle tentative après 30 secondes, 2 minutes, 10 minutes, 30
        minutes et 1 heure. Lorsqu'un premier message (`kind: SEND`) échoue
        définitivement, parce que le réseau l'a refusé ou que la sixième
        tentative a également échoué, le transfert passe à
        `COUNTERPARTY_VASP_NOT_REACHABLE` avec `last_error` dans sa `timeline` ;
        tout autre message échouant définitivement est consigné dans la
        `timeline`. Le `status` du transfert demeure la source de vérité pour
        l'échange lui-même.
      required:
        - kind
        - status
        - rail
        - attempts
        - last_error
        - next_attempt_at
        - delivered_at
      properties:
        kind:
          type: string
          enum:
            - SEND
            - ANSWER
            - TXID
            - CANCEL
            - POLL
          description: >-
            Ce que transporte le message. `SEND` : le premier message du
            transfert destiné à la contrepartie (sortant ; le réseau est choisi
            lors de son envoi). `ANSWER` : votre acceptation ou votre refus, dû
            au réseau qui en a fait la demande (entrant). `TXID` : le hash de
            transaction on-chain, une fois que vous avez terminé le transfert.
            `CANCEL` : l'annulation, une fois que vous l'avez annulé. `POLL` :
            une requête de statut adressée à un réseau qui en propose une,
            répétée toutes les 5 minutes pendant que le transfert est en attente
            de la contrepartie.
        status:
          type: string
          enum:
            - QUEUED
            - SENDING
            - RETRYING
            - DELIVERED
            - FAILED
          description: >-
            `QUEUED` : en attente d'envoi. `SENDING` : une tentative est en
            cours. `RETRYING` : une tentative a échoué et la suivante
            s'exécutera à `next_attempt_at`. `DELIVERED` : l'autre partie a reçu
            le message. `FAILED` : l'autre partie l'a refusé, ou la dernière
            tentative a échoué.
        rail:
          type: string
          enum:
            - INTERNAL
            - TRP
            - GTR
            - TRUST
            - VERIFYVASP
            - SYGNA
            - EMAIL
            - ''
          description: >-
            Le canal qui achemine le message. Vide jusqu'à ce que Didit en ait
            choisi un pour un premier message.
        attempts:
          type: integer
          minimum: 0
          description: >-
            Tentatives effectuées jusqu'à présent pour ce message. Un message
            qui n'est pas un sondage d'état fait l'objet de 6 tentatives au
            maximum.
        last_error:
          type: string
          description: >-
            Le type d'échec rencontré lors de la dernière tentative, `""`
            lorsqu'il n'y en a eu aucun : par exemple `email undeliverable`,
            `trp identity endpoint unreachable` ou `trp transfer inquiry
            delivery failed`. Il ne contient jamais la propre réponse de la
            contrepartie, qui reste sur la `timeline` du transfert.

            Lorsque GTR répond par une erreur, son propre code d'état et son
            message sont inclus. Les corps de réponse ne sont jamais inclus.
          example: email undeliverable
        next_attempt_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            Moment où la prochaine tentative s'exécute lorsque le message est
            `QUEUED` ou `RETRYING`.
        delivered_at:
          type: string
          format: date-time
          nullable: true
          description: Moment où l'autre partie a pris en charge le message.
    TravelRuleDiscoveryStep:
      type: object
      description: >-
        Une étape de la découverte de contrepartie exécutée par Didit pour un
        transfert sortant, dans l'ordre où elles ont été exécutées. La première
        étape qui désigne un VASP disposant d'une route met fin à la chaîne.
      properties:
        step:
          type: string
          enum:
            - internal_address_book
            - wallet_attribution
            - network_lookup
            - customer_hint
            - end_user
          description: >-
            `internal_address_book` : un autre client Didit ayant prouvé le
            contrôle du portefeuille de destination. `wallet_attribution` :
            l'attribution d'analyse blockchain du portefeuille. `network_lookup`
            : un réseau capable d'indiquer quel VASP détient l'adresse.
            `customer_hint` : le nom du VASP, le LEI ou la juridiction que vous
            avez indiqués dans `beneficiary_data`. `end_user` : la contrepartie
            choisie par l'utilisateur final (ou par vous), ou la demande d'en
            sélectionner une.
        outcome:
          type: string
          enum:
            - match
            - miss
            - skipped
          description: >-
            `match` : l'étape a identifié une contrepartie. `miss` : elle s'est
            exécutée et n'en a trouvé aucune. `skipped` : elle n'a pas pu
            s'exécuter, et `reason` en indique la raison.
        reason:
          type: string
          description: >-
            Raison lisible par machine, `""` en cas de correspondance :
            `no_proven_internal_wallet`, `attribution_disabled`,
            `already_attributed`, `no_attributed_entity`,
            `directory_match_no_route`, `gtr_address_lookup_runs_on_dispatch`,
            `no_membership`, `network_switched_off`,
            `no_network_address_lookup`, `no_directory_match`,
            `awaiting_end_user` ou `picked_member_without_proven_wallet`.
        vasp:
          type: string
          format: uuid
          nullable: true
          description: >-
            Le VASP de l'annuaire désigné par l'étape, lorsqu'elle en a désigné
            un.
        rail:
          type: string
          nullable: true
          description: >-
            Le canal qui permet d'atteindre cette contrepartie, lorsque l'étape
            en a trouvé un.
        at:
          type: string
          format: date-time
    TravelRuleNextAction:
      type: object
      description: >-
        Un élément permettant de faire avancer un transfert au statut
        `COUNTERPARTY_VASP_NOT_FOUND` ou `COUNTERPARTY_VASP_NOT_REACHABLE`.
        Consultez [Pourquoi un transfert est
        bloqué](/fr/transaction-monitoring/travel-rule#pourquoi-un-transfert-est-bloqué).
      properties:
        action:
          type: string
          enum:
            - select_counterparty_vasp
            - declare_self_hosted
            - add_vasp_hint
            - update_compliance_email
            - resend
          description: >-
            `select_counterparty_vasp` : l'utilisateur final choisit le VASP de
            destination dans le widget de possession de portefeuille, ou vous
            effectuez un PATCH avec `action=beneficiary_vasp`.
            `declare_self_hosted` : l'utilisateur final déclare le portefeuille
            comme auto-hébergé dans le widget. `add_vasp_hint` : indiquez à
            Didit qui est la contrepartie, avec un nom de VASP, un LEI ou une
            Travel Address (par exemple une `travel_address` sur l'entrée du
            carnet d'adresses du portefeuille de destination), puis renvoyez.
            `update_compliance_email` et `resend` sont des valeurs de `action`
            pour `PATCH /v3/transactions/{transaction_id}/travel-rule/` :
            fournissez à nouveau l'e-mail de conformité de la contrepartie, et
            relancez le routage.
        url:
          type: string
          format: uri
          description: >-
            Le lien du widget de propriété du portefeuille, pour
            `select_counterparty_vasp` et `declare_self_hosted` tant que le
            transfert a une session de widget ouverte.
      required:
        - action
    TravelRuleChainDetails:
      type: object
      description: >-
        Manière dont la blockchain du transfert nomme ses deux portefeuilles,
        lorsque plus d'une adresse en paie une autre. Vide (`{}`) pour un
        transfert sur une blockchain basée sur des comptes (EVM, Solana, Tron),
        où les deux adresses sont les portefeuilles. La correspondance, le
        routage et le carnet d'adresses lisent d'abord les portefeuilles ici.
      properties:
        chain:
          type: string
          description: >-
            Blockchain canonique, par ex. `BTC`, `XRP`, ou `LIGHTNING` pour un
            transfert Lightning.
        shape:
          type: string
          enum:
            - utxo
            - memo
            - lightning
        originator:
          $ref: '#/components/schemas/TravelRuleChainSide'
        beneficiary:
          $ref: '#/components/schemas/TravelRuleChainSide'
        utxo:
          type: object
          description: >-
            Sur un transfert UTXO : les entrées et sorties telles
            qu'enregistrées (montants sous forme de chaînes décimales) et la
            manière dont Didit a interprété chaque sortie.
          properties:
            inputs:
              type: array
              items:
                $ref: '#/components/schemas/TravelRuleUtxoEntry'
            outputs:
              type: array
              items:
                $ref: '#/components/schemas/TravelRuleUtxoEntry'
            change_output_indexes:
              type: array
              items:
                type: integer
              description: Sorties qui remboursent une adresse d'entrée.
            beneficiary_output_index:
              type: integer
              nullable: true
              description: "La sortie qui paie le bénéficiaire\_; null lorsqu'aucune n'a pu être distinguée."
        lightning:
          type: object
          description: >-
            Sur un transfert Lightning : ce qu'indique la demande de paiement.
            Toujours `kind` (`bolt11`, `bolt12_offer`, `bolt12_invoice`,
            `bolt12_invoice_request`, `lnurl`, `lightning_address`, `node_id` ou
            `unknown`) ; une facture BOLT11 ajoute `network`, `payee_node_id`,
            `payment_hash`, `amount_msat`, `created_at` et `expires_at` ; une
            chaîne BOLT12 ajoute `blinded_paths` et `payee_node_id` ; un LNURL
            ou une adresse Lightning ajoute son `domain`. Rien n'est résolu sur
            le réseau : la requête est uniquement décodée.
          additionalProperties: true
        warnings:
          type: array
          items:
            type: string
            enum:
              - declared_originator_not_an_input
              - declared_beneficiary_not_an_output
              - beneficiary_output_ambiguous
              - beneficiary_output_amount_differs
          description: >-
            Incohérences UTXO nécessitant une vérification : le donneur d'ordre
            déclaré n'est pas une entrée, le bénéficiaire déclaré n'est pas une
            sortie, aucune sortie de bénéficiaire unique n'a pu être distinguée,
            ou la sortie du bénéficiaire paie un montant différent de celui
            indiqué par la transaction.
        not_applicable_reason:
          type: string
          enum:
            - LIGHTNING_NO_PAYEE_IDENTIFIER
            - LIGHTNING_BOLT12_BLINDED_PAYEE
            - LIGHTNING_LNURL_NAMES_NO_PAYEE
          description: >-
            Sur un transfert Lightning sortant dont la demande de paiement ne
            mentionne aucun bénéficiaire : pourquoi le transfert est
            `NOT_APPLICABLE`. `LIGHTNING_NO_PAYEE_IDENTIFIER` (la demande ne
            mentionne aucun nœud bénéficiaire ou n'a pas pu être décodée),
            `LIGHTNING_BOLT12_BLINDED_PAYEE` (l'offre dissimule son bénéficiaire
            derrière des chemins aveugles), `LIGHTNING_LNURL_NAMES_NO_PAYEE` (un
            LNURL désigne un service, pas un bénéficiaire). Le même code ouvre
            la dernière entrée de la `timeline` du transfert.
    TravelRuleChainSide:
      type: object
      description: >-
        Le portefeuille de l'une des parties, tel que Didit l'a résolu à partir
        des données de la blockchain.
      properties:
        address:
          type: string
          description: >-
            Le portefeuille. Sur un réseau à mémo, l'adresse classique (une
            X-address XRP est divisée en son adresse classique et son tag) ; sur
            Lightning, l'identifiant du nœud du bénéficiaire ou la Lightning
            Address.
        memo:
          type: string
          description: >-
            Le tag de destination ou mémo faisant partie du portefeuille ; `""`
            en l'absence de mémo.
        source:
          type: string
          enum:
            - declared
            - x_address
            - largest_input
            - only_non_change_output
            - amount_match
            - invoice_payee
            - updated
          description: >-
            Origine du portefeuille : `declared` (votre requête), `x_address`
            (dérivée d'une adresse X XRP), `largest_input` (l'adresse d'entrée
            UTXO ayant le plus contribué), `only_non_change_output` (la seule
            sortie UTXO qui n'est pas de la monnaie rendue), `amount_match`
            (l'unique sortie UTXO payant le montant du transfert),
            `invoice_payee` (le bénéficiaire désigné par une demande de paiement
            Lightning), `updated` (défini ultérieurement avec `action:
            update_originator_wallet`).
    TravelRuleUtxoEntry:
      type: object
      description: >-
        Une entrée ou une sortie d'une transaction UTXO, telle qu'enregistrée
        par la blockchain.
      required:
        - address
      properties:
        address:
          type: string
          maxLength: 128
        amount:
          type: string
          nullable: true
          description: >-
            Chaîne décimale dans l'unité propre à la crypto-monnaie (BTC, et non
            en satoshis). Facultatif.
          example: '0.0125'
        txid:
          type: string
          maxLength: 128
          description: Facultatif. La transaction dépensée par une entrée.
        vout:
          type: integer
          nullable: true
          minimum: 0
          description: Facultatif. L'index de sortie dépensé par une entrée.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        La clé API de votre application, issue de Développeurs -> Clés API dans
        la Business Console. La clé principale dispose d'un accès complet. Une
        clé nommée peut être restreinte : aucun, lecture ou écriture par
        ressource, limitée à certains workflows ou aux sessions approuvées, à
        une liste d'adresses IP et à une date d'expiration. 401 signifie que la
        clé est incorrecte, révoquée ou expirée ; 403 signifie qu'aucune clé n'a
        été envoyée, que la clé n'a pas accès à cette ressource ou action, ou
        que la requête provient d'une adresse hors de sa liste d'IP ; 404 sur
        une route de session signifie que la session est hors des workflows ou
        des statuts de la clé. Une clé sans accès aux médias reçoit les URL
        d'images, de vidéos et de PDF à null, et une clé sans accès en écriture
        aux sessions reçoit les liens et tokens de session à null. Voir
        https://docs.didit.me/console/api-keys.

````

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