REST API · v1

Two endpoints. USDC in your wallet.

POST creates a hosted checkout. We GET your callbackwhen paid. That's it.

Quickstart

The whole integration in three lines: create the link, redirect, handle the callback. Copy below, replace the wallet + key, and you're live.

STEP 1

POST /v1/wallet

We return a checkout_url.

STEP 2

Redirect

Send the customer to checkout_url.

STEP 3

Receive callback

We GET your URL with status=paid.

Copy & run

Quickstart · curl
curl -X POST https://paylio.org/api/v1/wallet \
  -H "Authorization: Bearer plio_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address":  "0xYourPolygonWallet",
    "callback": "https://example.com/orders/123/paylio-callback",
    "amount":   "49.99",
    "currency": "USD",
    "passFeeToCustomer": true
  }'

Authentication

Every request needs an API key. Generate one in dashboard › API Keys. Send it in either header — never both:

HTTP headers
Authorization: Bearer plio_live_YOUR_KEY
# or
X-API-Key: plio_live_YOUR_KEY

Treat keys like passwords. We only store a SHA-256 hash. If a key leaks, revoke it and create a new one.

Create checkout link

Generates a hosted-checkout page and returns a ready-to-redirect URL plus an ipn_token for tracking.

POST/api/v1/wallet

Card-funded payments that settle as USDC on Polygon. For direct-crypto flows use the dashboard or the WooCommerce / WHMCS modules.

addressreq
string
Your Polygon USDC payout wallet (0x…). Funds land here.
callbackreq
url
Where PayLio GETs once the payment completes. See Callback.
amountreq
string | number
Order total. Decimal string preferred (e.g. "49.99").
currency
string
ISO code — EUR, USD, INR, CAD. Default USD.
passFeeToCustomer
boolean
When true, PayLio grosses up the hosted checkout amount so the customer covers processing fees and your requested amount remains the net order amount.
email
string
Customer email. Pre-fills the checkout, included in the callback.
note
string
Free-form note shown in your dashboard. Hidden from the customer.
provider
string
Lock the checkout to a single on-ramp provider and skip the selection screen. Pass a provider ID such as moonpay, wert,revolut, cryptocom, rampnetwork, or transak. Defaults to multi which shows the full picker.

Request

Request · curl
curl -X POST https://paylio.org/api/v1/wallet \
  -H "Authorization: Bearer plio_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address":  "0xYourPolygonWallet",
    "callback": "https://example.com/orders/123/paylio-callback",
    "amount":   "49.99",
    "currency": "USD",
    "passFeeToCustomer": true
  }'

Response · 200 OK

Response · JSON
{
  "address_in":         "0xa1B2c3...derived",
  "polygon_address_in": "0x32e854bD1270670C832634CA87858fFd9F3e2c78",
  "ipn_token":          "f7e9d3a1-4b8e-4a2f-9c6e-1234567890ab",
  "callback_url":       "https://example.com/orders/123/paylio-callback",
  "payment_id":         "clx9k2m3a0001a8w0b3v4r5g6",
  "short_code":         "a8wB3v4R",
  "short_url":          "https://paylio.org/p/a8wB3v4R",
  "checkout_url":       "https://paylio.org/pay/clx9k2m3a0001a8w0b3v4r5g6",
  "payment_type":       "card",
  "provider":           "multi",
  "amount":             "53.18",
  "original_amount":    "49.99",
  "customer_fee_amount": "3.19",
  "pass_fee_to_customer": true,
  "fee_percent":        5,
  "status":             "unpaid"
}
Response field reference
checkout_url
url
Redirect the customer here.
ipn_token
string
Save on your order row. Use it to verify the callback.
payment_id
string
PayLio internal ID. Alternative input for status checks.
short_url
url
Branded short link to the checkout (good for SMS / email).
address_in
string
Deposit address embedded in checkout_url.
polygon_address_in
string
Decrypted Polygon address — for internal reconciliation.
amount
string
Hosted checkout amount. If passFeeToCustomer is true, this is the gross customer-paid amount.
original_amount
string | null
Original requested amount before fee pass-through.
customer_fee_amount
string | null
Fee amount added to the customer checkout when fee pass-through is enabled.
pass_fee_to_customer
boolean
Whether fee pass-through was enabled for this checkout.
fee_percent
number
Your PayLio card fee percent used for the fee split.
payment_type
string
Always "card" for API-created payments.
status
string
Always "unpaid" at creation.

Direct Provider Links (Skip Selection)

When you specify a single provider (not multi), the returned checkout_url includes ?auto=1. This skips the provider selection screen and immediately redirects the customer to the chosen provider's checkout.

Example — Direct to MoonPay

Request · cURL
curl -X POST https://paylio.org/api/v1/wallet \
  -H "Authorization: Bearer plio_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address":  "0xYourPolygonWallet",
    "callback": "https://example.com/callback",
    "amount":   "99.99",
    "currency": "USD",
    "provider": "moonpay",
    "email":    "[email protected]"
  }'

Returns: checkout_url with ?email=...&auto=1 appended. Redirecting the customer immediately sends them to MoonPay — no clicks needed.

Supported Providers

  • moonpay — MoonPay
  • wert — Wert
  • revolut — Revolut
  • cryptocom — Crypto.com
  • rampnetwork — Ramp
  • transak — Transak
  • coinbase — Coinbase Pay
  • paypal — PayPal
  • stripe — Stripe
  • banxa — Banxa
  • klarna — Klarna (EUR only)

Query Parameters

  • ?auto=1 — Auto-redirect to provider
  • ?email=... — Pre-fill customer email

Note: auto=1 only works when both provider is a specific ID (not multi) AND email is provided.

Check payment status

Server-to-server verification. Always call this before fulfilling an order — query strings on your callback can be spoofed.

GET/api/v1/payment-status
ipn_token
string
The token from /wallet. Either this or payment_id is required.
payment_id
string
PayLio payment ID.

Request

Request · cURL
curl "https://paylio.org/api/v1/payment-status?ipn_token=f7e9d3a1-..." \
  -H "Authorization: Bearer plio_live_YOUR_KEY"

Response · 200 OK

Response · JSON
{
  "status":           "paid",
  "value_coin":       "49.4",
  "txid_in":          "0xa22a82b4...",
  "txid_out":         "0x94c2c3e8...",
  "coin":             "polygon_usdc",
  "address_in":       "0x32e854bD1270670C832634CA87858fFd9F3e2c78",
  "payment_id":       "clx9k2m3a0001a8w0b3v4r5g6",
  "amount":           "53.18",
  "original_amount":  "49.99",
  "customer_fee_amount": "3.19",
  "pass_fee_to_customer": true,
  "currency":         "USD",
  "forward_status":   "completed",
  "forwarded_amount": "49.4",
  "paid_at":          "2026-04-28T13:01:42.000Z",
  "created_at":       "2026-04-28T12:59:11.000Z"
}
Response field reference
status
string
unpaid · paid · canceled.
forward_status
string
pending · processing · completed · failed. Treat completed as final.
value_coin
string
Amount received in the settlement coin.
amount
string
Hosted checkout amount charged to the customer.
original_amount
string | null
Original requested amount before fee pass-through.
customer_fee_amount
string | null
Customer-paid fee amount when fee pass-through is enabled.
pass_fee_to_customer
boolean
Whether fee pass-through was enabled.
forwarded_amount
string
Final amount delivered to your wallet (after fees).
txid_in
string
Hash of the customer's deposit tx.
txid_out
string
Hash of the payout to your wallet.
coin
string
Settlement coin ticker (e.g. polygon_usdc).

Webhook callback

On payment completion, PayLio sends payment data to your callback URL and includes fee pass-through metadata when enabled. Treat callbacks as untrusted hints — always re-verify with /payment-status.

Express · Node.js
// Express · Node.js
app.get("/orders/:id/paylio-callback", async (req, res) => {
  // 1. Re-verify — query strings can be spoofed.
  const verify = await fetch(
    `https://paylio.org/api/v1/payment-status?ipn_token=${req.query.ipn_token}`,
    { headers: { Authorization: `Bearer ${process.env.PAYLIO_API_KEY}` } },
  ).then((r) => r.json());

  if (verify.status !== "paid") return res.status(400).send("not paid");

  // 2. Mark the order paid (idempotent).
  await markOrderPaid(req.params.id, { txid: verify.txid_out });

  // 3. Reply 200 within 10 s.
  res.status(200).send("ok");
});
Three rules:
  1. Re-verify with /payment-status before fulfilling.
  2. Make your handler idempotent — we retry on non-2xx responses.
  3. Reply 200 within 10 s; do heavy work async.

Errors

All errors return JSON: { "error": "...", "code": "..." } (the code field appears when actionable).

HTTPCauseWhat to do
400Validation failed (missing field, bad wallet, low amount).Read error, fix input, retry.
401Missing, invalid, or revoked API key.Generate a new key.
404Payment not found, or owned by a different user.Verify ipn_token / payment_id.
429Too many requests in a short window.Honour Retry-After; back off with jitter.
500Server error (upstream / RPC unreachable).Retry with exponential backoff.

Ship your first payment today.

Generate a key, copy a sample, watch USDC land in your wallet. No KYC, no SDK.