# Moonyversal Router > A swap API for Flipcash currencies. Quote a trade, build an unsigned transaction for your wallet, sign it yourself, send it, and read the receipt. The Router never signs, never sees a key, and never holds funds. Early access: request access at https://developer.moonyversal.com/request Flipcash currencies are Solana tokens issued against a bonding-curve reserve held in USDF, a dollar stablecoin. Nothing here makes any claim about the price or value of any currency. This file is the same reference as https://router.moonyversal.com/docs, as plain text. Use of the Router is governed by its terms: https://router.moonyversal.com/terms ## Basics - Base URL: https://router.moonyversal.com/api/v2 - Requests and responses are JSON. Amounts are decimal strings in whole units ("5" is five dollars of USDF). - An asset is USDF, USDC, or a Flipcash currency's mint address. Tickers are not unique, so currencies go by mint. GET /tokens lists them all. - Every response carries "source": "moonyversal-router". ## Keys and limits - Building and sending need an API key. Once your early-access request is approved, sign in at https://developer.moonyversal.com and create your own keys there. Quotes, the currency list and receipts answer without one, at a small allowance. - Send the key with every request: `Authorization: Bearer ` (or `x-api-key: `). - Test keys (mny_test_...) quote and build, with every build simulated; send refuses them with 403 test_key. Live keys (mny_live_...) can do everything. - Keep the key on a server: never in a browser app, a public repository or a URL. Only a fingerprint is stored, so a lost key is replaced, not recovered. - Limits are per key, per minute. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. Past the limit: 429 rate_limited with Retry-After in seconds. ## How a trade works 1. Quote: what you pay, what you get, the least you will accept, and every fee as its own line. 2. Build: an unsigned transaction for your wallet, simulated on the network first. 3. Sign: with your own Solana signer, such as a server key or a browser wallet. 4. Send: send it back to be seen through to confirmation, or broadcast it yourself. 5. Receipt: what was sold, what was bought, the value and every fee, as JSON. ## GET /tokens Returns { tokens: [...], total, note, source }. Each token: ticker, name, mint, decimals, kind ("dollar" for USDF and USDC, "currency" otherwise), priceUsd, tradeReady, and tradeNote when tradeReady is false (the Router will not trade it right now; the note says why). ## GET /quote Parameters: - pay (required): USDF, USDC or a currency mint. - receive (required): the same. - amount (required): how much of pay, in whole units, as a decimal string. - slippageBps (optional): how far below the expected amount you will accept, in basis points. Default 30 (0.3%). - partnerFeeBps (optional): your share of the buy fee, in basis points, from 0 to 50. Default: the share set on your key. Needs a key with a fee wallet. See Fees. Example: curl -G https://router.moonyversal.com/api/v2/quote \ -H "Authorization: Bearer $ROUTER_KEY" \ -d pay=USDF -d receive=4muAfB6m1P7C3Znad1VUsoqYFwvGQRkWGpJ3A4vupxz6 -d amount=5 Response (a real quote with a 0.5% partner share, Oct 7, 2026): { "kind": "buy", "route": ["USDF", "MNY"], "pay": { "asset": "5AMAA9JV9H97YYVxx8F6FsCMmTwXSuTTQneiup4RYAUQ", "symbol": "USDF", "amount": "5.000000", "base": "5000000" }, "receive": { "asset": "4muAfB6m1P7C3Znad1VUsoqYFwvGQRkWGpJ3A4vupxz6", "symbol": "MNY", "expected": "49.5186984656", "min": "49.3701423702", "minBase": "493701423702" }, "fees": [ { "label": "Router buy fee", "bps": 50, "amount": "0.025000", "asset": "USDF" }, { "label": "Partner fee", "bps": 50, "amount": "0.025000", "asset": "USDF" } ], "priceImpactPct": 0.01, "slippageBps": 30, "quotedAt": "2026-10-07T23:34:08.679Z", "source": "moonyversal-router" } expected is what you should get; min is the least the transaction will accept, enforced on chain. base and minBase are the same amounts in the token's smallest units. Route kinds (the quote's kind): - buy: USDF to a currency. - sell: a currency to USDF. - usdc-buy: USDC to a currency, through USDF, in one transaction. - usdc-sell: a currency to USDC, through USDF, in one transaction. - routed: one currency to another, in one transaction. - usdf-to-usdc, usdc-to-usdf: one for one. A quote is a price, not a hold. Build quotes again at the moment it builds, and the transaction carries that quote's minimum. ## POST /swap/build Body: { "wallet": "
", "pay": ..., "receive": ..., "amount": ..., "slippageBps"?: 30, "partnerFeeBps"?: <0..50>, "simulate"?: true }. wallet is the address that will sign and pay; it is the transaction's fee payer. Needs a key. curl https://router.moonyversal.com/api/v2/swap/build \ -H "Authorization: Bearer $ROUTER_KEY" \ -d '{ "wallet": "", "pay": "USDF", "receive": "4muAfB6m1P7C3Znad1VUsoqYFwvGQRkWGpJ3A4vupxz6", "amount": "5" }' Response fields: transaction (the unsigned transaction, base64, Solana legacy format), format ("legacy"), feePayer (your wallet), blockhash, lastValidBlockHeight, sizeBytes, builtAt, expiresInSeconds (60), expiresAt, quote (as above), simulation { ok, message?, unitsConsumed }, send ("/api/v2/swap/send"), receipt ("/api/v2/receipt/"), source. If the simulation fails, simulation.ok is false and message says why, before anything is signed. A wallet that cannot pay is refused with 400 insufficient_balance, for example "You need USDF to make this swap. Use USDC or buy USDF first." A built transaction lives about 60 seconds (its blockhash expires). If signing is slow, build again once expiresAt has passed. Sending an expired transaction answers 409 expired_blockhash and nothing is broadcast. ## Signing With any Solana signer. JavaScript, @solana/web3.js: import { Transaction } from "@solana/web3.js"; const tx = Transaction.from(Buffer.from(build.transaction, "base64")); tx.sign(keypair); // a server key // in a browser: const signed = await wallet.signTransaction(tx); const signedTransaction = tx.serialize().toString("base64"); ## POST /swap/send Body: { "signedTransaction": "", "simulateFirst"?: true }. Needs a live key. curl https://router.moonyversal.com/api/v2/swap/send \ -H "Authorization: Bearer $ROUTER_KEY" \ -d '{ "signedTransaction": "" }' Response: { "signature", "status": "confirmed" | "pending", "slot", "receipt": "/api/v2/receipt/", "source" }. Send checks the blockhash is still valid, simulates (unless simulateFirst is false), broadcasts, and waits for confirmation, sending again while it waits. "pending" means it did not confirm in that window: read the receipt before building another trade, so you never trade twice. You may broadcast the signed transaction yourself instead; the receipt works either way. ## GET /receipt/ Response: { signature, status, slot, blockTime, swap: { kind, sold: { mint, symbol, amount }, bought: { mint, symbol, amount }, valueUsd }, fees: [ { label, amount?, asset?, usdf?, lamports? } ], source }. Read from the chain after the fact. A signature the chain does not know yet answers 404 not_found; after a send, ask again until it appears. ## Fees - Calling the API: free. - Buys: up to 1%, inside the transaction: the Router's 0.5% ("Router buy fee") plus your share of up to 0.5% ("Partner fee"). Your users never pay more than 1% on a buy. - Your share: you set it, as a default on your key or as partnerFeeBps on any quote or build, from 0 to 50 basis points, the same for every currency. The buyer pays it straight to your wallet's USDF account in the same transaction; the Router never holds it. Charge less to pass the saving to your users. - Sells: no Router fee and no partner fee. Flipcash's reserve charges its own fee on every sell, whoever builds it; the quote shows it as its own line. - USDF and USDC: switching between them is one for one. - Network fees: paid in SOL by the signing wallet, for now. Coming soon: the Router will pay the network fee and be repaid inside the same transaction. ## Your fee wallet Set the wallet that receives your partner fee yourself, with your key, and change it whenever you like. The wallet needs a USDF account first: send it any amount of USDF once. The Router never creates that account, so your users never pay for it. curl -X PUT https://router.moonyversal.com/api/v2/key/partner-fee \ -H "Authorization: Bearer $ROUTER_KEY" \ -d '{ "wallet": "", "bps": 50 }' - wallet: the address whose USDF account receives your share. Required the first time. - bps (optional): your default share, 0 to 50 basis points. Default 50. Any quote or build can still pass partnerFeeBps. Response: { id, name, env, fees: { routerFeeBps: 50, partnerFee: { wallet, bps, updatedAt } | null, partnerFeeMaxBps: 50 }, source }. GET /api/v2/key shows your key's current settings; DELETE /api/v2/key/partner-fee removes the partner fee, so buys carry the Router's fee alone. A change takes effect within a minute. Whoever holds your key can change where your share goes, so keep it secret. ## Errors Every error is { error, code, retryable, hint? }, and the HTTP status means what it says. retryable says whether the same request can succeed later. - 400 invalid_input: the request itself (a missing field, a bad amount, a bad wallet address, a partnerFeeBps outside 0 to 50 or on a key with no fee wallet). - 400 insufficient_balance: the wallet cannot pay for this trade. - 400 simulation_failed: the built transaction fails when simulated as your wallet; the message says why. - 400 failed_on_chain: sent, landed, and reverted. - 401 invalid_key: the key is malformed, unknown or revoked. - 401 key_required: build and send need a key. - 403 forbidden_route: the pair is outside what your key may trade. - 403 test_key: a test key cannot send. - 404 unknown_asset: pay or receive is not USDF, USDC or a Flipcash currency mint. - 404 not_found: the chain does not know this signature yet. - 409 expired_blockhash (retryable): the transaction outlived its blockhash; nothing was sent; build again. - 429 rate_limited (retryable): wait for Retry-After. - 500 internal (retryable): something failed on our side. - 502 send_failed (retryable): the network did not take the transaction; the same signed bytes can be sent again while the blockhash is valid. - 503 no_liquidity (retryable): a market condition, not a request error. ## Access - [Request early access](https://developer.moonyversal.com/request) - [Developer dashboard](https://developer.moonyversal.com) - [Docs](https://router.moonyversal.com/docs) - Contact: contact@moonyversal.com Built by Moonyversal. Flipcash is a trademark of its owner.