Skip to content

Outgoing transactions

Integrate outgoing Travel Rule transactions with CryptoSwift, including post- and pre-transaction patterns.

Use this guide to build outbound Travel Rule transaction flows. It covers the standard post-transaction pattern, the request-before-broadcast pre-transaction variant, and how to handle status updates.

Always double-check you are using the correct environment when integrating. Using the wrong base URL or API key will result in authentication errors.

Post-transaction flow

The following example initiates a new outgoing Travel Rule transaction in compliance with FATF Recommendation 16. In the post-transaction flow, the Travel Rule message is sent immediately after the on-chain transaction is completed, allowing the transaction hash to be included in the Travel Rule message payload.

First make sure you have your API key ready:

API_KEY='a70fcedf-416b-4f83-845c-a05aba0d7da4'

Then send a POST request to the CryptoSwift API with the relevant data:

curl --location --request POST 'https://api-dev.cryptoswift.eu/transactions' \
  --header 'x-api-key: $API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "asset": "BTC",
      "amount": "0.00341",
      "blockchainInfo": {
          "blockchain": "Bitcoin",
          "transactionHash": "cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79",
          "origin": "17SkEw2md5avVNyYgj6RiXuQKNwkXaxFyQ",
          "destination": "1MLh2UVHgonJY4ZtsakoXtkcXDJ2EPU6RY",
          "destinationType": "CUSTODIAL"
      },
      "vaspInfo": {
          "beneficiaryVaspName": "SwiftExchange"
      },
      "originator": {
          "type": "NATURAL",
          "name": "Marwin Hillar",
          "accountNumber": "04143282398",
          "address": "Alexanderplatz 25, Berlin",
          "country": "Germany"
      },
      "beneficiary": {
          "type": "NATURAL",
          "name": "Hanne Nikol",
          "accountNumber": "1MLh2UVHgonJY4ZtsakoXtkcXDJ2EPU6RY"
      }
  }'

The request returns the full Travel Rule message payload, including the transaction UUID, so you can reconcile the payload later. This is useful if you need to patch the transaction data or track delivery statuses.

Using the post-transaction flow is currently the easiest and fastest way to achieve Travel Rule compliance because you do not need complex logic for response handling, timeouts, or fallback mechanisms.

Post-transaction workflow explained

See the Compliance Workflows section to find out more about the post-transaction flow.

Pre-transaction flow

If you need beneficiary confirmation before the actual on-chain settlement, create the Travel Rule message without the transaction hash and include blockchain context so the counterparty VASP understands what they are approving. This allows you to:

  • Send the Travel Rule data before the on-chain transaction happens
  • Wait until the counterparty responds
  • Execute the on-chain transaction
  • Update the Travel Rule message with the on-chain transaction hash

Make the transaction

Start by sending the Travel Rule data (note that the transaction hash is missing):

curl --location --request POST 'https://api-dev.cryptoswift.eu/transactions' \
  --header 'x-api-key: $API_KEY' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "asset": "BTC",
      "amount": "0.00341",
      "blockchainInfo": {
          "blockchain": "Bitcoin",
          "origin": "17SkEw2md5avVNyYgj6RiXuQKNwkXaxFyQ",
          "destination": "1MLh2UVHgonJY4ZtsakoXtkcXDJ2EPU6RY",
          "destinationType": "CUSTODIAL"
      },
      "vaspInfo": {
          "beneficiaryVaspName": "SwiftExchange"
      },
      "originator": {
          "type": "NATURAL",
          "name": "Marwin Hillar",
          "accountNumber": "04143282398",
          "address": "Alexanderplatz 25, Berlin",
          "country": "Germany"
      },
      "beneficiary": {
          "type": "NATURAL",
          "name": "Hanne Nikol",
          "accountNumber": "1MLh2UVHgonJY4ZtsakoXtkcXDJ2EPU6RY"
      }
  }'

Wait for counterparty response

After sending the Travel Rule data, you will receive a response with the full Travel Rule message payload, including the status of the transaction. In most cases this will be "PENDING" or "DELIVERED" - indicating whether CryptoSwift was able to identify the beneficiary VASP and deliver the message in real time.

If you have set up webhook notifications, your backend will receive status updates for the Travel Rule transaction. The status can be:

  • "DELIVERED" - for previously pending messages, indicating CryptoSwift was able to identify and deliver the message. This does not confirm that the beneficiary VASP has responded.
  • "CONFIRMED" - the beneficiary VASP confirmed the message, meaning the provided data is correct.
  • "DECLINED" - the beneficiary VASP declined the message. The statusReasoning field provides a mandatory free text explanation.
  • "FAILED" - the system encountered an error.

Make the on-chain payment

Once you have received the "CONFIRMED" status update for your message, proceed with the on-chain transfer. In real-world scenarios, getting an immediate "CONFIRMED" status update from the counterparty VASP may take longer than is reasonable to wait before executing the on-chain transaction. Also, many VASPs still do not use a Travel Rule solution or use one that is not connected to CryptoSwift's network. For a pre-transaction flow, always set up a fallback mechanism, for example, wait for a predefined amount of time before falling back to the post-transaction flow or another approach that aligns with your internal AML guidelines.

Patch the transaction hash

After the blockchain transfer completes, update the Travel Rule record so both VASPs can reconcile the message with the on-chain settlement.

curl --request PATCH "https://api-dev.cryptoswift.eu/transactions/{transactionId}" \
  --header 'x-api-key: $API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "blockchainInfo": {
      "transactionHash": "cca7507897abc89628f450e8b1e0c6fca4ec3f7b34cccf55f3f531c659ff4d79"
    }
  }'

You can include any additional data fields that you want to update with the PATCH call.

Pre-transaction workflow explained

See the Compliance Workflows section to find out more about the pre-transaction flow, including possible fallback scenarios.

Key data points explained

To begin with, specify the asset (for example, BTC or ETH) and the amount transferred in the transaction.

In the blockchainInfo and vaspInfo sections, include the essential data needed for us to deliver the Travel Rule message to the beneficiary VASP:

  • blockchain: The blockchain. Leave it blank if your desired blockchain is not in the list in our API.
  • transactionHash: The unique identifier of the on-chain transaction.
  • origin: The blockchain wallet address from which the transaction is initiated.
  • destination: The blockchain wallet address to which the transaction is being sent.
  • beneficiaryVaspName and beneficiaryVaspEmail: This information helps us deliver Travel Rule messages, especially if the destination address is unknown to CryptoSwift or belongs to a VASP outside our network. There are usually two options for obtaining this data:
    1. Ask your customer which crypto service provider the beneficiary is using. Use the Entities endpoint to build an auto-complete of known VASPs. You can fall back to free text entry if the VASP is not on the list.
    2. Use blockchain analytics tools to obtain the VASP name associated with the wallet address.

For more guidance on ensuring high-quality data, see Improving data quality.

The originator and beneficiary sections should include all required data for both parties. The accountNumber for both the originator and beneficiary serves as the internal identifier used by the VASP to recognize the user. This could be the wallet address itself or another available account identifier.

For detailed requirements regarding originator and beneficiary information mandated by regulations, refer to our blog post on data requirements for the Travel Rule. If you do not have all the necessary data available at the moment, you can still start the integration process. For guidance, check our blog post on iterative integration.

Warnings

When you fetch your Travel Rule messages list or details, outgoing messages can include a warnings list in the response if we detect possible data inconsistencies. See the warnings field in the Transactions API response for details. The possible values are:

  • WALLET_POSSIBLY_CUSTODIAL: The message states the destination wallet is non-custodial (self-hosted), but our records suggest it might be custodial.
  • WALLET_POSSIBLY_NON_CUSTODIAL: The message states the destination wallet is custodial, but our records suggest it might be self-hosted instead.
  • VASP_POSSIBLY_MISMATCH: A VASP name was provided in the payload, but our records suggest the name might be incorrect.

Testing your integration

In the development environment, we are not transferring live Travel Rule messages between real VASPs. Still, it is important to be able to test different statuses (PENDING, DELIVERED) and status updates (CONFIRMED, DECLINED) for outgoing Travel Rule messages. For this, we have a list of known wallet addresses available in the test environment that you can use for development and testing. See Testing webhook notifications for details.

Next steps