Field run

Ref: KB-2410-09

wavelength-field-test

Raw logs and driver scripts from a first-hand field test: an agent paying for APIs over Lightning with Wavelength v0.2.0 on Bitcoin mainnet (L402), compared with x402 (USDC on Base) on the same kind of call. Run on 2026-10-27/28 UTC by Swift Bot Labs.

Full write-up: https://dev.to/swiftbotlab/ref-kb-2410-09-an-agent-paid-real-apis-over-lightning-wavelength-mainnet-vs-x402-on-base-5hfl Proof of the working mainnet account: PROOF.md.

What is here

pathwhat
l402_run.pyheadless L402 driver: GET -> 402 -> decode the BOLT-11 amount locally -> wavecli send -> retry with Authorization: L402 <macaroon>:<preimage>; per-call and per-session sat caps; logs every step
recv_test.pyreceive-side test between two of our own Wavelength wallets (invoice -> pay -> wait until the receiver can spend)
x402_run.pyx402 v2 payer for the same kind of call: reads accepts, signs one EIP-3009 TransferWithAuthorization locally, retries with PAYMENT-SIGNATURE
results/l402_results.csvone row per step (challenge / pay / retry / token reuse): price, fee, rail, timings, result
results/x402_results.csvone row per paid call with the Base tx hash
results/limits/exact JSON errors from wavecli for the limit tests (receive above caps, sub-1,000-sat invoices, expired invoice)

Macaroons, invoices and preimages are cut to short prefixes in the public logs. Nothing here holds a key, seed or password.

Reproduce

  1. Install Wavelength v0.2.0 from github.com/lightninglabs/wavelength/releases (check the manifest SHA-256 and the release signatures), create a wallet, request mainnet access with your identity_pubkey.
  2. Start waved on mainnet (flags in the report), fund the wallet, unlock it.
  3. python3 l402_run.py probe (pays nothing), then python3 l402_run.py run --go.
  4. For x402: a Base wallet holding a little USDC; x402_run.py probe, then x402_run.py run 5 --go (the script derives its key from a local secrets file; adapt account() to your own key handling).

License

MIT for the scripts. The logs are our own measurements.

Ref: KB-2410-09

Proof of a working Wavelength mainnet account

Captured 2026-10-27 12:54 UTC from our own daemon with wavecli --json. The identity key (mailbox ID) is shortened; nothing secret is shown.

wavecli getinfo

{
  "version": "0.2.0",
  "commit": "b82bd54",
  "network": "mainnet",
  "block_height": 973400,
  "server_connected": true,
  "wallet_type": "lwwallet",
  "wallet_state": "WALLET_STATE_READY"
}

identity_pubkey: 03bdb9ea...d359bb1e (the value submitted with the mainnet access request on 2026-10-27).

Server limits reported by getinfo: max_user_balance 300,000 sats, max_vtxo_amount 50,000 sats, min_boarding_amount 1,000 sats, min_operator_fee 1,000 sats, boarding min_confirmations 6.

Funding (public chain data)

Wallet ledger (wavecli activity)

kindstatusamount (sats)fee fieldcounterparty
EXITPENDING-9298032Jcu66LAonGfFqnJoH4srozgZpGQAyx
RECVCOMPLETE10000
SENDCOMPLETE-10000
SENDCOMPLETE-20credit
SENDCOMPLETE-1000credit
SENDCOMPLETE-50credit
SENDCOMPLETE-10000
SENDCOMPLETE-20credit
DEPOSITCOMPLETE105530boarding
RECVFAILED50000

Reading the ledger from the bottom: the 5,000-sat RECV is a limit-test invoice nobody paid (it expired); DEPOSIT is the boarding; the first -1,000 SEND moved sats into server credit; the -2/-5/-100 SENDs are the paid L402 calls (settled from credit); the second -1,000 SEND paid our second wallet's invoice in-Ark and the +1,000 RECV is that wallet paying it back; EXIT is the cooperative leave.

Balance now (wavecli balance)

{
  "confirmed_sat": "0",
  "pending_in_sat": "0",
  "pending_out_sat": "9298",
  "credit_available_sat": "886",
  "credit_reserved_sat": "0"
}

The remaining sats were sent back on-chain with a cooperative leave (the EXIT row) after the test; the server credit stays with the operator for later calls.

Files

PROOF.md
README.md
summary-card.png