on this page

ChainGate

A self-custody crypto payment gateway API. Merchants accept payments across 4 EVM chains with no third-party custody and none of the 1-1.5% fees charged by Stripe or Coinbase Commerce.

ChainGate lets merchants accept cryptocurrency payments directly into their own wallet, with no Stripe, no Coinbase Commerce, no third-party custody, and none of the 1-1.5% fees those gateways charge. It’s an Express.js API that issues a unique deposit address per invoice, watches four EVM chains for incoming funds, and notifies your app the moment a payment confirms.

Receives money, can’t spend it

The server only ever holds an extended public key (xpub). It derives a fresh deposit address for every invoice but is cryptographically incapable of signing a transaction or moving funds, so your private keys never leave your hardware wallet.

Tech Stack

Node.js · TypeScript · Express.js · ethers.js · Prisma · PostgreSQL · Docker · Jest

How It Works

A merchant creates an invoice; the API returns a one-time deposit address derived from the merchant’s xpub. The customer pays it, the block scanner detects the transaction, and once it reaches the chain’s confirmation threshold a signed webhook fires back to the merchant’s app.

curl -X POST https://api.example.com/api/v1/invoices \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -d '{ "chainId": "ethereum", "amount": "0.05", "currency": "ETH", "expiresIn": 3600 }'
{
  "id": "uuid",
  "status": "created",
  "chainId": "ethereum",
  "depositAddress": "0x…",
  "amount": "0.05",
  "currency": "ETH",
  "expiresAt": "2026-01-01T01:00:00.000Z"
}

Key Features

  • Self-custody address derivation from an xpub, so the server can receive funds but never spend them
  • Parallel block scanner across all four chains that confirms payments within one block
  • Direct-to-wallet settlement with no gateway fees
  • HMAC-signed webhooks with automatic retries
  • Full invoice lifecycle tracking, including expired, overpaid, and underpaid states
  • Production setup with Zod validation, Prisma, PostgreSQL, Swagger docs, and Docker

Supported Chains

ChainChain IDConfirmationsBlock Time
Ethereum112~12s
Polygon13730~2s
BSC5615~3s
Arbitrum421611~250ms

Each chain activates only when its RPC URL is configured, so merchants run exactly the networks they need.

Verifying Webhooks

Every webhook is signed so the merchant can confirm it really came from ChainGate:

const crypto = require("crypto");
 
function verifyWebhook(body, secret, signature) {
  const expected = crypto.createHmac("sha256", secret).update(body).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(signature, "hex"),
  );
}