> ## Documentation Index
> Fetch the complete documentation index at: https://apidocs.finrock.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Send Crypto Transactions with the Finrock API

> Create and submit on-chain transactions via the Finrock API. Covers destination types, fee estimation, bulk UTXO payouts, and idempotency.

Finrock gives you a single `POST /dac/v1/transaction` endpoint to move funds across all supported blockchains — whether you are sending to an external wallet, shifting balances between sub-accounts, or pushing assets to a connected exchange. This guide covers every parameter you need, explains destination and source types, shows you how to estimate fees before committing, and explains how to use idempotency keys so retried requests never result in a double-spend.

## Overview

Submitting a transaction requires four core fields: the `asset` ticker, the `amount`, a `source_type`, and a `destination_type`. Additional fields control fee behaviour, AML tracking, bulk payouts, and idempotency.

**Endpoint:** `POST https://api.finrock.io/dac/v1/transaction`

## Destination Types

The `destination_type` field tells Finrock where the funds are going. Choose the value that matches your recipient:

<CardGroup cols={2}>
  <Card title="EXTERNAL" icon="arrow-up-right-from-square">
    Send to any address outside your Finrock workspace — for example, a customer's self-custody wallet or a third-party exchange deposit address.
  </Card>

  <Card title="INTERNAL" icon="building">
    Move funds into your own sub-account within the workspace — for example, pulling balance from a connected exchange into your custody wallet.
  </Card>

  <Card title="SUBACCOUNT" icon="arrows-left-right">
    Transfer to a different sub-account within the same workspace — for example, moving funds from a trading desk sub-account to a treasury sub-account.
  </Card>

  <Card title="EXCHANGE" icon="chart-candlestick">
    Send funds to a connected exchange — for example, depositing collateral to Binance or Kraken from your Finrock wallet.
  </Card>
</CardGroup>

## Source Types

The `source_type` field tells Finrock where the funds originate:

| Value      | Description                                                      |
| ---------- | ---------------------------------------------------------------- |
| `INTERNAL` | Funds originate from your Finrock workspace wallet               |
| `EXCHANGE` | Funds originate from a connected exchange outside your workspace |

Use `source_id` to specify a particular address or address label within your workspace when you want to spend from a specific balance rather than the aggregate wallet balance. For XRP and XLM, use `source_tag` to identify the originating address tag.

## Creating a Transaction

The example below sends 100 USDT on the Tron network to an external wallet address:

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
       --url https://api.finrock.io/dac/v1/transaction \
       --header 'Authorization: Token {JWT}' \
       --header 'x-api-key: YOUR_API_KEY' \
       --header 'content-type: application/json' \
       --header 'accept: application/json' \
       --data '{
         "asset": "USDT_TRX",
         "amount": 100.00,
         "source_type": "INTERNAL",
         "destination_type": "EXTERNAL",
         "destination_id": "TXyzAbcDefGhiJklMnoPqrStuVwx",
         "memo": "Payment for invoice #1234",
         "sequence_id": "order-8472"
       }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://api.finrock.io/dac/v1/transaction', {
    method: 'POST',
    headers: {
      'Authorization': 'Token YOUR_JWT',
      'x-api-key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    },
    body: JSON.stringify({
      asset: 'USDT_TRX',
      amount: 100.00,
      source_type: 'INTERNAL',
      destination_type: 'EXTERNAL',
      destination_id: 'TXyzAbcDefGhiJklMnoPqrStuVwx',
      memo: 'Payment for invoice #1234',
      sequence_id: 'order-8472',
    }),
  });

  const transaction = await response.json();
  console.log(transaction);
  ```
</CodeGroup>

### All Request Parameters

| Parameter          | Type    | Required | Description                                                                             |
| ------------------ | ------- | -------- | --------------------------------------------------------------------------------------- |
| `asset`            | string  | Yes      | Asset ticker from the supported-assets list                                             |
| `amount`           | double  | Yes      | Transfer amount (max 8 decimal places)                                                  |
| `source_type`      | string  | Yes      | `INTERNAL` or `EXCHANGE`                                                                |
| `source_id`        | string  | No       | Specific address or label to spend from                                                 |
| `source_tag`       | string  | No       | Address tag for XRP/XLM source addresses                                                |
| `destination_type` | string  | Yes      | `EXTERNAL`, `INTERNAL`, `SUBACCOUNT`, or `EXCHANGE`                                     |
| `destination_id`   | string  | Yes\*    | Target address, sub-account ID, or exchange ID (\*required unless using `destinations`) |
| `destination_tag`  | string  | No       | Destination tag for XRP/XLM recipients                                                  |
| `destinations`     | array   | No       | Array of recipient objects for bulk UTXO payouts                                        |
| `memo`             | string  | No       | Note added to the transaction history                                                   |
| `sequence_id`      | string  | No       | Unique string for idempotency (prevents double-spend on retry)                          |
| `max_amount`       | boolean | No       | When `true`, sends the maximum possible balance after fees are deducted                 |
| `aml_cid`          | string  | No       | Your external customer ID, used to link this transaction to an AML subject              |

### Sending the Maximum Balance

Set `max_amount: true` to instruct Finrock to calculate the maximum sendable amount after network fees and deduct accordingly. Omit `amount` when using this flag:

```bash theme={null}
curl --request POST \
     --url https://api.finrock.io/dac/v1/transaction \
     --header 'Authorization: Token {JWT}' \
     --header 'x-api-key: YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --header 'accept: application/json' \
     --data '{
       "asset": "BTC",
       "max_amount": true,
       "source_type": "INTERNAL",
       "destination_type": "EXTERNAL",
       "destination_id": "bc1qRecipientAddressHere"
     }'
```

## Bulk UTXO Payouts

For UTXO-based chains (Bitcoin, Litecoin, Dogecoin, Dash, Bitcoin Cash), you can send to multiple recipients in a single transaction using the `destinations` array instead of a single `destination_id`. This significantly reduces total network fees compared to sending individual transactions.

```bash theme={null}
curl --request POST \
     --url https://api.finrock.io/dac/v1/transaction \
     --header 'Authorization: Token {JWT}' \
     --header 'x-api-key: YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --header 'accept: application/json' \
     --data '{
       "asset": "BTC",
       "source_type": "INTERNAL",
       "destination_type": "EXTERNAL",
       "destinations": [
         { "address": "bc1qAddress1Here", "amount": 0.05 },
         { "address": "bc1qAddress2Here", "amount": 0.12 },
         { "address": "bc1qAddress3Here", "amount": 0.03 }
       ],
       "sequence_id": "batch-payout-2024-001"
     }'
```

<Note>
  The `destinations` array is supported only on UTXO chains (BTC, LTC, DOGE, DASH, BCH). For EVM, Tron, Solana, and other account-based chains, use a single `destination_id`.
</Note>

## AML Tracking with `aml_cid`

If you have AML screening enabled, pass your internal customer identifier in the `aml_cid` field. Finrock forwards this value to the AML provider (Chainalysis) so every transaction is linked to the correct subject in your compliance records:

```json theme={null}
{
  "asset": "ETH",
  "amount": 1.5,
  "source_type": "INTERNAL",
  "destination_type": "EXTERNAL",
  "destination_id": "0xRecipientAddress",
  "aml_cid": "customer-uuid-abc123"
}
```

## Fee Estimation

Before submitting a high-value transaction, call `POST /dac/v1/estimate-fee` to preview the expected network fee without committing the transaction:

```bash theme={null}
curl --request POST \
     --url https://api.finrock.io/dac/v1/estimate-fee \
     --header 'Authorization: Token {JWT}' \
     --header 'x-api-key: YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --header 'accept: application/json' \
     --data '{
       "asset": "BTC",
       "amount": 0.5,
       "fee_rate": 20
     }'
```

The `fee_rate` unit depends on the blockchain. Use this reference table:

| Blockchain | Example Assets            | Fee Rate Unit |
| ---------- | ------------------------- | ------------- |
| UTXO       | BTC, LTC, DASH, DOGE, BCH | Sat/Byte      |
| EVM        | ETH, BSC, POL, BASE       | GWei          |
| Tron       | TRX, USDT\_TRX            | Sun           |
| Ripple     | XRP                       | Drop          |
| Stellar    | XLM                       | Stroop        |
| Cardano    | ADA                       | Lovelace      |
| Solana     | SOL                       | Lamport       |

<Tip>
  For UTXO chains, `amount` is required in the fee estimation request because transaction size — and therefore fee — depends on the number of inputs needed to cover the output value.
</Tip>

## Idempotency with `sequence_id`

Network timeouts and application retries can cause your code to call the transaction endpoint more than once for the same intended transfer. Pass a unique `sequence_id` string with every transaction request. If Finrock receives a second request with the same `sequence_id` for the same sub-account, it returns the result of the original transaction instead of creating a new one.

```json theme={null}
{
  "asset": "USDT_TRX",
  "amount": 500,
  "source_type": "INTERNAL",
  "destination_type": "EXTERNAL",
  "destination_id": "TRecipientAddressHere",
  "sequence_id": "withdrawal-user-42-2024-11-26-001"
}
```

<Warning>
  Always use a `sequence_id` for withdrawal flows in production. Without it, a retry caused by a network error will create a duplicate transaction and move funds twice.
</Warning>

## Transaction Statuses

After submission, poll the transactions endpoint or listen to webhooks for status updates. See [Transaction Statuses](/reference/transaction-statuses) in the Platform Reference for the full list of status values and their meanings. For a deep dive on preventing duplicate transactions, see [Idempotency](/reference/idempotency).
