Getting Started
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:
| Service | RPC count | What it does | Reference |
|---|---|---|---|
AppService | 5 | Networks, public key, preimages, referral | General API |
WalletService | 7 | Deposit addresses, balances, transactions | Wallet API |
PricingService | 2 | Asset → fiat price | Pricing API |
ClientService | 9 | Build, sign, broadcast on-chain transactions | Client API |
AssetService | 4 | Asset metadata, add tokens | Asset API |
BlockchainService | 8 | Read-only chain queries, raw broadcasts | Blockchain API |
OrderbookService | 20 | Markets, orders, trades, market events | Orderbook API |
SwapService | 6 | Swap and SimpleSwap (auto-channel-setup swap) | Swap API |
NodeService | 40 | Channels, payments, invoices, allowances | Node API |
LiquidityService | 6 | Service-backed channel liquidity, releases, lease extensions | Lease API |
WatchOnlyNodeService | 8 | Read-only channel and payment queries | Watch-Only Node API |
EventService | 2 | Subscribe to client and node event streams | Events API |
SignerService | 4 | Sign messages and transactions | (covered in service-specific pages) |
HtlcService | 7 | Atomic 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:
| Field | Type | Notes |
|---|---|---|
protocol | Protocol enum | PROTOCOL_BITCOIN = 1, PROTOCOL_EVM = 2 |
id | string | Magic bytes (hex) for Bitcoin, decimal chain ID for EVM |
Older example code may use
chain_idandname— 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 |
|---|---|---|
| BTC | 0.1 BTC (10,000,000 sats) | 100 BTC |
| ETH | 0.1 ETH (10¹⁷ wei) | 100 ETH |
| USDC | 0.1 USDC | 100 USDC |
| HDN | 0.1 HDN | 100 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
| Field | Description |
|---|---|
id | Unique identifier on the network (hex contract address for ERC-20, zero-padded hash for native assets) |
name | Human-readable, e.g. "Bitcoin" |
symbol | Ticker, e.g. "BTC", "USDC" |
decimals | Smallest-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:
| Variant | Payload | Meaning |
|---|---|---|
exact | DecimalString | Send 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 fromblockchain.GetFeeEstimates. - Manual:
{ fee_rate: FeeRate }—FeeRateis{ max_fee_per_unit, priority_fee_per_unit }asU256String.
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.BroadcastRawTransactioninstead.
The two trading flows
SwapService has two ways to trade:
| RPC | When to use |
|---|---|
Swap | You already have offchain balance in both the sending and receiving currencies. Fast — just submits the order. |
SimpleSwap | You 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:
| Option | RPC | When to use |
|---|---|---|
| Self-funded | node.OpenChannel | You have on-chain balance and a willing peer. You pay the funding tx. |
| Service-backed lease | liquidity.RequestChannelLiquidity | The 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:
| Stream | RPC | Use |
|---|---|---|
| Client events | event.SubscribeClientEvents | Wallet-level updates (balances, transactions, channel state) |
| Node events | event.SubscribeNodeEvents | Channel and payment lifecycle events |
| Market events | orderbook.SubscribeMarketEvents | Orderbook 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 toSubscribeSimpleSwapsbefore callingSimpleSwap.
Error handling at a glance
Hydra App returns standard gRPC status codes. For a bot, the practical mental model:
| Status | Meaning | Retry? |
|---|---|---|
OK | Success | n/a |
INVALID_ARGUMENT | Your request is malformed | No — fix and resubmit |
FAILED_PRECONDITION | State doesn't allow this (e.g. channel not active) | Maybe — wait for state change |
RESOURCE_EXHAUSTED | Liquidity / capacity unavailable | Maybe — back off and retry |
UNAVAILABLE | Network blip or upstream outage | Yes — exponential backoff |
DEADLINE_EXCEEDED | Your deadline fired | Yes if idempotent |
INTERNAL / UNKNOWN | App bug | Log and surface; don't retry blindly |
Idempotency caveat:
Send*andOpen*RPCs are not idempotent — a retry afterDEADLINE_EXCEEDEDmay broadcast twice. Check viawallet.GetTransactionsornode.SendChannelPaymentresults before retrying.
See 40-errors.md for the full code list and per-RPC error mappings.
Next steps
- Bot Quickstart — runnable trading-bot template
- Common Patterns — fees, amounts, helper functions
- Browser & gRPC-Web Specifics — for browser clients only: manual framing, fetch-based streaming, CORS
- Service references: App · Wallet · Client · Orderbook · Swap · Node · Lease