Rewards
Pay a verified identity from your Reward Vault — game prizes, bounties, creator payouts, campaign rewards. No wallet collection, and the idempotency key makes every payout exactly-once.
/v1/rewardsscope rewards:createBody
recipientstringrequired- The Fomo handle:
@lyra. Must beVERIFIEDon Robinhood Chain. amountdecimal stringrequired- USDG, up to 6 decimals:
"500","12.5". idempotency_keystringrequired- 1–255 printable characters, no spaces. Derive it from your event —
FOMORUN_42_WINNER,BOUNTY_8812. May be sent as theIdempotency-Keyheader instead (if both are sent they must match). asset"USDG"optional- Reward Vaults hold USDG; this is the default. ETH has no ERC-20 allowance — pay ETH with a wallet payment.
reasonstringoptional- Shown on the receipt:
FomoRun #42 Winner. memostringoptional- A note for the recipient.
vault_idstringoptional- Which vault pays. Optional when the project has exactly one active USDG vault.
metadataobjectoptional- Your references (round id, bounty id). Returned on the payment and in every webhook.
eligibilityobjectoptional- Your own eligibility assertions (region, age declaration, campaign). Stored with the payout as you sent them — FomoPay doesn't invent eligibility.
visibilityprivate | unlisted | publicoptional- Receipt visibility. Projects may publish reward receipts; default
unlisted.
What happens
- Admission. The vault must be
ACTIVE, the amount within its per-payout and daily limits, and covered by both its balance and its remaining allowance. A rejected reward never becomes a payment. - Payment.
@lyrais resolved, the verified destination snapshotted and the risk engine consulted, exactly like any payment. You get the payment back (201) immediately. - Execution. FomoPay's payout signer sends
transferFrom(vault, @lyra's wallet, amount)on Robinhood Chain, paying gas in ETH itself. Payouts are serialized per signer so nonces never collide. - Confirmation. The payment moves
SUBMITTED→CONFIRMING→CONFIRMED, a receipt is issued andpayment.confirmedis delivered to your webhooks.
Errors you should handle
| Code | Status | What to do |
|---|---|---|
DUPLICATE_PAYMENT | 409 | This key was used with a different body. Don't retry — it's a bug or a genuinely different payout that needs its own key. |
RECIPIENT_UNVERIFIED · NO_PAYOUT_DESTINATION | 422 | Ask the winner to make their handle FomoPay Ready (/claim), then retry with the same key. |
VAULT_INSUFFICIENT | 422 | Top up the vault wallet with USDG. |
VAULT_ALLOWANCE_EXCEEDED | 422 | Raise the approved allowance from the vault wallet. |
VAULT_NOT_ACTIVE | 409 | Finish setup, unpause, or re-approve the vault. |
PAYMENT_LIMIT_EXCEEDED | 422 | Over a per-payout, daily, project or recipient limit. |
UNSUPPORTED_ASSET | 422 | Vaults pay USDG. There is no official USDC on Robinhood Chain. |
A reward can also come back with status: "HELD" (for example the winner changed their payout wallet within the cooldown) or PENDING_APPROVAL (over your approval threshold). Neither is an error: the payment exists and executes once released. All codes: Errors.
Bounties
Project approves the bounty → FomoPay resolves the winner's verified identity → the payout executes → the receipt is attached to the bounty. The key is the bounty id, so approving twice can't pay twice.
send is a reward
fomopay.send() — the one-liner — is rewards.create with an idempotency key generated for you, which keeps the SDK's own network retries safe. For exactly-once across restarts and redeploys, pass idempotencyKey yourself.
Paying many people at once? Use bulk payouts: every row is validated first and invalid handles are blocked before anything moves.