Fiber LogoFiber Docs
Build15 minute tutorial

Open a Fiber Channel and Send a Payment

Fund your browser node, open a real Testnet payment channel, and send CKB over Fiber—all from React and WASM.

ReactFiber WASMTestnet payment
Before you pay

A channel turns one on-chain setup into fast payments

Opening a channel commits Testnet CKB on-chain. Once the channel reaches ChannelReady, payments update the channel off-chain instead of creating a new CKB transaction each time.

Your browser nodeWASM + local keys
→ Channel →
Public Fiber nodeReceives keysend
This page uses real Testnet state

Starting and connecting do not move funds. Opening the channel and sending the payment happen only after you click their separate buttons.

1 Fund the browser identity

Send Testnet CKB to the generated address

Start the same browser identity used in the connection tutorial. The SDK derives its CKB funding address from default_funding_lock_script. Use the faucet, then refresh until the on-chain balance appears.

Keep the same localStorage identity and IndexedDB dataFund at least 499 CKB plus an on-chain transaction feeUse Testnet funds only
lib/balance.ts · lines 7–45
2 Convert the amount

Express CKB as hexadecimal shannons

Fiber RPC amounts use hexadecimal shannons. Parse the decimal string with BigInt so eight-decimal CKB values stay exact and do not pass through floating-point numbers.

499 CKB = 49,900,000,000 shannons0xb9e0ab300
lib/amounts.ts · lines 1–18
3 Open the channel

Commit funding to the public Testnet peer

Call openChannel() only after the browser node is running, the public peer is connected, and the funding address has enough CKB. The example makes the channel public so it can participate in routing.

Why 499 CKB?

The selected public Testnet node auto-accepts CKB channels at or above 499 CKB. Each side also reserves 99 CKB for channel contracts and shutdown.

lib/channel.ts · lines 7–19
4 Wait for ChannelReady

Do not enable payments when negotiation merely starts

openChannel() returns a temporary channel ID before the funding transaction is ready. Poll listChannels()and unlock the payment UI only when a channel state contains ready.

NegotiatingFunding: agree on channel parametersCollaboratingFundingTx: build the funding transactionSigningCommitment: exchange commitment signaturesAwaitingTxSignatures: finalize funding signaturesAwaitingChannelReady: wait for confirmation and both peersChannelReady: the channel can carry a payment
lib/channel.ts · lines 21–40
5 Send a payment

Use keysend for the smallest working example

Pass the recipient pubkey, an amount, and keysend: trueto sendPayment(). Keysend avoids invoice generation, which keeps this first payment flow entirely in the browser.

When do you need a backend?

Not for this direct keysend demo. A merchant app usually adds a backend to create invoices, match payments to orders, and grant access after server-side verification.

lib/payment.ts · lines 4–13
6 Confirm the result

Wait for a terminal payment status

A submitted payment can still be in flight. If the first response is not Success or Failed, callwaitForPayment() and update the React UI with its terminal status.

lib/payment.ts · lines 15–26
7.1 Wire the controls

Start, then connect

Starting restores local identity and channel data. Connecting is a separate user action, just like the first tutorial. The code panel highlights both handlers as one explicit preparation step.

app/pay/page.tsx · lines 23–37
7.2 Wire the controls

Open, then pay

The channel button requires a connected peer. The payment button remains disabled until a stored or new channel is ready, so every state-changing action stays separate and explicit.

app/pay/page.tsx · lines 39–49
Production checklist

Keep the browser node; harden everything around it

Before handling real funds, encrypt keys, add backup and recovery, validate channel liquidity, surface fees and timeouts, and decide whether invoices need server-side order verification.