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

Ramp Network Crypto On-Ramp: Integration, Verification, and Troubleshooting

A practical engineering guide to integrating Ramp Network's crypto on-ramp and off-ramp, verifying transactions on-chain, and diagnosing the failure modes that matter in production.

TL;DR

Ramp Network is a fiat-to-crypto and crypto-to-fiat ramp that lets users buy, sell, and swap digital assets from inside a wallet or dApp while keeping custody of their keys. For developers, the integration surface is small — a widget or SDK, a webhook receiver, and an RPC connection to confirm the resulting on-chain transfer — but the failure modes are subtle because fiat settlement, KYC, and blockchain confirmation happen on different clocks. This article explains the mental model, walks through a runnable integration and verification procedure, and shows how to measure and troubleshoot each stage. It separates documented ramp behavior from the checks you must run against your own infrastructure.

Scope and the mental model of a crypto ramp

A crypto ramp is the bridge between a payment rail (card, bank transfer, local method) and a blockchain address. Ramp Network operates as a non-custodial on-ramp and off-ramp: the user completes KYC and pays fiat, and the ramp delivers the purchased asset to an address the user controls. The ramp never holds the user's private keys, which is why the integration is usually described as a widget embedded in a self-custodial wallet.

The important engineering consequence is that a single purchase spans three independent systems with different clocks: the fiat payment processor (seconds to days, depending on method and fraud checks), the ramp's compliance and settlement layer (variable), and the destination blockchain (block time plus confirmation policy). Your integration must treat these as separate state machines and reconcile them, rather than assuming one synchronous success signal.

This guide assumes you are a developer integrating a ramp into a wallet, exchange front end, or dApp, and that you already have an RPC endpoint for the destination chain. If you have not chosen one yet, the RPC Assistant endpoint recommendations and the OnFinality network directory are the right starting points; this article stays focused on the integration and verification methodology.

  • Ramp handles fiat collection, KYC, and asset delivery; you handle the wallet, the address, and on-chain confirmation.
  • The user's wallet address is the join key between the ramp's off-chain record and your on-chain verification.
  • Never mark a purchase complete from a client-side callback alone — confirm the transfer on-chain.

Prerequisites and assumptions before you start

You need an API key and environment configuration from Ramp Network's developer dashboard, a publicly reachable HTTPS endpoint to receive webhooks, and an RPC URL for every chain you intend to support. You also need a way to map your internal user ID to the wallet address that will receive funds, because that mapping is what lets you reconcile webhook events with on-chain transfers.

Treat all credentials as server-side secrets. The widget's public key can be exposed to the browser, but webhook signing secrets and any server API keys must never ship to the client. Use separate keys for sandbox and production, and keep the sandbox flow in your CI so that integration regressions are caught before release.

Finally, decide your confirmation policy per chain before writing code. A policy of one confirmation is fine for a low-value testnet flow but is unsafe for high-value mainnet purchases on chains with probabilistic finality. Document the policy next to the code so it is reviewable.

Embedding the ramp widget and passing the destination address

The typical integration loads the Ramp SDK in the browser, configures it with your public key and the user's wallet address, and opens the widget when the user chooses to buy. The address you pass is the address the ramp will deliver to, so it must be validated and normalized before the widget opens — a checksummed EVM address or a base58 Solana address, depending on the chain.

The example below is a minimal browser-side configuration. Replace the placeholders with values from your dashboard and your own application state. The exact option names are defined by the SDK version you install, so pin the version and read its release notes when upgrading.

// Browser: open the Ramp widget for a purchase
// npm install @ramp-network/ramp-instant-sdk
import { RampInstantSDK } from '@ramp-network/ramp-instant-sdk';

const widget = new RampInstantSDK({
  hostAppName: 'Example Wallet',
  hostLogoUrl: 'https://example.com/logo.png',
  url: 'https://app.ramp.network/',
  userAddress: window.walletAddress, // validated, checksummed address
  swapAsset: 'ETH_ETH',              // asset identifier from Ramp docs
  fiatCurrency: 'EUR',
  fiatValue: 100,
});

widget.on('*', (event) => {
  // Client events are UX hints only; do not settle orders here.
  console.log('ramp widget event', event.type);
});

widget.show();

Receiving and verifying webhooks on your server

Ramp sends webhook events as the purchase progresses through its states. Your server should verify the signature, persist the raw payload, and update an internal order record keyed by the ramp's purchase identifier. Do not trust the payload's asset amount as final until you have matched it to an on-chain transfer.

The handler below is deliberately defensive: it verifies the signature, acknowledges quickly, and enqueues the reconciliation work. Webhook endpoints that do slow work inline tend to time out and trigger retries, which produces duplicate processing. Idempotency on the purchase identifier is mandatory.

# Server: verify a Ramp webhook and enqueue reconciliation
import hmac, hashlib, json, os
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = os.environ['RAMP_WEBHOOK_SECRET'].encode()

@app.post('/webhooks/ramp')
def ramp_webhook():
    raw = request.get_data()
    signature = request.headers.get('X-Ramp-Signature', '')
    expected = hmac.new(WEBHOOK_SECRET, raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, signature):
        abort(401)

    event = json.loads(raw)
    purchase_id = event['payload']['purchase']['id']
    # Idempotent upsert keyed by purchase_id, then enqueue on-chain check
    enqueue_reconciliation(purchase_id, event)
    return {'ok': True}, 200

Confirming the delivered transfer with an RPC call

The webhook tells you the ramp believes it has sent funds; the chain tells you whether those funds actually arrived at the expected address. Reconciliation means querying the destination address for transfers that match the expected asset, amount, and time window, then recording the transaction hash against the order.

For EVM chains, the most reliable primitive is to scan the address's recent transactions and filter by the token contract and the counterparty. For native-asset purchases, compare the balance delta around the expected delivery window. The script below is a diagnostic you can run manually against any RPC_URL; it prints candidate transactions for review rather than making an automatic settlement decision.

#!/usr/bin/env bash
# Diagnose: list recent transactions for a destination address
RPC_URL="https://your-rpc-endpoint.example"
ADDRESS="0xYourDestinationAddress"

curl -s "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getBalance\",\"params\":[\"$ADDRESS\",\"latest\"]}"

# For token deliveries, query the token contract's Transfer logs filtered
# by the destination address and the expected block range.
curl -s "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"eth_getLogs\",\"params\":[{\"address\":\"0xTokenContract\",\"fromBlock\":\"0xSTART\",\"toBlock\":\"latest\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",null,\"0x000000000000000000000000YourAddressWithout0x\"]}]}"

A measurement procedure for ramp latency and success

You cannot improve what you do not measure, and ramp performance is dominated by fiat rails and compliance rather than by the blockchain. Build a small measurement harness that timestamps each stage of every order: widget open, KYC completion, payment authorization, webhook receipt, and on-chain confirmation. Store these as structured events so you can compute stage-by-stage latency distributions.

Run the harness against your sandbox environment with a fixed set of payment methods and chains, and record results in a table like the one below. Do not fill in numbers from another source — populate the table only with values your harness actually observed, and note the sample size and date next to it.

  • | Stage | Metric | Your observed value | Sample size |
  • | Widget open → KYC complete | median seconds | (measure) | (n) |
  • | Payment authorized → webhook received | p50 / p95 seconds | (measure) | (n) |
  • | Webhook received → on-chain confirmed | p50 / p95 seconds | (measure) | (n) |
  • | End-to-end order success rate | percent | (measure) | (n) |

Expected verification result and what a healthy order looks like

A healthy order produces a webhook with a terminal success state, a matching on-chain transfer to the exact destination address, and an internal order record that transitions from pending to settled exactly once. When you replay the webhook, the order should remain settled and no duplicate credit should occur — that replay test is the single most valuable check in your integration suite.

On the chain side, the transaction hash in your order record should resolve to a confirmed transaction whose recipient and amount match the order within the tolerance you defined for fees and price movement. If the ramp delivers a slightly different amount because of spread or fees, your reconciliation rule must account for that explicitly rather than requiring exact equality.

Troubleshooting common integration failures

Most production incidents fall into a small number of categories: webhook signature mismatches, address format errors, confirmation-policy mismatches, and RPC reliability problems. Work through them in that order, because each is cheaper to rule out than the next.

Signature mismatches usually come from computing the HMAC over a re-serialized body instead of the raw bytes, or from using the wrong environment's secret. Address errors usually come from passing an unchecksummed EVM address or a testnet address to a mainnet widget. Confirmation mismatches appear when your policy expects more confirmations than the chain's finality model provides, leaving orders stuck in pending. RPC problems show up as timeouts or stale block heights during reconciliation; a fallback endpoint and a health check on block height lag resolve most of them.

  • Log the raw webhook body and the computed signature prefix on mismatch — never log the secret.
  • Validate and checksum addresses at the boundary, before they reach the widget or the database.
  • Alert when the reconciler's RPC block height lags the chain head by more than your threshold.
  • For endpoint selection and failover guidance, see the RPC Assistant notes on reliable endpoints and the OnFinality API service overview.

Limitations, tradeoffs, and when a ramp is the wrong tool

A hosted ramp abstracts away licensing, payment methods, and fraud controls, but it also constrains you: supported assets and countries are set by the provider, KYC is mandatory, and you inherit the provider's uptime and settlement behavior. If your users are already crypto-native and hold stablecoins, a direct swap or bridge may be cheaper and faster than a fiat ramp.

There is also a custody tradeoff to communicate clearly. A non-custodial ramp keeps keys with the user, but the fiat leg still involves regulated intermediaries. Your documentation should state plainly which party holds funds at each stage, because users reasonably assume "non-custodial" applies end to end.

Finally, treat the ramp as one dependency among several. Your on-chain verification depends on your RPC provider, and your order state depends on webhook delivery. Design for retries and idempotency on both sides rather than assuming either is perfectly reliable.

Next steps: harden, observe, and scale

Once the happy path works, add the replay test, a reconciliation job that runs on a schedule, and dashboards for the stage latencies you measured. Then extend to additional chains one at a time, validating the confirmation policy and token contract for each before enabling it for users.

If you need dedicated throughput or predictable latency for reconciliation across many chains, review the dedicated node options and the RPC pricing page, and compare them against your measured p95 confirmation times. For concrete endpoint and provider choices per network, use the RPC Assistant recommendations rather than hard-coding a single URL.

  • Add webhook replay and duplicate-delivery tests to CI.
  • Schedule reconciliation to catch missed webhooks within minutes.
  • Review the multi-chain endpoint guide before expanding to new networks.
  • Re-run the measurement harness after every SDK or provider upgrade.

Never Worry about Infrastructure Again

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

Get Started