API Reference v2

Developer Documentation

Accept fiat payments with instant USDC settlements. RESTful API with sandbox testing, webhooks, and multi-currency support.

BASE URLhttps://chain2pay.is/api/v2

Authentication

All API v2 endpoints require an API key. Generate keys from your Dashboard under the API section.

API Keys

Pass your key via the Authorization header or x-api-key header.

LIVEc2p_live_

Production payments - real money processing

SANDBOXc2p_sandbox_

Test payments - no real transactions

HTTP Header
Authorization: Bearer c2p_live_a1b2c3d4e5f6...

Note: Your API key is linked to a verified wallet. The merchant wallet is automatically resolved - you don't need to send it in requests.

CORS: The API is fully CORS-enabled. You can call it directly from any origin — including file:// HTML pages, localhost, and any domain — as long as you pass your Bearer key in the Authorization header. No allowlist, no preflight headaches.

Rate limits:

  • 300 requests / minute / API key on /api/v2/* (5 req/sec)
  • 1,200 requests / minute / IP globally (30-second block after overflow)

When exceeded, the API responds with 429 Too Many Requests and a Retry-After header (in seconds).

Create Payment

Generate a hosted payment page. Redirect your customer to the checkout_url to complete the transaction.

POST/api/v2/payments

Request Body

amount
NumberRequired

Payment amount in fiat (e.g. 49.99). Minimum varies per provider, maximum 10000.

currency
StringOptional

Fiat currency: USD, EUR, GBP, or CAD. Default: USD.

callback_url
StringOptional

Your server's webhook endpoint for payment notifications.

customer_email
StringOptional

Customer email for receipt delivery.

provider
StringOptional

Force a specific gateway. Default: multihosted (auto-routing).

metadata
ObjectOptional

Arbitrary key-value pairs for your own reference.

Code Examples

curl -X POST https://chain2pay.is/api/v2/payments \
  -H "Authorization: Bearer c2p_sandbox_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 55.00,
    "currency": "EUR",
    "callback_url": "https://yoursite.com/webhooks/c2p",
    "customer_email": "[email protected]"
  }'

Response

201 CreatedJSON
{
  "id": "C2P-1741380553-a7f3c9e1b2d4f6a8",
  "object": "payment",
  "amount": 55.00,
  "currency": "EUR",
  "status": "pending",
  "sandbox": false,
  "checkout_url": "https://checkout.chain2pay.is/c/e3c3da6f06e89d65a7eb",
  "provider": "multihosted",
  "merchant_wallet": "0x606Ea6BfA08f0E5C390Ef3bBCcF620f46EC673C8",
  "callback_url": "https://yoursite.com/webhooks/c2p",
  "metadata": null,
  "created_at": "2026-04-07T18:00:00.000Z"
}

Redirect your customer to the checkout_url to complete the transaction. The merchant_wallet is automatically resolved from your API key.

Get Payment

Retrieve the current status and details of a payment.

GET/api/v2/payments/:id

Parameters

id
StringRequired

The payment ID returned from POST /api/v2/payments.

cURL
curl https://chain2pay.is/api/v2/payments/C2P-1741380553-a7f3c9e1b2d4f6a8 \
  -H "Authorization: Bearer c2p_sandbox_a1b2c3d4e5f6..."

Response

200 OKJSON
{
  "id": "C2P-1741380553-a7f3c9e1b2d4f6a8",
  "object": "payment",
  "amount": 55.00,
  "currency": "EUR",
  "status": "paid",
  "sandbox": false,
  "checkout_url": "https://checkout.chain2pay.is/c/e3c3da6f06e89d65a7eb",
  "provider": "multihosted",
  "merchant_wallet": "0x606Ea6B...",
  "callback_url": "https://yoursite.com/webhooks/c2p",
  "tx_hash": "0xb4f7b8a3c2...",
  "paid_amount": 55.00,
  "paid_coin": "polygon_usdc",
  "metadata": null,
  "created_at": "2026-04-07T18:00:00.000Z"
}

Status values: pending, processing, paid, expired, dispatch_failed

processing is a rare transient state: it appears when funds arrive on the temporary wallet after an order was already marked expired (late blockchain confirmation, RPC hiccup, safety-check recovery). The order is automatically re-opened and settled as usual.

Pending payments are kept alive for 7 days. After that, a cron running every 5 minutes marks them expired if the temporary wallet is still empty.

Sandbox Mode

Use sandbox API keys (c2p_sandbox_*) to create test payments. Sandbox payments are identical to live payments but don't process real money.

How it works: Create a payment with your sandbox key. The payment appears in your dashboard as a test transaction. Confirm it via the API or the dashboard's "Send Test Callback" button.

1. Create a sandbox payment

Use the same POST /api/v2/payments endpoint with your sandbox key.

SANDBOX
curl -X POST https://chain2pay.is/api/v2/payments \
  -H "Authorization: Bearer c2p_sandbox_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{"amount": 10.00, "currency": "USD", "callback_url": "https://yoursite.com/webhooks/c2p"}'

2. Confirm the payment

POST/api/v2/payments/:id/sandbox-confirm

Simulates a successful payment. The callback is sent to your callback_url with sandbox=true and txid_out=SANDBOX_TEST.

SANDBOX
curl -X POST https://chain2pay.is/api/v2/payments/C2P-xxx/sandbox-confirm \
  -H "Authorization: Bearer c2p_sandbox_a1b2c3d4e5f6..."

Sandbox Confirm Response

200 OKJSON
{
  "id": "C2P-1741380553-a7f3c9e1b2d4f6a8",
  "object": "payment",
  "status": "paid",
  "sandbox": true,
  "callback_sent": true,
  "callback_status": 200
}

You can also confirm sandbox payments from your DashboardTransactions → click a sandbox order → "Send Test Callback".

Webhooks

When a payment succeeds, Chain2Pay sends a GET request to your callback_url with the following query parameters.

Webhook Parameters

chain2pay_order_id

Unique payment ID (e.g. C2P-...).

txid_out

Polygon transaction hash - proof of USDC transfer. SANDBOX_TEST for sandbox.

value_coin

Amount paid in USDC.

coin

Payout cryptocurrency (e.g. polygon_usdc or currency code).

provider

Payment processor used (e.g. revolut, unlimit).

sandbox

true for test payments, absent for live.

customer_email

Buyer's email (if provided at creation).

Example Webhook Call

GET https://yoursite.com/webhooks/c2p
  ?chain2pay_order_id=C2P-1741380553-a7f3c9e1b2d4f6a8
  &txid_out=0xb4f7b8a3c2...
  &value_coin=55.00
  &coin=polygon_usdc
  &provider=revolut
  &[email protected]

Signature (optional)

Generate a webhook secret key from Settings → Webhooks in your dashboard. Once a secret is set, every callback we deliver includes an x-chain2pay-signature header whose value is the lowercase hex HMAC-SHA256 of the full request URL (including the query string) using that secret. Verify it on your server to ensure the webhook is genuinely from Chain2Pay. The dashboard also exposes a Send test webhook button that fires a signed GET at any URL so you can dry-run your verification handler before going live.

Node.js — verify signature
const crypto = require('crypto');

function verifyChain2PaySignature(fullUrl, header, secret) {
  const expected = crypto.createHmac('sha256', secret).update(fullUrl).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header || ''));
}

Delivery & Retries

Chain2Pay retries failed deliveries up to 4 times with exponential backoff (1s, 2s, 4s). After a successful 2xx response the webhook is marked as delivered and will not be re-sent. A hard cap of 10 total attempts across all triggers prevents retry loops. TLS errors (expired or invalid certificates) stop retries immediately.

Security tip: Always verify the chain2pay_order_id against your database (and if configured, the x-chain2pay-signature header) before fulfilling the order. Treat the webhook as a hint — never the source of truth.

Providers & Limits

Fetch the list of active payment providers and their minimum transaction limits.

The status field reflects live provider health. It is either "active" (provider currently accepts buyers) or "maintenance" (the provider has been flagged DOWN by Chain2Pay's health monitor — buyer-facing pages display a maintenance banner and the provider is excluded from MultiHosted routing). Avoid forcing a maintenance provider via the provider parameter on /api/v2/intents until it recovers; otherwise checkout will fall back to the MultiHosted chooser at runtime.

GET/api/v2/providers
cURL
curl https://chain2pay.is/api/v2/providers \
  -H "Authorization: Bearer c2p_sandbox_a1b2c3d4e5f6..."

Response

{
  "object": "list",
  "data": [
    { "id": "multihosted", "name": "MultiHosted Aggregator", "status": "active", "minimum_amount": 6, "minimum_currency": "USD", "currency_specific": null },
    { "id": "revolut", "name": "Revolut (EU/EEA)", "status": "active", "minimum_amount": 6, "minimum_currency": "USD", "currency_specific": { "USD": 6, "EUR": 6, "GBP": 6, "CAD": 10 } },
    { "id": "unlimit", "name": "Unlimit (Global)", "status": "maintenance", "minimum_amount": 12, "minimum_currency": "USD", "currency_specific": { "USD": 12, "EUR": 11, "CAD": 17 } },
    { "id": "binance", "name": "Binance Connect", "status": "active", "minimum_amount": 15, "minimum_currency": "USD", "currency_specific": null },
    { "id": "transak", "name": "Transak", "status": "active", "minimum_amount": 6, "minimum_currency": "USD", "currency_specific": { "USD": 6, "EUR": 6, "GBP": 6, "CAD": 8 } },
    { "id": "stripe", "name": "Stripe", "status": "active", "minimum_amount": 3, "minimum_currency": "USD", "currency_specific": null },
    { "id": "robinhood", "name": "Robinhood", "status": "active", "minimum_amount": 5, "minimum_currency": "USD", "currency_specific": null },
    { "id": "moonpay", "name": "MoonPay", "status": "active", "minimum_amount": 20, "minimum_currency": "USD", "currency_specific": null },
    { "id": "paypal", "name": "PayPal", "status": "active", "minimum_amount": 5, "minimum_currency": "USD", "currency_specific": { "USD": 5, "EUR": 5, "GBP": 5, "CAD": 5 } },
    { "id": "blockchain", "name": "Blockchain.com", "status": "active", "minimum_amount": 15, "minimum_currency": "USD", "currency_specific": { "USD": 15, "EUR": 15, "GBP": 15, "CAD": 20 } },
    { "id": "cryptocom", "name": "Crypto.com", "status": "active", "minimum_amount": 5, "minimum_currency": "USD", "currency_specific": { "USD": 5, "EUR": 5, "GBP": 5, "CAD": 5 } },
    { "id": "coinbase", "name": "Coinbase", "status": "active", "minimum_amount": 10, "minimum_currency": "USD", "currency_specific": { "USD": 10, "EUR": 10, "GBP": 10, "CAD": 10 } },
    { "id": "alchemy", "name": "Alchemy Pay", "status": "active", "minimum_amount": 5, "minimum_currency": "USD", "currency_specific": { "USD": 5, "EUR": 5, "GBP": 5, "CAD": 8 } },
    { "id": "kryptonim", "name": "Kryptonim", "status": "active", "minimum_amount": 5, "minimum_currency": "USD", "currency_specific": { "USD": 5, "EUR": 5, "GBP": 5, "CAD": 7 } },
    { "id": "banxa", "name": "Banxa", "status": "active", "minimum_amount": 10, "minimum_currency": "USD", "currency_specific": { "USD": 10, "EUR": 10, "GBP": 10, "CAD": 15 } },
    { "id": "ramp", "name": "Ramp Network", "status": "active", "minimum_amount": 5, "minimum_currency": "USD", "currency_specific": { "USD": 5, "EUR": 5, "GBP": 5, "CAD": 8 } },
    { "id": "topper", "name": "Topper", "status": "active", "minimum_amount": 10, "minimum_currency": "USD", "currency_specific": { "USD": 10, "EUR": 10, "GBP": 10, "CAD": 10 } },
    { "id": "guardarian", "name": "Guardarian", "status": "active", "minimum_amount": 20, "minimum_currency": "USD", "currency_specific": { "USD": 20, "EUR": 20, "GBP": 20, "CAD": 20 } },
    { "id": "swapped", "name": "Swapped", "status": "active", "minimum_amount": 5, "minimum_currency": "USD", "currency_specific": { "USD": 5, "EUR": 5, "GBP": 5, "CAD": 5 } },
    { "id": "simplex", "name": "Simplex (Nuvei)", "status": "active", "minimum_amount": 50, "minimum_currency": "USD", "currency_specific": { "USD": 50, "EUR": 42, "GBP": 40, "CAD": 70 } },
    { "id": "finchpay", "name": "FinchPay", "status": "active", "minimum_amount": 35, "minimum_currency": "USD", "currency_specific": { "USD": 35, "EUR": 30, "GBP": 27, "CAD": 48 } }
  ]
}

Provider Reference

stripe

Stripe (USA)

$3
alchemy

Alchemy Pay

$5
cryptocom

Crypto.com

$5
paypal

PayPal (USA)

$5
ramp

Ramp Network

$5
robinhood

Robinhood (USA)

$5
swapped

Swapped

$5
kryptonim

Kryptonim

$5
simplex

Simplex (Nuvei)

$50
finchpay

FinchPay

$35
multihosted

MultiHosted

$6
revolut

Revolut (EU/EEA)

$6
transak

Transak

$6
banxa

Banxa

$10
coinbase

Coinbase

$10
topper

Topper

$10
unlimit

Unlimit (Global)

$12
binance

Binance Connect

$15
blockchain

Blockchain.com

$15
guardarian

Guardarian

$20
moonpay

MoonPay

$20

Error Handling

All errors follow a consistent Stripe-inspired format.

Error Response Format

{
  "error": {
    "type": "invalid_request_error",
    "message": "Amount must be positive"
  }
}

HTTP Status Codes

400validation_error

Invalid or missing parameters

400invalid_request_error

Business rule violation (e.g. wallet not linked)

401authentication_error

Missing or invalid API key

403invalid_request_error

Action not allowed (e.g. sandbox-confirm with live key)

404invalid_request_error

Payment not found or does not belong to you

429

Rate limited - too many requests

500

Internal server error

Ready to integrate?

Get your API keys and start accepting payments in minutes.