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

# Finish, Cancel, or Resend a Transfer

> Provide `payment_txn_id` to report the on-chain hash and move an outbound COMPLETED transfer to FINISHED (its INTERNAL-rail counterpart also moves to FINISHED), `{"action": "cancel"}` to cancel a non-terminal transfer, or `{"action": "resend"}` to re-run routing for an outbound transfer stuck in COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA (improve the counterparty data first, e.g. add a travel_address to the destination wallet entry).

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="Travel Rule Transfer Actions API Prompt"
  prompt={`Act on an existing Travel Rule transfer: report the on-chain hash to finish it, cancel it, or re-run counterparty routing.

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.

Three mutually exclusive bodies:

1. Finish (close out after broadcasting on-chain):
{"payment_txn_id": "0xchainhash"}
- 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.

2. Cancel:
{"action": "cancel"}
- Allowed from any non-terminal status; moves the transfer to CANCELLED.

3. Resend (re-run the routing ladder):
{"action": "resend"}
- Allowed only from COUNTERPARTY_VASP_NOT_FOUND, COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA - otherwise 409.
- First improve the counterparty data (add a travel_address to the destination wallet-address entry, catalogue the VASP in the directory, or supply better beneficiary_data), then resend.
- A previously recorded blockchain-analytics attribution is reused - no new lookup, no new charge.

What to read from the response:
- The full transfer object: status, rail, direction, ownership_confirmed, deadline_at, timeline, counterparty_vasp.

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.

Failure modes:
- 409 - action not allowed from the transfer's current status (see the per-action rules above).
- 404 - unknown transaction or no Travel Rule transfer attached.

Full guide: /transaction-monitoring/travel-rule#sending-a-transfer.`}
/>


## OpenAPI

````yaml PATCH /v3/transactions/{transaction_id}/travel-rule/
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/:
    patch:
      tags:
        - Travel Rule
      summary: Finish, cancel, or resend a Travel Rule transfer
      description: >-
        Provide `payment_txn_id` to report the on-chain hash and move an
        outbound COMPLETED transfer to FINISHED (its INTERNAL-rail counterpart
        also moves to FINISHED), `{"action": "cancel"}` to cancel a non-terminal
        transfer, or `{"action": "resend"}` to re-run routing for an outbound
        transfer stuck in COUNTERPARTY_VASP_NOT_FOUND,
        COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA
        (improve the counterparty data first, e.g. add a travel_address to the
        destination wallet entry).
      operationId: patchTravelRuleTransfer
      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/TravelRuleTransferPatchRequest'
            examples:
              Finish:
                value:
                  payment_txn_id: 0xchainhash
              Cancel:
                value:
                  action: cancel
              Resend:
                value:
                  action: resend
      responses:
        '200':
          description: The updated transfer.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TravelRuleTransferDetail'
        '400':
          description: >-
            Neither payment_txn_id nor a supported action (cancel, resend) was
            provided.
        '409':
          description: >-
            The transfer is not in a state that allows this operation (e.g. not
            COMPLETED/outbound for finish, already terminal for cancel, or not
            an outbound transfer in a resendable status for resend).
      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"}'
components:
  schemas:
    TravelRuleTransferPatchRequest:
      type: object
      description: >-
        Provide exactly one of: payment_txn_id (finish), action=cancel, or
        action=resend.
      properties:
        payment_txn_id:
          type: string
          description: >-
            The on-chain transaction hash. Requires the transfer to be an
            outbound transfer in COMPLETED status.
        action:
          type: string
          enum:
            - cancel
            - resend
          description: >-
            "cancel" cancels a non-terminal transfer. "resend" re-runs routing
            for an outbound transfer stuck in COUNTERPARTY_VASP_NOT_FOUND,
            COUNTERPARTY_VASP_NOT_REACHABLE, or NOT_ENOUGH_COUNTERPARTY_DATA.
    TravelRuleTransferDetail:
      type: object
      description: >-
        Full transfer object returned by the ownership-confirmation and
        finish/cancel endpoints. originator_data/beneficiary_data are omitted
        while PII is masked (see description).
      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
            - EMAIL
            - 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
        counterparty_vasp:
          type: object
          nullable: true
          properties:
            name:
              type: string
            lei:
              type: string
            dd_score:
              type: integer
        originator_data:
          type: object
        beneficiary_data:
          type: object
        created_at:
          type: string
          format: date-time
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````