Create, fetch, list and cancel invoices — full field reference, statuses, and lifecycle.

Invoices

An invoice is a single payment request. You create it with a USD amount and a network; recv converts the price to the on-chain payable_amount, assigns one of your payout wallets as the destination_address, and tracks the payment until it settles.

All endpoints below live under https://recv.money/v1 and require an API key.

Create an invoice

POST /v1/invoices        (scope: invoices:write)

Request body

FieldTypeRequiredDescription
titlestringYesLabel shown on checkout (e.g. "Order #9841"). Must be non-empty.
base_amount_usdstringYesAmount in USD as a decimal string (e.g. "149.00"). Must be positive.
payable_networkstringYes unless payment_options is usedLegacy single-option network.
payable_assetstringNoAsset for legacy single-option requests. Defaults from the network.
payment_optionsarrayNoMultiple { "network": "...", "asset": "..." } options, for example USDT and SOL on one invoice.
expires_in_minutesintegerNoPayment window in minutes. Defaults to 30 for stablecoins and 10 when any native volatile asset is present. Native volatile invoices reject values above 15.

The invoice environment (test/live) is inherited from the API key — there is no mode field in the body.

Headers

HeaderPurpose
Content-Type: application/jsonRequired.
Idempotency-KeyOptional. Makes the create call safe to retry — see Idempotency.

Example (curl)

curl -X POST https://recv.money/v1/invoices \
  -H "X-API-Key: $RECV_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-9841" \
  -d '{
    "title": "Premium Subscription",
    "base_amount_usd": "100.00",
    "payment_options": [
      { "network": "TRON", "asset": "USDT" },
      { "network": "SOLANA", "asset": "SOL" }
    ]
  }'

Example (Python)

import requests

resp = requests.post(
    "https://recv.money/v1/invoices",
    headers={"X-API-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
    json={
        "title": "Premium Subscription",
        "base_amount_usd": "100.00",
        "payment_options": [
            {"network": "TRON", "asset": "USDT"},
            {"network": "SOLANA", "asset": "SOL"},
        ],
    },
)
invoice = resp.json()
print("Checkout:", "https://recv.money" + invoice["checkout_url"])

Invoice object

A 201/200 response returns the invoice object:

{
  "id": 482,
  "public_id": "pub_abcdef123",
  "title": "Premium Subscription",
  "kind": "merchant",
  "subscription_days": 0,
  "plan_code": "developer",
  "checkout_badge": "Merchant Checkout",
  "base_amount_usd": "100.00",
  "payable_amount": "100.000000",
  "payable_network": "TRON",
  "payable_asset": "USDT",
  "payment_options": [
    {
      "network": "TRON",
      "asset": "USDT",
      "payable_amount": "100.000123",
      "destination_address": "TQDt...",
      "payment_comment": "",
      "payment_uri": "TQDt...",
      "is_default": true
    },
    {
      "network": "SOLANA",
      "asset": "SOL",
      "payable_amount": "0.684211",
      "destination_address": "9x...",
      "payment_comment": "",
      "payment_uri": "9x...",
      "is_default": false
    }
  ],
  "destination_address": "EQC...",
  "payment_comment": "",
  "status": "awaiting_payment",
  "environment": "live",
  "mode": "live",
  "expires_at": "2026-05-31T22:00:00Z",
  "created_at": "2026-05-31T21:00:00Z",
  "tx_hash": null,
  "received_amount": "0.000000",
  "review_reason": null,
  "finalized_at": null,
  "checkout_url": "/app/checkout/pub_abcdef123",
  "payment_uri": "ton://transfer/EQC...?amount=100000000000&text="
}

Field reference

FieldTypeDescription
idintegerNumeric invoice ID. Use this in the path of get/cancel/simulate calls.
public_idstringPublic identifier used in the checkout URL.
titlestringThe title you supplied.
kindstringmerchant for API-created invoices; subscription for recv plan billing.
subscription_daysintegerDays granted by a subscription invoice; 0 for merchant invoices.
plan_codestringPlan associated with the invoice.
checkout_badgestringBadge text shown on the hosted checkout.
base_amount_usdstringUSD price, 2 decimals.
payable_amountstringOn-chain amount to pay, 6 decimals.
payable_networkstringNetwork the customer pays on.
payable_assetstringAsset for the legacy/default payment option.
payment_optionsarrayAll payment choices available on the hosted checkout.
destination_addressstringYour payout wallet that must receive the payment.
payment_commentstringMemo/comment required by some networks (empty string if none).
statusstringCurrent status — see Statuses.
environment / modestringtest or live. Both fields carry the same value.
expires_attimestampWhen the payment window closes (RFC 3339).
created_attimestampCreation time.
tx_hashstring | nullMatching transaction hash once observed.
received_amountstringTotal received so far, 6 decimals.
review_reasonstring | nullWhy the invoice is in manual_review, when applicable.
finalized_attimestamp | nullWhen the invoice reached a terminal state.
checkout_urlstringRelative hosted-checkout path: https://recv.money{checkout_url}.
payment_uristringDeep-link / address for the customer's wallet. For TON, a ton://transfer/... URI with amount in nanotons; for other networks, the destination address.

Statuses

StatusMeaning
draftCreated but not yet active.
awaiting_paymentOpen and waiting for payment.
paidThe expected amount was received and confirmed.
expiredThe payment window closed before payment (also the state set when you cancel).
underpaidA transfer arrived but was less than payable_amount.
overpaidA transfer exceeded payable_amount.
manual_reviewNeeds merchant confirmation — e.g. a payment arrived after expiry, or an overpayment.

A read of an invoice whose window has elapsed while still awaiting_payment is reported as expired.

Get an invoice

GET /v1/invoices/:id     (scope: invoices:read)
curl https://recv.money/v1/invoices/482 -H "X-API-Key: $RECV_API_KEY"

Returns the invoice object above, or 404 if it does not belong to your workspace.

List invoices

GET /v1/invoices         (scope: invoices:read)
Query paramDefaultNotes
page11-based page number.
page_size20Clamped to 1–100; out-of-range values reset to 20.
curl "https://recv.money/v1/invoices?page=1&page_size=50" \
  -H "X-API-Key: $RECV_API_KEY"
{ "items": [ /* invoices */ ], "total": 134, "page": 1, "page_size": 50 }

Cancel an invoice

POST /v1/invoices/:id/cancel     (scope: invoices:write)

Cancelling sets the invoice to expired. Only workspace-created merchant invoices can be cancelled; subscription/plan invoices cannot (400).

curl -X POST https://recv.money/v1/invoices/482/cancel \
  -H "X-API-Key: $RECV_API_KEY"

Simulating payments (test mode)

POST /v1/test/invoices/:id/simulate-payment     (scope: invoices:write)

Marks a test invoice as paid and fires webhooks, without any on-chain transfer. Requires an test_ key and a test invoice; otherwise returns 403/400.

curl -X POST https://recv.money/v1/test/invoices/482/simulate-payment \
  -H "X-API-Key: $RECV_API_KEY"

Idempotency

POST /v1/invoices accepts an Idempotency-Key header. recv stores the result against the key + request body hash:

  • Same key, same body → returns the original stored response.
  • Same key, different body409 Conflict.
  • Same key, original still processing409 Conflict.

Use a stable key per logical order (e.g. your order ID) so network retries never create duplicate invoices.

Example (Go)

req, _ := http.NewRequest("GET", "https://recv.money/v1/invoices/"+id, nil)
req.Header.Set("X-API-Key", apiKey)

resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()

var invoice map[string]any
json.NewDecoder(resp.Body).Decode(&invoice)
fmt.Println("Status:", invoice["status"])

Ready to accept crypto payments?