Creating a Transaction

Prerequisites

Overview

Every transaction on the Fireblocks platform is initiated using the Create a new transaction API call. Its default operation type is TRANSFER, however, other important operations are available as valid values for the operation body parameter.

See all operation valid values.

The main available transaction operations are:

  • TRANSFER: transfer an asset from one source to one destination
  • CONTRACT_CALL: Directly invoke a smart contract
  • RAW: Sign arbitrary data using the Raw Signing API
  • MINT: Perform a mint operation (increase supply) on a supported token
  • BURN: Perform a burn operation (reduce supply) on a supported token
  • TYPED_MESSAGE: allows users to sign messages, but only using specific standard formats that prefix the message with a magic string, such as Ethereum personal messages, and (EIP712 typed structured data) type structured data

The API call serves all possible source and destination combinations including a one-time address destination (OTA), vault account, pre-whitelisted internal wallet, external wallet & contract wallet, Fireblocks Network connections and any connected exchange account and fiat account.

📘

Note:

Although there are required parameters for the Create a new transaction API call, you can pass other optional body parameters depending on the asset or the required operation.

The endpoint also accepts the addition of the extraParameters object, used to describe additional details required for raw message signing, contract calls, and specific UTXO selections.

Learn how the extraParameters object works in transaction responses.

Your first transaction

Vault account to vault account transaction

To start, initiate a transaction from one Fireblocks vault account to another. Account-based assets allow single-destination transfer and UTXO assets allow multi-destination transfer.

Single destination transfer (ETH)

The example transfers 0.001 amount of ETH from vault account ID 0 to vault account ID 1.

const transactionPayload = {
  assetId: "ETH",
  amount: "0.001",
  source: {
    type: TransferPeerPathType.VaultAccount,
    id: "0",
  },
  destination: {
    type: TransferPeerPathType.VaultAccount,
    id: "1",
  },
  note: "Your first transaction!",
};

const createTransaction = async (
  transactionPayload: TransactionRequest,
): Promise<CreateTransactionResponse | undefined> => {
  try {
    const transactionResponse = await fireblocks.transactions.createTransaction(
      {
        transactionRequest: transactionPayload,
      },
    );
    console.log(JSON.stringify(transactionResponse.data, null, 2));
    return transactionResponse.data;
  } catch (error) {
    console.error(error);
  }
};

createTransaction(transactionPayload);

async function createTransaction(assetId, amount, srcId, destId){ 
    let payload = {
        assetId,
        amount,
        source: {
            type: PeerType.VAULT_ACCOUNT,
            id: String(srcId)
        },
        destination: {
            type: PeerType.VAULT_ACCOUNT,
            id: String(destId)
        },
        note: "Your first transaction!"
    };
    const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1");
def create_transaction(asset_id, amount, src_id, dest_id):
   tx_result = fireblocks.create_transaction(
       asset_id=asset_id,
       amount=amount,
       source=TransferPeerPath(VAULT_ACCOUNT, src_id),
       destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
       note="Your first transaction!"
   )
   print(tx_result)

create_transaction("ETH", "0.001", "0", "1")

Multiple destinations transfer

Transfer 0.001 BTC from the first vault account ("1"), by sending 0.0005 BTC to the second vault account (using id: "2") and 0.0005 BTC to the third vault account (id: "3") as destinations.

const transactionPayload = {
  assetId: "BTC",
  amount: "0.001",
  source: {
    type: TransferPeerPathType.VaultAccount,
    id: "1",
  },
  destinations: [
    {
      amount: "0.0005",
      destination: {
        type: TransferPeerPathType.VaultAccount,
        id: "2",
      },
    },
    {
      amount: "0.0005",
      destination: {
        type: TransferPeerPathType.VaultAccount,
        id: "3",
      },
    },
  ],
  note: "Your first multiple destination transaction!",
};

const createTransaction = async (
  transactionPayload: TransactionRequest,
): Promise<CreateTransactionResponse | undefined> => {
  try {
    const transactionResponse = await fireblocks.transactions.createTransaction(
      {
        transactionRequest: transactionPayload,
      },
    );
    console.log(JSON.stringify(transactionResponse.data, null, 2));
    return transactionResponse.data;
  } catch (error) {
    console.error(error);
  }
};
createTransaction(transactionPayload);

async function createTransaction(assetId, amount, srcId){
    let payload = {
        assetId,
        amount,
        source: {
            type: PeerType.VAULT_ACCOUNT, 
            id: String(srcId)
        },
        destinations: [
            {amount: "0.0005", destination: {type: PeerType.VAULT_ACCOUNT, id: "2"}},
            {amount: "0.0005", destination: {type: PeerType.VAULT_ACCOUNT, id: "3"}}
        ],
        note: "Your first multiple destination transaction!"
    };
    const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "1");
def create_transaction(asset_id, amount, src_id):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destinations=[
            TransactionDestination("0.0005", DestinationTransferPeerPath(VAULT_ACCOUNT, "2")),
            TransactionDestination("0.0005", DestinationTransferPeerPath(VAULT_ACCOUNT, "3"))

        ],
        note="Your first multiple destination transaction!"
    )
    print(tx_result)

create_transaction("BTC", "0.001", "1")

Vault account to one-time address transaction

Transfer 0.01 ETH between the vault account ("1") to a specific one-time blockchain address.

const transactionPayload = {
  assetId: "ETH",
  amount: "0.001",
  source: {
    type: TransferPeerPathType.VaultAccount,
    id: "1",
  },
  destination: {
    type: TransferPeerPathType.OneTimeAddress,
    oneTimeAddress: {
      address: "0x13277a70e3F48EEAD9C8a8bab12EbEDbC3DB6446",
    },
  },
  note: "Your first OTA transaction!",
};

const createTransaction = async (
  transactionPayload: TransactionRequest,
): Promise<CreateTransactionResponse | undefined> => {
  try {
    const transactionResponse = await fireblocks.transactions.createTransaction(
      {
        transactionRequest: transactionPayload,
      },
    );
    console.log(JSON.stringify(transactionResponse.data, null, 2));
    return transactionResponse.data;
  } catch (error) {
    console.error(error);
  }
};
createTransaction(transactionPayload);

async function createTransaction(assetId, amount, srcId, address){
    let payload = {
        assetId,
        amount,
        source: {
            type: PeerType.VAULT_ACCOUNT, 
            id: String(srcId)
        },
        destination: {
            type: PeerType.ONE_TIME_ADDRESS,
            oneTimeAddress: {
                address: String(address)
            }
        },
        note: "Your first OTA transaction!"
    };
   const result = await fireblocks.createTransaction(payload);
   console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "1", "0x13277a70e3F48EEAD9C8a8bab12EbEDbC3DB6446");
def create_transaction(asset_id, amount, src_id, address):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destination=DestinationTransferPeerPath(ONE_TIME_ADDRESS, None, {"address": address}),
        note="Your first OTA transaction!"
    )
    print(tx_result)
	
create_transaction("ETH", "0.001", "1", "0x13277a70e3F48EEAD9C8a8bab12EbEDbC3DB6446")

API idempotency best practice

Fireblocks supports API idempotency in the submission of requests. It is important to ensure a request will not be processed twice via the API Gateway, avoiding replay attacks, double-spending issues, or other transaction errors.

The best practice for creating transactions is to use the externalTxId parameter as seen in the Optional parameters section.

📘

API idempotency for POST requests

Use the idempotency key for the additonal POST requests such as Creating a new asset deposit address or Creating a new vault account.

Learn more about API Idempotency.


Optional parameters

Some blockchains have different technicalities when building transactions, handled using optional parameters.

externalTxId

The critical practice to avoid multiple identical POST transaction requests being processed more than once is to use the externalTxId parameter in the Create a new transaction API call.

The externalTxId value is the internal identifier of the transaction you will have on your end.

This value is securely stored in the Fireblocks system and additional transaction requests with the same externalTxId value will not be processed on our system.

const transactionPayload = {
  assetId: "ETH",
  amount: "0.001",
  externalTxId: "UniqueIdentifier", // the unique identifier of the transaction outside of Fireblocks
  source: {
    type: TransferPeerPathType.VaultAccount,
    id: "0",
  },
  destination: {
    type: TransferPeerPathType.VaultAccount,
    id: "1",
  },
  note: "Your first transaction!",
};

const createTransaction = async (
  transactionPayload: TransactionRequest,
): Promise<CreateTransactionResponse | undefined> => {
  try {
    const transactionResponse = await fireblocks.transactions.createTransaction(
      {
        transactionRequest: transactionPayload,
      },
    );
    console.log(JSON.stringify(transactionResponse.data, null, 2));
    return transactionResponse.data;
  } catch (error) {
    console.error(error);
  }
};
createTransaction(transactionPayload);

async function createTransaction(assetId, amount, srcId, destId, externalTxId){
    let payload = {
        assetId,
        amount,
        externalTxId, // the unique identifier of the transaction outside of Fireblocks
        source: {
            type: PeerType.VAULT_ACCOUNT, 
         		id: String(srcId)
        },
        destination: {
            type: PeerType.VAULT_ACCOUNT, 
        		id: String(destId)
        },
        note: "Your first transaction identified by an external ID"
    };
		const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1", "uniqueTXid");
def create_transaction(asset_id, amount, src_id, dest_id, external_tx_id):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        external_tx_id=external_tx_id, # the unique identifier of the transaction outside of Fireblocks
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
        note="Your first transaction identified by an external ID"
    )
    print(tx_result)

create_transaction("ETH", "0.001", "0", "1", "uniqueTXid")

treatAsGrossAmount

The value isfalse by default. If it is set to true, the network fee will be deducted from the requested amount.

const transactionPayload = {
	assetId: "ETH",
	amount: "0.001",
	treatAsGrossAmount: true, // true or false (by default - false)
	source: {
		type: TransferPeerPathType.VaultAccount,
		id: "0",
	},
	destination: {
		type: TransferPeerPathType.VaultAccount,
		id: "1",
	},
	note: "Your first treat as gross transaction!"
}

const createTransaction = async (
	transactionPayload:TransactionRequest
):Promise<CreateTransactionResponse | undefined > => {
	try {
		const transactionResponse = await fireblocks.transactions.createTransaction(
			{
				transactionRequest:transactionPayload
			}
		);
		console.log(JSON.stringify(transactionResponse.data, null, 2));
		return transactionResponse.data;
	}
	catch(error){
		console.error(error);
	}
}
createTransaction(transactionPayload);
async function createTransaction(assetId, amount, srcId, destId){
    let payload = {
       assetId,
       amount,
       treatAsGrossAmount: true, // true / false (by default)
       source: {
           type: PeerType.VAULT_ACCOUNT,
           id: String(srcId)
       },
       destination: {
           type: PeerType.VAULT_ACCOUNT, 
           id: String(destId)
       },
       note: "Your first treat as gross transaction!"
    };
    const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1");
def create_transaction(asset_id, amount, src_id, dest_id):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        treat_as_gross_amount=True, # true / false (by default)
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
     note: "Your first treat as gross transaction!"
    )
    print(tx_result)

create_transaction("ETH", "0.001", "0", "1")

fee

For UTXO-based assets, fee refers to the fee per byte in the asset's smallest unit (Satoshi, Latoshi, etc).

const transactionPayload = {
	assetId: "BTC",
	amount: "0.001",
	fee: "15", // Satoshi per Byte
	source: {
		type: TransferPeerPathType.VaultAccount,
		id: "0",
	},
	destination: {
		type: TransferPeerPathType.VaultAccount,
		id: "1",
	},
	note: "Your first high fee transaction!"
}

const createTransaction = async (
	transactionPayload:TransactionRequest
):Promise<CreateTransactionResponse | undefined > => {
	try {
		const transactionResponse = await fireblocks.transactions.createTransaction(
			{
				transactionRequest:transactionPayload
			}
		);
		console.log(JSON.stringify(transactionResponse.data, null, 2));
		return transactionResponse.data;
	}
	catch(error){
		console.error(error);
	}
}
createTransaction(transactionPayload);
async function createTransaction(assetId, amount, srcId, destId, fee){
    let payload = {
        assetId,
        amount,
        fee, //Satoshi per Byte
        source: {
            type: PeerType.VAULT_ACCOUNT, 
         		id: String(srcId)
        },
        destination: {
            type: PeerType.VAULT_ACCOUNT, 
        		id: String(destId)
        },
        note: "Your first high fee transaction!"
    };
    const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "0", "1", "15");
def create_transaction(asset_id, amount, src_id, dest_id, fee):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        fee=fee, #Satoshi per Byte
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
        note="Your first high fee transaction!"
    )
    print(tx_result)

create_transaction("ETH", "0.001", "0", "1", "15")

feeLevel

Defines the blockchain fee level which will be paid for the transaction (only for Ethereum and UTXO-based blockchains). Set to MEDIUM by default. Valid values are LOW MEDIUM & HIGH.

const transactionPayload = {
  assetId: "ETH",
  amount: "0.001",
  feeLevel: TransactionRequestFeeLevelEnum.High, // Low / Medium / High
  source: {
    type: TransferPeerPathType.VaultAccount,
    id: "0",
  },
  destination: {
    type: TransferPeerPathType.VaultAccount,
    id: "1",
  },
  note: "Your first high fee level transaction!",
};

const createTransaction = async (
  transactionPayload: TransactionRequest,
): Promise<CreateTransactionResponse | undefined> => {
  try {
    const transactionResponse = await fireblocks.transactions.createTransaction(
      {
        transactionRequest: transactionPayload,
      },
    );
    console.log(JSON.stringify(transactionResponse.data, null, 2));
    return transactionResponse.data;
  } catch (error) {
    console.error(error);
  }
};
createTransaction(transactionPayload);
async function createTransaction(assetId, amount, srcId, destId, feeLevel){
    let payload = {
        assetId,
        amount,
        feeLevel, // LOW / MEDIUM / HIGH  
        source: {
            type: PeerType.VAULT_ACCOUNT, 
         		id: String(srcId)
        },
        destination: {
            type: PeerType.VAULT_ACCOUNT, 
        		id: String(destId)
        },
        note: "Your first high fee level transaction!"
    };
    const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "0", "1", "HIGH");
def create_transaction(asset_id, amount, src_id, dest_id, fee_level):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        fee_level=fee_level, # LOW / MEDIUM / HIGH
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
        note="Your first high fee level transaction!"
    )
    print(tx_result)

create_transaction("BTC", "0.001", "0", "1", "HIGH")

failOnLowFee

Set tofalse by default. If set to true, and the feeLevel (value: MEDIUM) is higher than the acceptable amount specified in the transaction, the transaction will fail, to avoid getting stuck with 0 confirmations.

const transactionPayload = {
  assetId: "ETH",
  amount: "0.001",
  failOnLowFee: true, // true / false (default - false)
  source: {
    type: TransferPeerPathType.VaultAccount,
    id: "0",
  },
  destination: {
    type: TransferPeerPathType.VaultAccount,
    id: "1",
  },
  note: "Your first failOnLowFee transaction",
};

const createTransaction = async (
  transactionPayload: TransactionRequest,
): Promise<CreateTransactionResponse | undefined> => {
  try {
    const transactionResponse = await fireblocks.transactions.createTransaction(
      {
        transactionRequest: transactionPayload,
      },
    );
    console.log(JSON.stringify(transactionResponse.data, null, 2));
    return transactionResponse.data;
  } catch (error) {
    console.error(error);
  }
};
createTransaction(transactionPayload);
async function createTransaction(assetId, amount, srcId, destId, failOnLowFee){
    let payload = {
        assetId,
        amount,
        failOnLowFee, // true / false (default)
        source: {
            type: PeerType.VAULT_ACCOUNT, 
         		id: String(srcId)
        },
        destination: {
            type: PeerType.VAULT_ACCOUNT, 
        		id: String(destId)
        },
        note: "Your first failOnLowFee transaction"
    };
    const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("BTC", "0.001", "0", "1", true);
def create_transaction(asset_id, amount, src_id, dest_id, fail_on_low_fee):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        fail_on_low_fee=fail_on_low_fee, # True / False (by default)
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
        note="Your first failOnLowFee transaction"
    )
    print(tx_result)

create_transaction("BTC", "0.001", "0", "1", True)

replaceTxByHash

For Ethereum blockchain transactions, the replaceTxByHash parameter is the hash of the stuck transaction that needs to be replaced.

const transactionPayload = {
  assetId: "ETH",
  amount: "0.001",
	replaceTxByHash, // the hash of the transaction you wish to be replaced
  source: {
    type: TransferPeerPathType.VaultAccount,
    id: "0",
  },
  destination: {
    type: TransferPeerPathType.VaultAccount,
    id: "1",
  },
  note: "Your first failOnLowFee transaction",
};

const createTransaction = async (
  transactionPayload: TransactionRequest,
): Promise<CreateTransactionResponse | undefined> => {
  try {
    const transactionResponse = await fireblocks.transactions.createTransaction(
      {
        transactionRequest: transactionPayload,
      },
    );
    console.log(JSON.stringify(transactionResponse.data, null, 2));
    return transactionResponse.data;
  } catch (error) {
    console.error(error);
  }
};
createTransaction(transactionPayload);
async function createTransaction(assetId, amount, srcId, destId, replaceTxByHash){
    let payload = {
        assetId,
        amount,
        replaceTxByHash, // the hash of the transaction you wish to be replaced
        source: {
            type: PeerType.VAULT_ACCOUNT, 
         		id: String(srcId)
        },
        destination: {
            type: PeerType.VAULT_ACCOUNT, 
        		id: String(destId)
        },
        note: "Your first fee replacement transaction"
    };
    const result = await fireblocks.createTransaction(payload);
    console.log(JSON.stringify(result, null, 2));
}
createTransaction("ETH", "0.001", "0", "1", "0x5e0ce0b1242d1c85c17fc5127daa88e9eb842650e3e6a9a6de7c1bd9c3977cc2");
def create_transaction(asset_id, amount, src_id, dest_id, replace_tx_by_hash):
    tx_result = fireblocks.create_transaction(
        asset_id=asset_id,
        amount=amount,
        replace_tx_by_hash=replace_tx_by_hash, # the hash of the transaction you wish to be replaced
        source=TransferPeerPath(VAULT_ACCOUNT, src_id),
        destination=DestinationTransferPeerPath(VAULT_ACCOUNT, dest_id),
        note="Your first fee replacement transaction"
    )
    print(tx_result)

create_transaction("ETH", "0.001", "0", "1", "0x5e0ce0b1242d1c85c17fc5127daa88e9eb842650e3e6a9a6de7c1bd9c3977cc2")