Get started

Quickstart

Send your first reward to a verified Fomo identity: create a key, install the SDK, fund a vault, pay @lyra, and get told when it's confirmed.

  1. Create an API key

    In the dashboard open API → Keys and create a key with the scopes you need (rewards:create and payments:read for this guide). The raw key is shown once; FomoPay only stores a hash. fp_test_… keys work against the local development chain, fp_live_… keys against Robinhood Chain mainnet.

    const me = await fp.me();
    // { project: { id: "proj_…", name: "FomoRun" }, key: { mode: "test", scopes: [...] }, chain: { id: 4663, … } }
  2. Install the SDK

    Terminal
    npm install @fomopay/sdk

    Zero dependencies, ESM, typed. Runs on Node 18+, Bun, Deno and edge runtimes. Server-side only — the SDK refuses to run in a browser because API keys are secrets.

  3. Fund a Reward Vault

    Rewards are paid from a Reward Vault: a wallet you control (ideally a dedicated wallet or Safe) holding USDG, which approves FomoPay's payout signer for a capped allowance. Create one in Dashboard → Vaults; the funds never leave your wallet until a payout, and approve(signer, 0) revokes access any time.

  4. Pay @lyra

    import { FomoPay } from "@fomopay/sdk";
    
    const fp = new FomoPay({ apiKey: process.env.FOMOPAY_API_KEY });
    
    const payment = await fp.rewards.create({
      recipient: "@lyra",
      amount: "100",
      asset: "USDG",
      reason: "Quickstart reward",
      idempotencyKey: "reward_123",
    });
    
    console.log(payment.payment_id, payment.status); // pay_… CREATED
    201 Created (abridged)
    {
      "object": "payment",
      "payment_id": "pay_8k2m4q7r9t1v3x5z6b0c",
      "status": "CREATED",
      "type": "REWARD",
      "source": "vault",
      "recipient": { "handle": "@lyra", "display_name": "Lyra Okoye", "sandbox": false },
      "amount": "500",
      "asset": "USDG",
      "network": "robinhood",
      "reason": "FomoRun #42",
      "idempotency_key": "FOMORUN_42_WINNER",
      "idempotent_replayed": false,
      "tx_hash": null,
      "receipt_url": "https://fomopay.family/payment/pay_8k2m4q7r9t1v3x5z6b0c"
    }

    Run it twice: the second call returns the same payment with idempotent_replayed: true and HTTP 200 — nothing is paid twice. Change the amount but keep the key and you get 409 DUPLICATE_PAYMENT. See Idempotency.

  5. Know when it's paid

    wait.ts
    // Simple scripts: poll until the chain confirms and FomoPay verifies the transfer.
    const done = await fp.payments.wait(payment.payment_id, { timeoutMs: 120_000 });
    console.log(done.status, done.tx_hash); // CONFIRMED 0x…
    
    // Production: subscribe to payment.confirmed instead (next step).

    CONFIRMED means the transfer is on Robinhood Chain with enough confirmations and FomoPay verified it matches the payment (sender, recipient, amount, reference). Register a webhook to receive payment.confirmed:

    payment.confirmed
    {
      "id": "evt_5c7e9g1j3m5p7r9t1v3x",
      "type": "payment.confirmed",
      "created_at": "2026-10-12T18:04:19.000Z",
      "data": {
        "payment_id": "pay_8k2m4q7r9t1v3x5z6b0c",
        "status": "CONFIRMED",
        "type": "REWARD",
        "source": "vault",
        "recipient": "@lyra",
        "recipient_profile_id": "fp_2b4d6f8h0k2m4p6r8t0v",
        "sandbox": false,
        "amount": "500",
        "asset": "USDG",
        "network": "robinhood",
        "chain_id": 4663,
        "tx": "0x5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2",
        "explorer_url": "https://robinhoodchain.blockscout.com/tx/0x5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2",
        "memo": null,
        "reason": "FomoRun #42",
        "metadata": {},
        "idempotency_key": "FOMORUN_42_WINNER",
        "receipt_number": "FP-2026-000042",
        "receipt_url": "https://fomopay.family/payment/pay_8k2m4q7r9t1v3x5z6b0c",
        "error": null,
        "bulk_batch_id": null,
        "vault_id": "vault_3n5p7r9t1v3x5z7b9d1f"
      }
    }
    route.ts
    // app/api/fomopay/route.ts — Next.js route handler, Vercel Edge, Cloudflare Workers, Deno, Bun
    import { FomoPay } from "@fomopay/sdk";
    
    export async function POST(request: Request) {
      const raw = await request.text();
      try {
        const event = await FomoPay.webhooks.verify(raw, request.headers, process.env.FOMOPAY_WEBHOOK_SECRET!);
        await handle(event); // dedupe on event.id — deliveries are at-least-once
        return new Response("ok");
      } catch {
        return new Response("invalid signature", { status: 400 });
      }
    }

Optional: preview a recipient

You don't need to resolve before paying — FomoPay resolves server-side on every payment. Use resolve to show a recipient in your own UI (it never returns an address).

TypeScript
const r = await fp.resolve("@lyra", { asset: "USDG" });
r.state; // "VERIFIED" → FomoPay Ready: payable on Robinhood Chain
r.profile; // { handle: "@lyra", display_name: "Lyra Okoye", avatar_url: null, verified: true, sandbox: false, … }
r.payouts; // [{ network: "robinhood", asset_support: ["ETH", "USDG"], status: "verified" }]

Run it against the local stack

The FomoPay repo runs the whole platform locally — API, worker and a local anvil chain (id 31337) with a 6-decimal USDG at the real USDG address — so every example here works end to end with real transactions and no real money.

Terminal
# in the FomoPay repo
pnpm dev-key                                   # → {"apiKey":"fp_test_…", "projectId":"proj_…", …}
export FOMOPAY_API_KEY=fp_test_…
export FOMOPAY_BASE_URL=http://localhost:6280/v1
TypeScript
const fp = new FomoPay({
  apiKey: process.env.FOMOPAY_API_KEY,
  baseUrl: process.env.FOMOPAY_BASE_URL, // http://localhost:6280/v1 against the local stack
});
Sandbox identities

Locally (and until the live Fomo identity integration is authorized) @lyra, @mia, @frog and @builder are sandbox identities. They are labelled “Sandbox” everywhere and carry a SANDBOX_IDENTITY warning.