Api

Client API

On-chain transaction creation, signing, and broadcasting

The Client API exposes Hydra App's ClientService — on-chain transaction creation, signing, and broadcasting for native assets, tokens, fee bumps, and token allowances.

JSON-RPC namespace: client

The service exposes two parallel flows:

  • Build → sign → finalizeCreate*Transaction returns an unsigned TransactionRequest. Sign it with signer.SignTransaction, then submit with FinalizeAndBroadcastTransaction. Use this when you want to inspect the transaction or use an external signer.
  • One-shot sendSendTransaction, SendTokenTransaction, BumpTransaction, SetTokenAllowance build, sign, and broadcast in a single call.

Looking for GetDepositAddress? That moved to the Wallet API.

Endpoints

Build → sign → finalize

One-shot


Create Send Transaction

Builds an unsigned native asset send transaction. Returns a generic TransactionRequest that can be inspected, signed via signer.SignTransaction, and then submitted via FinalizeAndBroadcastTransaction.

Method: CreateSendTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network
tostringYESRecipient address
amountAmountYESAmount to send (exact or all-available)
fee_optionFeeOptionYESFee selection

Response:

FieldTypeDescription
transaction_requestTransactionRequestUnsigned transaction request

Example Request:

import { CreateSendTransactionRequest } from './proto/client_pb'

const request = new CreateSendTransactionRequest()
request.setNetwork({ protocol: 1, id: '0a03cf40' })
request.setTo('bc1qrecipient...')
request.setAmount({ exact: { value: '0.01' } })
request.setFeeOption({ /* see Fee API for options */ })

const response = await client.createSendTransaction(request, {})
const txRequest = response.getTransactionRequest()
// → pass txRequest to signer.SignTransaction

Create Bump Transaction

Builds an unsigned fee-bump (RBF / speed-up) transaction request for an existing unconfirmed transaction.

Method: CreateBumpTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network
txidstringYESTransaction ID to replace
fee_optionFeeOptionYESNew (higher) fee option

Response:

FieldTypeDescription
transaction_requestTransactionRequestUnsigned bump transaction

Example Request:

import { CreateBumpTransactionRequest } from './proto/client_pb'

const request = new CreateBumpTransactionRequest()
request.setNetwork({ protocol: 1, id: '0a03cf40' })
request.setTxid('abc123...')
request.setFeeOption({ /* higher fee */ })

const response = await client.createBumpTransaction(request, {})
const txRequest = response.getTransactionRequest()

Create Token Send Transaction

Builds an unsigned ERC-20 / token transfer transaction. For native asset transfers use Create Send Transaction.

Method: CreateTokenSendTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network (must support tokens, e.g. EVM)
tostringYESRecipient address
token_idstringYESToken contract address / identifier
amountAmountYESAmount of tokens
fee_optionFeeOptionYESFee selection

Response:

FieldTypeDescription
transaction_requestTransactionRequestUnsigned token transfer transaction

Example Request:

import { CreateTokenSendTransactionRequest } from './proto/client_pb'

const request = new CreateTokenSendTransactionRequest()
request.setNetwork({ protocol: 2, id: '11155111' })
request.setTo('0xrecipient...')
request.setTokenId('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48') // USDC
request.setAmount({ exact: { value: '100' } })
request.setFeeOption({ /* ... */ })

const response = await client.createTokenSendTransaction(request, {})
const txRequest = response.getTransactionRequest()

Create Set Token Allowance Transaction

Builds an unsigned token allowance approval transaction. Supports ERC-20, ERC-721, and ERC-1155.

Method: CreateSetTokenAllowanceTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network (must support tokens, e.g. EVM)
spenderstringYESSpender address to approve
allowanceSetTokenAllowanceYESToken type, amount, and approval status
fee_optionFeeOptionYESFee selection

Response:

FieldTypeDescription
transaction_requestTransactionRequestUnsigned allowance approval transaction

Example Request:

import { CreateSetTokenAllowanceTransactionRequest } from './proto/client_pb'

const request = new CreateSetTokenAllowanceTransactionRequest()
request.setNetwork({ protocol: 2, id: '11155111' })
request.setSpender('0xspender...')
request.setAllowance({ /* SetTokenAllowance */ })
request.setFeeOption({ /* ... */ })

const response = await client.createSetTokenAllowanceTransaction(request, {})
const txRequest = response.getTransactionRequest()

Finalize And Broadcast Transaction

Submits a signed transaction to the network. Accepts a SignedTransactionRequest (as returned by signer.SignTransaction) and returns the resulting transaction ID.

Method: FinalizeAndBroadcastTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESTarget network
signed_txSignedTransactionRequestYESSigned transaction to finalize and broadcast

Response:

FieldTypeDescription
txidstringBroadcast transaction ID

Example Request:

import { FinalizeAndBroadcastTransactionRequest } from './proto/client_pb'

// signedTx is the SignedTransactionRequest returned by signer.SignTransaction
const request = new FinalizeAndBroadcastTransactionRequest()
request.setNetwork({ protocol: 1, id: '0a03cf40' })
request.setSignedTx(signedTx)

const response = await client.finalizeAndBroadcastTransaction(request, {})
console.log('Broadcast TXID:', response.getTxid())

Example Response:

{ "txid": "abc123def456..." }

Send Transaction

Send the native asset of a network to another address.

Service: ClientServiceMethod: SendTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESNetwork to send transaction on
to_addressstringYESRecipient address
amountAmountYESAmount to send
fee_optionFeeOptionYESFee option for the transaction

Amount Object:

FieldTypeDescription
valueDecimalStringAmount as decimal string
asset_idstringAsset identifier

FeeOption Enum:

OptionDescription
LOWLow fee, slower confirmation
MEDIUMMedium fee, moderate confirmation time
HIGHHigh fee, faster confirmation
CUSTOMCustom fee rate (sats/vB for Bitcoin, gwei for EVM)

Response:

FieldTypeDescription
txidstringTransaction ID

Example Request:

TypeScript
import { FeeOption } from './proto/models'

const response = await hydraGrpcClient.sendTransaction({
  network: {
    protocol: Protocol.BITCOIN,
    id: '0a03cf40'
  },
  toAddress: 'tb1q...',
  amount: {
    value: '0.001',
    assetId: 'BTC'
  },
  feeOption: FeeOption.MEDIUM
})

console.log('Transaction ID:', response.txid)
Go
req := &pb.SendTransactionRequest{
    Network: &pb.Network{
        Protocol: pb.Protocol_BITCOIN,
        Id:       "0a03cf40",
    },
    To: "tb1q...",
    Amount: &pb.Amount{
        Value:   "0.001",
        AssetId: "BTC",
    },
    FeeOption: pb.FeeOption_MEDIUM,
}

resp, err := client.SendTransaction(context.Background(), req)
if err != nil {
    log.Fatal(err)
}

txid := resp.Txid
Rust
let request = tonic::Request::new(SendTransactionRequest {
    network: Some(Network {
        protocol: Protocol::Bitcoin as i32,
        id: "0a03cf40".to_string(),
    }),
    to_address: "tb1q...".to_string(),
    amount: Some(Amount {
        value: "0.001".to_string(),
        asset_id: "BTC".to_string(),
    }),
    fee_option: FeeOption::Medium as i32,
});

let response = client.send_transaction(request).await?;
let txid = response.into_inner().txid;

Example Response:

{
  "txid": "abc123..."
}

Send Token Transaction

Send a token (non-native asset) to another address on a network.

Service: ClientServiceMethod: SendTokenTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESNetwork to send transaction on
to_addressstringYESRecipient address
token_idstringYESToken contract address or asset ID
amountAmountYESAmount to send
fee_optionFeeOptionYESFee option for the transaction

Response:

FieldTypeDescription
txidstringTransaction ID

Example Request:

TypeScript
// Send USDC on Ethereum Sepolia
const response = await hydraGrpcClient.sendTokenTransaction({
  network: {
    protocol: Protocol.EVM,
    id: '11155111'
  },
  toAddress: '0x...',
  tokenId: '0x...', // USDC contract address
  amount: {
    value: '100.0',
    assetId: 'USDC'
  },
  feeOption: FeeOption.MEDIUM
})
Go
req := &pb.SendTokenTransactionRequest{
    Network: &pb.Network{
        Protocol: pb.Protocol_EVM,
        Id:       "11155111",
    },
    To: "0x...",
    TokenId:   "0x...",
    Amount: &pb.Amount{
        Value:   "100.0",
        AssetId: "USDC",
    },
    FeeOption: pb.FeeOption_MEDIUM,
}

resp, err := client.SendTokenTransaction(context.Background(), req)
Rust
let request = tonic::Request::new(SendTokenTransactionRequest {
    network: Some(Network {
        protocol: Protocol::Evm as i32,
        id: "11155111".to_string(),
    }),
    to_address: "0x...".to_string(),
    token_id: "0x...".to_string(),
    amount: Some(Amount {
        value: "100.0".to_string(),
        asset_id: "USDC".to_string(),
    }),
    fee_option: FeeOption::Medium as i32,
});

let response = client.send_token_transaction(request).await?;

Example Response:

{
  "txid": "0x..."
}

Bump Transaction

Increase the fee of an existing unconfirmed transaction to speed up confirmation.

Service: ClientServiceMethod: BumpTransaction

Parameters:

NameTypeRequiredDescription
networkNetworkYESNetwork where transaction exists
txidstringYESTransaction ID to bump
fee_optionFeeOptionYESNew fee option (must be higher than original)

Response:

FieldTypeDescription
txidstringNew transaction ID (or same if RBF)

Example Request:

TypeScript
const response = await hydraGrpcClient.bumpTransaction({
  network: {
    protocol: Protocol.BITCOIN,
    id: '0a03cf40'
  },
  txid: 'abc123...',
  feeOption: FeeOption.HIGH
})
Go
req := &pb.BumpTransactionRequest{
    Network: &pb.Network{
        Protocol: pb.Protocol_BITCOIN,
        Id:       "0a03cf40",
    },
    Txid:      "abc123...",
    FeeOption: pb.FeeOption_HIGH,
}

resp, err := client.BumpTransaction(context.Background(), req)
Rust
let request = tonic::Request::new(BumpTransactionRequest {
    network: Some(Network {
        protocol: Protocol::Bitcoin as i32,
        id: "0a03cf40".to_string(),
    }),
    txid: "abc123...".to_string(),
    fee_option: FeeOption::High as i32,
});

let response = client.bump_transaction(request).await?;

Example Response:

{
  "txid": "def456..."
}

Set Token Allowance

Set the allowance for a spender to use a certain amount of a token on behalf of the owner (EVM only).

Service: ClientServiceMethod: SetTokenAllowance

Parameters:

NameTypeRequiredDescription
networkNetworkYESEVM network
spenderstringYESSpender address
allowanceSetTokenAllowanceYESAllowance details
fee_optionFeeOptionYESFee option for the transaction

SetTokenAllowance Object:

FieldTypeDescription
token_idstringToken contract address
amountDecimalStringAmount to allow

Response:

FieldTypeDescription
txidstringTransaction ID

Example Request:

TypeScript
const response = await hydraGrpcClient.setTokenAllowance({
  network: {
    protocol: Protocol.EVM,
    id: '11155111'
  },
  spender: '0x...', // Contract or address to approve
  allowance: {
    tokenId: '0x...', // Token contract
    amount: '1000.0'
  },
  feeOption: FeeOption.MEDIUM
})
Go
req := &pb.SetTokenAllowanceRequest{
    Network: &pb.Network{
        Protocol: pb.Protocol_EVM,
        Id:       "11155111",
    },
    Spender: "0x...",
    Allowance: &pb.SetTokenAllowance{
        TokenId: "0x...",
        Amount:  "1000.0",
    },
    FeeOption: pb.FeeOption_MEDIUM,
}

resp, err := client.SetTokenAllowance(context.Background(), req)
Rust
let request = tonic::Request::new(SetTokenAllowanceRequest {
    network: Some(Network {
        protocol: Protocol::Evm as i32,
        id: "11155111".to_string(),
    }),
    spender: "0x...".to_string(),
    allowance: Some(SetTokenAllowance {
        token_id: "0x...".to_string(),
        amount: "1000.0".to_string(),
    }),
    fee_option: FeeOption::Medium as i32,
});

let response = client.set_token_allowance(request).await?;

Example Response:

{
  "txid": "0x..."
}

Network ID Formats

Different networks use different ID formats:

Bitcoin Networks

  • Mainnet: 0a03cf40
  • Testnet3: 0b110907
  • Testnet4: 1c163f28
  • Signet: 0a03cf40
  • Regtest: fabfb5da

EVM Networks

  • Ethereum Mainnet: 1
  • Ethereum Sepolia: 11155111
  • Arbitrum One: 42161
  • Arbitrum Sepolia: 421614
  • Optimism: 10
  • Polygon: 137

Common Patterns

Get deposit address for all configured networks

TypeScript
async function getAllDepositAddresses() {
  const networks = await hydraGrpcClient.getNetworks()
  const addresses: Record<string, string> = {}

  for (const network of networks) {
    try {
      const address = await hydraGrpcClient.getDepositAddress(network)
      addresses[network.id] = address
    } catch (error) {
      console.error(`Failed to get address for ${network.id}:`, error)
    }
  }

  return addresses
}
Go
func getAllDepositAddresses(client pb.ClientServiceClient) (map[string]string, error) {
    networksResp, err := appClient.GetNetworks(context.Background(), &pb.GetNetworksRequest{})
    if err != nil {
        return nil, err
    }

    addresses := make(map[string]string)

    for _, network := range networksResp.Networks {
        resp, err := client.GetDepositAddress(context.Background(), &pb.GetDepositAddressRequest{
            Network: network,
        })
        if err != nil {
            log.Printf("Failed to get address for %s: %v", network.Id, err)
            continue
        }

        addresses[network.Id] = resp.Address
    }

    return addresses, nil
}
Rust
async fn get_all_deposit_addresses(
    client: &mut ClientServiceClient<Channel>,
    app_client: &mut AppServiceClient<Channel>,
) -> Result<HashMap<String, String>, Box<dyn std::error::Error>> {
    let networks = app_client
        .get_networks(GetNetworksRequest {})
        .await?
        .into_inner()
        .networks;

    let mut addresses = HashMap::new();

    for network in networks {
        match client
            .get_deposit_address(GetDepositAddressRequest {
                network: Some(network.clone()),
            })
            .await
        {
            Ok(resp) => {
                addresses.insert(network.id.clone(), resp.into_inner().address);
            }
            Err(e) => {
                eprintln!("Failed to get address for {}: {}", network.id, e);
            }
        }
    }

    Ok(addresses)
}

Error Handling

Error CodeDescriptionSolution
INVALID_ARGUMENTInvalid network, address, or amountVerify all parameters are correctly formatted
FAILED_PRECONDITIONInsufficient balance or wallet not initializedCheck balance and wallet status
NOT_FOUNDTransaction not found (for BumpTransaction)Verify transaction exists and is unconfirmed
UNAVAILABLEService temporarily unavailableRetry with exponential backoff

Best Practices

  1. Validate addresses - Always validate recipient addresses before sending
  2. Check balances - Verify sufficient balance before sending transactions
  3. Use appropriate fees - Choose fee option based on urgency (LOW for non-urgent, HIGH for urgent)
  4. Cache deposit addresses - Deposit addresses don't change frequently
  5. Monitor transactions - Use the Wallet API to monitor transaction confirmations
  6. Handle errors gracefully - Network issues can occur, implement retry logic

← Back to API Reference | Next: Asset API →


Copyright © 2025