Api

Getting Started

First API calls and key concepts

This page is for client-side developers who already have a Hydra App running (see the Setup Guide). It covers what services exist, how to call them, and the few primitive types that show up everywhere.

Want a runnable bot template instead? Skip to the Bot Quickstart.


Available services

Hydra App exposes one gRPC server with the following services. Each has its own dedicated reference page:

ServiceRPC countWhat it doesReference
AppService5Networks, public key, preimages, referralGeneral API
WalletService7Deposit addresses, balances, transactionsWallet API
PricingService2Asset → fiat pricePricing API
ClientService9Build, sign, broadcast on-chain transactionsClient API
AssetService4Asset metadata, add tokensAsset API
BlockchainService8Read-only chain queries, raw broadcastsBlockchain API
OrderbookService20Markets, orders, trades, market eventsOrderbook API
SwapService6Swap and SimpleSwap (auto-channel-setup swap)Swap API
NodeService40Channels, payments, invoices, allowancesNode API
LiquidityService6Service-backed channel liquidity, releases, lease extensionsLease API
WatchOnlyNodeService8Read-only channel and payment queriesWatch-Only Node API
EventService2Subscribe to client and node event streamsEvents API
SignerService4Sign messages and transactions(covered in service-specific pages)
HtlcService7Atomic HTLC create / claim / refund(proto reference only)

JSON-RPC namespaces match the service names lowercased: app, wallet, pricing, client, asset, blockchain, orderbook, swap, node, liquidity, watchOnlyNode, event.


Connecting

Hydra App listens on the port set by settings.server_port in your config (default 5003). Connect with any gRPC client:

import { AppServiceClient } from './proto/AppServiceClientPb'

const client = new AppServiceClient('http://localhost:5003')

No client-side authentication. Hydra App handles auth with the upstream Hydranet services on your behalf — derived from the seed you configured at setup. Your client connects to the local app over plain gRPC with no API keys, no headers, no auth handshake. If you find yourself looking for a "Bearer token" or "API key" parameter, you're looking at the wrong layer — it's all transparent to clients.


Your first call: list active networks

AppService.GetNetworks requires no parameters and confirms the app is up.

import { GetNetworksRequest } from './proto/app_pb'

const response = await client.getNetworks(new GetNetworksRequest(), {})
for (const n of response.getNetworksList()) {
  console.log(`protocol=${n.getProtocol()} id=${n.getId()}`)
}
// → protocol=1 id=0a03cf40   (Bitcoin Signet)
// → protocol=2 id=11155111   (Ethereum Sepolia)
// → protocol=2 id=421614     (Arbitrum Sepolia)

Key concepts

Network

Identifies a blockchain. Two fields only:

FieldTypeNotes
protocolProtocol enumPROTOCOL_BITCOIN = 1, PROTOCOL_EVM = 2
idstringMagic bytes (hex) for Bitcoin, decimal chain ID for EVM

Older example code may use chain_id and name — those fields no longer exist. See the Setup Guide's network identifier table.

DecimalString

All monetary amounts are passed as strings to preserve precision. The string is in the asset's human-readable unit, not its smallest unit.

Asset"0.1" means"100" means
BTC0.1 BTC (10,000,000 sats)100 BTC
ETH0.1 ETH (10¹⁷ wei)100 ETH
USDC0.1 USDC100 USDC
HDN0.1 HDN100 HDN

So { value: "0.1" } always means "one-tenth of one whole asset" — never "0.1 satoshis" or "0.1 wei".

Asset and asset IDs

FieldDescription
idUnique identifier on the network (hex contract address for ERC-20, zero-padded hash for native assets)
nameHuman-readable, e.g. "Bitcoin"
symbolTicker, e.g. "BTC", "USDC"
decimalsSmallest-unit decimal places — informational only; you don't apply this when filling DecimalString

Amount (for sends)

Used by client.SendTransaction, client.CreateSendTransaction, etc. A oneof:

VariantPayloadMeaning
exactDecimalStringSend exactly this amount
all{}Send all available balance (UTXO sweep / EVM full transfer)

FeeOption

How a transaction's fee is selected. Common shapes:

  • Estimate-based: { priority: LOW | MEDIUM | HIGH } — pulls from blockchain.GetFeeEstimates.
  • Manual: { fee_rate: FeeRate }FeeRate is { max_fee_per_unit, priority_fee_per_unit } as U256String.

See the Common Patterns doc for the full shape.


The two transaction flows

ClientService exposes two parallel ways to make an on-chain transaction. Pick the one that fits your signing model.

One-shot (Hydra App signs and broadcasts)

SendTransaction      → txid
SendTokenTransaction → txid
BumpTransaction      → txid
SetTokenAllowance    → txid

Use this when Hydra App holds the private key (most bots).

Build → sign → finalize (you sign externally)

CreateSendTransaction              → TransactionRequest
                                       ↓ sign with signer.SignTransaction
                                     SignedTransactionRequest
                                       ↓
                                     FinalizeAndBroadcastTransaction → txid

Use this when you want to inspect the transaction before signing, or when the signing key lives in an external HSM / hardware wallet.

For raw transactions you've already signed entirely outside Hydra (e.g. PSBT workflows), use blockchain.BroadcastRawTransaction instead.


The two trading flows

SwapService has two ways to trade:

RPCWhen to use
SwapYou already have offchain balance in both the sending and receiving currencies. Fast — just submits the order.
SimpleSwapYou don't have balance yet. Hydra App sets up the necessary channels (open / deposit / lease) before submitting the order. Charges on-chain fees.

A bot starting from cold will almost always use SimpleSwap for the first trade and Swap thereafter.


The two ways to get inbound liquidity

A new node has zero channels. Two options:

OptionRPCWhen to use
Self-fundednode.OpenChannelYou have on-chain balance and a willing peer. You pay the funding tx.
Service-backed leaseliquidity.RequestChannelLiquidityThe liquidity service provisions a channel for you. You pay a service fee instead of doing the funding yourself.

For bots, the lease flow is usually simpler — see the Lease API.


Streaming RPCs

Three subscriptions a bot will care about:

StreamRPCUse
Client eventsevent.SubscribeClientEventsWallet-level updates (balances, transactions, channel state)
Node eventsevent.SubscribeNodeEventsChannel and payment lifecycle events
Market eventsorderbook.SubscribeMarketEventsOrderbook updates for a market (use for live prices, fills)

Subscribe before you act. If you place an order before subscribing to the market stream, you can miss the fill notification. Same for SimpleSwap — subscribe to SubscribeSimpleSwaps before calling SimpleSwap.


Error handling at a glance

Hydra App returns standard gRPC status codes. For a bot, the practical mental model:

StatusMeaningRetry?
OKSuccessn/a
INVALID_ARGUMENTYour request is malformedNo — fix and resubmit
FAILED_PRECONDITIONState doesn't allow this (e.g. channel not active)Maybe — wait for state change
RESOURCE_EXHAUSTEDLiquidity / capacity unavailableMaybe — back off and retry
UNAVAILABLENetwork blip or upstream outageYes — exponential backoff
DEADLINE_EXCEEDEDYour deadline firedYes if idempotent
INTERNAL / UNKNOWNApp bugLog and surface; don't retry blindly

Idempotency caveat: Send* and Open* RPCs are not idempotent — a retry after DEADLINE_EXCEEDED may broadcast twice. Check via wallet.GetTransactions or node.SendChannelPayment results before retrying.

See 40-errors.md for the full code list and per-RPC error mappings.


Next steps


Copyright © 2025