API Reference
IZIPAY Business API
Issue virtual cards for your users programmatically, fund them with crypto, and track everything in real time. A single REST API with predictable JSON responses and webhook events.
Base URL https://izipay.me/api/v1
The API speaks JSON over HTTPS. Every request must be authenticated with a Bearer token. All responses share a consistent envelope with a top-level success flag.
Authentication
Authenticate every request by sending your secret API key in the Authorization header as a Bearer token.
Header
Authorization: Bearer YOUR_API_KEY
!
Keys prefixed with izpk_live_ are live keys tied to real card issuance and payments. Treat them like passwords: never expose them in client-side code or public repositories, and rotate them periodically from your dashboard.
Requests without a valid key return 401 INVALID_AUTH.
Request signing (optional, recommended)
Each key has a secret (izps_…, shown once when the key is created). Sign requests with it so that a leaked API key alone is useless. Enable it per key in the cabinet (API keys → Signing): while optional, a signature is verified only when sent; when required, unsigned requests return 401.
Headers
X-Timestamp: 1725465600 # unix seconds, within ±5 min of server time
X-Signature: <hex HMAC-SHA256> # over: timestamp + "\n" + METHOD + "\n" + path_with_query + "\n" + raw_body
Node.js
const ts = Math.floor(Date.now() / 1000).toString();
const sig = crypto.createHmac('sha256', SECRET).update(`${ts}\n${method}\n${pathWithQuery}\n${rawBody}`).digest('hex');
headers['X-Timestamp'] = ts; headers['X-Signature'] = sig;
Example string to sign for GET /api/v1/cards?limit=50: "1725465600\nGET\n/api/v1/cards?limit=50\n" (empty body). Every signature is accepted once (replay protection). Keys created before September 2026 cannot enable signing — create a new key.
Quickstart
The typical flow to put a funded card in your user's hands is four steps:
| 1 | Issue a card — call POST /cards/issue with the cardholder's email. You receive a crypto deposit address. |
| 2 | Collect payment — have your user send the exact pay_amount to the returned deposit_address. |
| 3 | Wait for issuance — once payment confirms, the card is provisioned automatically. |
| 4 | Receive a webhook — a card.issued event is delivered to your registered endpoint. |
Sandbox (testing)
Build and test your entire integration with zero real crypto and zero real cards. Use a test API key (starts with izpk_test_) — every call is mocked and isolated from production. When you're ready, switch to your live key (izpk_live_) and nothing else changes.
| Get a test key | Ask your account manager for a sandbox key (izpk_test_…). Same endpoints, same auth. |
| Issue / top up | With a test key, POST /cards/issue and /topup return a fake deposit_address and payment_id, and the response includes "sandbox": true. No crypto is expected and no real card exists. |
| Simulate payment | Call POST /sandbox/confirm with the payment_id to instantly "pay". A fake test card is provisioned (test BIN 4111…) or the top-up is credited, and the same webhooks fire (card.issued, topup.completed). |
| Go live | Replace the test key with your live key. Test cards (BIN 4111) can never be used for real spending. |
1 · Issue in sandbox
curl -X POST https://izipay.me/api/v1/cards/issue \
-H "Authorization: Bearer izpk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "cardholder_email": "alice@example.com" }'
# → { "data": { "card_id": "card_test_...",
# "sandbox": true,
# "payment": { "payment_id": "gwtest_...",
# "deposit_address": "TEST...", ... } } }
2 · Simulate the payment
curl -X POST https://izipay.me/api/v1/sandbox/confirm \
-H "Authorization: Bearer izpk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "payment_id": "gwtest_..." }'
# → { "data": { "issue_status": "issued",
# "card": { "number": "4111111111116204",
# "exp": "07/29", "cvv": "123", "last4": "6204" } } }
iSandbox is fully isolated: no HD deposit address is consumed, no crypto is watched, and no card is issued through the provider. You can create unlimited test cards at no cost — they are fake and cannot spend.
Card types
You can issue three kinds of cards. Pick one per request with the card_type field on POST /cards/issue (defaults to visa).
| | card BIN 4004 (card_type: visa) | Mastercard BIN 5378 (card_type: mastercard_standard) | Apple Pay Mastercard (card_type: mastercard) |
| Issue price | Your account's card price | Same as visa | Your account's Apple Pay price (default $20) |
| Funding | Balance or crypto | Balance or crypto | Balance or crypto (not the prepaid pool) |
| Top-up funding | Crypto or account balance | Crypto or account balance | Crypto (USDT TRC-20) or account balance |
| Top-up fee | Your top-up rate + network fee | Same rate as visa + network fee | Your top-up rate (default 3%) + a fixed $1.70 network fee — same for crypto and balance |
| Apple Pay / Google Pay | Supported | Not supported (online payments only) | Supported (this is the recommended card for wallets) |
i
Bank spending fees (Apple Pay Mastercard only). The issuing bank charges the cardholder a small fee on each purchase, deducted automatically from the card balance: 1% on cross-border transactions, $0.30 on transactions under $50, and 0.2% on Apple Pay payments. Declined transactions are never charged. These fees come out of the card's own balance — you are not billed for them. They appear as separate fee lines in GET /cards/{card_id}/transactions.
i
Aliases accepted for card_type: visa for the online-payment card BIN 4004, mastercard_standard / 5378 for the Mastercard BIN 5378, and apple_pay / mastercard for the Apple Pay Mastercard.
Issue a card
POST/cards/issue
Creates a new card for one of your end-users and returns a crypto deposit address. The card is provisioned automatically once the payment is received on-chain. To pay from your account balance instead of crypto, send "pay_currency": "balance" — the card is charged instantly with no on-chain step. See Card types to choose between card and Apple Pay Mastercard.
Body parameters
| Field | Type | Required | Description |
| cardholder_email | string | required | The end-user's email address. |
| card_type | string | optional | Which card to issue: visa (default, BIN 4004), mastercard_standard (Mastercard BIN 5378, same price as visa, no Apple Pay) or mastercard (Apple Pay Mastercard, priced at your account's Apple Pay rate, default $20). See Card types. |
| cardholder_alias | string | optional | Display name. Defaults to the email prefix. |
| client_card_ref | string | optional | Your own reference for this card (e.g. your internal user ID). Echoed back in webhooks. |
| pay_currency | string | optional | How to pay for the card. Defaults to usdttrc20. Use balance to charge your account balance instantly (no crypto step). Also accepts usdterc20, usdcerc20, and others. |
Headers
| X-Idempotency-Key | recommended | A unique string per logical request. Retrying with the same key never issues a second card. |
Request
curl -X POST https://izipay.me/api/v1/cards/issue \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: unique-request-id" \
-d '{
"cardholder_email": "alice@example.com",
"cardholder_alias": "Alice",
"client_card_ref": "user_42"
}'
Response · 200
{
"success": true,
"data": {
"card_id": "card_abc123def456",
"issue_status": "pending_payment",
"payment": {
"provider": "izipay_gateway",
"deposit_address": "TKhWqGZ...",
"pay_amount": 50,
"pay_currency": "usdttrc20",
"network": "trc20",
"amount_usd": 50,
"expires_at": "2026-05-22T09:04:20Z"
}
}
}
Example · Apple Pay Mastercard, paid from balance
Request
curl -X POST https://izipay.me/api/v1/cards/issue \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"cardholder_email": "bob@example.com",
"card_type": "mastercard",
"pay_currency": "balance"
}'
Response · 201
{
"success": true,
"data": {
"card_id": "card_9f2a...c1",
"issue_status": "paid_pending_issue",
"card_type": "mastercard",
"provider": "izipay_gateway",
"funded_from": "balance",
"price_paid_usd": 30,
"balance_usd": 470.00
}
}
i
An Apple Pay card is provisioned by the issuer a few minutes after issuance. Poll GET /cards/{card_id} until issue_status becomes issued, or listen for the card.issued webhook. If the issuer ever rejects the card, a balance-funded charge is refunded automatically.
Get card details
GET/cards/{card_id}
Retrieves the current state of a card, including its masked number, balance, and issuance status.
Request
curl https://izipay.me/api/v1/cards/card_abc123def456 \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": {
"card_id": "card_abc123def456",
"card_number": "5258 47** **** 1937",
"balance": 100.00,
"issue_status": "issued",
"payment_status": "paid",
"issued_at": "2026-05-22T08:15:00Z"
}
}
List cards
GET/cards
Returns all cards you have issued, most recent first, with pagination.
Query parameters
| Field | Type | Required | Description |
| page | integer | optional | Page number, starting at 1. Default 1. |
| limit | integer | optional | Cards per page. Default 100. |
| status | string | optional | Filter by issue status, e.g. issued, pending_payment. |
Request
curl https://izipay.me/api/v1/cards?limit=2 \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": {
"cards": [
{
"card_id": "card_abc123def456",
"client_card_ref": null,
"cardholder_email": "user@example.com",
"issue_status": "issued",
"payment_status": "paid",
"balance": 100.00,
"pending_topup": 0.00,
"is_frozen": false,
"created_at": "2026-05-22T08:15:00Z",
"issued_at": "2026-05-22T08:15:05Z"
}
],
"page": 1,
"limit": 2,
"total": 128,
"total_pages": 64
}
}
Top up a card
POST/cards/{card_id}/topup
Requests a balance top-up for an existing card. Returns a payment invoice, the same way card issuance does.
Body parameters
| Field | Type | Required | Description |
| amount_usd | number | required | Amount to add to the card balance, in USD. |
| pay_currency | string | optional | How to fund the top-up. Defaults to usdttrc20 (crypto — returns a deposit address to send USDT to). Use balance to charge your prepaid account balance instantly, with no on-chain step — works for any card (Visa or Mastercard). Also accepts usdterc20, usdcerc20, and others. |
Request
curl -X POST https://izipay.me/api/v1/cards/card_abc123/topup \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount_usd": 100,
"pay_currency": "usdttrc20"
}'
i
The response returns a deposit_address and the exact pay_amount in crypto your customer must send. A commission (your account's top-up rate) is deducted, so amount_on_card is what actually lands on the card. The card is credited automatically once the payment confirms on-chain.
Request — from account balance (instant, no crypto)
curl -X POST https://izipay.me/api/v1/cards/card_abc123/topup \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount_usd": 100,
"pay_currency": "balance"
}'
i
Fund from your account balance (any card). With "pay_currency": "balance" the card is credited instantly from your prepaid balance — no deposit address, no on-chain wait. The response returns status: "credited" and funded_from: "balance". Your balance is debited by amount_usd; amount_on_card is what lands after your top-up fee and network fee. Because your account balance itself can be funded with any crypto (auto-converted to USD), this is usually the simplest way to fund cards.
i
Apple Pay Mastercard top-ups. A
mastercard card can be topped up two ways, both with a flat
3% fee and a
$5 minimum:
- From your balance — "pay_currency": "balance". Credited instantly, no deposit address. A network fee applies because your funds are swept from your deposit wallet: $1.70 if they sit on TRON, $0.50 on BEP-20 / ERC-20 / Polygon (pass "network" to say where your deposit is held). So a $100 top-up lands $95.30. Since your account balance can be funded with any crypto (auto-converted to USD), this is the simplest way. Response: status: "credited".
- Direct crypto — "pay_currency" one of usdttrc20, usdtbep20, usdterc20, usdtpoly (USDT on TRON, BNB Smart Chain, Ethereum or Polygon). Network fee: $1.70 on TRON (a $100 top-up lands $95.30), $0.50 on BEP-20, ERC-20 and Polygon (a $100 top-up lands $96.50). Credited after the payment confirms on-chain.
The response includes
card_type: "mastercard",
fee_pct and
amount_on_card. Bank spending fees are charged separately per purchase — see
Card types.
Return card balance
POST/cards/{card_id}/return
Moves unspent funds from a card back to your account balance. Use it before retiring a card, or to reclaim liquidity. The returned amount lands on your account balance and can be reused to issue or top up other cards.
Body parameters
| Field | Type | Required | Description |
| amount_usd | number | string | optional | Amount to return, in USD. Pass "all" to return the entire available balance (default). |
Request
curl -X POST https://izipay.me/api/v1/cards/card_abc123/return \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "amount_usd": "all" }'
Response · 200
{
"success": true,
"data": {
"card_id": "card_abc123",
"status": "returned",
"amount_returned": 42.15,
"card_balance": 0.00,
"balance_usd": 382.70
}
}
i
Requests are idempotent per card while a return is in flight. If the card balance is lower than the amount requested, the call returns INSUFFICIENT_CARD_BALANCE (402) and no funds are moved.
Transfer between cards
POST/cards/{card_id}/transfer
Moves funds directly from one of your cards to another of your cards. No fee — the money never leaves the system, so this is free (unlike a return followed by a top-up, where the top-up commission applies). Both cards must be issued and belong to your account. {card_id} in the path is the source card.
Body parameters
| Field | Type | Required | Description |
| to_card_id | string | required | Destination card id (must differ from the source and belong to your account). |
| amount | number | required | Amount to move, in USD. Must not exceed the source card's available balance. |
Request
curl -X POST https://izipay.me/api/v1/cards/card_abc123/transfer \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: unique-key-123" \
-d '{ "to_card_id": "card_def456", "amount": 50.00 }'
Response · 200
{
"success": true,
"data": {
"from_card_id": "card_abc123",
"to_card_id": "card_def456",
"amount": 50.00,
"fee": 0.00,
"amount_credited": 50.00,
"from_balance": 120.00,
"to_balance": 80.00,
"reference_id": "…"
}
}
i
Pass X-Idempotency-Key to make retries safe — a repeat with the same key returns the original result instead of transferring again. If the destination step fails, the source card is restored automatically and no funds are lost.
Get transactions
GET/cards/{card_id}/transactions
Returns the spending and top-up history for a card, most recent first.
Request
curl https://izipay.me/api/v1/cards/card_abc123/transactions \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": [
{
"type": "purchase",
"amount": -12.40,
"merchant": "Spotify",
"date": "2026-05-23T10:11:00Z"
},
{
"type": "topup",
"amount": 100.00,
"date": "2026-05-22T08:30:00Z"
}
]
}
Verification codes — Apple Pay / Google Pay & 3-D Secure
POST/cards/{card_id}/apple-pay-code
When a cardholder adds an Apple Pay Mastercard to their wallet, the issuer sends a one-time verification code by email. This endpoint captures that code and returns it to you. Only Mastercard (Apple Pay / Google Pay) cards use codes — Visa cards do not.
Two steps. First POST to arm the card (tell us a code is expected), then add the card to the wallet, and finally receive the code by webhook or by polling GET.
1 · Arm — POST
Request
curl -X POST https://izipay.me/api/v1/cards/card_abc123/apple-pay-code \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": {
"card_id": "card_abc123",
"status": "armed",
"expires_in": 600,
"delivery": {
"webhook": "card.otp",
"poll": "GET /cards/card_abc123/apple-pay-code"
}
}
}
2 · Retrieve — GET (poll)
Request
curl https://izipay.me/api/v1/cards/card_abc123/apple-pay-code \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200 (delivered)
{
"success": true,
"data": {
"card_id": "card_abc123",
"status": "delivered",
"code": "481923",
"matched_at": "2026-05-22T08:31:12Z"
}
}
i
The arm request lives for
10 minutes. While waiting,
GET returns
status: "waiting". Once the issuer's email arrives it flips to
"delivered" with the
code, and a
card.otp webhook fires.
Arm one card at a time — the issuer sends the code without a card number, so a second concurrent request cannot be matched reliably.
3-D Secure — online purchases
This is different from wallet activation. When your cardholder pays at an online merchant that requires 3-D Secure verification, the issuer generates a one-time code for that specific transaction. IZIPAY captures it and pushes it to you automatically on the card.otp webhook — no arming needed. The 3-D Secure code is tied to the exact card, so it is always matched correctly. Just handle the webhook and show the code to your cardholder to complete the payment.
card.otp webhook body — payment_3ds
{
"id": "evt_9f2c8a1b…",
"type": "card.otp",
"created": 1788169014,
"data": {
"card_id": "card_abc123",
"last4": "3624",
"code": "884916",
"kind": "payment_3ds"
}
}
card.otp webhook body — wallet_provision
{
"id": "evt_7a1b5e90…",
"type": "card.otp",
"created": 1788169100,
"data": {
"card_id": "card_abc123",
"last4": "3624",
"code": "481923",
"kind": "wallet_provision"
}
}
i
The kind field separates the two flows: payment_3ds is an online-purchase 3-D Secure code (fires automatically, no arm), and wallet_provision is an Apple Pay / Google Pay activation code (fires after you arm the card above). Every delivery carries headers X-Izipay-Signature (HMAC-SHA256 of the raw body, keyed with your webhook signing secret), X-Izipay-Event and X-Izipay-Delivery-Id — verify the signature before trusting the payload. Codes expire in about 10 minutes, so relay them to your cardholder promptly and return HTTP 200.
Get account balance
GET/balance
Returns summary statistics for your account: cards issued, total volume, and your current prepaid balance.
Request
curl https://izipay.me/api/v1/balance \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": {
"cards_issued": 128,
"cards_active": 119,
"balance_usd": 340.55
}
}
Fund the prepaid pool
POST/pool/topup
Pre-pays for a batch of card issuances at your account's card price. Funding the pool up front means later card issuance is drawn from the pool at no extra on-chain step. Pass either a number of cards or a USD amount.
Body parameters
| Field | Type | Required | Description |
| cards | integer | optional | Number of cards to pre-pay for. The USD amount is cards × card_price. |
| amount | number | optional | USD amount to add to the pool directly. Provide this or cards. |
| pay_currency | string | optional | Settlement currency. Defaults to usdttrc20. USDT/USDC/native coins on TRC-20, BSC, Ethereum, Polygon, Solana or BTC. |
Request
curl -X POST https://izipay.me/api/v1/pool/topup \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "cards": 100, "pay_currency": "usdttrc20" }'
Response · 200
{
"success": true,
"data": {
"pool_topup_id": "pool_abc123",
"cards": 100,
"amount_usd": 600.00,
"payment": {
"deposit_address": "TXs...address",
"pay_amount": 600.00,
"pay_currency": "usdttrc20",
"network": "trc20"
}
}
}
i
The pool is credited automatically once the deposit confirms on-chain. Pool balance is shown in
GET /balance. The prepaid pool applies to card
issuance; card top-ups are charged separately.
Exchange · list assets
GET/exchange/assets
Your account balance and prepaid pool are spent in USDT on Tron, Polygon or Ethereum only.
Anything else you deposit — Bitcoin, Solana, USDC — has to be moved into one of those first.
This endpoint lists what you currently hold and where it can go.
Balances are read from the blockchain, so this call takes a few seconds. Cache it rather than polling.
Request
curl https://izipay.me/api/v1/exchange/assets \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": {
"assets": [
{
"id": "sol",
"network": "sol",
"ticker": "SOL",
"label": "Solana native",
"balance": 0.27268135,
"balance_usd": 20.00,
"unit_usd": 73.35
}
],
"targets": [
{ "network": "polygon", "currency": "usdtmatic" }
]
}
}
Not exchangeable: native TRX, ETH, BNB and POL sitting on your addresses. Those are gas we
top up ourselves so sweeps can run — they are not part of your balance.
Exchange · quote
GET/exchange/quote
Minimum for a direction and an estimate of what you would receive. Every direction has its own
minimum, set by our exchange partner, and it is often higher than a small balance —
minimum_usd is returned alongside so you can tell at a glance.
Request
curl "https://izipay.me/api/v1/exchange/quote?from=sol&to_network=polygon&amount=0.5" \
-H "Authorization: Bearer YOUR_API_KEY"
Query parameters
"from" required · id from /exchange/assets
"to_network" required · trc20 | polygon | eth
"amount" optional · units of the source coin
Response · 200
{
"success": true,
"data": {
"from": "sol",
"to_network": "polygon",
"minimum": 0.16042,
"minimum_usd": 11.78,
"unit_usd": 73.44,
"to_amount_estimated": 36.21
}
}
Cost varies sharply by destination. Payouts in Tron carry a much larger fixed fee than
Polygon — on small amounts the difference can be a third of the sum. Always quote before exchanging.
Exchange · create
POST/exchange
Moves an asset from your address into USDT on the network you pick. There is no destination
address field — funds always land on your own deposit address in the target network, so an
exchange can never send money anywhere else.
Your USD balance does not change: this moves money between networks, it does not add or remove it.
Only the exchange fee is charged, after completion, as a separate swap_cost entry.
Sending runs in the background — it needs gas, and energy rental on Tron — so the response returns
immediately with pending. Poll GET /exchange/{order_ref} for progress.
Request
curl -X POST https://izipay.me/api/v1/exchange \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Idempotency-Key: your-unique-id" \
-H "Content-Type: application/json" \
-d "{"from":"sol","to_network":"polygon","amount":0.5}"
Body
"from" required · id from /exchange/assets
"to_network" required · trc20 | polygon | eth
"amount" required · units of the source coin
Response · 201
{
"success": true,
"data": {
"order_ref": "SW16AED598FE",
"status": "pending",
"from": { "currency": "sol", "amount": 0.5 },
"to": { "network": "polygon", "amount_estimated": 36.21 },
"destination": "0xc074c8...10b1"
}
}
Use X-Idempotency-Key. An exchange cannot be undone. With the key, a retried
request returns the original order instead of creating a second one — without it, a network timeout
on your side can cost you a duplicate exchange.
Exchange · status and history
GET/exchange/{order_ref}
GET/exchange
Status of one exchange, or your history (newest first, ?limit= up to 200).
status
"pending" created, funds not confirmed yet
"paid" partner received, exchanging
"done" USDT credited to your address
"failed" did not go through
"refunded" returned to the source address
"expired" order lapsed
send_status · our leg
"queued" → "sending" → "sent"
Response · 200
{
"success": true,
"data": {
"order_ref": "SW16AED598FE",
"status": "done",
"send_status": "sent",
"to": {
"amount_estimated": 19.753338,
"amount_received": 19.750278
},
"send_tx": "2Dwigm...GXuG",
"payout_tx": "0x312ad3...2433"
}
}
amount_received is what actually arrived; amount_estimated was the quote at
creation. The two differ slightly — the difference is the exchange fee and is charged from your
balance once, on completion.
Payment gateway · create a payment
POST/payments
The payment gateway lets you accept crypto from your own customers. Create a payment, show the returned address and amount to your customer, and receive funds (converted to USD) into your gateway balance — from which you can pay out. A flat gateway_fee_pct applies; see Gateway balance.
Body parameters
| Field | Type | Required | Description |
| price_amount | number | required | Amount to charge, in USD. |
| pay_currency | string | required | What the customer pays in, e.g. usdttrc20, btc, eth. Or pass a base coin (usdt) plus network. |
| order_id | string | optional | Your reference for the order (≤128 chars). |
| order_description | string | optional | Human-readable description (≤255 chars). |
| ipn_callback_url | string | optional | URL to receive status callbacks for this payment. |
Request
curl -X POST https://izipay.me/api/v1/payments \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"price_amount": 49.99,
"pay_currency": "usdttrc20",
"order_id": "order-8842"
}'
Response · 201
{
"success": true,
"data": {
"payment_id": "pay_abc123",
"order_id": "order-8842",
"status": "waiting",
"pay_address": "TXs...address",
"pay_amount": 49.99,
"pay_currency": "usdttrc20",
"network": "trc20",
"price_amount": 49.99,
"expires_at": "2026-05-22T09:15:00Z",
"qr_data": "tron:TXs...?amount=49.99"
}
}
Payment gateway · list payments
GET/payments
Lists gateway payments, most recent first.
Query parameters
| Field | Type | Required | Description |
| limit | integer | optional | Max rows (1–200). Default 50. |
| offset | integer | optional | Rows to skip. Default 0. |
| status | string | optional | Filter, e.g. confirmed, waiting. |
Response · 200
{
"success": true,
"data": {
"payments": [
{
"payment_id": "pay_abc123",
"order_id": "order-8842",
"status": "confirmed",
"pay_amount": 49.99,
"amount_paid": 49.99,
"pay_currency": "usdttrc20",
"network": "trc20",
"price_amount": 49.99,
"created_at": "2026-05-22T08:15:00Z",
"confirmed_at": "2026-05-22T08:22:00Z"
}
],
"count": 1,
"limit": 50,
"offset": 0
}
}
Payment gateway · get a payment
GET/payments/{payment_id}
Retrieves the current status of a single gateway payment.
Request
curl https://izipay.me/api/v1/payments/pay_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": {
"payment_id": "pay_abc123",
"order_id": "order-8842",
"status": "confirmed",
"pay_address": "TXs...address",
"pay_amount": 49.99,
"amount_paid": 49.99,
"pay_currency": "usdttrc20",
"network": "trc20",
"price_amount": 49.99
}
}
i
Statuses: waiting, partially_paid, confirmed, expired, failed, refund_needed.
Payment gateway · balance
GET/gateway/balance
Your gateway balance (customer payments received, net of fees) and lifetime totals. This balance is what you draw from when creating a payout.
Response · 200
{
"success": true,
"data": {
"balance_usd": 1240.55,
"gateway_fee_pct": 1.0,
"lifetime": {
"total_received_usd": 8600.00,
"total_fees_usd": 86.00,
"total_paid_out_usd": 7273.45
}
}
}
Payment gateway · create a payout
POST/payouts
Withdraws funds from your gateway balance to a crypto address you control. The payout is queued and sent on-chain.
Body parameters
| Field | Type | Required | Description |
| amount_usd | number | required | Amount to withdraw from your gateway balance, in USD. |
| network | string | required | Network to send on, e.g. trc20, bsc, polygon, eth. |
| address | string | required | Destination wallet address. |
| currency | string | optional | Asset to send. Default usdt. |
Request
curl -X POST https://izipay.me/api/v1/payouts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount_usd": 500,
"network": "trc20",
"address": "TXs...address"
}'
Response · 200
{
"success": true,
"data": {
"payout_id": "payout_abc123",
"status": "pending",
"amount_usd": 500.00,
"network": "trc20",
"currency": "usdt",
"to_address": "TXs...address",
"balance_usd": 740.55
}
}
Payment gateway · list payouts
GET/payouts
Lists your payouts, most recent first. Supports limit (1–200, default 50) and offset.
Response · 200
{
"success": true,
"data": {
"payouts": [
{
"payout_id": "payout_abc123",
"status": "sent",
"amount_usd": 500.00,
"network": "trc20",
"currency": "usdt",
"to_address": "TXs...address",
"amount_sent": 500.00,
"tx_hash": "a1b2c3...",
"created_at": "2026-05-22T08:15:00Z",
"processed_at": "2026-05-22T08:20:00Z"
}
],
"count": 1
}
}
i
Payouts are reviewed before they are sent on-chain, so status moves from pending to sent once processed. tx_hash is populated after broadcast.
Webhooks
Register an HTTPS endpoint to receive event notifications as they happen. Events are delivered as POST requests with a JSON body and are retried with backoff if your endpoint does not return 2xx.
Event types
card.createdA card record was created and is awaiting payment.
card.paidThe customer's invoice was paid.
card.issuedThe card was provisioned and is ready to use.
card.failedProvisioning failed; no charge applies.
topup.completedA top-up was applied to a card balance.
card.otpA one-time verification code was captured for a card. Two kinds via the data.kind field: payment_3ds (3-D Secure online purchase — fires automatically) and wallet_provision (Apple Pay / Google Pay activation — after you arm the card). See verification codes & 3-D Secure.
payment.confirmedA payment gateway charge was fully paid and credited to your gateway balance.
payout.sentA gateway payout was broadcast on-chain.
Example payload
{
"id": "evt_abc123",
"type": "card.issued",
"created": 1733923200,
"data": {
"card_id": "card_abc123",
"card_number": "5258 47** **** 1937",
"client_card_ref": "user_42",
"cardholder_email": "alice@example.com"
}
}
Verifying signatures
Each delivery includes an X-IZIPAY-Signature header — an HMAC-SHA256 of the raw request body, signed with your webhook secret. Always verify it before trusting an event.
Node.js
const crypto = require('crypto');
app.post('/webhooks/izipay', (req, res) => {
const signature = req.headers['x-izipay-signature'];
const expected = crypto.createHmac('sha256', WEBHOOK_SECRET)
.update(req.rawBody).digest('hex');
if (signature !== expected) {
return res.status(401).send('Invalid signature');
}
// Event is authentic — process it
res.json({ received: true });
});
List webhooks
GET/webhooks
Returns the webhook endpoints registered on your account.
Request
curl https://izipay.me/api/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY"
Response · 200
{
"success": true,
"data": {
"webhooks": [
{
"id": 7,
"url": "https://yoursite.com/hooks/izipay",
"events": ["*"],
"is_active": true,
"created_at": "2026-05-20T10:00:00Z"
}
]
}
}
Error codes
Errors return a non-2xx status and a JSON body with success: false and a machine-readable code.
| HTTP | Code | Meaning |
| 400 | VALIDATION_ERROR | A request parameter is missing or invalid. |
| 401 | INVALID_AUTH | The API key is missing or invalid. |
| 403 | FORBIDDEN | Account suspended or a limit was reached. |
| 404 | NOT_FOUND | The requested resource does not exist. |
| 409 | IDEMPOTENCY_CONFLICT | Same idempotency key reused with a different body. |
| 402 | INSUFFICIENT_BALANCE | Not enough account balance to fund the card or top-up. Top up your balance first. |
| 409 | CARD_NOT_READY | The card is not issued/activated yet. Wait for issue_status: issued before topping up. |
| 429 | RATE_LIMIT | Too many requests. Slow down and retry. |
| 502 | ISSUER_ERROR | The card issuer could not provision the card. A balance-funded charge is refunded automatically; retry later. |
| 500 | INTERNAL_ERROR | Unexpected server error. Retry with backoff. |
| 503 | UPSTREAM_ERROR | A payment or issuing partner is temporarily unavailable. |
Rate limits
Each account has a per-minute request limit and a daily card-issuance cap. Limits depend on your plan and can be raised on request.
Request rate
Per-plan req / min
Daily issuance
Per-plan cards / day
Exceeding a limit returns 429 RATE_LIMIT. Need more headroom? Contact us.