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

# Create Transactions

> Create Fireblocks transactions with the SDK, API or CLI, and learn how to make transaction creation idempotent, policy-controlled and scalable in production.

Every transaction on the Fireblocks platform is created with the same endpoint, [Create a new transaction](/api-reference/transactions/create-a-new-transaction), and the `operation` field in the request body selects the transaction type. The default operation is `TRANSFER`. This page walks you through the shape of a request, setting up your client and sending your first transfer, and then covers how to run transaction creation securely and at scale. Once you have sent your first transaction, [explore the other transaction types](#explore-transaction-types) and the guides available for each of them.

## Anatomy of a request

The fields below are shared by most transaction types. The [API reference](/api-reference/transactions/create-a-new-transaction) is the source of truth for full schemas, enums and limits.

| Field | Purpose |
| - | - |
| `assetId` | The asset to transact with, such as `ETH_TEST5` for Ethereum Sepolia. |
| `amount` | The amount to transfer, as a numeric string in the asset's unit. |
| `source` | The peer that funds the transaction, such as a vault account. |
| `destination` or `destinations` | The peer that receives the funds, or a list of recipients on UTXO blockchains. |
| `operation` | The transaction type, which defaults to `TRANSFER`. |
| `note` | A custom note that describes the transaction in your workspace and is not sent to the blockchain. |
| `externalTxId` | A unique ID of your own that Fireblocks uses to reject duplicate transactions. |
| `extraParameters` | Additional data for specific operations, such as contract call data or the message to sign. |

The valid source and destination peer types for each operation are listed in [Sources and destinations](/reference/transaction-sources-destinations), and the shape of the response is described in [Transaction objects](/reference/transaction-objects).

## Choose an interface

You can create transactions with the Fireblocks SDKs, directly through the REST API or from the command line, and every guide in this section shows all three.

* **SDK:** Install the [TypeScript](/reference/typescript-sdk), [Python](/reference/new-python-sdk) or [Java](/reference/java-sdk) SDK. If you use an older SDK, see the [SDK migration guide](/reference/sdk-migration-guide).
* **API:** Send a signed request to `POST /v1/transactions`, as described in [Signing a request](/reference/signing-a-request-jwt-structure).
* **CLI:** Install the [Fireblocks CLI](/docs/fireblocks-cli) and run `fireblocks transactions create-transaction`.

### Set up your client

Every example in this section assumes you have already set up credentials for your chosen interface. Each option below reads your API key from the `FIREBLOCKS_API_KEY` environment variable and your private key from the file at `FIREBLOCKS_SECRET_KEY_PATH`, so no credentials appear in your code or shell history.

<Tabs>
  <Tab title="SDK">
    The SDK examples assume an initialized `fireblocks` client. Use `BasePath.Sandbox` to work against a sandbox workspace.

    <CodeGroup>
      ```typescript TypeScript theme={"system"}
      import { readFileSync } from "fs";
      import { Fireblocks, BasePath } from "@fireblocks/ts-sdk";

      const fireblocks = new Fireblocks({
        apiKey: process.env.FIREBLOCKS_API_KEY,
        secretKey: readFileSync(process.env.FIREBLOCKS_SECRET_KEY_PATH!, "utf8"),
        basePath: BasePath.US, // Conditional - Required unless FIREBLOCKS_BASE_PATH is set. Also BasePath.Sandbox, BasePath.EU, BasePath.EU2
      });
      ```

      ```python Python theme={"system"}
      import os
      from fireblocks.client import Fireblocks
      from fireblocks.client_configuration import ClientConfiguration
      from fireblocks.base_path import BasePath

      with open(os.environ["FIREBLOCKS_SECRET_KEY_PATH"], "r") as f:
          secret_key = f.read()

      configuration = ClientConfiguration(
          api_key=os.environ["FIREBLOCKS_API_KEY"],
          secret_key=secret_key,
          base_path=BasePath.US,  # Conditional - Required unless FIREBLOCKS_BASE_PATH is set. Also BasePath.Sandbox, BasePath.EU, BasePath.EU2
      )

      # The client is a context manager; make the calls below inside this block
      with Fireblocks(configuration) as fireblocks:
          ...
      ```

      ```java Java theme={"system"}
      import com.fireblocks.sdk.BasePath;
      import com.fireblocks.sdk.ConfigurationOptions;
      import com.fireblocks.sdk.Fireblocks;
      import java.nio.file.Files;
      import java.nio.file.Paths;

      String secretKey = Files.readString(Paths.get(System.getenv("FIREBLOCKS_SECRET_KEY_PATH")));

      ConfigurationOptions configurationOptions = new ConfigurationOptions()
          .basePath(BasePath.US) // Conditional - Required unless FIREBLOCKS_BASE_PATH is set. Also BasePath.Sandbox, BasePath.EU, BasePath.EU2
          .apiKey(System.getenv("FIREBLOCKS_API_KEY"))
          .secretKey(secretKey);
      Fireblocks fireblocks = new Fireblocks(configurationOptions);
      ```
    </CodeGroup>
  </Tab>

  <Tab title="API">
    Send requests to the base URL for your workspace:

    | Workspace | Base URL |
    | - | - |
    | US mainnet or testnet | `https://api.fireblocks.io/v1` |
    | US sandbox | `https://sandbox-api.fireblocks.io/v1` |
    | EU mainnet or testnet | `https://eu-api.fireblocks.io/v1` |
    | EU2 mainnet or testnet | `https://eu2-api.fireblocks.io/v1` |

    Every request carries 2 authentication headers. `X-API-Key` holds your API key, and `Authorization` holds a JWT that you sign with your API private key for that specific request.

    ```http theme={"system"}
    POST /v1/transactions
    Host: api.fireblocks.io
    X-API-Key: <FIREBLOCKS_API_KEY>
    Authorization: Bearer <SIGNED_JWT>
    Content-Type: application/json
    ```

    The JWT is unique to each request because it includes the request path and a hash of the request body. See [Signing a request](/reference/signing-a-request-jwt-structure) for the claims it must contain and how to sign it.
  </Tab>

  <Tab title="CLI">
    [Install the Fireblocks CLI](/docs/fireblocks-cli#installation), then provide credentials either through environment variables or through a saved profile.

    ```bash theme={"system"}
    # Option 1: environment variables, suited to CI and scripts
    export FIREBLOCKS_API_KEY="<YOUR_API_KEY>"
    export FIREBLOCKS_SECRET_KEY_PATH="/path/to/fireblocks_secret.key"
    export FIREBLOCKS_BASE_URL="https://sandbox-api.fireblocks.io" # Optional - Defaults to https://api.fireblocks.io

    # Option 2: an interactive profile saved to ~/.config/fireblocks/config.json
    fireblocks configure

    # Confirm the credentials work
    fireblocks whoami
    ```

    See [CLI authentication](/docs/cli-authentication) for credential resolution order and named profiles.
  </Tab>
</Tabs>

## Your first transaction

The following example sends 0.001 ETH on the Sepolia testnet from one vault account to another, which is the simplest transaction you can create.

<Tabs>
  <Tab title="SDK">
    <CodeGroup>
      ```typescript TypeScript theme={"system"}
      import { TransferPeerPathType } from "@fireblocks/ts-sdk";

      const response = await fireblocks.transactions.createTransaction({
        transactionRequest: {
          assetId: "ETH_TEST5",
          amount: "0.001",
          source: {
            type: TransferPeerPathType.VaultAccount,
            id: "<SOURCE_VAULT_ACCOUNT_ID>",
          },
          destination: {
            type: TransferPeerPathType.VaultAccount,
            id: "<DESTINATION_VAULT_ACCOUNT_ID>",
          },
          note: "First transfer", // Optional - Free-text note shown in your workspace, not sent to the blockchain
          externalTxId: "<YOUR_UNIQUE_ID>", // Optional - Your unique ID; Fireblocks rejects later requests with the same value
        },
      });
      console.log(response.data);
      ```

      ```python Python theme={"system"}
      from fireblocks.models.transaction_request import TransactionRequest
      from fireblocks.models.source_transfer_peer_path import SourceTransferPeerPath
      from fireblocks.models.destination_transfer_peer_path import DestinationTransferPeerPath
      from fireblocks.models.transfer_peer_path_type import TransferPeerPathType
      from fireblocks.models.transaction_request_amount import TransactionRequestAmount

      transaction_request = TransactionRequest(
          asset_id="ETH_TEST5",
          amount=TransactionRequestAmount("0.001"),
          source=SourceTransferPeerPath(
              type=TransferPeerPathType.VAULT_ACCOUNT,
              id="<SOURCE_VAULT_ACCOUNT_ID>",
          ),
          destination=DestinationTransferPeerPath(
              type=TransferPeerPathType.VAULT_ACCOUNT,
              id="<DESTINATION_VAULT_ACCOUNT_ID>",
          ),
          note="First transfer",  # Optional - Free-text note shown in your workspace, not sent to the blockchain
          external_tx_id="<YOUR_UNIQUE_ID>",  # Optional - Your unique ID; Fireblocks rejects later requests with the same value
      )

      future = fireblocks.transactions.create_transaction(
          transaction_request=transaction_request,
      )
      print(future.result().data)  # create_transaction returns a Future
      ```

      ```java Java theme={"system"}
      import com.fireblocks.sdk.model.*;

      TransactionRequest transactionRequest = new TransactionRequest()
          .assetId("ETH_TEST5")
          .amount(new TransactionRequestAmount("0.001"))
          .source(new SourceTransferPeerPath()
              .type(TransferPeerPathType.VAULT_ACCOUNT)
              .id("<SOURCE_VAULT_ACCOUNT_ID>"))
          .destination(new DestinationTransferPeerPath()
              .type(TransferPeerPathType.VAULT_ACCOUNT)
              .id("<DESTINATION_VAULT_ACCOUNT_ID>"))
          .note("First transfer") // Optional - Free-text note shown in your workspace, not sent to the blockchain
          .externalTxId("<YOUR_UNIQUE_ID>"); // Optional - Your unique ID; Fireblocks rejects later requests with the same value

      CreateTransactionResponse transaction = fireblocks.transactions()
          .createTransaction(
              transactionRequest,
              null, // Optional - xEndUserWalletId (UUID), only for end-user wallet operations
              null) // Optional - Not used for transactions; use externalTxId in the request body
          .get()
          .getData();
      System.out.println(transaction);
      ```
    </CodeGroup>
  </Tab>

  <Tab title="API">
    ```http theme={"system"}
    POST /v1/transactions
    ```

    ```json theme={"system"}
    {
      "assetId": "ETH_TEST5",
      "amount": "0.001",
      "source": { "type": "VAULT_ACCOUNT", "id": "<SOURCE_VAULT_ACCOUNT_ID>" },
      "destination": { "type": "VAULT_ACCOUNT", "id": "<DESTINATION_VAULT_ACCOUNT_ID>" },
      "note": "First transfer",
      "externalTxId": "<YOUR_UNIQUE_ID>"
    }
    ```

    Sign the request with a JWT; see [Signing a request](/reference/signing-a-request-jwt-structure).
  </Tab>

  <Tab title="CLI">
    ```bash theme={"system"}
    # Preview the request without sending it
    fireblocks transactions create-transaction \
      --data '{"assetId":"ETH_TEST5","amount":"0.001","source":{"type":"VAULT_ACCOUNT","id":"<SOURCE_VAULT_ACCOUNT_ID>"},"destination":{"type":"VAULT_ACCOUNT","id":"<DESTINATION_VAULT_ACCOUNT_ID>"},"externalTxId":"<YOUR_UNIQUE_ID>"}' \
      --dry-run

    # Execute
    fireblocks transactions create-transaction \
      --data '{"assetId":"ETH_TEST5","amount":"0.001","source":{"type":"VAULT_ACCOUNT","id":"<SOURCE_VAULT_ACCOUNT_ID>"},"destination":{"type":"VAULT_ACCOUNT","id":"<DESTINATION_VAULT_ACCOUNT_ID>"},"externalTxId":"<YOUR_UNIQUE_ID>"}' \
      --no-confirm
    ```
  </Tab>
</Tabs>

To send to a one-time address, an allowlisted wallet, an exchange account or several recipients at once, continue with [Transfers](/transactions/transfers).

## After you submit

A successful request returns the new transaction's ID and its initial status, and the transaction then moves through the approval, signing and blockchain confirmation stages on its own. Fireblocks recommends subscribing to [webhooks](/reference/webhooks-overview) to learn about status changes as they happen instead of polling the API, and you can read about the available statuses in [Transaction statuses](/reference/statuses) and about both approaches in [Monitoring transaction status](/reference/monitoring-transaction-status).

## Secure and scale transaction creation

The sections below cover the practices that matter once you move from a first test transaction to a production integration.

### Make requests idempotent

Network errors and timeouts can leave you unsure whether a request was processed, and retrying blindly risks sending the same transaction twice. To prevent that, include a unique `externalTxId` in the body of every transaction request, and Fireblocks rejects any later transaction request that reuses the same value. If a request fails with a network error, you can look the transaction up with [Get a transaction by external ID](/api-reference/transactions/get-a-specific-transaction-by-external-transaction-id) to check whether the earlier attempt went through before you decide to resend it. See [Transaction idempotency](/reference/api-idempotency#transaction-idempotency) for details. Do not use the `Idempotency-Key` request header to create transactions, because it is meant for [other endpoints](/reference/api-idempotency#idempotency-key).

### Control what can be sent

The [Transaction Authorization Policy](/reference/configure-transaction-authorization-policy) decides which transactions are approved, which need extra approvals and which are blocked, and it applies to transactions created through the API in the same way as those created in the console. Sending to [allowlisted destinations](/docs/whitelist-addresses) lets the policy restrict transfers to addresses you have already vetted, whereas one-time addresses let a transaction reach any address and are best governed by a stricter rule. If your workspace needs Travel Rule data on transfers, see the [Travel Rule overview](/docs/travel-rule-overview).

### Automate signing

To approve and sign transactions without manual steps, use an API Co-signer. Start with the [Co-signer architecture overview](/cosigners/overview/cosigner-architecture-overview), run more than one Co-signer for resilience as described in [multiple Co-signers for high availability](/cosigners/operations/multiple-cosigners-high-availability), and use a [callback handler](/cosigners/callback-handler/create-api-co-signer-callback-handler) to apply your own approval logic to each transaction.

### Scale throughput

High transaction volumes on a single vault account can queue up behind each other, so [Wallet Pools](/docs/wallet-pools) let you spread transactions across several vault accounts and use a `WALLET_POOL` as the source of a transfer. For sizing guidance and blockchain-specific recommendations, see [Manage withdrawals at scale](/docs/manage-withdrawals-at-scale). On UTXO blockchains you can reduce the number of transactions by sending to [multiple destinations](/transactions/transfers#send-to-multiple-destinations) in one request and by [consolidating UTXOs](/reference/consolidate-utxos) during quiet periods. On EVM blockchains, the [Gas Station](/docs/work-with-gas-station) keeps your vault accounts fueled and can use a Wallet Pool as its tank to avoid a single nonce stream becoming a bottleneck.

### Handle fees and stuck transactions

Set the fee with the `feeLevel` field or with explicit fee parameters, and use [fee estimation](/reference/estimate-transaction-fee) to see the current cost before you submit. If a transaction stays unconfirmed, you can [boost or replace it](/docs/boost-transactions), and [Account Traffic Control](https://support.fireblocks.io/hc/en-us/articles/27129539023004-Account-Traffic-Control) and [transaction timeouts](https://support.fireblocks.io/hc/en-us/articles/27174908726044-Transaction-Timeout-Configuration) help you detect and clear queues. Account Traffic Control sends a `transaction.alert.stuck` webhook when a transaction is stuck, and you can find more guidance in [Manage withdrawals at scale](/docs/manage-withdrawals-at-scale).

### Stay within rate limits

The API limits how many requests you can send in a given period, so design batch jobs and retries with that in mind. See [Rate limiting](/reference/rate-limiting) for the current limits and how to handle throttled responses.

## Explore transaction types

The table below lists the values of the `operation` field that most integrations use, grouped by what you want to do, and the [API reference](/api-reference/transactions/create-a-new-transaction) has the full list. Operations with their own guide include request examples for the SDK, the API and the CLI, and the rest link to the best existing reference.

| Goal | Operation | What it does | Guide |
| - | - | - | - |
| Move assets | `TRANSFER` | Moves funds from a source to one or more destinations. This is the default operation. | [Transfers](/transactions/transfers) |
| Call on-chain code | `CONTRACT_CALL` | Calls a smart contract method on an EVM blockchain. | [Contract calls](/transactions/contract-calls) |
| | `PROGRAM_CALL` | Runs Solana program instructions. | [Solana program calls](/transactions/solana-program-calls) |
| Sign off-chain | `TYPED_MESSAGE` | Signs a readable off-chain message in Ethereum Personal Message or EIP-712 format, or the equivalent formats on Tron and Bitcoin. | [Typed messages](/transactions/typed-messages) |
| | `RAW` | Signs arbitrary message data, including for protocols that Fireblocks does not support natively. | [Raw signing](/transactions/raw-signing) |
| Manage token supply and allowances | `MINT` | Increases the supply of a token on Stellar, Ripple and EVM-based blockchains. | [API reference](/api-reference/transactions/create-a-new-transaction) |
| | `BURN` | Reduces the supply of a token on Stellar, Ripple and EVM-based blockchains. | [API reference](/api-reference/transactions/create-a-new-transaction) |
| | `APPROVE` | Calls a token's approve function so that another address can spend tokens on behalf of the signer. | [Transaction webhook reference](/reference/webhooks-structures-eventtypes-transaction) |
| Set up an asset | `ENABLE_ASSET` | Creates the on-chain asset wallet that Algorand, DigitalBits, Solana and Stellar require before an address can receive deposits. Fireblocks creates this transaction automatically when you add one of these assets to a vault account. | [Transaction webhook reference](/reference/webhooks-structures-eventtypes-transaction) |

<Note>
  If you issued your token with ERC-20F or another Fireblocks-deployed EVM token template, mint and burn it through the [ERC-20F operational guide](/reference/operational-guide-for-erc20f-token), which calls the token contract directly rather than using the `MINT` or `BURN` operation.
</Note>

Transactions that you read back or receive in webhooks can also carry operations that you do not create with this endpoint, such as `STAKE` for staking activity. See [Staking](/reference/staking-overview) for how those transactions are created.
