LIVE · STATUS
USDC/USD 1.0000 GATEWAY ▲ ONLINE PAYOUTS ▲ INSTANT ONBOARDING ▲ INSTANT NETWORKS POLYGON · ETH · BSC · TRC20 CARDS ▲ VISA · MC · AMEX USDC/USD 1.0000 GATEWAY ▲ ONLINE PAYOUTS ▲ INSTANT ONBOARDING ▲ INSTANT NETWORKS POLYGON · ETH · BSC · TRC20 CARDS ▲ VISA · MC · AMEX
Instant onboarding · Register your business in under a minute · Instant USDC settlement · All legal high-risk verticals welcome — see our Acceptable Use Policy.
NO API KEY REQUIRED REST · GET · JSON USDC PAYOUTS

API Documentation.

Integrate the Risksless card and crypto gateway into any stack — PHP, Node, Python, Go, mobile, no-code. The whole card flow is two GET requests: mint a tracking address bound to your USDC payout wallet, then send the customer to the hosted checkout. When the customer pays, we GET your callback URL with the settlement details and the USDC lands in your wallet.

Everything on one screen.

Base URLs, authentication and every endpoint. Each row links to its full section below.

Base URLs: https://api.risksless.com for all API calls (returns JSON, sends CORS headers, so it can be called from a browser or a server) · https://checkout.risksless.com for the hosted checkout pages your customer is redirected to.
Authentication: none today. There is no API key, no signup form and no secret to store. Your identity is the USDC Polygon wallet address you pass as address — settlements go there and nowhere else. All endpoints are plain HTTP GET with query-string parameters and JSON responses. Per-merchant API keys may be introduced later; if that happens the current endpoints will keep working and this page will be updated first.
ENDPOINTPURPOSESECTION
GET /control/wallet.phpMint a card tracking address (address_in) bound to your payout wallet and callback URL.02 · Card gateway
GET checkout.risksless.com/pay.phpHosted multi-provider checkout page. Recommended redirect target.02 · Card gateway
GET checkout.risksless.com/process-payment.phpDirect checkout on one named provider (provider=stripe etc.).02 · Card gateway
GET /control/provider-status/Live list of card providers, their status and minimum amount.03 · Provider status
GET /control/convert.phpConvert an amount in EUR, CAD, INR, GBP… to its USD value.04 · Currency conversion
GET {your callback URL}We call you on settlement with value_coin, txid_out and more.05 · Callbacks
GET /crypto/{ticker}/wallet.phpMint a one-time crypto receiving address that forwards to your wallet.06 · Crypto gateway
GET /crypto/{ticker}/convert.phpFiat amount → coin amount for a ticker.06 · Crypto gateway
GET /crypto/{ticker}/qrcode.phpBase64 PNG QR code for a receiving address.06 · Crypto gateway
GET /crypto/{ticker}/info.phpTicker metadata, minimum and live USD price.06 · Crypto gateway

Four steps, every time.

The Payment Link Generator, the PHP SDK and all 19 official plugins do exactly this. If your integration does the same four things, it works.

┌ YOUR SERVER ───────────────────────────────────────────────────────────────┐
│ 1. GET api.risksless.com/control/wallet.php?address={your wallet}&callback={url}
│    → { "address_in": "…" }        # a fresh tracking address for THIS order
│    Persist address_in with the order.
│
│ 2. Redirect the customer to
│    checkout.risksless.com/pay.php?address={address_in}&amount=99.00&currency=USD&email=…
└────────────────────────────────────────────────────────────────────────────┘
┌ CUSTOMER ──────────────────────────────────────────────────────────────────┐
│ 3. Pays with Visa / Mastercard / Amex / Apple Pay / Google Pay / SEPA / UPI…
│    on the hosted page. The provider settles USDC to address_in, which
│    forwards it on-chain to your wallet.
└────────────────────────────────────────────────────────────────────────────┘
┌ RISKSLESS → YOUR SERVER ───────────────────────────────────────────────────┐
│ 4. GET {your callback url}&address_in=…&value_coin=96.53&coin=usdc&txid_out=0x…
│    Verify, mark the order paid, reply 200 "OK".
└────────────────────────────────────────────────────────────────────────────┘

Build a checkout URL.

Card checkouts are a two-step flow. First generate a tracking address bound to your payout wallet, then send the customer to the hosted checkout URL.

Step 1 — Generate a tracking address

GEThttps://api.risksless.com/control/wallet.php
  ?address=0xYourPolygonWalletAddress
  &callback=https%3A%2F%2Fyoursite.com%2Fwebhook%3Forder%3D42%26token%3Dk3Jd9s
PARAMETERREQUIREDDESCRIPTION
addressYesYour merchant USDC wallet on Polygon: 0x followed by 40 hex characters. Must be a self-custodial wallet (MetaMask, Trust Wallet, Rabby, Ledger…). Do not use an exchange deposit address (exchanges freeze gateway payouts) and do not paste the USDC token contract address. All settlements for this address_in are forwarded here.
callbackYesAbsolute, publicly reachable HTTPS URL, URL-encoded exactly once. We GET it when the payment settles. Put your order ID and an unguessable per-order token in its query string — everything you include is echoed back on the callback so you can correlate and authenticate it.

Response

{
  "address_in": "0x8f2a91c84e3d…",          # tracking address — use this as `address` in step 2
  "polygon_address_in": "0x8f2a91c84e3d…",  # plain Polygon form of the tracking address (for receipts / explorer lookups)
  "callback_url": "https://yoursite.com/webhook?order=42&token=k3Jd9s",
  "ipn_token": "…"                          # reserved; safe to ignore
}
FIELDDESCRIPTION
address_inThe value you pass to the checkout page. Treat it as an opaque, already URL-safe string. On white-label deployments it is an encrypted token rather than a bare 0x address and may contain %2F / %3D. Store it verbatim.
polygon_address_inThe underlying Polygon tracking address. Useful as a human-readable payment reference and for looking the order up on Polygonscan. On non-white-label deployments it is identical to address_in.
callback_urlEcho of the decoded callback URL. Check it matches — if it is truncated, you did not URL-encode the callback parameter.
ipn_tokenReserved token; safe to ignore.
If the response has no address_in, the request was rejected. The two causes we see: address is not a valid 0x… Polygon address, or callback is missing / not an absolute URL. Fix and retry — do not redirect the customer without an address_in.

Step 2 — Redirect the customer to checkout

Two checkout pages exist on checkout.risksless.com. /pay.php is the hosted multi-provider page: it geo-detects the customer and lets them pick the best provider for their country. /process-payment.php skips the picker and opens one named provider directly. Use /pay.php unless you have a reason not to.

Option A — Hosted checkout (recommended)

GEThttps://checkout.risksless.com/pay.php
  ?address=0x8f2a91c84e3d…           # address_in from step 1, embedded RAW (see warning below)
  &amount=99.00
  &currency=USD
  &email=customer%40example.com
  &logo=https%3A%2F%2Fyoursite.com%2Flogo.png  # optional branding, see table

Option B — Direct to one provider

GEThttps://checkout.risksless.com/process-payment.php
  ?address=0x8f2a91c84e3d…
  &amount=99.00
  &provider=stripe
  &currency=USD
  &email=customer%40example.com
PARAMETERREQUIREDDESCRIPTION
addressYesThe address_in from step 1 — not your main wallet. Concatenate it into the URL as-is; do not URL-encode it again.
amountYesAmount to charge in currency, as a decimal with up to two places (99.00). No thousands separators, no currency symbol. Must meet the provider minimum (see Provider status).
currencyYesUpper-case ISO 4217 code. USD, EUR, CAD and INR are exposed in the Payment Link Generator; the official plugins pass the store currency through and any currency that /control/convert.php can convert is accepted. Several providers are currency-locked — see the table below.
provider/process-payment.php: Yes
/pay.php: No
Provider id as returned by /control/provider-status/. On /pay.php it may be omitted or set to hosted.
emailNoCustomer email, URL-encoded. Pre-fills the checkout and is used for the receipt. If omitted the checkout page asks for it.
logoNo/pay.php only. URL-encoded absolute URL of your logo, shown at the top of the hosted page.
backgroundNo/pay.php only. Hex colour for the page background (URL-encode the #, e.g. %23111111).
themeNo/pay.php only. Hex colour for the page accent colour.
buttonNo/pay.php only. Hex colour for the pay button.
Do not re-encode address_in. It comes back from wallet.php already URL-safe. On white-label deployments it is an encrypted token containing %2F and %3D; passing it through encodeURIComponent, URLSearchParams, urlencode(), http_build_query() or urllib.parse.urlencode() turns those into %252F / %253D and the checkout silently fails the moment the customer picks a provider. Build the URL by string concatenation and encode only the other parameters. This single mistake is the most common reason an integration "loads the page but never completes".

Provider ids, currency locks and minimums

/control/provider-status/ is authoritative for what is active right now and for the minimum amount. The table below lists every id the platform knows, plus the locks and minimums that the official plugins enforce before redirecting, so you can validate on your side and show a helpful error instead of a failed checkout.

PROVIDER IDCURRENCYMINIMUMNOTES
hostedAny supported1 (client-side)Recommended. Multi-provider page with geo-routing. Use /pay.php. Not listed in provider-status; it always exists.
stripeUSD only2 USDCards, Apple Pay, Google Pay.
revolutAny supported6 EURGood for UK / EU customers.
paypalUSD only5 USD
rampnetworkUSD only4 USD
robinhoodUSD only5 USDUS customers.
bitnovoUSD only10 USD
binanceAny supported15 USD
transfiUSD only70 USDAPAC coverage.
wertUSD onlysee provider-statusHigher approval rates for crypto-native merchants.
upiINR only1600 INRIndia — UPI rails.
interacCAD only100 CADCanada — Interac e-Transfer.
idealEUR only46 EURNetherlands — iDEAL.
klarnaSEK125 SEKKlarna.
transak, moonpay, banxa, utorg, sardine, topper, simplex, mercuryo, alchemypayAny supportedsee provider-statusOn-ramp providers. Availability varies by customer country and by day — alchemypay, for example, is currently reported as unstable, so always check status.
customprovider——Placeholder for a provider tag assigned to your account by Risksless. Only use the exact tag you were given.

Each minimum is in the provider's own currency, exactly as minimum_amount / minimum_currency report it. Where this table shows a value the official plugins enforce, the live value from provider-status still wins if it differs. When a provider is missing from provider-status or has a status other than active, do not route to it — fall back to hosted, which is a client-side choice and never appears in that response.

Code examples

JavaScript (browser or Node 18+)

// 1. Mint the tracking address (works client-side thanks to CORS, but do it
//    server-side if you need to trust the amount).
const wallet   = '0xYourPolygonWallet';
const callback = encodeURIComponent('https://yoursite.com/webhook?order=42&token=k3Jd9s');
const res = await fetch(
  `https://api.risksless.com/control/wallet.php?address=${wallet}&callback=${callback}`
);
const { address_in } = await res.json();
if (!address_in) throw new Error('wallet.php returned no address_in');
// persist (orderId, address_in) here

// 2. Redirect — address_in RAW, everything else encoded.
const amount = (99).toFixed(2);   // "99.00"
const email  = encodeURIComponent('customer@example.com');
window.location.href =
  `https://checkout.risksless.com/pay.php?address=${address_in}` +
  `&amount=${amount}&currency=USD&email=${email}`;

Python (requests)

import requests
from urllib.parse import quote

WALLET   = "0xYourPolygonWallet"
callback = "https://yoursite.com/webhook?order=42&token=k3Jd9s"

r = requests.get(
    "https://api.risksless.com/control/wallet.php",
    params={"address": WALLET, "callback": callback},  # requests encodes these once — correct
    timeout=15,
)
address_in = r.json()["address_in"]

# Concatenate: address_in raw, email encoded.
checkout_url = (
    "https://checkout.risksless.com/pay.php"
    f"?address={address_in}&amount={99:.2f}&currency=USD"
    f"&email={quote('customer@example.com')}"
)
# redirect the customer to checkout_url

cURL

# --data-urlencode encodes the callback exactly once
curl -G "https://api.risksless.com/control/wallet.php" \
  --data-urlencode "address=0xYourPolygonWallet" \
  --data-urlencode "callback=https://yoursite.com/webhook?order=42&token=k3Jd9s"

# → {"address_in":"0x8f2a…","polygon_address_in":"0x8f2a…","callback_url":"https://yoursite.com/webhook?order=42&token=k3Jd9s","ipn_token":"…"}

# Then send the customer to:
# https://checkout.risksless.com/pay.php?address=0x8f2a…&amount=99.00&currency=USD&email=customer%40example.com

PHP developers: use the single-file PHP SDK, which wraps both steps and the callback verification.

List active card providers.

Returns every routing provider, its status, display name and minimum amount. Query it when you render a provider picker, or once at checkout to validate the amount before redirecting.

GEThttps://api.risksless.com/control/provider-status/
# Response
{
  "providers": [
    { "id": "stripe",     "provider_name": "Stripe",     "status": "active",   "minimum_amount": 2,    "minimum_currency": "USD" },
    { "id": "paypal",     "provider_name": "PayPal",     "status": "active",   "minimum_amount": 5,    "minimum_currency": "USD" },
    { "id": "revolut",    "provider_name": "Revolut",    "status": "active",   "minimum_amount": 6,    "minimum_currency": "EUR" },
    { "id": "upi",        "provider_name": "UPI",        "status": "active",   "minimum_amount": 1600, "minimum_currency": "INR" },
    { "id": "alchemypay", "provider_name": "Alchemy Pay", "status": "unstable", "minimum_amount": …,    "minimum_currency": "USD" },  # not "active" → do not route to it
    …
  ]
}
FIELDTYPEDESCRIPTION
idstringThe value to pass as provider on the checkout URL.
provider_namestringHuman-readable label for your UI.
statusstringactive means routable. Skip any other value (for example unstable).
minimum_amountnumberMinimum charge for this provider, in the provider's own currency (minimum_currency), not in USD. Treat a missing value as 1.
minimum_currencystringISO code the minimum is expressed in: USD, EUR, SEK, INR or CAD. Live examples: revolut 6 EUR, ideal 46 EUR, klarna 125 SEK, upi 1600 INR, interac 100 CAD. Convert with /control/convert.php if you need to compare against a USD order.

The Payment Link Generator uses this exact response to build its dropdown: it keeps only status === "active", shows each provider_name with its minimum_amount, and refuses to build a link below the minimum. When you display the minimum, print it with minimum_currency rather than assuming dollars. Note that hosted is not an entry in this response — it is a client-side option that always exists (it is the multi-provider /pay.php page), which is why the generator can fall back to it when this request fails. Do the same.

Non-USD orders to USD.

Settlement is always USDC, so an order in EUR, CAD, INR or GBP has to be compared against its USD value when the callback arrives. This endpoint gives you that value. Every official plugin calls it for non-USD stores.

GEThttps://api.risksless.com/control/convert.php
  ?from=eur          # source currency, lower-case ISO code
  &value=99.00       # amount in that currency
# Response (99.00 EUR)
{ "status": "success", "value_coin": "112.42", "exchange_rate": "1.13554" }
FIELDTYPEDESCRIPTION
statusstringsuccess when the conversion was performed. Treat anything else as a failure.
value_coinstringThe USD value of value at the current rate, as a decimal string. Parse it as a float.
exchange_ratestringUSD per one unit of from (value_coin = value × exchange_rate). Store it if you want to reproduce the conversion later.

Get notified on settlement.

The callback URL you passed to /control/wallet.php (or to any /crypto/{ticker}/wallet.php) is requested by HTTP GET when the matching address_in receives funds and the required confirmations clear. This is the authoritative signal that a payment settled — tracking is event-driven, not poll-based.

Payload

# Your own query parameters come first, exactly as you passed them:
GET https://yoursite.com/webhook?order=42&token=k3Jd9s
  &address_in=0x8f2a91c84e3d…    # the tracking address that was paid
  &value_coin=96.53            # amount forwarded, in units of `coin` (net of provider fees)
  &coin=usdc                   # what was delivered — see the coin table
  &txid_in=0x9af2c1…           # provider → address_in
  &txid_out=0xbc77d2…          # address_in → your wallet (the payout tx; show it on receipts)
  &confirmations=3
PARAMETERDESCRIPTION
(yours)Every query parameter in the callback URL you registered, unchanged. Use them for the order ID and the auth token.
address_inTracking address that received the payment. Matches what you stored from step 1 (for white-label tokens compare polygon_address_in).
value_coinDecimal amount forwarded to you, in units of coin. This is net of provider fees, so it is usually a few percent below the amount you charged.
coinAsset delivered. Normally usdc (Polygon). Can be another stablecoin or a native coin — see below.
txid_in / txid_outOn-chain transaction hashes. txid_out is the transfer into your wallet; store it as the payment reference.
confirmationsBlock confirmations at the time of the callback.

Which coin can arrive

Payouts default to USDC on Polygon, but depending on the provider a payout may be delivered as USDT, POL (Polygon native), ETH or BNB — the same self-custodial wallet address receives all of them. Your callback handler must handle coin:

coin VALUEMEANINGHOW TO GET THE USD VALUE
usdcUSDC on Polygon (default)value_coin is already ≈ USD.
other stablecoins (USDT / USDC on Polygon or BEP-20)Stablecoin payoutvalue_coin is already ≈ USD.
polygon_polPOL, Polygon nativevalue_coin × prices.USD, where prices.USD comes from GET /crypto/{ticker}/info.php and {ticker} is the coin value with _ replaced by / (polygon_pol → polygon/pol, bep20_bnb → bep20/bnb, eth → eth).
ethEther, Ethereum mainnet
bep20_bnbBNB, BNB Chain

Verifying the amount

Because value_coin is net of fees, an exact comparison against the order total will reject every legitimate payment. All official plugins use a tolerance threshold: accept when value_usd ≥ threshold × expected_usd. The plugins default to 0.60 (accept ≥ 60%), which tolerates the highest provider fees while still catching a customer who edited the amount on the checkout page. Tighten it (0.90) if all your traffic goes through low-fee providers.

// Node / Express — full callback handler
app.get('/webhook', async (req, res) => {
  const { order, token, address_in, value_coin, coin, txid_out } = req.query;

  const o = await db.orders.findOne({ id: order });
  if (!o || o.callback_token !== token)      return res.status(403).send('bad token');
  if (o.address_in !== address_in)          return res.status(400).send('wrong address_in');
  if (o.status === 'paid')                  return res.send('OK');   // idempotent

  // value_coin → USD
  let valueUsd = parseFloat(value_coin);
  if (['polygon_pol', 'eth', 'bep20_bnb'].includes(coin)) {
    const info = await fetch(`https://api.risksless.com/crypto/${coin.replace('_', '/')}/info.php`).then(r => r.json());
    valueUsd = valueUsd * parseFloat(info.prices.USD);
  }

  // o.expected_usd was stored at order creation (via /control/convert.php for non-USD)
  if (valueUsd < 0.6 * o.expected_usd) {
    await db.orders.update(o.id, { status: 'failed', note: `underpaid ${valueUsd} / ${o.expected_usd}` });
    return res.status(200).send('underpaid');  // 200: we handled it, don't retry
  }

  await db.orders.update(o.id, { status: 'paid', txid: txid_out, paid_usd: valueUsd });
  res.status(200).send('OK');
});

Securing the callback

The callback is an unauthenticated GET. Anyone who learns the URL can request it, so never mark an order paid on the strength of the URL alone. Do all of the following — it is what the official plugins do:

Responding

No callback server? Every payout is a public on-chain transfer to your wallet. The tracker opens your wallet on the right block explorer, and the Payment Link Generator uses a throw-away callback for exactly this reason.

Generate a receiving address.

Accept crypto directly. Mint a one-time address that forwards any incoming funds to your destination wallet and fires the same callback as the card flow. Every endpoint is namespaced by ticker (polygon/usdc, trc20/usdt, btc, sol/usdc…).

Mint a receiving address

GEThttps://api.risksless.com/crypto/polygon/usdc/wallet.php
  ?address=0xYourDestinationWallet     # a wallet on the SAME network as the ticker
  &callback=https%3A%2F%2Fyoursite.com%2Fwebhook%3Forder%3D42%26token%3Dk3Jd9s
# Response
{
  "address_in": "0x8f2a91c84e3d…",   # show this to the customer (and a QR — below)
  "callback_url": "https://yoursite.com/webhook?order=42&token=k3Jd9s"
}

The customer sends the coin to address_in. When it confirms, the funds are forwarded to the destination wallet you passed as address and your callback is requested with the same payload as a card payment (value_coin is in units of the ticker's coin, coin names it).

Convert fiat to coin amount

GEThttps://api.risksless.com/crypto/polygon/usdc/convert.php
  ?from=USD
  &value=99.00
# Response — how much of the coin equals 99.00 USD right now
{ "value_coin": "99.00", "coin": "usdc" }

Use it to tell the customer exactly how much to send. Note the difference from /control/convert.php: that one returns a USD value, this one returns a coin amount.

Render a QR code for the receiving address

GEThttps://api.risksless.com/crypto/polygon/usdc/qrcode.php?address=0x8f2a91c84e3d…
# Response — qr_code is a base64 PNG
{ "status": "success", "qr_code": "iVBORw0KGgoAAAANS…" }

<!-- inline it directly -->
<img src="data:image/png;base64,{qr_code}" alt="Pay">

Ticker info, minimum and live price

GEThttps://api.risksless.com/crypto/polygon/usdc/info.php
# Response (abridged)
{
  "coin": "USD Coin (Native)",      # display name of the coin (the key is `coin`, not `name`)
  "minimum": 0.665,                 # number — smallest amount that will be forwarded
  "prices": { "USD": "1.00", … }   # live price per 1 coin — used to value native-coin payouts
}

Supported tickers

Tickers are path segments. The wallet address you pass must be valid on that network.

NETWORKTICKERSMINIMUMTYPICAL CONFIRMATION
Polygonpolygon/usdc · polygon/usdt · polygon/pol$1< 10 seconds
BNB Chain (BEP20)bep20/usdc · bep20/usdt · bep20/bnb$1< 15 seconds
Tron (TRC20)trc20/usdt$1< 30 seconds
Solanasol/usdc · sol/sol$2< 5 seconds
Ethereum (ERC20)eth · erc20/usdc · erc20/usdt · erc20/dai$201–3 minutes (gas-dependent)
Bitcoinbtc$1010–30 minutes
Litecoinltc$52–5 minutes
Dogecoindoge$31–3 minutes
Other L2sbase/usdc · arbitrum/usdc · optimism/usdc · avax-c/usdc · linea/usdcsee info.phpseconds

Always read minimum from info.php at runtime rather than hard-coding it. Try the flow interactively with the crypto wallet generator, which calls these four endpoints in the browser.

Vanilla PHP in two calls.

For PHP merchants without WooCommerce / WHMCS / OpenCart / PrestaShop, the same flow drops into a single-file SDK. Zero dependencies, no composer. It implements everything on this page — including the raw address_in rule, the currency conversion and the tolerance check.

Download risksless-php-sdk.zip, drop Risksless.php into your project, and require_once it. Requires PHP 7.2+ and the curl extension. The zip also contains example.php, a working pay + callback endpoint in one file.

Server-side: create a payment

// Persist $payment['address_in'] alongside your order, then redirect.
require_once __DIR__ . '/Risksless.php';

$r = new Risksless('0xYourPolygonWallet');
$payment = $r->createPayment([
    'order_id'     => 'INV-1042',               // appended to callback_url as ?order=INV-1042
    'amount'       => 99.00,
    'currency'     => 'USD',
    'email'        => 'customer@example.com',
    'callback_url' => 'https://yoursite.com/risksless-cb.php?token=k3Jd9s',
    // 'provider' => 'stripe',  // optional; default is the hosted picker
]);

// $payment = [ 'redirect_url' => …, 'address_in' => …, 'polygon_address_in' => …, 'callback_url' => … ]
header('Location: ' . $payment['redirect_url']);
exit;

Callback endpoint: verify settlement

// risksless-cb.php — the URL you passed as callback_url above.
require_once __DIR__ . '/Risksless.php';

// 1. Authenticate the request with the token you put in callback_url.
if (!hash_equals('k3Jd9s', $_GET['token'] ?? '')) { http_response_code(403); exit; }

// 2. Load the order by $_GET['order'] and its expected total, then verify.
$r = new Risksless('0xYourPolygonWallet');
$result = $r->verifyCallback($_GET, [
    'expected_amount'   => 99.00,
    'expected_currency' => 'USD',     // non-USD is converted via /control/convert.php for you
]);

if ($result['ok']) {
    // Mark the order paid; $result['txid_out'] is the on-chain payout tx.
    echo 'OK';
} else {
    // $result['reason'] is 'underpaid' or 'missing_value_coin';
    // $result['value_coin'] and $result['expected_usd'] tell you by how much.
    echo $result['reason'];
}

Default settlement threshold is 60% — pass a second argument to the constructor (new Risksless($wallet, 0.95)) to require ≥ 95% of expected before accepting. $r->listProviders() returns the /control/provider-status/ list if you want to render your own picker. Supported provider values: hosted (default), revolut, stripe, paypal, rampnetwork, transak, moonpay, banxa, utorg, transfi, sardine, topper, bitnovo, robinhood, upi, interac, simplex, binance, customprovider.

Ready-made modules for WooCommerce, WHMCS, OpenCart, PrestaShop and HOSTINPL are on the modules page.

Before you message support.

These cover almost every integration ticket we receive. Check them in order.

SYMPTOMCAUSEFIX
Checkout page opens but fails or hangs when the customer picks a provideraddress_in was URL-encoded a second time (%252F in your URL).Concatenate address_in raw. Encode only email, logo, etc. See the warning.
Payment completes but you never get a callbackCallback URL not public, not HTTPS, behind auth, or returned non-2xx. Or the callback parameter was not URL-encoded so its query string was cut off.Check callback_url in the wallet.php response equals what you intended. Test your endpoint with curl from outside your network. Return 200 fast.
Callback arrives but you can't tell which order it is forNothing identifying was put in the callback URL.Add ?order=…&token=… to the callback URL before encoding it, and/or index orders by address_in.
Legit payments rejected as underpaidExact comparison of value_coin against the amount.Provider fees are deducted first. Use a tolerance (≥ 60% is the plugin default), and convert non-USD orders with /control/convert.php.
value_coin is tiny (e.g. 0.031) for a $99 orderPayout arrived as a native coin (coin=eth, polygon_pol, bep20_bnb).Multiply by prices.USD from /crypto/{ticker}/info.php before comparing.
wallet.php returns no address_inInvalid wallet (not 0x + 40 hex, or the USDC contract address), or missing callback.Validate with /^0x[a-fA-F0-9]{40}$/ before calling. Use your own self-custodial wallet address.
Checkout says amount too lowBelow the provider minimum.Read minimum_amount and minimum_currency from /control/provider-status/ and validate before redirecting. The minimum is in the provider's currency, not USD.
An API call answers with a 302 redirect to a Risksless error page instead of JSONA parameter name is wrong or missing (for example amount instead of value on convert.php, or wallet instead of address).Use the exact parameter names on this page. Your HTTP client may follow the redirect and hand you HTML — check the status code and content type before parsing.
Checkout rejects the currencyProvider is currency-locked (Stripe → USD, UPI → INR, Interac → CAD, iDEAL → EUR…).Use provider=hosted, or match the lock. See the provider table.
Funds arrived on-chain but the exchange "froze" themAn exchange deposit address was used as the payout wallet.Always use a self-custodial wallet (MetaMask, Trust Wallet, Rabby, Ledger). Withdraw to an exchange afterwards if you need to.
Browser console shows a CORS errorYou called checkout.risksless.com with fetch.Checkout pages are for navigation only. Only api.risksless.com is meant to be fetched.
Where is the sandbox / test mode?There is no separate sandbox.Test live with the smallest amount the provider allows (hosted: $1). It settles to your wallet like any other payment.
Still stuck? Send support the address_in (or polygon_address_in) of the affected order and the full checkout URL you generated. With those two things we can see whether the payment was made, what was forwarded and what your callback returned.

Need a hand?

Work through the troubleshooting table first — it resolves most integration questions in minutes. If you are still blocked, include your address_in and checkout URL when you reach out.

WHATSAPP SUPPORT → PLUGINS & SDK READ THE FAQ