Logo
New RPC users get 35% off their first monthView the offer
OnFinality Learn
Integration & Development11 min read

Cryptocurrency Gateways: Architecture, Integration, and Verification

A technical guide to how cryptocurrency payment gateways work under the hood, how to integrate one safely, and how to verify settlement and reconciliation against on-chain data.

TL;DR

A cryptocurrency gateway is a service layer that sits between a merchant's checkout and public blockchains: it creates payment intents, watches addresses for incoming transfers, applies confirmation and risk rules, and settles value to the merchant in crypto or fiat. This article explains the architecture behind that flow, shows how to integrate a gateway through its API and webhooks, and gives reproducible procedures for verifying that a reported payment actually exists on-chain. It separates documented gateway behavior from design recommendations and from measurements you must run against your own provider and nodes. The goal is a checkout you can audit, not just one that renders a QR code.

What a cryptocurrency gateway actually does

A cryptocurrency gateway is a payment processor for digital assets. At checkout, the customer is quoted an amount in a specific coin or token, usually derived from a fiat price with a short validity window. The gateway assigns a deposit address or payment intent, monitors the chain for a matching transfer, applies confirmation thresholds and risk checks, and then either credits the merchant's gateway balance or triggers settlement to a bank account or stablecoin wallet.

The important mental model is that the gateway does not move funds through a card network. Value moves as ordinary on-chain transactions to addresses the gateway controls. Everything else, the invoice, the exchange rate, the webhook, the ledger entry, is bookkeeping layered on top of those transfers. That distinction matters because it tells you where failures can occur: a webhook can be delayed or duplicated while the on-chain transfer is final, and a gateway ledger can be wrong while the chain is right.

Gateways are optional. A merchant can accept crypto directly to a self-custodied wallet, but then owns address management, price quoting, confirmation policy, accounting, and refunds. A gateway removes most of that operational work in exchange for fees, custody or settlement terms, and dependence on a third party's uptime.

  • Payment intent: the invoice record tying an order to an amount, asset, address, and expiry.
  • Chain watcher: the service that scans blocks for transfers to gateway-controlled addresses.
  • Confirmation policy: how many blocks or finality conditions must pass before a payment is treated as settled.
  • Settlement: conversion and transfer of value to the merchant, in crypto or fiat.
  • Reconciliation: matching gateway ledger entries to on-chain transactions and your own order records.

Assumptions and prerequisites before you integrate

This guide assumes you already have a checkout or order system with a server-side component, a database where you can store payment state, and the ability to receive HTTPS callbacks. You should know which assets and networks you intend to accept, because a USDT payment on one chain is not the same integration as USDT on another: address formats, confirmation behavior, and fee economics differ.

You also need a way to read chain data independently of the gateway. That is where an RPC provider fits. A gateway tells you what it believes happened; an RPC endpoint lets you confirm what the chain actually recorded. OnFinality's multi-chain RPC endpoints can serve that verification role, and the supported networks list tells you which chains are available. If you expect sustained verification traffic, review dedicated node options rather than assuming shared public capacity is sufficient.

Finally, decide your settlement model before writing code. Custodial auto-conversion to fiat, stablecoin settlement, and direct crypto settlement produce different ledger shapes and different reconciliation steps.

The payment flow from checkout to settlement

A typical gateway flow has six stages. First, your server creates a payment or invoice through the gateway API, passing the order ID, amount, currency, and callback URL. Second, the gateway returns a payment identifier, a deposit address, the exact crypto amount, an exchange rate, and an expiry time. Third, your checkout displays that information, often as a QR code plus a copyable address and amount.

Fourth, the customer broadcasts a transfer. Fifth, the gateway's chain watcher detects the transfer, waits for its confirmation policy, and marks the payment as confirmed or partially paid. Sixth, the gateway sends a signed webhook to your callback URL and updates its ledger. Settlement to you happens on the gateway's schedule, which may be immediate per payment, batched, or on demand.

Two details cause most integration bugs. The quoted crypto amount is time-limited, so a payment sent after expiry may be underpaid relative to the new rate. And the amount must match exactly after accounting for network fees, which the sender typically pays on top; a customer who subtracts fees from the transfer produces a shortfall the gateway will report as partial.

Creating a payment intent through the gateway API

The exact endpoint and field names differ by provider, so treat the following as a shape rather than a specification. Always confirm against your provider's current API reference. The pattern is consistent: authenticate with an API key held server-side, create an invoice, persist the returned identifier and address, and never trust client-supplied amounts.

The curl example below uses placeholders for the gateway base URL and credentials. Run it from a server environment, not a browser, and log the response body alongside your order ID so you can reconcile later.

curl -X POST "$GATEWAY_BASE_URL/v1/payments" \
  -H "Authorization: Bearer $GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "order_1042",
    "price_amount": 49.00,
    "price_currency": "USD",
    "pay_currency": "USDT",
    "network": "ETH",
    "callback_url": "https://merchant.example.com/webhooks/gateway",
    "success_url": "https://merchant.example.com/checkout/success"
  }'

Handling webhooks idempotently

Webhooks are the gateway's notification channel, and they are not guaranteed to arrive once, in order, or at all. Your handler must verify the signature, look up the payment by the gateway identifier, and apply a state transition only if it moves the payment forward. Store the raw payload and a hash of it so duplicate deliveries are detectable.

The JavaScript sketch below shows the essential guard: verify, deduplicate, then transition. It deliberately does not contain provider-specific signature logic, because that depends on the gateway's documented scheme.

import crypto from "node:crypto";

// Verify signature per your gateway's documented scheme.
function verify(rawBody, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

async function handleWebhook(req, res) {
  const raw = req.rawBody; // preserve the unparsed body
  if (!verify(raw, req.headers["x-gateway-signature"], process.env.GATEWAY_WEBHOOK_SECRET)) {
    return res.status(401).end();
  }
  const event = JSON.parse(raw);
  const payment = await db.payments.findByGatewayId(event.payment_id);
  if (!payment) return res.status(404).end();

  const seen = await db.webhookEvents.exists(event.event_id);
  if (seen) return res.status(200).end();

  await db.transaction(async (tx) => {
    await tx.webhookEvents.insert({ id: event.event_id, payload: raw });
    if (event.status === "confirmed" && payment.status !== "paid") {
      await tx.payments.markPaid(payment.id, event.txid);
    }
  });
  return res.status(200).end();
}

Verifying a reported payment against the chain

A webhook is a claim. Before you ship goods or release funds above a risk threshold, confirm the claim against an RPC endpoint you control. The procedure is: fetch the transaction by hash, check that it succeeded, check that the recipient matches the deposit address, check the transferred amount and asset, and check the confirmation depth.

The Python example below uses JSON-RPC over HTTP with a placeholder RPC_URL. It is written for an EVM-style chain and native-value transfers; token transfers require decoding the logs or calling the token contract's transfer event instead. Adapt the asset check to the chain you accept.

import os, requests

RPC_URL = os.environ["RPC_URL"]

def rpc(method, params):
    r = requests.post(RPC_URL, json={"jsonrpc":"2.0","id":1,"method":method,"params":params}, timeout=10)
    r.raise_for_status()
    body = r.json()
    if "error" in body:
        raise RuntimeError(body["error"])
    return body["result"]

def verify_payment(tx_hash, expected_to, expected_wei, min_confirmations):
    tx = rpc("eth_getTransactionByHash", [tx_hash])
    receipt = rpc("eth_getTransactionReceipt", [tx_hash])
    if tx is None or receipt is None:
        return {"ok": False, "reason": "not_found"}
    if receipt["status"] != "0x1":
        return {"ok": False, "reason": "reverted"}
    if tx["to"].lower() != expected_to.lower():
        return {"ok": False, "reason": "wrong_recipient"}
    if int(tx["value"], 16) < expected_wei:
        return {"ok": False, "reason": "underpaid"}
    head = int(rpc("eth_blockNumber", []), 16)
    depth = head - int(receipt["blockNumber"], 16) + 1
    return {"ok": depth >= min_confirmations, "depth": depth}

Measuring confirmation latency and webhook delay

Gateway dashboards rarely publish the latency you will actually experience, because it depends on your chain, your confirmation policy, and network conditions at the time. Measure it yourself. For each test payment, record four timestamps: when the invoice was created, when the transaction was first seen in a block, when the gateway marked it confirmed, and when your webhook handler received the event.

Run at least twenty test payments per asset and network you plan to accept, spread across different times of day. Compute the median and 95th percentile for chain inclusion time and for webhook delay. Do not publish or rely on numbers from another merchant's environment; block times and provider behavior change.

Record results in a table like the one below, filling in your own measurements. The column structure is the deliverable; the values are yours to produce.

  • Columns: asset, network, confirmation threshold, median inclusion time, p95 inclusion time, median webhook delay, p95 webhook delay, sample size.
  • Exclude test payments that were never broadcast or were sent with insufficient fees.
  • Re-run the measurement after any gateway plan change, chain upgrade, or confirmation-policy change.

Troubleshooting common integration failures

Most failures fall into a small set of categories, and each has a diagnostic path. Work from the chain outward: confirm the transfer exists, then confirm the gateway saw it, then confirm your system recorded it.

If the customer says they paid but the invoice shows pending, ask for the transaction hash and verify it against your RPC endpoint. A transfer to the wrong address, a transfer on the wrong network, or a transfer of the wrong asset will not be credited. If the transaction is correct and confirmed but the gateway has not updated, the issue is on the gateway side or in its confirmation policy; check its status page and support channel.

If the gateway shows confirmed but your order is unpaid, the webhook likely failed signature verification, arrived at an endpoint that returned an error, or was dropped. Reconcile by polling the gateway's payment-status endpoint for open invoices on a schedule, and treat polling as a backstop rather than a replacement for webhooks.

  • Underpayment: customer subtracted network fees or sent after the quote expired.
  • Wrong network: same asset symbol on a different chain, unrecoverable without gateway support.
  • Duplicate credit: webhook handler not idempotent, or retries applied twice.
  • Signature mismatch: raw body altered by a framework's JSON parser before verification.
  • Stuck pending: confirmation threshold not reached, or chain reorganization rolled back the block.

Settlement models and their tradeoffs

Custodial auto-conversion settles each payment into fiat or a stablecoin at the gateway, removing price exposure but adding counterparty and regulatory dependence. The gateway holds funds briefly, applies its conversion rate, and pays out on a schedule. Your ledger records fiat amounts, and reconciliation compares gateway statements to bank or stablecoin receipts.

Stablecoin settlement keeps value in a dollar-pegged asset on-chain, which suits businesses that already operate in crypto but still want to avoid volatility. Direct crypto settlement pays you in the asset received, which means you carry price risk between payment and conversion and must manage your own treasury.

Self-custody acceptance, where you generate addresses and watch the chain yourself, gives maximum control and no gateway fee, but requires you to run or rent reliable infrastructure, implement confirmation policy, and handle refunds manually. It is a reasonable choice for high-volume merchants with engineering capacity; for most others, a gateway plus independent on-chain verification is the pragmatic middle.

Limitations, compliance, and what to verify before launch

Gateways operate under licensing regimes that vary by jurisdiction, and their supported assets, settlement currencies, and KYC requirements differ accordingly. Confirm that your provider is licensed to serve your customers' and your own jurisdictions, and that its terms permit your business category. This article does not provide legal advice; treat licensing as a procurement question with documented answers.

Technically, no gateway eliminates chain risk. Reorganizations, congested blockspace, and fee spikes all affect confirmation timing. Your confirmation thresholds should reflect the value at risk: a small digital purchase may need one confirmation, while a large transfer may warrant a deeper threshold or a finality-aware chain.

Before launch, verify four things end to end: a successful payment credits the order exactly once, a failed or reverted transaction does not credit, a duplicate webhook does not double-credit, and a refund path exists that your support team can execute. Each of these should be a repeatable test in your staging environment.

Next steps for a production-ready integration

Start by building the verification layer alongside the gateway integration rather than after it. A small service that takes a transaction hash and returns a verified status, backed by an RPC endpoint you control, gives you an independent source of truth for support, reconciliation, and fraud review. OnFinality's RPC API service and network coverage are the starting points; review RPC pricing to size verification traffic, and consider dedicated nodes if you need predictable throughput.

If you are still choosing an endpoint or provider for the verification layer, the RPC Assistant's guide to RPC endpoints explains the tradeoffs, and the multi-chain RPC endpoints guide covers operating across several chains. For teams building broader Web3 infrastructure, the best RPC provider for Web3 projects comparison is a useful companion.

Then instrument the flow: log every invoice creation, webhook receipt, and verification result with a shared correlation ID. Run the latency measurement described above, set confirmation thresholds per asset, and schedule a quarterly reconciliation between gateway statements, on-chain records, and your own ledger. That combination, a gateway for the payment experience and your own chain reads for the truth, is what makes a cryptocurrency gateway integration auditable.

Never Worry about Infrastructure Again

OnFinality takes away the heavy lifting of DevOps so you can build smarter and faster.

Get Started