Build

TypeScript SDK

nara-agent: payFiat, jobs, errors and costs.

nara-agent pays a person from the agent's USDG in one call: it finds the runner, encrypts the recipient's details to them, locks the USDG with a single permit transaction, and waits. ESM, Node 18+ and modern browsers; it depends on viem and @noble/* only.

npm i https://usenara.cash/pkg/nara-agent-0.1.1.tgz

createNaraAgent(options)#

OptionDefault
privateKeyrequiredThe agent wallet's key. Kept in memory only: never logged or serialized.
baseUrlhttps://usenara.cashNara API.
chain"mainnet""mainnet" (Robinhood Chain 4663) or "local" (anvil, development).
rpcUrlthe chain's public RPCMust serve that chain.
poll{ minMs: 2000, maxMs: 10000 }Polling cadence.

nara.payFiat(params)#

Param
railrequiredA rail id: paypal, zelle, revolut, venmo, sepa…
torequiredThe recipient as they gave it (email, phone, @handle, IBAN, or a fields object for US and UK banks).
amountUsdrequiredWhat the recipient receives, $1 to $1,000. Fees come on top.
memoThe payment note the runner writes, ≤ 140 chars. Encrypted.
maxFeeBps300Highest runner fee you accept (max 500 = 5 %).
deadlineMin60The runner's payment window once funded (15 to 2880).
waitFor"paid"Resolve at "funded", "paid" or "released".
autoReleasefalseRelease as soon as the runner marks it paid (gives up the dispute window).
onUpdate(event) => void: created, assigned, secret_sent, funding, funded, paid, released, refunded…

nara.startPayment(params) does the same but returns { job, done } as soon as the job exists, with the rest running in the background.

CashJob#

id, state, snapshotThe last state seen: costs, runner alias and track record, deadlines, every transaction (fund, paid, release…).
status()Fresh state from Nara.
wait(state)Until the job reaches that state.
proof()The runner's proof, decrypted with the agent key.
release()Pay the runner now (from funded or paid). Irreversible.
dispute()Within the 24 h window, from paid.
finalize() / expire()Anyone can: after the dispute window, or after the runner's deadline.
cancel()Before funding only.

Also: nara.job(id), nara.jobs(), nara.resume(id) after a restart, nara.limits(), nara.rails(), nara.stats(), nara.balance() and nara.quote() (the worst-case cost before creating anything).

Errors#

CodeMeaningLocked?
INSUFFICIENT_USDGThe wallet can't cover amount + max runner fee + Nara fee.No
INSUFFICIENT_GASNo ETH on Robinhood Chain for the funding transaction.No
CAP_EXCEEDEDAbove $1,000 per payment, $5,000 per agent per day, or 10 jobs in progress.No
NO_RUNNERNo runner accepted in time. The job is cancelled.No
RUNNER_TIMEOUTThe runner missed the deadline; the SDK refunded the escrow.Refunded
SERVER_MISMATCHNara answered something the SDK won't fund (a fee above your max, a signature that doesn't match).No
UNAUTHORIZEDRequest signature refused: wrong key, or a clock more than 5 minutes off.

The server can't redirect your money#

Before funding, the SDK checks that the job id is derived from your wallet and its salt, that the runner's per-job key signed its payout address and fee, that the fee is within your max, and that the escrow is Nara's, on your chain. Anything else, and it refuses to fund.

Nara is not a bank. Nara is not affiliated with, endorsed by, or officially connected with Robinhood Markets, Inc. Built on Robinhood Chain. Terms · Privacy