Payaider Docs Non-custodial crypto payments API 2026-08-27

API Reference

Every endpoint in the v1 API, generated from the OpenAPI 3.1.0 document.

Payment Intents

get /v1/payment_intents

List payment intents, newest first

Cursor pagination (§7.3): read has_more, then pass the last object’s id as starting_after. Use this to reconcile, never as a substitute for webhooks — polling every intent is how you meet the rate limiter.

response
{
  "object": "list",
  "url": "/v1/payment_intents",
  "has_more": false,
  "data": [
    {
      "id": "pi_7Fk2Qd9RmTs4Vb",
      "object": "payment_intent",
      "mode": "test",
      "status": "confirmed",
      "merchant_id": "mch_3Xn8Kp2Wq5Zt",
      "amount": "10000",
      "currency": "USD",
      "currency_decimals": 2,
      "received_amount": "100043100",
      "metadata": {
        "order_id": "1234"
      },
      "created": "2026-08-27T10:15:00.000Z",
      "expires_at": "2026-08-27T10:30:00.000Z",
      "checkout_url": "https://checkout.payaider.com/c/pi_7Fk2Qd9RmTs4Vb",
      "payment_method": {
        "object": "payment_method",
        "quote_id": "qt_9Tw3Mn8Rp2Yk",
        "token_id": "usdt-tron",
        "network_id": "tron",
        "asset_symbol": "USDT",
        "token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
        "token_decimals": 6,
        "wallet_id": "wal_5Rm2Ht9Jc4Nq",
        "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
        "amount_due": "100043100",
        "rate": "1.000431",
        "rate_sources": [
          {
            "source": "primary_cex",
            "rate": "1.000390"
          },
          {
            "source": "usd_composite_x_fx",
            "rate": "1.000472"
          }
        ],
        "locked_at": "2026-08-27T10:15:00.000Z",
        "expires_at": "2026-08-27T10:30:00.000Z",
        "pay_uri": "tron:TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB?amount=100.0431&token=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
      }
    },
    {
      "id": "pi_7Fk2Qd9RmTs4Vb",
      "object": "payment_intent",
      "mode": "test",
      "status": "awaiting_payment",
      "merchant_id": "mch_3Xn8Kp2Wq5Zt",
      "amount": "10000",
      "currency": "USD",
      "currency_decimals": 2,
      "received_amount": "0",
      "metadata": {
        "order_id": "1234"
      },
      "created": "2026-08-27T10:15:00.000Z",
      "expires_at": "2026-08-27T10:30:00.000Z",
      "checkout_url": "https://checkout.payaider.com/c/pi_7Fk2Qd9RmTs4Vb",
      "payment_method": {
        "object": "payment_method",
        "quote_id": "qt_9Tw3Mn8Rp2Yk",
        "token_id": "usdt-tron",
        "network_id": "tron",
        "asset_symbol": "USDT",
        "token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
        "token_decimals": 6,
        "wallet_id": "wal_5Rm2Ht9Jc4Nq",
        "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
        "amount_due": "100043100",
        "rate": "1.000431",
        "rate_sources": [
          {
            "source": "primary_cex",
            "rate": "1.000390"
          },
          {
            "source": "usd_composite_x_fx",
            "rate": "1.000472"
          }
        ],
        "locked_at": "2026-08-27T10:15:00.000Z",
        "expires_at": "2026-08-27T10:30:00.000Z",
        "pay_uri": "tron:TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB?amount=100.0431&token=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
      }
    }
  ]
}

post /v1/payment_intents

Create a payment intent

Step 1 of the 15-minute integration (§7.4). Price the order in fiat; settlement is crypto, which is exactly why going global is cheap here.

The intent starts in created with no asset chosen and no address to pay. Redirect the customer to checkout_url and let them pick asset and network there — that is what locks a 15-minute quote and reserves the unique amount.

Send an Idempotency-Key: a retried create without one can mint two intents for one order, and a customer who pays both cannot be refunded by anyone, including us.

request
{
  "amount": 10000,
  "currency": "USD",
  "metadata": {
    "order_id": "1234"
  },
  "success_url": "https://shop.example/thanks"
}
response
{
  "id": "pi_7Fk2Qd9RmTs4Vb",
  "object": "payment_intent",
  "mode": "test",
  "status": "created",
  "merchant_id": "mch_3Xn8Kp2Wq5Zt",
  "amount": "10000",
  "currency": "USD",
  "currency_decimals": 2,
  "received_amount": "0",
  "metadata": {
    "order_id": "1234"
  },
  "created": "2026-08-27T10:15:00.000Z",
  "expires_at": null,
  "checkout_url": "https://checkout.payaider.com/c/pi_7Fk2Qd9RmTs4Vb",
  "payment_method": null
}

get /v1/payment_intents/{id}

Retrieve a payment intent

The authoritative status. This is also the recovery path when a webhook is missed: webhook delivery is at-least-once and unordered, so re-polling here is how a consumer resynchronizes (§8).

response
{
  "id": "pi_7Fk2Qd9RmTs4Vb",
  "object": "payment_intent",
  "mode": "test",
  "status": "awaiting_payment",
  "merchant_id": "mch_3Xn8Kp2Wq5Zt",
  "amount": "10000",
  "currency": "USD",
  "currency_decimals": 2,
  "received_amount": "0",
  "metadata": {
    "order_id": "1234"
  },
  "created": "2026-08-27T10:15:00.000Z",
  "expires_at": "2026-08-27T10:30:00.000Z",
  "checkout_url": "https://checkout.payaider.com/c/pi_7Fk2Qd9RmTs4Vb",
  "payment_method": {
    "object": "payment_method",
    "quote_id": "qt_9Tw3Mn8Rp2Yk",
    "token_id": "usdt-tron",
    "network_id": "tron",
    "asset_symbol": "USDT",
    "token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "token_decimals": 6,
    "wallet_id": "wal_5Rm2Ht9Jc4Nq",
    "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
    "amount_due": "100043100",
    "rate": "1.000431",
    "rate_sources": [
      {
        "source": "primary_cex",
        "rate": "1.000390"
      },
      {
        "source": "usd_composite_x_fx",
        "rate": "1.000472"
      }
    ],
    "locked_at": "2026-08-27T10:15:00.000Z",
    "expires_at": "2026-08-27T10:30:00.000Z",
    "pay_uri": "tron:TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB?amount=100.0431&token=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
  }
}

post /v1/payment_intents/{id}/select_method

Choose asset + wallet: locks a 15-minute quote and reserves a unique amount

Moves the intent created → awaiting_payment (§3.2). Three things happen atomically:

  1. An FX quote is locked for 15 minutes from at least two independent sources, with the divergence alarm between the legs (§4.2–§4.3).
  2. A globally unique amount for this (wallet, token) is reserved. Because funds go straight to the merchant’s shared address, the amount is the only on-chain discriminator there is (§5.1); uniqueness is enforced by a database constraint, so concurrent quotes across API instances cannot collide by construction (§5.2).
  3. payment_method is filled in with the address, exact amount, contract and pay URI.

Hosted checkout calls this for you. Call it directly only if you are building your own checkout — and then show the customer the network name, the token contract, the exact amount and the countdown (§6.3).

request
{
  "token_id": "usdt-tron",
  "wallet_id": "wal_5Rm2Ht9Jc4Nq"
}
response
{
  "id": "pi_7Fk2Qd9RmTs4Vb",
  "object": "payment_intent",
  "mode": "test",
  "status": "awaiting_payment",
  "merchant_id": "mch_3Xn8Kp2Wq5Zt",
  "amount": "10000",
  "currency": "USD",
  "currency_decimals": 2,
  "received_amount": "0",
  "metadata": {
    "order_id": "1234"
  },
  "created": "2026-08-27T10:15:00.000Z",
  "expires_at": "2026-08-27T10:30:00.000Z",
  "checkout_url": "https://checkout.payaider.com/c/pi_7Fk2Qd9RmTs4Vb",
  "payment_method": {
    "object": "payment_method",
    "quote_id": "qt_9Tw3Mn8Rp2Yk",
    "token_id": "usdt-tron",
    "network_id": "tron",
    "asset_symbol": "USDT",
    "token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "token_decimals": 6,
    "wallet_id": "wal_5Rm2Ht9Jc4Nq",
    "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
    "amount_due": "100043100",
    "rate": "1.000431",
    "rate_sources": [
      {
        "source": "primary_cex",
        "rate": "1.000390"
      },
      {
        "source": "usd_composite_x_fx",
        "rate": "1.000472"
      }
    ],
    "locked_at": "2026-08-27T10:15:00.000Z",
    "expires_at": "2026-08-27T10:30:00.000Z",
    "pay_uri": "tron:TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB?amount=100.0431&token=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
  }
}

post /v1/payment_intents/{id}/cancel

Cancel a payment intent that has not yet been paid

Allowed from created and awaiting_payment only. There is no edge from detected onwards to canceled (§3.2) — money already on its way must never be cancelled out from under the customer, so that attempt returns 409 invalid_state_transition.

request
{
  "reason": "customer abandoned checkout"
}
response
{
  "id": "pi_7Fk2Qd9RmTs4Vb",
  "object": "payment_intent",
  "mode": "test",
  "status": "canceled",
  "merchant_id": "mch_3Xn8Kp2Wq5Zt",
  "amount": "10000",
  "currency": "USD",
  "currency_decimals": 2,
  "received_amount": "0",
  "metadata": {
    "order_id": "1234"
  },
  "created": "2026-08-27T10:15:00.000Z",
  "expires_at": "2026-08-27T10:30:00.000Z",
  "checkout_url": "https://checkout.payaider.com/c/pi_7Fk2Qd9RmTs4Vb",
  "payment_method": {
    "object": "payment_method",
    "quote_id": "qt_9Tw3Mn8Rp2Yk",
    "token_id": "usdt-tron",
    "network_id": "tron",
    "asset_symbol": "USDT",
    "token_contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "token_decimals": 6,
    "wallet_id": "wal_5Rm2Ht9Jc4Nq",
    "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
    "amount_due": "100043100",
    "rate": "1.000431",
    "rate_sources": [
      {
        "source": "primary_cex",
        "rate": "1.000390"
      },
      {
        "source": "usd_composite_x_fx",
        "rate": "1.000472"
      }
    ],
    "locked_at": "2026-08-27T10:15:00.000Z",
    "expires_at": "2026-08-27T10:30:00.000Z",
    "pay_uri": "tron:TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB?amount=100.0431&token=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"
  }
}

Invoices

get /v1/invoices

List invoices, newest first

Cursor-paginated (§7.3).

response
{
  "object": "list",
  "url": "/v1/invoices",
  "has_more": false,
  "data": [
    {
      "id": "inv_3Bn6Ls9Xd4Kq",
      "object": "invoice",
      "mode": "test",
      "status": "open",
      "number": "SP-2026-000117",
      "customer": {
        "name": "Adaeze Okafor",
        "email": "adaeze@example.com",
        "country": "NG"
      },
      "amount": "4500000",
      "currency": "NGN",
      "currency_decimals": 2,
      "due_date": "2026-09-03T23:59:59.000Z",
      "hosted_invoice_url": "https://pay.payaider.com/invoice/3Bn6Ls9Xd4Kq",
      "payment_intent": "pi_7Fk2Qd9RmTs4Vb",
      "metadata": {
        "po_number": "PO-88214"
      },
      "created": "2026-08-27T08:30:00.000Z"
    }
  ]
}

post /v1/invoices

Create an invoice with customer details and an expiry

An invoice is a payment link with a customer, a number and a due date, rendered as a payable page with QR and countdown (§7.2, Stage 8). The customer’s country gates the page against prohibited jurisdictions (§12).

request
{
  "amount": 4500000,
  "currency": "NGN",
  "customer": {
    "name": "Adaeze Okafor",
    "email": "adaeze@example.com",
    "country": "NG"
  },
  "due_date": "2026-09-03T23:59:59.000Z",
  "metadata": {
    "po_number": "PO-88214"
  }
}
response
{
  "id": "inv_3Bn6Ls9Xd4Kq",
  "object": "invoice",
  "mode": "test",
  "status": "open",
  "number": "SP-2026-000117",
  "customer": {
    "name": "Adaeze Okafor",
    "email": "adaeze@example.com",
    "country": "NG"
  },
  "amount": "4500000",
  "currency": "NGN",
  "currency_decimals": 2,
  "due_date": "2026-09-03T23:59:59.000Z",
  "hosted_invoice_url": "https://pay.payaider.com/invoice/3Bn6Ls9Xd4Kq",
  "payment_intent": "pi_7Fk2Qd9RmTs4Vb",
  "metadata": {
    "po_number": "PO-88214"
  },
  "created": "2026-08-27T08:30:00.000Z"
}

get /v1/invoices/{id}

Retrieve an invoice

Includes the payment intent minted when the customer opened the invoice, if any.

response
{
  "id": "inv_3Bn6Ls9Xd4Kq",
  "object": "invoice",
  "mode": "test",
  "status": "open",
  "number": "SP-2026-000117",
  "customer": {
    "name": "Adaeze Okafor",
    "email": "adaeze@example.com",
    "country": "NG"
  },
  "amount": "4500000",
  "currency": "NGN",
  "currency_decimals": 2,
  "due_date": "2026-09-03T23:59:59.000Z",
  "hosted_invoice_url": "https://pay.payaider.com/invoice/3Bn6Ls9Xd4Kq",
  "payment_intent": "pi_7Fk2Qd9RmTs4Vb",
  "metadata": {
    "po_number": "PO-88214"
  },
  "created": "2026-08-27T08:30:00.000Z"
}

Webhooks

get /v1/webhook_endpoints

List webhook endpoints

The signing secret is never included here — it is revealed once, at creation.

response
{
  "object": "list",
  "url": "/v1/webhook_endpoints",
  "has_more": false,
  "data": [
    {
      "id": "we_6Bd4Lq2Xs7Hf",
      "object": "webhook_endpoint",
      "mode": "test",
      "url": "https://shop.example/webhooks/payaider",
      "description": "Order fulfilment",
      "enabled_events": [
        "*"
      ],
      "api_version": "2026-08-27",
      "status": "enabled",
      "created": "2026-08-27T09:00:00.000Z"
    }
  ]
}

post /v1/webhook_endpoints

Register a webhook endpoint (returns the signing secret once)

Step 3 of the 15-minute integration (§7.4): confirm server-side via webhook, never via success_url alone.

The response carries secret — the whsec_… HMAC key — exactly once. Store it in your secret manager before you close the response: a forged payment.confirmed ships real goods against crypto nobody can claw back, and this signature is your only defence (§8).

"Exactly once" includes idempotent replays. If you send an Idempotency-Key and retry this call, the replay returns the same endpoint object with secret ABSENT: the secret is never written to the 24h replay buffer, which has none of the encryption at rest it is kept under everywhere else (§7.3, §12). A retry that answers Idempotent-Replayed: true is telling you the first call already created the endpoint — if you lost that response, roll the secret rather than registering a second endpoint.

The URL is checked at registration (scheme, embedded credentials, literal private addresses, reserved names) and re-resolved by DNS on every delivery attempt.

request
{
  "url": "https://shop.example/webhooks/payaider",
  "description": "Order fulfilment",
  "enabled_events": [
    "payment.confirmed",
    "payment.underpaid",
    "payment.overpaid"
  ]
}
response
{
  "id": "we_6Bd4Lq2Xs7Hf",
  "object": "webhook_endpoint",
  "mode": "test",
  "url": "https://shop.example/webhooks/payaider",
  "description": "Order fulfilment",
  "enabled_events": [
    "payment.confirmed",
    "payment.underpaid",
    "payment.overpaid"
  ],
  "api_version": "2026-08-27",
  "status": "enabled",
  "created": "2026-08-27T09:00:00.000Z",
  "secret": "whsec_EXAMPLE_NOT_A_REAL_SECRET_00000000"
}

get /v1/webhook_endpoints/{id}/deliveries

List delivery attempts for a webhook endpoint, newest first

Every attempt, with status code, latency and a truncated copy of your response (§8).

Retries follow 1m, 5m, 30m, 2h, 6h, 12h, 24h — eight attempts over about three days. Only a 2xx counts as delivered: a redirect is a failure, as are 4xx, 5xx, TLS errors and timeouts. After sustained failure the endpoint is disabled and you are emailed, and the events stay queryable.

response
{
  "object": "list",
  "url": "/v1/webhook_endpoints/we_6Bd4Lq2Xs7Hf/deliveries",
  "has_more": false,
  "data": [
    {
      "id": "whd_4Kq7Bn2Ls9Xd",
      "object": "webhook_delivery_attempt",
      "delivery_id": "whdl_8Vp3Hf5Jc1Wg",
      "endpoint_id": "we_6Bd4Lq2Xs7Hf",
      "event_id": "evt_2Ay0Zt7Rm9Kq",
      "event_type": "payment.confirmed",
      "attempt": 2,
      "url": "https://shop.example/webhooks/payaider",
      "status_code": 200,
      "outcome": "delivered",
      "latency_ms": 143,
      "response_body": "ok",
      "error": null,
      "requested_at": "2026-08-27T10:36:00.000Z",
      "next_retry_at": null
    },
    {
      "id": "whd_1Ls9Xd4Kq7Bn",
      "object": "webhook_delivery_attempt",
      "delivery_id": "whdl_8Vp3Hf5Jc1Wg",
      "endpoint_id": "we_6Bd4Lq2Xs7Hf",
      "event_id": "evt_2Ay0Zt7Rm9Kq",
      "event_type": "payment.confirmed",
      "attempt": 1,
      "url": "https://shop.example/webhooks/payaider",
      "status_code": 502,
      "outcome": "failed",
      "latency_ms": 10000,
      "response_body": "",
      "error": "upstream timeout after 10000ms",
      "requested_at": "2026-08-27T10:35:00.000Z",
      "next_retry_at": "2026-08-27T10:36:00.000Z"
    }
  ]
}

post /v1/webhook_endpoints/{id}/deliveries/{delivery_id}/redeliver

Redeliver one event to one endpoint

Queues an immediate extra attempt. It never cancels the automatic retry schedule (§8), so a redelivery and a scheduled retry can both arrive — which is fine, because your consumer dedupes on event.id.

response
{
  "id": "whd_7Bn2Ls9Xd4Kq",
  "object": "webhook_delivery_attempt",
  "delivery_id": "whdl_8Vp3Hf5Jc1Wg",
  "endpoint_id": "we_6Bd4Lq2Xs7Hf",
  "event_id": "evt_2Ay0Zt7Rm9Kq",
  "event_type": "payment.confirmed",
  "attempt": 3,
  "url": "https://shop.example/webhooks/payaider",
  "status_code": null,
  "outcome": "failed",
  "latency_ms": 0,
  "response_body": "",
  "error": null,
  "requested_at": "2026-08-27T11:02:00.000Z",
  "next_retry_at": null
}

Wallets

get /v1/wallets

List your receiving wallets

Your own addresses. Payaider holds no key for any of them and cannot move a single token out (§0, §12) — which is the product, and also why verification is strict.

response
{
  "object": "list",
  "url": "/v1/wallets",
  "has_more": false,
  "data": [
    {
      "id": "wal_5Rm2Ht9Jc4Nq",
      "object": "wallet",
      "mode": "test",
      "network_id": "tron",
      "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
      "label": "Treasury (TRON)",
      "status": "verified",
      "verification_method": "signed_message",
      "verified_at": "2026-08-20T14:02:00.000Z",
      "is_exchange_hosted": false,
      "created": "2026-08-20T13:58:00.000Z"
    },
    {
      "id": "wal_8Hf5Jc1Wg0Ay",
      "object": "wallet",
      "mode": "test",
      "network_id": "base",
      "address": "0x9f2c4a1d7b83e6045c1a2b9d8e7f6a5b4c3d2e1f",
      "label": "Ops (Base)",
      "status": "verified",
      "verification_method": "signed_message",
      "verified_at": "2026-08-21T09:41:00.000Z",
      "is_exchange_hosted": false,
      "created": "2026-08-21T09:37:00.000Z"
    }
  ]
}

post /v1/wallets

Add a receiving wallet (starts unverified)

The wallet lands in pending and receives no quotes until it is verified (§6.2).

Exchange deposit addresses are rejected (decision D10). You cannot sign for one, and decisively: a customer paying from the *same* exchange settles as an off-chain internal ledger transfer with no on-chain transaction at all — invisible to every watcher. You would be credited on the exchange while the invoice expired unpaid.

request
{
  "network_id": "tron",
  "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
  "label": "Treasury (TRON)",
  "controls_private_key": true
}
response
{
  "id": "wal_5Rm2Ht9Jc4Nq",
  "object": "wallet",
  "mode": "test",
  "network_id": "tron",
  "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
  "label": "Treasury (TRON)",
  "status": "pending",
  "verification_method": null,
  "verified_at": null,
  "is_exchange_hosted": false,
  "created": "2026-08-20T13:58:00.000Z"
}

post /v1/wallets/{id}/verify

Prove control of a wallet address

Two accepted proofs (§6.2):

  • signed_message — sign the challenge issued for this wallet with the address (WalletConnect or a manual signature; TIP-191-style on TRON).
  • micro_deposit — send an exact randomized micro-amount from the claimed address to the Payaider verification address within its TTL; the match is on the sender.

This is a high-risk action: MFA re-prompt, audit event and an email notification (§12).

request
{
  "method": "signed_message",
  "signature": "0x7f3c2a1b9d8e6f504132a5b6c7d8e9f0a1b2c3d4e5f60718293a4b5c6d7e8f901"
}
response
{
  "id": "wal_5Rm2Ht9Jc4Nq",
  "object": "wallet",
  "mode": "test",
  "network_id": "tron",
  "address": "TAF2p47aRXHmN2WwBumwgR2yf2j27HeqbB",
  "label": "Treasury (TRON)",
  "status": "verified",
  "verification_method": "signed_message",
  "verified_at": "2026-08-20T14:02:00.000Z",
  "is_exchange_hosted": false,
  "created": "2026-08-20T13:58:00.000Z"
}

Routes

get /v1/routes

List (asset, network) → wallet routes

At most one active route per (asset, network), enforced by a database constraint (§6.1).

response
{
  "object": "list",
  "url": "/v1/routes",
  "has_more": false,
  "data": [
    {
      "id": "rt_2Qd9RmTs4Vb7",
      "object": "route",
      "asset_symbol": "USDT",
      "network_id": "tron",
      "token_id": "usdt-tron",
      "wallet_id": "wal_5Rm2Ht9Jc4Nq",
      "active": true,
      "created": "2026-08-20T14:05:00.000Z"
    }
  ]
}

put /v1/routes

Set where money for each (asset, network) lands

A high-risk action (§6.1): MFA re-prompt, audit event, email notification, and a cool-down before new routes receive quotes.

That cool-down exists because re-routing is what an account takeover is *for*. Without it, one stolen session silently redirects every future payment; with it, you get an email and a window to act.

request
{
  "routes": [
    {
      "asset_symbol": "USDT",
      "network_id": "tron",
      "wallet_id": "wal_5Rm2Ht9Jc4Nq"
    },
    {
      "asset_symbol": "USDC",
      "network_id": "base",
      "wallet_id": "wal_8Hf5Jc1Wg0Ay"
    }
  ]
}
response
{
  "object": "list",
  "url": "/v1/routes",
  "has_more": false,
  "data": [
    {
      "id": "rt_2Qd9RmTs4Vb7",
      "object": "route",
      "asset_symbol": "USDT",
      "network_id": "tron",
      "token_id": "usdt-tron",
      "wallet_id": "wal_5Rm2Ht9Jc4Nq",
      "active": true,
      "created": "2026-08-20T14:05:00.000Z"
    },
    {
      "id": "rt_9RmTs4Vb7Qd2",
      "object": "route",
      "asset_symbol": "USDC",
      "network_id": "base",
      "token_id": "usdc-base",
      "wallet_id": "wal_8Hf5Jc1Wg0Ay",
      "active": true,
      "created": "2026-08-20T14:05:00.000Z"
    }
  ]
}

Exchange Rates

get /v1/exchange_rates

Indicative rates for a currency

Display and estimation only. The rate that binds a payment is the one locked on its quote for 15 minutes (§4.3), together with the source observations it was derived from — that quote row is the evidence produced in every support dispute (§4.4).

Currencies whose official and parallel FX rates diverge are quoted from crypto-market-native sources, not from an official peg (§4.2).

response
{
  "object": "list",
  "url": "/v1/exchange_rates?currency=USD",
  "has_more": false,
  "data": [
    {
      "object": "exchange_rate",
      "asset_symbol": "USDT",
      "currency": "USD",
      "rate": "1.000431",
      "sources": [
        {
          "source": "primary_cex",
          "rate": "1.000390"
        },
        {
          "source": "usd_composite_x_fx",
          "rate": "1.000472"
        }
      ],
      "fetched_at": "2026-08-27T10:14:52.000Z"
    },
    {
      "object": "exchange_rate",
      "asset_symbol": "USDC",
      "currency": "USD",
      "rate": "0.999870",
      "sources": [
        {
          "source": "primary_cex",
          "rate": "0.999910"
        },
        {
          "source": "usd_composite_x_fx",
          "rate": "0.999830"
        }
      ],
      "fetched_at": "2026-08-27T10:14:52.000Z"
    }
  ]
}

Health

get /healthz

Liveness probe (public)

Unauthenticated and deliberately shallow: it proves this process is serving and nothing else. A health check that queries the database turns one slow query into a fleet-wide outage as every load balancer pulls every instance at once.

response
{
  "object": "health",
  "status": "ok",
  "service": "payaider-api",
  "api_version": "2026-08-27",
  "time": "2026-08-27T10:15:00.000Z"
}