Skip to content
LogoLogo

Send a payment

Pay ARRK (or any issued asset) from a key you control to an address.

You need: a regtest node with a funded key (Quick start) and the SDK (TypeScript or Python).

What the example does

  1. Creates a client for the node and reads the network from GET /v1/chain.
  2. Derives a wallet from a seed (hardened ML-DSA-65 keys at m/9000'/0'/0'/change'/index').
  3. On regtest with an admin token, mines 101 blocks to fund itself (coinbase outputs mature after 100 blocks).
  4. Collects mature, unspent coins of the wallet's addresses.
  5. Builds the transaction (deterministic coin selection, change to the wallet's change address) at the node's fee estimate. Amounts are integers in base units (parseArrk("1.5") → 150000000n).
  6. Signs every input. The signature hash commits to the network, the transaction and the asset, amount and lock of every spent output.
  7. Broadcasts it (POST /v1/txs) and prints the txid and fee.

The TypeScript version spells out each step (getCoins, buildTransaction, signTransaction, sendTransaction); the Python version uses the client.send_payment(...) helper, which does the same.

TypeScript · send-payment.ts
/**
 * Send a payment: derive a wallet, fund it on regtest, pay 1.5 ARRK, confirm.
 *
 *   ARREKTA_URL=http://127.0.0.1:28332 ARREKTA_ADMIN_TOKEN=... npx tsx examples/send-payment.ts
 */
import { createClient, formatArrk, fromHex, generateSeed, getAddress, getChain, getCoins, keychainFromSeed, mine, sendPayment } from 'arrekta-sdk';
 
const URL = process.env.ARREKTA_URL ?? 'http://127.0.0.1:28332';
const ADMIN = process.env.ARREKTA_ADMIN_TOKEN; // regtest mining for the demo
const SEED = fromHex(process.env.ARREKTA_SEED ?? 'a1'.repeat(32));
 
// 1. Connect and read the chain.
const client = createClient({ url: URL, adminToken: ADMIN });
const chain = await getChain(client);
console.log(`connected to ${chain.network} at height ${chain.height}`);
 
// 2. Alice's wallet from her seed; Bob gets a fresh one.
const alice = keychainFromSeed(SEED, { network: chain.network });
const bob = keychainFromSeed(generateSeed(), { network: chain.network });
 
// 3. Fund Alice (regtest: mine past coinbase maturity).
if ((await getCoins(client, { wallet: alice })).length === 0) await mine(client, alice.address(0), 101);
 
// 4. Pay Bob 1.5 ARRK (fee rate from the node's estimate).
const sent = await sendPayment(client, { wallet: alice, to: bob.address(0), amount: '1.5' });
console.log(`sent ${sent.txid} (fee ${formatArrk(sent.fee)} ARRK)`);
 
// 5. Confirm and check Bob's balance.
await mine(client, alice.address(0), 1);
const balance = (await getAddress(client, { address: bob.address(0) })).balances[0]!;
console.log(`bob has ${formatArrk(balance.spendable)} ARRK`);

Source: sdk/typescript/examples/send-payment.ts (updated 2026-11-02) · sdk/python/examples/send_payment.py (updated 2026-11-02). Runnable against a regtest node; CI runs every example.

If something goes wrong

Error codeMeaning
missing-inputsa coin is already spent, or not yet known to the node
insufficient-feea conflicting transaction pays more; bump the fee
asset-frozenthe issuer froze this asset for the sending lock
tx-expiredvalidUntil is below the next block height

A payment stuck at a low fee can be replaced (bumpFee) or pulled in by a child (cpfp); see Fees.