BTC BTC
ETH ETH
BNB BNB
USDT USDT
USDC USDC
BCH BCH
LTC LTC
DOGE DOGE
TRX TRX
SOL SOL
DOT DOT
TON TON
DAI DAI
XAUT XAUT
XMR XMR
BTC BTC
ETH ETH
BNB BNB
USDT USDT
USDC USDC
BCH BCH
LTC LTC
DOGE DOGE
TRX TRX
SOL SOL
DOT DOT
TON TON
DAI DAI
XAUT XAUT
XMR XMR

API Reference

Accept cryptocurrency payments that settle directly into your own wallet. Non-custodial — the gateway never holds funds.

Base URL  https://cryptoipg.com   JSON   Bearer auth

Authentication

Send your secret API key as a bearer token on every protected request:

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Create keys in your dashboard under your website or project → API keys. The secret is shown once — keep it server-side only. To create live invoices you need a wallet (plain address) for the coin you charge in, and — for a website — a verified domain. A project has no domain to verify, so once it has a wallet its key works immediately.

Never expose a secret key in browser, mobile, or bot client code. For read-only status checks from untrusted clients, use the public status endpoint below.
No website? (Telegram bots, apps, scripts)
You don't need a site to accept crypto. In your dashboard click + Project / bot, give it a name (e.g. "My Telegram Bot"), add a wallet address for each coin, and create an API key. There's no domain and no verification step — the same endpoints below work exactly the same. Your bot calls POST /api/v1/invoices, shows the buyer the returned address + amount (or the checkout_url), and reacts to the webhook when it's paid.

Quickstart

curl -X POST https://cryptoipg.com/api/v1/invoices \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 49.99,
    "currency": "EUR",
    "asset": "BTC",
    "network": "bitcoin",
    "order_id": "ORDER-1024",
    "redirect_url": "https://yourshop.com/thank-you"
  }'

Response 201 Created:

{
  "invoice": {
    "id": "b1e7c0f2-5a3d-4e9b-9f21-8c7d6e5a4b30",
    "status": "awaiting_payment",
    "asset": "BTC",
    "network": "bitcoin",
    "amount": "0.00098421",
    "amount_paid": "0",
    "address": "bc1qexampleaddressxxxxxxxxxxxxxxxxxxxxx",
    "price_amount": "49.99",
    "price_currency": "EUR",
    "confirmations": 0,
    "required_confirmations": 2,
    "expires_at": "2026-07-06 12:30:00",
    "order_id": "ORDER-1024",
    "checkout_url": "https://cryptoipg.com/pay/b1e7c0f2-..."
  }
}

Then redirect the customer to checkout_url (hosted page with QR, coin switching, live status), or show address + amount yourself and poll for status.

Create an invoice

POST/api/v1/invoices  auth

FieldTypeReqDescription
amountnumberyesPrice to charge, in currency.
assetstringyesCoin code (see Assets).
networkstringyesChain the coin is on.
currencystringnoISO fiat (EUR, USD…). Defaults to your website's currency.
order_idstringnoYour reference. Returned on the invoice and webhooks — use it to match your order.
descriptionstringnoShown on the checkout.
buyer_emailstringnoCustomer email, for your records.
redirect_urlstringnoWhere the customer returns after paying.

The crypto amount is priced at a live rate at creation and frozen, with a tiny unique offset so payments are matchable — the customer must send the exact amount.

Responses

201Created — { "invoice": { … } }
401{ "error": "missing_api_key" | "invalid_api_key" }
422{ "error": "invalid_request", "message": "…" } — e.g. no wallet for that network, unknown asset, amount ≤ 0.

Retrieve an invoice

GET/api/v1/invoices/{id}  auth

FieldDescription
idInvoice id (UUID); also in the checkout URL.
statusLifecycle status (see below).
asset / networkCoin and chain.
amountCrypto amount to pay (exact string).
amount_paidCrypto received so far.
addressDeposit address (your wallet).
price_amount / price_currencyThe fiat price you set.
confirmations / required_confirmationsConfirmation progress.
expires_atWhen payment stops being accepted (UTC).
order_idYour reference.
checkout_urlHosted checkout page.

Public status no key

GET/pay/{id}/status

Returns the same invoice fields without your secret key — safe to call from a browser, app, or bot. Ideal for polling a checkout you rendered yourself.

curl https://cryptoipg.com/pay/b1e7c0f2-.../status

Webhooks

The reliable way to learn a payment succeeded — don't depend on the customer returning. Add your HTTPS endpoint in your website → Webhooks and copy the signing secret (whsec_…). On payment we send:

POST  https://yourserver.com/your-webhook
Content-Type: application/json
X-CryptoIPG-Event: invoice.paid
X-CryptoIPG-Delivery: <delivery-uuid>
X-CryptoIPG-Signature: sha256=<hex-hmac>

{
  "id": "<delivery-uuid>",
  "event": "invoice.paid",
  "created_at": "2026-07-06T12:15:04+00:00",
  "data": {
    "id": "b1e7c0f2-...",
    "order_id": "ORDER-1024",
    "asset": "BTC",
    "network": "bitcoin",
    "amount": "0.00098421",
    "address": "bc1q...",
    "price_amount": "49.99",
    "price_currency": "EUR"
  }
}

Treat the event field as authoritative; match your order via data.order_id.

Verify the signature

HMAC-SHA256 the raw body with your secret and compare (constant-time):

$payload  = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $payload, $WEBHOOK_SECRET);
if (!hash_equals($expected, $_SERVER['HTTP_X_CRYPTOIPG_SIGNATURE'] ?? '')) {
    http_response_code(401); exit;
}

Respond 2xx to acknowledge. Failures retry: 30s → 2m → 10m → 30m → 2h → 6h (6 attempts, then exhausted). Handle retries idempotently.

Assets & networks

AssetNetwork(s)
BTCbitcoin
LTClitecoin
DOGEdogecoin
ETHethereum
TRXtron
SOLsolana
DOTpolkadot
USDT / USDCethereum, tron, solana
Automatic on-chain confirmation is live for bitcoin, litecoin, dogecoin, tron, solana (no key needed). ethereum and polkadot activate once you add a free API key in your config. Stablecoins USDT and USDC are confirmed on tron (keyless) and ethereum (with the key).

Invoice statuses

StatusMeaning
awaiting_paymentWaiting for funds.
detectedPayment seen (0 conf).
confirmingGathering confirmations.
underpaidReceived less than required.
paid / overpaid / completedSettled — fulfill the order.
expiredWindow elapsed, no payment.
failed / refundedTerminal states.

Examples

PHP

$ch = curl_init('https://cryptoipg.com/api/v1/invoices');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $SECRET,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'amount' => 49.99, 'currency' => 'EUR',
        'asset' => 'BTC', 'network' => 'bitcoin',
        'order_id' => 'ORDER-1024',
    ]),
]);
$invoice = json_decode(curl_exec($ch), true)['invoice'];
header('Location: ' . $invoice['checkout_url']);

Node.js

const res = await fetch("https://cryptoipg.com/api/v1/invoices", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CRYPTOIPG_SECRET}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: 49.99, currency: "EUR",
    asset: "BTC", network: "bitcoin",
    order_id: "ORDER-1024",
  }),
});
const { invoice } = await res.json();
console.log(invoice.checkout_url, invoice.address, invoice.amount);

Python

import requests

r = requests.post(
    "https://cryptoipg.com/api/v1/invoices",
    headers={"Authorization": f"Bearer {SECRET}"},
    json={"amount": 49.99, "currency": "EUR",
          "asset": "BTC", "network": "bitcoin", "order_id": "ORDER-1024"},
)
invoice = r.json()["invoice"]
print(invoice["checkout_url"], invoice["amount"], invoice["address"])

Bot polling

# poll the public status endpoint (no secret key needed)
import requests, time

inv_id = invoice["id"]
while True:
    s = requests.get(f"https://cryptoipg.com/pay/{inv_id}/status").json()
    if s["status"] in ("paid", "overpaid", "completed"):
        deliver_product(); break
    if s["status"] in ("expired", "failed"):
        break
    time.sleep(15)

Telegram bot no website needed

# Telegram bot — sell a product for crypto with python-telegram-bot
# The user has NO website: create a "Project / bot" in the dashboard,
# add a wallet per coin, make an API key -> put it in SECRET below.
import requests
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, ContextTypes

SECRET = "sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"   # your project's API key
API    = "https://cryptoipg.com"

async def buy(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
    # 1) create an invoice for this Telegram user
    r = requests.post(f"{API}/api/v1/invoices",
        headers={"Authorization": f"Bearer {SECRET}"},
        json={"amount": 9.99, "currency": "EUR", "asset": "USDT",
              "network": "tron", "order_id": f"tg-{update.effective_user.id}"})
    inv = r.json()["invoice"]

    # 2) show the buyer the exact amount + address, and a QR via the checkout page
    text = (f"Send *{inv['amount']} USDT* (TRON) to:\n`{inv['address']}`\n\n"
            f"Or pay on the web page below — you'll be unlocked automatically once it confirms.")
    kb = InlineKeyboardMarkup([[InlineKeyboardButton("Open payment page", url=inv["checkout_url"])]])
    await update.message.reply_markdown(text, reply_markup=kb)

app = Application.builder().token("TELEGRAM_BOT_TOKEN").build()
app.add_handler(CommandHandler("buy", buy))
app.run_polling()

# 3) Unlock delivery from your webhook endpoint (see Webhooks section):
#    when a signed "invoice.paid" arrives, read order_id -> tg-<user_id>
#    and message that user their product. Do NOT trust client-side polling alone.

Notes & limits

Test vs live: use a sk_test_… key while integrating. Exact amounts: payments match by unique amount — send exactly amount. Idempotency: each create makes a new invoice; reuse the returned id rather than duplicating per order_id. Fees: network fees are paid by the customer on top. Timestamps are UTC.

Non-custodial software. You are responsible for tax, sanctions, and licensing (incl. EU MiCA) in your jurisdiction. Not legal or financial advice.