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

# Send a Travel Rule Message

> Sends a message or a document request to the counterparty VASP. Works on INTERNAL transfers (the other Didit customer sees it on its side of the pair) and EMAIL transfers (the counterparty is emailed and answers in the pickup portal). A transfer over TRP, GTR, TRUST, VerifyVASP or Sygna carries no messages, because those protocols have none. Limits: 100 messages per transfer, 5000 characters per body, 10 requested documents, 5 files of 10 MB each.

export const AgentPromptAccordion = ({prompt, title = "AI Agent Integration Prompt"}) => {
  const [copied, setCopied] = React.useState(false);
  const handleCopy = e => {
    e.stopPropagation();
    if (!prompt) return;
    navigator.clipboard.writeText(prompt.trim()).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  };
  const agents = ["Claude Code", "Codex", "Cursor", "Devin", "Windsurf", "GitHub Copilot"];
  return <div className="didit-agent-card">
      {}
      <div className="didit-agent-titlebar">
        <div className="didit-agent-dots" aria-hidden="true">
          <span className="didit-agent-dot didit-agent-dot-red"></span>
          <span className="didit-agent-dot didit-agent-dot-yellow"></span>
          <span className="didit-agent-dot didit-agent-dot-green"></span>
        </div>
        <span className="didit-agent-filename">{title}</span>
        <button type="button" className={`didit-agent-copy ${copied ? "didit-agent-copy-copied" : ""}`} onClick={handleCopy} title="Copy prompt to clipboard" aria-label={copied ? "Copied!" : "Copy prompt to clipboard"}>
          {copied ? <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <path d="M3 8.5l3.5 3.5L13 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              <span>Copied</span>
            </> : <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <rect x="5" y="5" width="9" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.5" />
                <path d="M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5" stroke="currentColor" strokeWidth="1.5" />
              </svg>
              <span>Copy</span>
            </>}
        </button>
      </div>

      {}
      <pre className="didit-agent-body"><code>{prompt.trim()}</code></pre>

      {}
      <div className="didit-agent-footer">
        <span className="didit-agent-footer-label">Paste into</span>
        <div className="didit-agent-chips">
          {agents.map(name => <span key={name} className="didit-agent-chip">{name}</span>)}
        </div>
      </div>
    </div>;
};

<AgentPromptAccordion
  title="Send a Travel Rule Message API Prompt"
  prompt={`Send a message or a document request to the counterparty VASP of a Travel Rule transfer, so a disputed transfer is resolved inside Didit.

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

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

Request body (JSON, or multipart/form-data when attaching files):
- kind - MESSAGE (default) or DOCUMENT_REQUEST.
- body - up to 5000 characters. A MESSAGE needs a body or a file.
- requested_documents - up to 10 names. A DOCUMENT_REQUEST needs at least one; a MESSAGE must not have any.
- reply_to - uuid of an earlier message of the same transfer. A reply carrying a document fulfils the request it answers.
- files - multipart only, up to 5 files of 10 MB each.

Example call:
curl -X POST "https://verification.didit.me/v3/transactions/{transaction_id}/travel-rule/messages/" \\
-H "x-api-key: YOUR_API_KEY" -H "Content-Type: application/json" \\
-d '{"kind": "DOCUMENT_REQUEST", "body": "Please confirm the beneficiary date of birth.", "requested_documents": ["Proof of address"]}'

Behavior:
- Works on INTERNAL transfers (the other Didit customer sees it on its side) and EMAIL transfers (the counterparty is emailed and answers in the pickup portal).
- A transfer holds up to 100 messages.

Failure modes:
- 400 - invalid body, file rejected, 100 messages reached, or reply_to is not a message of this transfer.
- 404 - unknown transaction, or no Travel Rule transfer on it.
- 409 - no message can reach the counterparty; detail gives the reason: a network rail (TRP, GTR, TRUST, VerifyVASP, Sygna) carries no messages, no counterparty yet, an INTERNAL transfer whose data did not match the wallet holder, or an EMAIL transfer whose pickup link expired or whose transfer is closed.

Full guide: /transaction-monitoring/travel-rule#messages-and-document-requests.`}
/>


## OpenAPI

````yaml POST /v3/transactions/{transaction_id}/travel-rule/messages/
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/transactions/{transaction_id}/travel-rule/messages/:
    post:
      tags:
        - Travel Rule
      summary: Send a Travel Rule message or document request
      description: >-
        Sends a message or a document request to the counterparty VASP. Works on
        INTERNAL transfers (the other Didit customer sees it on its side of the
        pair) and EMAIL transfers (the counterparty is emailed and answers in
        the pickup portal). A transfer over TRP, GTR, TRUST, VerifyVASP or Sygna
        carries no messages, because those protocols have none. Limits: 100
        messages per transfer, 5000 characters per body, 10 requested documents,
        5 files of 10 MB each.
      operationId: createTravelRuleMessage
      parameters:
        - name: transaction_id
          in: path
          required: true
          description: Didit-stable transaction UUID that owns the transfer.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TravelRuleMessageCreateRequest'
            example:
              kind: DOCUMENT_REQUEST
              body: Please confirm the date of birth of the beneficiary.
              requested_documents:
                - Proof of address
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/TravelRuleMessageCreateRequest'
      responses:
        '201':
          description: The stored message.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleMessage'
        '400':
          description: >-
            Invalid body, a file type or size that is not accepted, more than
            100 messages on the transfer, or a `reply_to` that is not a message
            of this transfer.
          content:
            application/json:
              schema:
                type: object
              example:
                requested_documents:
                  - Name at least one document the counterparty should send.
        '404':
          description: >-
            Unknown transaction or token, or no Travel Rule transfer on the
            transaction.
        '409':
          description: >-
            No message can reach the counterparty. `detail` gives the reason:
            the transfer runs over a network rail (TRP, GTR, TRUST, VerifyVASP
            or Sygna), it has no counterparty yet, an INTERNAL transfer's data
            did not match the wallet holder so nothing reached the recipient, or
            an EMAIL transfer's pickup link has expired or the transfer is
            closed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: >-
            curl -X POST
            https://verification.didit.me/v3/transactions/{transaction_id}/travel-rule/messages/
            \
              -H 'x-api-key: YOUR_API_KEY' -H 'Content-Type: application/json' \
              -d '{"kind": "DOCUMENT_REQUEST", "body": "Please confirm the date of birth of the beneficiary.", "requested_documents": ["Proof of address"]}'
components:
  schemas:
    TravelRuleMessageCreateRequest:
      type: object
      description: Send as JSON, or as multipart/form-data with the attachments in `files`.
      properties:
        kind:
          type: string
          enum:
            - MESSAGE
            - DOCUMENT_REQUEST
          default: MESSAGE
        body:
          type: string
          maxLength: 5000
          description: Required for a MESSAGE unless a file is attached.
        requested_documents:
          type: array
          items:
            type: string
            maxLength: 255
          maxItems: 10
          description: >-
            Required (at least one) for a DOCUMENT_REQUEST, and only allowed
            there.
        reply_to:
          type: string
          format: uuid
          nullable: true
          description: >-
            A message of the same transfer. A reply that carries a document
            fulfils the document request it answers.
        files:
          type: array
          items:
            type: string
            format: binary
          maxItems: 5
          description: Multipart only. Up to 5 files of 10 MB each.
    TravelRuleMessage:
      type: object
      properties:
        id:
          type: string
          format: uuid
        kind:
          type: string
          enum:
            - MESSAGE
            - DOCUMENT_REQUEST
        direction:
          type: string
          enum:
            - INBOUND
            - OUTBOUND
          description: >-
            `OUTBOUND` is what the reader's own side sent. In the pickup portal
            the direction is from the counterparty's side.
        author:
          type: string
          description: >-
            Who wrote it on its own side: a console user's email or an API key
            label, or the other VASP's name.
        body:
          type: string
        requested_documents:
          type: array
          items:
            type: string
          description: What a DOCUMENT_REQUEST asks for, in the requester's words.
        reply_to:
          type: string
          format: uuid
          nullable: true
        fulfilled_at:
          type: string
          format: date-time
          nullable: true
          description: Set on a DOCUMENT_REQUEST once a reply to it carries a document.
        attachment:
          $ref: '#/components/schemas/TravelRuleMessageAttachment'
        created_at:
          type: string
          format: date-time
    TravelRuleMessageAttachment:
      type: object
      nullable: true
      description: >-
        The document attached to a message, stored like any other transaction
        document.
      properties:
        uuid:
          type: string
          format: uuid
        label:
          type: string
          nullable: true
        note:
          type: string
          nullable: true
        uploaded_by:
          type: string
          nullable: true
          description: >-
            Who attached it. In the pickup portal, a file you sent shows your
            VASP name, never the person or API key behind it.
        created_at:
          type: string
          format: date-time
        files:
          type: array
          items:
            type: object
            properties:
              uuid:
                type: string
                format: uuid
              file_url:
                type: string
                nullable: true
                description: Time-limited download URL.
              original_filename:
                type: string
              file_size:
                type: integer
  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 missing, wrong, revoked or expired; 403 means 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.