Developer API
All requests require X-Public-Key and X-Secret-Key headers (get them from your merchant dashboard). Base URL: https://crypto2pay.co
Authentication
All API requests must include both header keys:
X-Public-Key— your public key (safe to ship in code)X-Secret-Key— your secret key (server-side only)
/api/v1/payment/createCreate a payment session
curl -X POST https://crypto2pay.co/api/v1/payment/create \
-H "X-Public-Key: pk_live_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"amount":100,"coin":"USDT","network":"TRC20","order_id":"ORDER-123","description":"Order #123","success_url":"https://your-site.com/thank-you","cancel_url":"https://your-site.com/cancelled"}'{
"id": "9b9...",
"deposit_address": "T...",
"status": "waiting",
"expires_at": "2026-...",
"amount": 100,
"coin": "USDT",
"network": "TRC20"
}/api/v1/payment/status/{payment_id}Check payment status
curl -X GET https://crypto2pay.co/api/v1/payment/status/PAYMENT_ID \ -H "X-Public-Key: pk_live_xxxxxxxxxxxxxxxx" \ -H "X-Secret-Key: sk_live_xxxxxxxxxxxxxxxx"
{
"id": "9b9...",
"status": "paid",
"tx_hash": "0x...",
"received_amount": 100,
"net_amount": 98,
"platform_fee": 2,
"confirmations": 19
}/api/v1/transaction/{transaction_id}Get a confirmed transaction
curl -X GET https://crypto2pay.co/api/v1/transaction/TX_ID \ -H "X-Public-Key: pk_live_xxxxxxxxxxxxxxxx" \ -H "X-Secret-Key: sk_live_xxxxxxxxxxxxxxxx"
{
"id": "t-...",
"tx_hash": "0x...",
"amount": 100,
"net_amount": 98,
"status": "confirmed"
}/api/v1/balanceGet your balance
curl -X GET https://crypto2pay.co/api/v1/balance \ -H "X-Public-Key: pk_live_xxxxxxxxxxxxxxxx" \ -H "X-Secret-Key: sk_live_xxxxxxxxxxxxxxxx"
{
"available": 1250,
"pending": 100,
"withdrawn": 5000,
"total_received": 6350
}/api/v1/withdrawal/requestRequest a withdrawal
curl -X POST https://crypto2pay.co/api/v1/withdrawal/request \
-H "X-Public-Key: pk_live_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"amount":500,"coin":"USDT","network":"TRC20","destination_address":"T...","region":"global"}'{
"id": "w-...",
"status": "pending",
"net_amount": 435,
"fee": 65
}Webhook signature verification
When a payment is confirmed, we POST a JSON payload to your configured webhook_url with an X-Signature header (HMAC-SHA256 over the raw body using your secret_key). Always verify before trusting the body.
# Verify webhook signature (FastAPI / Flask)
import hmac, hashlib
def verify_webhook(secret_key: str, raw_body: bytes, signature: str) -> bool:
expected = hmac.new(secret_key.encode(), raw_body,
hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)Webhook payload schema
{
"event": "payment.confirmed",
"payment_id": "uuid",
"merchant_id": "uuid",
"amount": 100.0,
"net_amount": 98.0,
"coin": "USDT",
"network": "TRC20",
"tx_hash": "0x...",
"order_id": "ORDER-123",
"timestamp": "2026-01-01T00:00:00Z"
}Payment return pages
You have two ways to handle the post-payment redirect:
Use our built-in success page
Don't pass success_url/cancel_url and we'll show our branded confirmation card with the tx hash and a return-to-merchant link.
Redirect to your own page
Pass success_url and cancel_url when creating the payment. After confirmation we show a "Continue to merchant" button linking to your URL. Always rely on the webhook for the source of truth.
Embed snippet
One-line drop-in: open a checkout window from any HTML page.
<script src="https://crypto2pay.co/api/embed.js"></script>
<button onclick="Crypto2Pay.open('YOUR_PAYMENT_LINK_SLUG')">
Pay with Crypto
</button>
<!-- OR auto-inject a styled button: -->
<div id="pay-here"></div>
<script>
Crypto2Pay.button({
target: '#pay-here',
slug: 'YOUR_PAYMENT_LINK_SLUG',
label: 'Pay $99 with Crypto'
});
</script>Need help?
Email hello@crypto2pay.co — we typically respond within an hour.