> ## 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.

# Match Travel Rule Deposit API: Pair a Message

> Pair an inbound deposit that waits for originator data with the Travel Rule message the originating VASP sent, so the deposit takes its originator data.



Match Unmatched Travel Rule Deposit API Prompt
        Copy prompt to clipboard



      
      

\<pre>

\`Pair an inbound deposit that still waits for originator data with the Travel Rule message the originating VASP sent for it.

Endpoint:
POST https://verification.didit.me/v3/travel-rule/unmatched/{transaction_uuid}/match/

Authentication:
Use the x-api-key header with my Didit API key. A scoped API key needs the transactions privilege.

Path parameter:
\- transaction_uuid - the transaction_id of the unmatched deposit, from GET /v3/travel-rule/unmatched/.

Request body (JSON, required):
\- transaction_id (UUID) - the transaction_id of the received Travel Rule message: a row with kind "message" from GET /v3/travel-rule/transfers/?kind=message. The transfer's own id is not found.

curl example:
curl -X POST "https://verification.didit.me/v3/travel-rule/unmatched/<DEPOSIT_TRANSACTION_ID>/match/" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"transaction_id": "<MESSAGE_TRANSACTION_ID>"}'

Response 200:
\- deposit - the deposit row after the match: it now carries the message's originator data, counterparty VASP and rail, and matched_transaction_id points to the message.
\- message - the message row, with matched_transaction_id pointing to the deposit.

Failure modes:
\- 400 - transaction_id is missing, is the deposit itself, is not a received Travel Rule message, or is for a different asset than the deposit; or the transaction in the path is not an inbound deposit.
\- 401 - invalid API key.
\- 403 - the key lacks the transactions privilege.
\- 404 - the deposit or the message does not exist or was deleted.
\- 409 - the deposit no longer waits for originator data, or the message is already matched to a deposit. Nothing changes.

Full guide: /transaction-monitoring/travel-rule.`

\</pre>



      
      

Paste into

## When to use itUse it when a deposit from [List unmatched deposits](https://docs.didit.me/management-api/travel-rule/list-unmatched-deposits.md) has a received Travel Rule message that belongs to it and Didit did not pair the two on its own.
The deposit takes the message's originator data, counterparty VASP and rail, and both transfers record the match on their timelines.## Request```bash theme={null}
curl -X POST "https://verification.didit.me/v3/travel-rule/unmatched/DEPOSIT_TRANSACTION_ID/match/" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id": "MESSAGE_TRANSACTION_ID"}'
```## Notes- `transaction_uuid` in the path is the deposit. `transaction_id` in the body is the message.
- The message must be for the same asset as the deposit.
- The call fails with `409` when either side has already moved on, and changes nothing.
- A transaction deleted from the Console answers `404`, on either side.## Related- [List unmatched deposits](https://docs.didit.me/management-api/travel-rule/list-unmatched-deposits.md)
- [List Travel Rule transfers](https://docs.didit.me/management-api/travel-rule/list-transfers.md)
- [Travel Rule](https://docs.didit.me/transaction-monitoring/travel-rule.md)


## OpenAPI

````yaml POST /v3/travel-rule/unmatched/{transaction_uuid}/match/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/travel-rule/unmatched/{transaction_uuid}/match/:
    post:
      tags:
        - Travel Rule
      summary: Match a Travel Rule deposit to a received message
      description: >-
        Pair an inbound deposit that is still waiting for originator data with
        the Travel Rule message the originating VASP sent for it. The deposit
        takes the message's originator data, counterparty VASP and rail, and
        both transfers record the match on their timelines. `transaction_uuid`
        is the deposit's `transaction_id` from `GET /v3/travel-rule/unmatched/`.
        `transaction_id` in the body is the received message's `transaction_id`,
        from a row of `GET /v3/travel-rule/transfers/?kind=message`; the
        transfer's own `id` is not found. The message must be for the same asset
        as the deposit. A deposit or message deleted from the Console answers
        `404`; one that has already moved on (matched, or no longer waiting)
        answers `409`.
      operationId: matchUnmatchedTravelRuleDeposit
      parameters:
        - name: transaction_uuid
          in: path
          required: true
          description: The `transaction_id` of the unmatched deposit.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TravelRuleManualMatchRequest'
            example:
              transaction_id: e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24
      responses:
        '200':
          description: Both transfers after the match.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleManualMatchResponse'
              example:
                deposit:
                  id: 7d3a1c55-0b9e-4d52-8a3c-1f6e2b9d4a08
                  transaction_id: c41f9b2e-5a8d-4e0c-9f17-3b6d8a2e5c91
                  txn_id: dep-2026-10-20-0007
                  txn_date: '2026-10-19T08:41:12Z'
                  kind: deposit
                  direction: INBOUND
                  status: AWAITING_COUNTERPARTY
                  rail: TRP
                  asset: ETH
                  amount: '1.25'
                  originator_vasp: Example Counterparty VASP
                  beneficiary_vasp: Example Counterparty VASP
                  originator_wallet: '0x77ccff0cc624a53cd8b8d8703ced826710211ec7'
                  beneficiary_wallet: '0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb'
                  originator_memo: ''
                  beneficiary_memo: ''
                  originator_wallet_type: vasp
                  beneficiary_wallet_type: vasp
                  matched_transaction_id: e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24
                  deadline_at: null
                  created_at: '2026-10-19T08:41:13Z'
                message:
                  id: 2b8e6f10-9c3a-47d1-b5e2-0a4c7d9f3e66
                  transaction_id: e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24
                  txn_id: msg-2026-10-20-0003
                  txn_date: '2026-10-19T08:41:12Z'
                  kind: message
                  direction: INBOUND
                  status: COMPLETED
                  rail: TRP
                  asset: ETH
                  amount: '1.25'
                  originator_vasp: Origin CASP SL
                  beneficiary_vasp: Example Counterparty VASP
                  originator_wallet: '0x77ccff0cc624a53cd8b8d8703ced826710211ec7'
                  beneficiary_wallet: '0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb'
                  originator_memo: ''
                  beneficiary_memo: ''
                  originator_wallet_type: vasp
                  beneficiary_wallet_type: vasp
                  matched_transaction_id: null
                  deadline_at: '2026-10-21T08:41:13Z'
                  created_at: '2026-10-19T08:41:13Z'
        '400':
          description: >-
            Validation error: `transaction_id` is missing, is the deposit
            itself, is not a received Travel Rule message, or is for a different
            asset than the deposit; or the transaction in the path is not an
            inbound deposit.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
              examples:
                Error:
                  value:
                    transaction_id:
                      - >-
                        The travel rule message is for a different asset than
                        the deposit.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: Unknown deposit or message, or one of them was deleted.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
              example:
                detail: No TravelRuleTransfer matches the given query.
        '409':
          description: >-
            The deposit is no longer waiting for originator data, or the message
            is already matched to a deposit.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
              examples:
                Error:
                  value:
                    detail: This deposit is no longer waiting for originator data.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.travel_rule.unmatched_deposits.match(
                "11111111-2222-3333-4444-555555555555",
                transaction_id="e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24",
            )
            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.travelRule.unmatchedDeposits.match("11111111-2222-3333-4444-555555555555",
            {
              transaction_id: "e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24",
            });

            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.TravelRule.UnmatchedDeposits.Match(ctx, \"11111111-2222-3333-4444-555555555555\", didit.TravelRuleManualMatchRequest{\n\tTransactionID: \"e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24\",\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.TravelRuleManualMatchRequest;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.travelRule().unmatchedDeposits().match("11111111-2222-3333-4444-555555555555",
            TravelRuleManualMatchRequest.builder()
                    .transactionId("e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24")
                    .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->travelRule->unmatchedDeposits->match('11111111-2222-3333-4444-555555555555',
            [
                'transaction_id' => 'e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24',
            ]);

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

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

            result = didit.travel_rule.unmatched_deposits.match(
              "11111111-2222-3333-4444-555555555555",
              transaction_id: "e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24"
            )
            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.TravelRule.UnmatchedDeposits.MatchAsync("11111111-2222-3333-4444-555555555555",
            new TravelRuleManualMatchRequest

            {
                TransactionId = "e90a4d7b-1c2f-4b83-a6d5-8f0e3c1b7a24",
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  schemas:
    TravelRuleManualMatchRequest:
      type: object
      required:
        - transaction_id
      properties:
        transaction_id:
          type: string
          format: uuid
          description: >-
            The `transaction_id` of the received Travel Rule message (a row with
            `kind: message`).
    TravelRuleManualMatchResponse:
      type: object
      required:
        - deposit
        - message
      properties:
        deposit:
          $ref: '#/components/schemas/TravelRuleTransferRow'
        message:
          $ref: '#/components/schemas/TravelRuleTransferRow'
    TravelRuleTransferRow:
      type: object
      description: >-
        One Travel Rule transfer as the transfers list shows it: VASP names,
        wallets and memos only, never the originator or beneficiary person data.
      properties:
        id:
          type: string
          format: uuid
          description: The transfer's id.
        transaction_id:
          type: string
          format: uuid
          description: The Didit transaction the transfer belongs to.
        txn_id:
          type: string
          nullable: true
          description: >-
            Your own id for the transaction. Transfers Didit books for you, such
            as a Didit Test VASP inbound transfer, carry a generated one.
        txn_date:
          type: string
          format: date-time
        kind:
          type: string
          enum:
            - withdrawal
            - deposit
            - message
          description: >-
            withdrawal: outbound. message: an inbound transfer a rail created
            from a counterparty's message (a TRP inquiry, the INTERNAL inbound
            leg, or a GTR, VerifyVASP or Sygna Bridge message). deposit: any
            other inbound transfer.
        direction:
          type: string
          enum:
            - INBOUND
            - OUTBOUND
        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
        reason:
          type: string
          description: >-
            Why a `COUNTERPARTY_VASP_NOT_FOUND` or
            `COUNTERPARTY_VASP_NOT_REACHABLE` transfer is stuck, the same value
            as the transfer's own `reason`, so the list tells a bounced
            compliance email from a counterparty with no route without opening
            each transfer. `""` for any other status. See [Why a transfer is
            stuck](/transaction-monitoring/travel-rule#why-a-transfer-is-stuck).
        rail:
          type: string
          nullable: true
          enum:
            - INTERNAL
            - TRP
            - GTR
            - TRUST
            - VERIFYVASP
            - SYGNA
            - EMAIL
            - TEST_VASP
            - null
        asset:
          type: string
          description: The transaction's currency.
        amount:
          type: string
          description: The amount as a plain decimal, for example "1.25".
        originator_vasp:
          type: string
          description: >-
            Outbound: your VASP's legal name. Inbound: the counterparty's name,
            from its directory entry, the Didit network member, the TRP sender,
            the Didit Test VASP, or the name the transfer declared. Empty when
            none is known.
        beneficiary_vasp:
          type: string
          description: >-
            Outbound: the counterparty's name, worked out the same way. Inbound:
            your VASP's legal name.
        originator_wallet:
          type: string
        beneficiary_wallet:
          type: string
        originator_memo:
          type: string
          description: Memo or destination tag, empty on chains without one.
        beneficiary_memo:
          type: string
        originator_wallet_type:
          type: string
          enum:
            - vasp
            - self_hosted
            - own
          description: >-
            vasp, self_hosted (declared unhosted) or own (a wallet your address
            book records as yours). Your own side is always vasp.
        beneficiary_wallet_type:
          type: string
          enum:
            - vasp
            - self_hosted
            - own
        matched_transaction_id:
          type: string
          format: uuid
          nullable: true
          description: >-
            The other side of a deposit you matched to an announced transfer by
            hand.
        deadline_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            When the transfer expires if it is still waiting on its
            counterparty. Set on every transfer you create with `POST
            /v3/transactions/` that needs an exchange, outbound or inbound. Null
            below the threshold, on a Lightning payment the Travel Rule does not
            apply to, and on inbound transfers Didit creates when a counterparty
            reaches you (an inbound TRP inquiry, a network message or the
            INTERNAL inbound leg).
        created_at:
          type: string
          format: date-time
  responses:
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          examples:
            Invalid API Key:
              summary: Invalid API Key
              value:
                detail: Invalid API Key.
    Forbidden:
      description: Forbidden
      content:
        application/json:
          examples:
            No Permission:
              summary: No Permission
              value:
                detail: You do not have permission to perform this action.
            Not Enough Credits:
              summary: Not Enough Credits
              value:
                error: >-
                  You don't have enough credits to perform this request. Please
                  top up at https://business.didit.me
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Your application's API key, from Developers -> API keys in the Business
        Console. The primary key has full access. A named key can be scoped:
        none, read or write per resource, limited to some workflows or to
        approved sessions, to a list of IP addresses, and to an expiry date. 401
        means the key is wrong, revoked or expired; 403 means no key was sent,
        the key has no access to this resource or action, or the request came
        from an address outside its IP list; 404 on a session route means the
        session is outside the key's workflows or statuses. A key without media
        access receives image, video and PDF URLs as null, and a key without
        sessions write receives session links and tokens as null. See
        https://docs.didit.me/console/api-keys.

````

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