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.