Invisible Web3 top-ups for your customers.
White-label, non-custodial fiat-to-stablecoin top-up infrastructure. End-users log in with email, top up in USDT or USDC, and authorise every transfer themselves. You receive a signed webhook and credit your own balance.
Drop-in widget, signed webhooks, no licensing burden
5-minute integration
One JS snippet on the page, one HMAC verification on the backend. WordPress, Shopify, Next.js, plain HTML — all covered with copy-paste recipes.
Non-custodial by design
End-user keys live in a 2-of-3 MPC network. We never see or sign them. Every transfer is user-authorised in the browser via Web3Auth.
Multi-chain stablecoins
USDT & USDC native on Polygon, Base, Arbitrum, Optimism, BSC, Avalanche. Testnets included from day one for merchant sandbox flows.
Signed webhook events
HMAC-SHA256 over {timestamp}.{body},
replay-window enforced. Drop-in
verifyWebhook() in our Node, Python and PHP
SDKs.
Audit-ready
Append-only audit log, OFAC SDN screening before broadcast, configurable AML thresholds. We log; you decide.
Cloud-agnostic
Serverless adapters for AWS Lambda and GCP Cloud Functions. Postgres anywhere. KMS via AWS or GCP.
How a single top-up looks
Your customer never leaves your site. We never touch fiat. The fiat-to-crypto leg is handled by a licensed on-ramp partner.
User logs in with email
Web3Auth derives a persistent MPC wallet for that address. No seed phrases, no MetaMask.
User tops up in fiat
Embedded Transak widget converts card / bank → USDT or USDC into the user's wallet.
User clicks "Send"
The browser builds an ERC-20 transfer; the MPC network co-signs with the user. We never see the key.
We validate & relay
Server checks destination = your master wallet, screens sanctions, then broadcasts the user-signed tx.
Webhook to you
You receive transfer.broadcast and transfer.confirmed HMAC-signed events. Credit your own ledger.
Verify a webhook in three languages
Same shape, same constants, same constant-time compare.
Node.js
import { verifyWebhook } from '@cryptopay/sdk';
if (!verifyWebhook({
rawBody: req.rawBody,
header: req.headers['x-cryptopay-signature'],
secret: process.env.SECRET,
})) return res.sendStatus(401);
Python
from cryptopay import verify_webhook
if not verify_webhook(
raw_body=request.body,
header=request.headers["X-CryptoPay-Signature"],
secret=settings.SECRET,
):
return 401, b""
PHP
use CryptoPay\Webhook;
if (!Webhook::verify(
file_get_contents('php://input'),
$_SERVER['HTTP_X_CRYPTOPAY_SIGNATURE'],
getenv('SECRET'),
)) {
http_response_code(401); exit;
}
Or curl, for debugging
SIG=$(printf '%s.%s' "$TS" "$BODY" \
| openssl dgst -sha256 -hmac "$SECRET" \
| awk '{print $2}')
echo "t=$TS,v1=$SIG"
Want to integrate?
Pilot integrations are free during our testnet phase. Production tier launches once our on-ramp partner KYB completes. Drop us a line and we'll respond within a working day.