Developers

Payment gateway integration

Accept crypto on your site with Bit2Fiat SCI. Create invoices from your server, redirect buyers to a hosted pay page, then settle into the merchant wallet and notify your backend via IPN.

Quick start

  1. Create a Bit2Fiat account and open Settings → Payment gateway.
  2. Enable SCI and copy your api_key and api_secret (secret is shown once).
  3. From your server, POST https://bit2fiat.com/sci with amount, coin, and order details.
  4. Redirect the buyer to payment_url from the response.
  5. Listen for IPN webhooks (and/or poll status) to mark the order paid.

Authentication

All create-payment requests must authenticate the merchant. Prefer HMAC signatures in production so the secret never leaves your server in query strings.

Option A — API secret (server-to-server)

Send credentials in the JSON/form body or headers:

Field / headerDescription
api_keyPublic merchant key (also X-Api-Key or Basic auth username).
api_secretPrivate secret (also X-Api-Secret or Basic auth password).
Authorization: Basic …base64(api_key:api_secret)

Option B — HMAC signature

Build a message and sign with your secret using HMAC-SHA256 (hex):

signature message
api_key|coin|amount|order_id|timestamp|nonce
FieldRules
timestampUnix seconds; must be within ±300s of server time.
nonceRandom unique string per request.
signaturehash_hmac('sha256', message, api_secret) as hex.
order_idUse empty string in the message if you omit order_id.
PHP example
$message = implode('|', [$apiKey, $coin, $amount, $orderId, $timestamp, $nonce]);
$signature = hash_hmac('sha256', $message, $apiSecret);

Create a payment

POST https://bit2fiat.com/sci

CSRF is not required for this endpoint (server-to-server). Send JSON with Content-Type: application/json and Accept: application/json for a JSON response. Without JSON headers, a successful create redirects to the pay page.

Request fields

FieldRequiredDescription
api_keyYes*Merchant API key (*or via header / Basic auth).
api_secret / signatureYesOne of secret or HMAC signature.
coinYesAsset code, e.g. USDT_TRC20, BTC.
amountYesHuman decimal amount, e.g. 25.00.
order_idNoYour reference (unique per merchant while active).
success_urlNoBuyer redirect after paid (we append payment_id, order_id, status).
cancel_urlNoBuyer cancel / expired return URL.
ipn_urlNoYour webhook URL for payment notifications.
buyer_emailNoOptional buyer contact.
jsonNoSet 1 to force JSON response.

cURL example

bash
curl -X POST 'https://bit2fiat.com/sci' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
    "api_key": "b2f_YOUR_KEY",
    "api_secret": "YOUR_SECRET",
    "coin": "USDT_TRC20",
    "amount": "25.00",
    "order_id": "ORD-1042",
    "success_url": "https://yoursite.com/paid",
    "cancel_url": "https://yoursite.com/cancel",
    "ipn_url": "https://yoursite.com/webhooks/bit2fiat"
  }'

Success response

200 JSON
{
  "ok": true,
  "payment_id": "uuid",
  "payment_url": "https://bit2fiat.com/pay/uuid",
  "address": "T…",
  "coin": "USDT_TRC20",
  "amount": "25",
  "order_id": "ORD-1042",
  "expires_at": "2026-08-06T14:00:00+00:00",
  "status": "pending"
}
Redirect the customer to payment_url. Do not show raw deposit addresses from your own UI unless you also poll status yourself.

Checkout page & status

GET https://bit2fiat.com/pay/{payment_id}

Hosted pay page (QR, address, countdown, partial payment progress).

GET https://bit2fiat.com/pay/{payment_id}/status

JSON status for polling (the pay page polls this every few seconds).

status payload (excerpt)
{
  "payment_id": "uuid",
  "order_id": "ORD-1042",
  "status": "pending",
  "status_label": "Awaiting payment",
  "coin": "USDT_TRC20",
  "address": "T…",
  "amount_expected": "25",
  "amount_received": "0",
  "amount_remaining": "25",
  "progress_pct": 0,
  "success_url": null,
  "expires_at": "…"
}

IPN (merchant webhooks)

When a payment status changes in a way that settles (paid / overpaid) or reports underpaid, Bit2Fiat POSTs form fields to your ipn_url. Respond with HTTP 200 (body containing ok is preferred). Failed deliveries are retried with backoff.

IPN fields

FieldDescription
payment_idBit2Fiat payment UUID
order_idYour order reference
statuse.g. paid, overpaid, underpaid
coinCoin code
amount_expectedInvoice amount (human)
amount_receivedAmount buyer sent (human)
amount_remainingStill due (human)
fee_amountPlatform product fee if configured
tx_hashLatest on-chain transaction
confirmationsConfirmations observed
addressDeposit address
paid_at / credited_atISO timestamps when set
signatureHMAC of other fields

Verify IPN signature

Sort all fields except signature by key ascending, join as key=value with &, then:

PHP
ksort($payload);
unset($payload['signature']);
$pairs = [];
foreach ($payload as $k => $v) {
    if (is_array($v)) continue;
    $pairs[] = $k.'='.$v;
}
$expected = hash_hmac('sha256', implode('&', $pairs), $apiSecret);
hash_equals($expected, $receivedSignature);
Treat IPN as the source of truth for order fulfillment. Browser redirects can be bookmarked or skipped.

Payment statuses

StatusMeaning
pendingInvoice created; waiting for chain payment.
confirmingTransaction seen; waiting for confirmations.
underpaidPartial payment received; remaining amount still due (same address).
paidFully paid; merchant wallet credited for invoice amount.
overpaidBuyer sent more than invoice; still settles as success (invoice amount credited).
expiredPayment window ended without full settlement.
cancelledCancelled (reserved).

Supported coins

Pass the exact code in the coin field. Currently active:

BTC ETH USDC_BEP20 USDC_ERC20 USDT_BEP20 USDT_ERC20 USDT_TRC20

Errors

JSON error shape:

error
{ "ok": false, "error": "Human readable message" }
HTTPTypical cause
401Missing/invalid api_key, secret, or signature.
422Validation failed, unsupported coin, duplicate finished order_id, etc.
500Unexpected server/provider error (e.g. address generation).

Security checklist

  1. Keep api_secret only on your server — never in browser JS or mobile apps.
  2. Prefer HMAC signatures for create requests in production.
  3. Always verify IPN signature before fulfilling orders.
  4. Use HTTPS for success_url, cancel_url, and ipn_url.
  5. Make fulfillment idempotent: the same payment_id may notify more than once.