> ## 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: завершение, повтор, обновление

> Завершите перевод Travel Rule хешем транзакции в блокчейне, отмените или повторите его, либо укажите кошелёк, с которого фактически отправлены средства. Didit.



Промпт API действий для переводов по Travel Rule
        Скопировать промпт в буфер обмена



      
      

\<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>



      
      

Вставьте в



## OpenAPI

````yaml ru/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 верификации личности. Аутентификация выполняется с помощью заголовка
    x-api-key.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/transactions/{transaction_id}/travel-rule/:
    patch:
      tags:
        - Travel Rule
      summary: >-
        Завершить, отменить, повторно отправить или обновить кошелёк отправителя
        для перевода Travel Rule
      description: >-
        Укажите `payment_txn_id`, чтобы передать ончейн-хеш и перевести
        исходящий перевод из COMPLETED в FINISHED (его аналог по каналу INTERNAL
        также переходит в FINISHED), `{"action": "cancel"}`, чтобы отменить
        перевод в нетерминальном статусе, или `{"action": "resend"}` чтобы
        повторно маршрутизировать исходящий перевод, зависший в статусах
        COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE или
        NOT_ENOUGH_COUNTERPARTY_DATA (сначала дополните данные контрагента,
        например добавьте travel_address в запись кошелька назначения). resend
        применяется только к исходящим переводам. `{"action":
        "update_compliance_email", "compliance_email": "desk@example.com"}`
        заменяет email комплаенса для исходящего перевода в одном из этих трёх
        статусов (решение проблемы `reason: email_undeliverable`): статус не
        меняется, и следующий `resend` отправит запрос на этот адрес. Повторная
        отправка ставится в очередь, а не выполняется внутри запроса: в ответе
        перевод снова отображается в статусе AWAITING_COUNTERPARTY с записью
        `resend queued` в таймлайне и поставленной в очередь `delivery`, а
        информация о том, куда он был направлен, приходит в виде webhook
        `travel_rule.status.updated`. Если перевод отправлен через GTR,
        VerifyVASP или Sygna Bridge, сеть получает информацию об ончейн-хеше или
        отмене после ответа; выполняются повторные попытки; `delivery`
        показывает текущее состояние этого сообщения. `{"action":
        "update_originator_wallet", "wallet_address": "..."}` фиксирует кошелёк,
        с которого фактически ушли средства при исходящем переводе, например
        адрес, с которого был отправлен вывод UTXO, а не основной заявленный
        вами кошелёк. Это изменяет только запись: контрагенту повторно ничего не
        отправляется, и статус сохраняется. Отправитель становится
        `chain_details.originator` с `source: updated`, изменение добавляется в
        `timeline` с предыдущим и новым кошельками, а аналог перевода по каналу
        INTERNAL обновляется аналогичным образом. `{"action":
        "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"}`
        позволяет вручную указать контрагента, если обнаружение не удалось, для
        исходящего перевода в статусе COUNTERPARTY_VASP_NOT_FOUND,
        COUNTERPARTY_VASP_NOT_REACHABLE или NOT_ENOUGH_COUNTERPARTY_DATA:
        перевод маршрутизируется к этому VASP и отправляется повторно.
      operationId: patchTravelRuleTransfer
      parameters:
        - name: transaction_id
          in: path
          required: true
          description: Стабильный UUID транзакции Didit, которой принадлежит перевод.
          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: >-
            Обновлённый перевод. После `update_compliance_email` его статус
            остаётся неизменным и сохраняет `reason: email_undeliverable` до
            следующего `resend`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleTransferDetail'
        '400':
          description: >-
            Не указаны ни payment_txn_id, ни поддерживаемое действие,
            отсутствует `compliance_email` или значение не является адресом
            электронной почты для `update_compliance_email`, либо для
            `update_originator_wallet` не указан wallet_address, кошелёк или
            memo не поддерживаются блокчейном перевода, кошелёк не входит во
            входы UTXO перевода, либо отсутствует `beneficiary_vasp` или он не
            является действительным идентификатором VASP из справочника.
          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: >-
            Неизвестная транзакция, у транзакции отсутствует перевод Travel
            Rule, либо (действие `beneficiary_vasp`) запись с таким id
            отсутствует в справочнике.
        '409':
          description: >-
            Перевод находится в состоянии, не допускающем эту операцию
            (например, не имеет статуса COMPLETED или не является исходящим для
            finish, уже находится в терминальном статусе для cancel или не
            является исходящим переводом в статусе, допускающем повторную
            отправку, для resend). `update_compliance_email` возвращает `409`
            для входящего перевода и для исходящего вне статусов
            COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE и
            NOT_ENOUGH_COUNTERPARTY_DATA. `update_originator_wallet` возвращает
            `409` для входящего, отмененного перевода или перевода с истекшим
            сроком. `beneficiary_vasp` возвращает `409`, если только перевод не
            является исходящим и не находится в статусе
            COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE или
            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: >-
        Укажите ровно один из параметров: payment_txn_id (завершение),
        action=cancel, action=resend, action=update_compliance_email с
        compliance_email, action=update_originator_wallet с wallet_address или
        action=beneficiary_vasp с beneficiary_vasp.
      properties:
        payment_txn_id:
          type: string
          description: >-
            Хеш ончейн-транзакции. Требуется, чтобы перевод был исходящим и
            находился в статусе COMPLETED.
        action:
          type: string
          enum:
            - cancel
            - resend
            - update_compliance_email
            - update_originator_wallet
            - beneficiary_vasp
          description: >-
            "cancel" отменяет перевод в неконечном статусе. "resend" повторно
            запускает маршрутизацию для исходящего перевода, зависшего в статусе
            COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE или
            NOT_ENOUGH_COUNTERPARTY_DATA. "update_compliance_email" заменяет
            комплаенс-email, на который отправляется запрос, для исходящего
            перевода в одном из этих трёх статусов; после этого отправьте
            "resend". "update_originator_wallet" записывает кошелёк, с которого
            фактически ушли средства (`wallet_address`, `memo`).
            "beneficiary_vasp" позволяет вручную указать VASP контрагента
            (требуется `beneficiary_vasp`) для исходящего перевода в одном из
            этих статусов: перевод будет перенаправлен этому VASP и отправлен
            повторно.
        compliance_email:
          type: string
          format: email
          maxLength: 254
          description: >-
            Обязательно при `action: update_compliance_email`. Сохраняется как
            `beneficiary_data.counterparty_vasp_email` этого перевода: относится
            только к этому переводу и не добавляется ни в запись справочника, ни
            в список контактов.
        wallet_address:
          type: string
          maxLength: 128
          description: >-
            С `action: update_originator_wallet`: кошелёк, с которого были
            отправлены средства. Если UTXO-входы перевода известны, он должен
            быть одним из них.
        memo:
          type: string
          maxLength: 256
          description: >-
            С `action: update_originator_wallet`: memo или тег кошелька в сети с
            memo. Необязательно.
        beneficiary_vasp:
          type: string
          format: uuid
          description: >-
            Обязательно при action=beneficiary_vasp: `id` VASP из справочника,
            полученный из `GET /v3/travel-rule/vasps/`. Ваш выбор имеет
            приоритет над каждым шагом автоматического обнаружения, который
            никогда его не переопределяет.
    TravelRuleTransferDetail:
      type: object
      description: >-
        Полный объект перевода, возвращаемый endpoint’ами подтверждения владения
        и завершения/отмены. Пока владение кошельком для входящего перевода не
        подтверждено, данные контрагента `originator_data` и `beneficiary_data`
        возвращаются маскированными (сохраняется первая буква каждого слова;
        кошелёк, сеть и маршрутизация VASP остаются читаемыми), а флаг
        `data_masked` равен 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: >-
            Транспортная сеть (rail), через которую был направлен перевод, или
            null, если сеть не была выбрана (например, ниже порога,
            некастодиальный кошелёк контрагента, регистрация после депозита или
            отсутствие доступного контрагента). INTERNAL означает, что обе
            стороны являются приложениями Didit; EMAIL означает, что контрагент
            получил ссылку для получения по электронной почте. TEST_VASP
            означает, что Didit Test VASP ответил на перевод в песочнице. В
            сетях GTR, VERIFYVASP и SYGNA Didit считывает ответ контрагента из
            ответа сети или опрашивает её каждые 5 минут. TRUST работает только
            на отправку, поэтому перевод через TRUST остаётся в статусе
            AWAITING_COUNTERPARTY до истечения срока действия. Сетевой rail
            используется только тогда, когда вы подключили собственное участие
            (membership) для этой сети. Он выбирается после возврата ответа
            создания транзакции, поэтому в этом ответе он равен null.
        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: >-
                  Сравнение имён, на основании которого принято решение в этой
                  записи, рядом с `detail`. Отсутствует в записях, где сравнение
                  имени не проводилось.
              reason:
                type: string
                description: >-
                  Присутствует только в записи о переходе, вызванном неудачной
                  доставкой: `email_undeliverable` или `delivery_failed`,
                  значение, которое возвращает поле `reason` перевода.
        counterparty_vasp:
          type: object
          nullable: true
          properties:
            name:
              type: string
            lei:
              type: string
            dd_score:
              type: integer
              description: >-
                Оценка дью-дилидженс от 0 до 100, где большее значение лучше. Та
                же шкала, что и в каталоге VASP.
            dd_score_breakdown:
              type: object
              description: >-
                Вклад каждого компонента в dd_score: один объект на компонент в
                соответствии со справочником VASP (jurisdiction, verification,
                protocol, lei, history, essentials, responsiveness), каждый со
                структурой {points, max, reason, detail}. Пустой объект {}, пока
                контрагент не был оценён.
              additionalProperties:
                type: object
                properties:
                  points:
                    type: number
                    description: Баллы, начисленные за этот компонент.
                  max:
                    type: integer
                    description: >-
                      Максимальное количество баллов, которое может начислить
                      этот компонент.
                  reason:
                    type: string
                    description: Машиночитаемый код вердикта компонента.
                  detail:
                    type: string
                    description: Понятная человеку причина начисления баллов.
            dd_assessed_at:
              type: string
              format: date-time
              nullable: true
              description: >-
                Когда в последний раз проводилась оценка в рамках комплексной
                проверки. Null, пока контрагент не был оценён.
        originator_data:
          type: object
          description: >-
            Сторона-отправитель. Для входящего перевода значения контрагента
            маскируются до тех пор, пока владение не будет подтверждено.
        beneficiary_data:
          type: object
          description: >-
            Сторона-получатель. Для входящего перевода значения контрагента
            маскируются до подтверждения владения.
        name_match:
          allOf:
            - $ref: '#/components/schemas/TravelRuleNameMatch'
          nullable: true
          description: >-
            Сравнение имен, на основе которого было принято решение по переводу,
            или null до выполнения проверки. Пока стороны маскированы, а также в
            копии транзакции INTERNAL у другого клиента, поля `transfer_name`,
            `compared_name`, `matched_names` и `mismatched_names` скрыты.
            Значения `score` и `matched` могут расходиться: `matched` следует
            уровню строгости, а `score` отражает степень сходства двух полных
            имен.
        data_match:
          $ref: '#/components/schemas/TravelRuleDataMatch'
        mismatched_fields:
          type: array
          items:
            type: string
          description: >-
            Сокращение для `data_match.mismatched_fields`. Пусто, если различий
            нет.
        data_unmasked:
          $ref: '#/components/schemas/TravelRuleDataUnmasked'
        data_masked:
          type: boolean
          description: >-
            Имеет значение true, пока персональные данные контрагента
            маскируются в этом ответе.
        created_at:
          type: string
          format: date-time
        delivery:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/TravelRuleDelivery'
          description: >-
            Текущий статус последнего сообщения, которое этот перевод должен
            отправить другой стороне. Null, если перевод не требовал отправки
            сообщения (например, ниже `threshold_amount`, заявленный
            некастодиальный кошелёк или регистрация в рамках sunrise-периода).
        discovery:
          type: array
          description: >-
            Как Didit выполнял поиск контрагента: по одной записи на каждый
            выполненный шаг. Пусто, если поиск не выполнялся, например для
            входящего перевода.
          items:
            $ref: '#/components/schemas/TravelRuleDiscoveryStep'
        reason:
          type: string
          description: >-
            Причина, по которой перевод со статусом
            `COUNTERPARTY_VASP_NOT_FOUND` или `COUNTERPARTY_VASP_NOT_REACHABLE`
            приостановлен; `""` для любого другого статуса. Неудачная доставка
            определяет её в первую очередь и только при
            `COUNTERPARTY_VASP_NOT_REACHABLE`: `email_undeliverable` (почтовый
            провайдер отклонил комплаенс-письмо, и адресов для повторной попытки
            не осталось: при отправке, при напоминании или в виде постоянного
            сбоя доставки, о котором сообщено позже) или `delivery_failed`
            (канал доставки окончательно вышел из строя: сетевой канал отклонил
            сообщение или исчерпал лимит повторных попыток, хост идентификации
            `TRP` не ответил либо `TRP`-хост контрагента не принял запрос). В
            противном случае её определяет трассировка `discovery`:
            `awaiting_end_user` (ни на одном шаге не указан контрагент, с
            которым Didit может связаться), `directory_match_no_route` (на шаге
            указан VASP из каталога, у которого нет маршрута),
            `picked_member_without_proven_wallet` (конечный пользователь выбрал
            клиента Didit, который не подтвердил контроль над кошельком) или
            `no_directory_match`, если трассировка не возвращает иной причины.
            Повторная отправка продвигает перевод дальше, поэтому причина
            сбрасывается. См. [Почему перевод
            приостановлен](/ru/transaction-monitoring/travel-rule#почему-перевод-застрял).
        next_actions:
          type: array
          description: >-
            Действия, продвигающие перевод дальше; `[]` для любого статуса,
            кроме `COUNTERPARTY_VASP_NOT_FOUND` или
            `COUNTERPARTY_VASP_NOT_REACHABLE`. `email_undeliverable` предлагает
            `update_compliance_email`, затем `resend`. `delivery_failed`
            предлагает `resend`. Причина типа discovery предлагает
            `select_counterparty_vasp`, `declare_self_hosted`, `add_vasp_hint` и
            `resend`.
          items:
            $ref: '#/components/schemas/TravelRuleNextAction'
        chain_details:
          $ref: '#/components/schemas/TravelRuleChainDetails'
    TravelRuleNameMatch:
      type: object
      nullable: true
      description: >-
        Сравнение имен, на основе которого было принято решение по переводу, или
        null до выполнения проверки. Пока стороны маскированы, а также в копии
        транзакции INTERNAL у другого клиента, поля `transfer_name`,
        `compared_name`, `matched_names` и `mismatched_names` скрыты. Значения
        `score` и `matched` могут расходиться: `matched` следует уровню
        строгости, а `score` отражает степень сходства двух полных имен.
      properties:
        score:
          type: integer
          minimum: 0
          maximum: 100
          description: >-
            Степень сходства двух полных имен, от 0 до 100. Равно 0, если хотя
            бы одно имя пустое.
        matched:
          type: boolean
          description: >-
            Соответствуют ли имена значению `strictness`. Исход перевода зависит
            от `data_match`, где сравнивается каждое поле, поэтому перевод может
            иметь статус COUNTERPARTY_MISMATCHED_DATA, даже если здесь true.
        method:
          type: string
          enum:
            - none
            - exact_token
            - token_subset
            - token_containment
            - sequence_ratio
          description: >-
            Как определялось `matched`: none (`NONE`), exact_token (`STRICT`),
            token_subset (`DEFAULT`), token_containment (`CONTAINS`) или
            sequence_ratio (`FUZZY`).
        strictness:
          type: string
          enum:
            - NONE
            - STRICT
            - CONTAINS
            - DEFAULT
            - FUZZY
        compared_with:
          type: string
          enum:
            - wallet_holder
            - counterparty_vasp
          description: >-
            wallet_holder: владелец, указанный для кошелька. counterparty_vasp:
            название, указанное контрагентом на странице ответа по электронной
            почте, или ответ Didit Test VASP в песочнице.
        transfer_name:
          type: string
          description: Имя в переводе.
        compared_name:
          type: string
          description: Имя, с которым проводилось сравнение.
        matched_names:
          type: array
          items:
            type: string
          description: Слова из `transfer_name`, найденные в `compared_name`.
        mismatched_names:
          type: array
          items:
            type: string
          description: >-
            Слова из `transfer_name`, отсутствующие в `compared_name`, затем
            слова из `compared_name`, отсутствующие в `transfer_name`.
    TravelRuleDataMatch:
      type: object
      nullable: true
      description: >-
        Сравнение по каждому полю данных стороны перевода с тем, что известно
        другой стороне о владельце кошелька. Указывает поля и результаты, но
        никогда значения, сохраняя читаемость при маскировании данных
        контрагента. Имеет значение null до запуска сравнения.
      properties:
        matched:
          type: boolean
          description: True, когда ни одно из сравниваемых полей не отличается.
        mismatched_fields:
          type: array
          items:
            type: string
            enum:
              - name
              - date_of_birth
              - address
              - account
          description: Поля, которые различаются.
        fields:
          type: object
          description: >-
            Одна запись на каждое сравниваемое поле для типа стороны (`name`,
            `date_of_birth`, `address`, `account`; у компании нет поля
            `date_of_birth`).
          additionalProperties:
            type: object
            properties:
              result:
                type: string
                enum:
                  - matched
                  - mismatched
                  - not_compared
                description: >-
                  `not_compared`, если правило имеет значение `NONE` или на
                  одной из сторон отсутствует значение для поля.
              strictness:
                type: string
                enum:
                  - NONE
                  - STRICT
                  - CONTAINS
                  - DEFAULT
                  - FUZZY
    TravelRuleDataUnmasked:
      type: object
      nullable: true
      description: >-
        Запись аудита момента, когда данные контрагента были демаскированы.
        Имеет значение null, пока данные всё ещё замаскированы, а также для
        исходящих переводов.
      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: >-
            Что подтвердило владение: ownership_confirmed (ваше подтверждение
            через консоль или API), wallet_proof (подтверждение кошелька в
            виджете или входящий перевод INTERNAL, устанавливается при его
            создании), address_book_match (верифицированный кошелёк из адресной
            книги), own_verified_wallet (собственный верифицированный кошелёк
            вашего пользователя), inquiry_approved (ваше одобрение входящего
            TRP-запроса или сообщения GTR либо Sygna), known_payment_method
            (кошелёк, с которого ваш пользователь уже совершал оплату) или
            travel_address (Travel Address конкретного кошелька, обозначающий
            этот кошелёк).
        actor:
          type: string
          description: >-
            Кто подтвердил решение: email пользователя консоли или метка
            API-ключа. Пусто для автоматического решения.
    TravelRuleDelivery:
      type: object
      description: >-
        Текущий статус последнего сообщения, которое перевод должен отправить
        другой стороне. Didit связывается с контрагентом после возврата ответа
        на запрос, создавший или изменивший перевод, поэтому данный объект
        показывает, было ли доставлено это сообщение: в очереди, отправляется,
        ожидает повторной попытки после ошибки, доставлено или произошел сбой. В
        случае сбоя, после которого сеть еще может восстановиться (нет ответа
        вовремя, ошибка соединения, HTTP `408`, `429` или `5xx`), повторная
        попытка выполняется через 30 секунд, 2 минуты, 10 минут, 30 минут и 1
        час. Если первое сообщение (`kind: SEND`) окончательно завершается сбоем
        из-за отказа сети или неудачи шестой попытки, перевод переходит в статус
        `COUNTERPARTY_VASP_NOT_REACHABLE` с полем `last_error` в истории
        `timeline`; любое другое сообщение, окончательно завершившееся ошибкой,
        фиксируется в `timeline`. Поле `status` перевода остается
        первоисточником истины для самого обмена.
      required:
        - kind
        - status
        - rail
        - attempts
        - last_error
        - next_attempt_at
        - delivered_at
      properties:
        kind:
          type: string
          enum:
            - SEND
            - ANSWER
            - TXID
            - CANCEL
            - POLL
          description: >-
            Что содержит сообщение. `SEND`: первое сообщение перевода
            контрагенту (исходящее; канал передачи выбирается при отправке).
            `ANSWER`: ваше согласие или отклонение, направляемое запросившей
            сети (входящее). `TXID`: хеш ончейн-транзакции после завершения
            перевода. `CANCEL`: отмена после того, как вы отменили перевод.
            `POLL`: запрос статуса к сети, поддерживающей такую возможность,
            повторяемый каждые 5 минут, пока перевод ожидает ответа от
            контрагента.
        status:
          type: string
          enum:
            - QUEUED
            - SENDING
            - RETRYING
            - DELIVERED
            - FAILED
          description: >-
            `QUEUED`: ожидает отправки. `SENDING`: выполняется попытка.
            `RETRYING`: попытка завершилась неудачей, следующая запустится в
            `next_attempt_at`. `DELIVERED`: принимающая сторона приняла
            сообщение. `FAILED`: принимающая сторона отклонила его или последняя
            попытка завершилась неудачей.
        rail:
          type: string
          enum:
            - INTERNAL
            - TRP
            - GTR
            - TRUST
            - VERIFYVASP
            - SYGNA
            - EMAIL
            - ''
          description: >-
            Транспортная сеть (rail), передающая сообщение. Пусто до тех пор,
            пока Didit не выберет её для первого сообщения.
        attempts:
          type: integer
          minimum: 0
          description: >-
            Количество попыток, сделанных для этого сообщения на данный момент.
            Для сообщения, не являющегося опросом статуса, выполняется не более
            6 попыток.
        last_error:
          type: string
          description: >-
            Тип сбоя, возникшего при последней попытке, либо `""`, если сбоев не
            было: например `email undeliverable`, `trp identity endpoint
            unreachable` или `trp transfer inquiry delivery failed`. Он никогда
            не содержит собственный ответ контрагента, который сохраняется в
            `timeline` перевода.

            Когда GTR возвращает ошибку, включаются собственный код состояния и
            сообщение. Тела ответов никогда не включаются.
          example: email undeliverable
        next_attempt_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            Время следующей попытки, пока сообщение находится в статусе `QUEUED`
            или `RETRYING`.
        delivered_at:
          type: string
          format: date-time
          nullable: true
          description: Время получения сообщения другой стороной.
    TravelRuleDiscoveryStep:
      type: object
      description: >-
        Один шаг поиска контрагента, выполненный Didit для исходящего перевода,
        в порядке их выполнения. Первый шаг, определяющий VASP с доступным
        маршрутом, завершает цепочку.
      properties:
        step:
          type: string
          enum:
            - internal_address_book
            - wallet_attribution
            - network_lookup
            - customer_hint
            - end_user
          description: >-
            `internal_address_book`: другой клиент Didit, подтвердивший контроль
            над кошельком назначения. `wallet_attribution`: атрибуция
            блокчейн-аналитики кошелька. `network_lookup`: сеть, способная
            определить, какой VASP управляет адресом. `customer_hint`: имя VASP,
            LEI или юрисдикция, переданные вами в `beneficiary_data`.
            `end_user`: контрагент, выбранный конечным пользователем (или вами),
            либо запрос на его выбор.
        outcome:
          type: string
          enum:
            - match
            - miss
            - skipped
          description: >-
            `match`: шаг определил контрагента. `miss`: шаг был выполнен, но
            совпадений не найдено. `skipped`: шаг не удалось выполнить, причина
            указана в `reason`.
        reason:
          type: string
          description: >-
            Машиночитаемая причина, `""` при совпадении:
            `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` или `picked_member_without_proven_wallet`.
        vasp:
          type: string
          format: uuid
          nullable: true
          description: VASP из каталога, указанный на данном шаге, если он был указан.
        rail:
          type: string
          nullable: true
          description: >-
            Транспортная сеть (rail), через которую достигается этот контрагент,
            если шаг её обнаружил.
        at:
          type: string
          format: date-time
    TravelRuleNextAction:
      type: object
      description: >-
        Одно действие, которое позволяет продвинуть перевод со статусом
        `COUNTERPARTY_VASP_NOT_FOUND` или `COUNTERPARTY_VASP_NOT_REACHABLE`. См.
        раздел [Почему перевод
        завис](/ru/transaction-monitoring/travel-rule#почему-перевод-застрял).
      properties:
        action:
          type: string
          enum:
            - select_counterparty_vasp
            - declare_self_hosted
            - add_vasp_hint
            - update_compliance_email
            - resend
          description: >-
            `select_counterparty_vasp`: конечный пользователь выбирает VASP
            назначения в виджете владения кошельком, либо вы отправляете PATCH с
            `action=beneficiary_vasp`. `declare_self_hosted`: конечный
            пользователь объявляет кошелёк некастодиальным в виджете.
            `add_vasp_hint`: укажите Didit, кто является контрагентом, с помощью
            названия VASP, LEI или Travel Address (например, `travel_address` в
            записи адресной книги кошелька назначения), затем повторите
            отправку. `update_compliance_email` и `resend` являются значениями
            `action` для `PATCH /v3/transactions/{transaction_id}/travel-rule/`:
            передайте адрес электронной почты комплаенс-службы контрагента
            повторно и перезапустите маршрутизацию.
        url:
          type: string
          format: uri
          description: >-
            Ссылка на виджет подтверждения владения кошельком, при
            `select_counterparty_vasp` и `declare_self_hosted`, пока у перевода
            есть открытая сессия виджета.
      required:
        - action
    TravelRuleChainDetails:
      type: object
      description: >-
        Как блокчейн перевода именует два своих кошелька, когда перевод
        выполняется не просто с одного адреса на другой. Пусто (`{}`) для
        переводов в сетях на основе аккаунтов (EVM, Solana, Tron), где эти два
        адреса и есть кошельки. Сопоставление, маршрутизация и адресная книга
        читают кошельки в первую очередь отсюда.
      properties:
        chain:
          type: string
          description: >-
            Каноническая сеть, например `BTC`, `XRP` или `LIGHTNING` для
            перевода через Lightning.
        shape:
          type: string
          enum:
            - utxo
            - memo
            - lightning
        originator:
          $ref: '#/components/schemas/TravelRuleChainSide'
        beneficiary:
          $ref: '#/components/schemas/TravelRuleChainSide'
        utxo:
          type: object
          description: >-
            Для перевода UTXO: входы и выходы в сохраненном виде (суммы в виде
            десятичных строк) и то, как именно Didit интерпретировал выходы.
          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: Выходы, возвращающие средства обратно на адрес входа.
            beneficiary_output_index:
              type: integer
              nullable: true
              description: >-
                Выход, выплачивающий средства получателю; null, если не удалось
                определить ни один.
        lightning:
          type: object
          description: >-
            Для перевода Lightning: содержимое платежного запроса. Всегда `kind`
            (`bolt11`, `bolt12_offer`, `bolt12_invoice`,
            `bolt12_invoice_request`, `lnurl`, `lightning_address`, `node_id`
            или `unknown`); инвойс BOLT11 добавляет `network`, `payee_node_id`,
            `payment_hash`, `amount_msat`, `created_at` и `expires_at`; строка
            BOLT12 добавляет `blinded_paths` и `payee_node_id`; LNURL или
            Lightning Address добавляет свой `domain`. По сети ничего не
            запрашивается: выполняется только декодирование запроса.
          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: >-
            Несоответствия UTXO, заслуживающие внимания: заявленный отправитель
            отсутствует во входах (inputs), заявленный получатель отсутствует в
            выходах (outputs), невозможно выделить единственный выход получателя
            или сумма в выходе получателя отличается от указанной в транзакции.
        not_applicable_reason:
          type: string
          enum:
            - LIGHTNING_NO_PAYEE_IDENTIFIER
            - LIGHTNING_BOLT12_BLINDED_PAYEE
            - LIGHTNING_LNURL_NAMES_NO_PAYEE
          description: >-
            Для исходящего перевода Lightning, в платежном запросе которого не
            указан получатель: причина, почему перевод имеет статус
            `NOT_APPLICABLE`. `LIGHTNING_NO_PAYEE_IDENTIFIER` (в запросе не
            указан узел получателя или запрос не удалось декодировать),
            `LIGHTNING_BOLT12_BLINDED_PAYEE` (предложение скрывает своего
            получателя за слепыми путями), `LIGHTNING_LNURL_NAMES_NO_PAYEE`
            (LNURL указывает сервис, а не получателя). Тот же код открывает
            последнюю запись `timeline` перевода.
    TravelRuleChainSide:
      type: object
      description: Кошелёк одной из сторон, определённый Didit на основе данных блокчейна.
      properties:
        address:
          type: string
          description: >-
            Кошелёк. В сетях с memo это классический адрес (XRP X-address
            разделяется на классический адрес и тег); в Lightning это
            идентификатор узла получателя или Lightning Address.
        memo:
          type: string
          description: >-
            Destination tag или memo, являющиеся частью кошелька; `""`, если
            отсутствует.
        source:
          type: string
          enum:
            - declared
            - x_address
            - largest_input
            - only_non_change_output
            - amount_match
            - invoice_payee
            - updated
          description: >-
            Откуда получен кошелёк: `declared` (ваш запрос), `x_address`
            (выделен из X-адреса XRP), `largest_input` (входной адрес UTXO с
            наибольшим вкладом), `only_non_change_output` (единственный выход
            UTXO, не являющийся сдачей), `amount_match` (единственный выход
            UTXO, выплачивающий сумму перевода), `invoice_payee` (получатель,
            указанный в платежном запросе Lightning), `updated` (установлен
            позже с помощью `action: update_originator_wallet`).
    TravelRuleUtxoEntry:
      type: object
      description: >-
        Один вход или выход UTXO-транзакции в том виде, в каком он зафиксирован
        в блокчейне.
      required:
        - address
      properties:
        address:
          type: string
          maxLength: 128
        amount:
          type: string
          nullable: true
          description: >-
            Десятичная строка в единицах самой монеты (BTC, не сатоши).
            Необязательно.
          example: '0.0125'
        txid:
          type: string
          maxLength: 128
          description: Необязательно. Транзакция, которую расходует вход (input).
        vout:
          type: integer
          nullable: true
          minimum: 0
          description: >-
            Необязательно. Индекс выхода (output index), который расходуется
            входом (input).
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        API-ключ вашего приложения из раздела «Разработчикам» -> «API-ключи» в
        Business Console. Основной ключ имеет полный доступ. Именованный ключ
        может иметь ограниченную область действия: без доступа, чтение или
        запись для каждого ресурса, ограничение определенными сценариями или
        одобренными сессиями, списком IP-адресов и сроком действия. 401
        означает, что ключ неверен, отозван или его срок действия истек; 403
        означает, что ключ не был передан, у ключа нет доступа к этому ресурсу
        или действию, либо запрос поступил с адреса вне его списка IP-адресов;
        404 на маршруте сессии означает, что сессия не входит в сценарии или
        статусы ключа. Ключ без доступа к медиа получает URL изображений, видео
        и PDF как null, а ключ без прав на запись сессий получает ссылки на
        сессии и токены как null. См. https://docs.didit.me/console/api-keys.

````

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