One Blockchain API for Crypto Payments, Seven Chains
Accept and send crypto payments across Bitcoin, Ethereum, TRON, Solana, BNB Smart Chain, Polygon and Arbitrum. One REST API for wallets, token transfers and deposit webhooks.
Chaingateway is a REST API for blockchain payments. You generate wallet addresses and send tokens with plain HTTPS calls, and when a deposit hits one of your addresses, a webhook notifies your server in real time. The same API covers Bitcoin, Ethereum, TRON, Solana, BNB Smart Chain, Polygon and Arbitrum.
That coverage matters more than any single feature. Most blockchain APIs handle one network; teams that add a second chain usually end up with a second codebase, because every network has its own RPC format and its own client libraries. Chaingateway removes that split. The route for an ERC-20 transfer on Ethereum is POST /api/v2/ethereum/transactions/erc20; on Polygon it is POST /api/v2/polygon/transactions/erc20. Change one path segment and your existing code runs on the next chain.
There is no node to sync and no SDK to install. Authentication is a Bearer token in the Authorization header. One extra header, X-Network: testnet, points any call at the test network instead of mainnet. A free 7-day trial starts without KYC.
What the API covers
Wallets and addresses
Create password-protected wallets for Ethereum, BSC, Polygon and TRON, or bring existing keys through import endpoints such as POST /api/v2/ethereum/addresses/import. Private keys are stored encrypted with a password only you know — Chaingateway keeps neither keys nor passwords in plain form, so without your credentials, funds stay put. Solana addresses come from POST /api/v2/solana/addresses. For payment products, the usual pattern is one address per customer or per invoice, which keeps attribution trivial: whatever arrives on address X belongs to customer X, with no matching by amount or memo.
Native and token transactions
Send ETH, BNB, POL, TRX or BTC with a single call, and move ERC-20, BEP-20, TRC-20 and SPL tokens through the same interface. Gas, gas price and nonce are optional request fields — leave them out and the API fills them in, so you pass a recipient and an amount instead of assembling raw transactions. Amounts are token units, not base units: 100 means 100 tokens of whatever contract address you supply. TRON goes further than the other chains: freeze and delegate endpoints cover staking (with unfreeze and undelegate to reverse), and TRC-10 sits next to TRC-20.
Decoded blockchain data
Responses come back as readable JSON, not hex. A decoded TRON transaction includes sender, recipient, the amount in token units, the block number and the current confirmation count. That is what a blockchain data API should return: values your application can store and display without an ABI parser.
Webhooks for incoming payments
Subscribe to on-chain events and receive a notification as soon as a deposit settles on-chain. Set a personal secret in your profile and every notification carries an X-Signature header your server can verify. Deliveries that failed are listed by the API and can be re-sent with a single call.
What works on which chain
The table condenses the current API reference into one view: which chains have address routes, which token standards you can send, and where deposit webhooks are documented.
| Chain | Addresses | Token transfers | Deposit webhooks |
|---|---|---|---|
| Bitcoin | POST /api/v2/bitcoin/wallets/{wallet}/addresses | — (no token standard) | GET /api/v2/bitcoin/webhooks/notifications |
| Ethereum | POST /api/v2/ethereum/addresses/import | ERC-20: POST /api/v2/ethereum/transactions/erc20 | GET /api/v2/ethereum/webhooks/notifications |
| TRON | POST /api/v2/tron/addresses/import | TRC-20 and TRC-10: POST /api/v2/tron/transactions/trc20 and .../trc10 | GET /api/v2/tron/webhooks/notifications |
| Solana | POST /api/v2/solana/addresses | SPL: POST /api/v2/solana/transactions/SPL | — |
| BNB Smart Chain | POST /api/v2/bsc/addresses/import | BEP-20: POST /api/v2/bsc/transactions/bep20 | GET /api/v2/bsc/webhooks/notifications |
| Polygon | POST /api/v2/polygon/addresses/import | ERC-20: POST /api/v2/polygon/transactions/erc20 | GET /api/v2/polygon/webhooks/notifications |
| Arbitrum | POST /api/v2/arbitrum/addresses/import | ERC-20: POST /api/v2/arbitrum/transactions/erc20 | GET /api/v2/arbitrum/webhooks/notifications |
Two footnotes to read the table correctly. First: TRON is the deepest integration on the platform. Beyond the routes above, the reference documents staking (POST /api/v2/tron/freeze and /delegate), chain parameters, and a self-signing pair — /transactions/trc20/build to construct a transaction and /transactions/broadcast to submit one you signed locally. If your compliance team insists that private keys never leave your servers, that build-and-broadcast pattern is your way in.
Second: a dash means the current reference documents no v2 route for that cell, not that the network is second-class. Bitcoin has no token standard, hence the empty token cell — native BTC runs through its own wallet model instead: create a password-encrypted wallet with POST /api/v2/bitcoin/wallets, derive deposit addresses under it, and send with POST /api/v2/bitcoin/transactions. Solana's reference covers address creation, SOL and SPL transfers, and balance and block lookups, but no webhooks yet. For anything not listed here, the API reference has the current state.
A blockchain API example: the first call in four languages
Get an API key (next section), then confirm it works. GET /api/account returns your account details and proves the key is valid.
curl https://app.chaingateway.io/api/account \
-H "Authorization: Bearer YOUR_API_KEY"That's the whole authentication check — create an account and the same call proves your own key works.
How to get a blockchain API key
Register at app.chaingateway.io/register. The 7-day trial starts without KYC.
Copy the API key from your dashboard.
Send it with every request as Authorization: Bearer YOURAPIKEY, and keep it server-side only. Client-side code would expose it to anyone who opens the browser console. The account panel can additionally restrict the key to your servers' IP addresses, so a leaked key is useless anywhere else. More hardening steps are in our security tips for the blockchain API.
Receiving deposits: the webhook flow
A payment integration usually looks like this:
Create or import a deposit address for each customer.
The customer sends coins or tokens to that address.
Once the transfer settles, Chaingateway POSTs a notification to your callback URL — with an X-Signature header if you have set a personal secret.
Your server verifies the signature and credits the customer account.
Webhook security in practice
A webhook endpoint is a door into your backend, and this particular door credits money. Chaingateway gives you three mechanisms to guard it; a production handler should use all three. This applies to the six chains with deposit webhooks — Solana deposit detection uses polling instead, covered further down.
1. Verify the signature
Set a personal secret in your profile settings — from then on every notification carries an X-Signature header, built as base64 of an HMAC-SHA256 over the txid field of the payload, keyed with that secret. Recompute it from the received txid, compare it to the header value before you credit anything, and use a constant-time comparison — most standard libraries ship one. Reject failures with a 401. This closes the obvious attack: anyone who discovers your callback URL can POST fabricated deposits to it, and without signature checks your shop would ship goods for payments that never happened.
2. Design for redelivery
A notification can reach you more than once — you can re-send failed ones through the API, and nothing guarantees exactly-once delivery in between. Key your credit logic to the transaction hash rather than to the number of callbacks received — an INSERT ... ON CONFLICT DO NOTHING on the hash column costs one line and retires the whole double-credit class of bugs. Respond with a 2xx as soon as the notification is persisted and do slow processing afterwards; a handler that does heavy work inline runs into timeouts and turns one deposit into a support case.
3. Use the recovery routes
If your endpoint was down or answered with an error, the delivery lands on the failed list: GET /api/v2/{chain}/webhooks/notifications/failed shows what did not get through, and POST /api/v2/{chain}/webhooks/notifications/{id}/retry re-sends each one on your command. For everything else — a database failover, a bad deploy, an expired TLS certificate — GET /api/v2/{chain}/webhooks/notifications returns the full delivery history, so a nightly reconciliation job can compare it against your ledger and repair the gaps. Payload details and verification code are in the webhook guide.
Test on testnet, ship the same code
Every route accepts one extra header, X-Network: testnet, and runs against the test network instead of mainnet. Endpoints, request bodies and response shapes stay identical; the coins are worthless. That last property is the point. Your integration tests can create addresses, move tokens and receive webhooks all day without touching real funds.
A practical setup looks like this. Put the header behind an environment variable, so staging sends it and production does not — no code diff between the two. Give staging its own callback URL, otherwise test deposits land in your production webhook handler and confuse the ledger. Test coins come free from the public faucets each ecosystem runs; the supported-networks page in the docs names the test network per chain — Sepolia for Ethereum, Nile for TRON, Amoy for Polygon, testnet3 for Bitcoin.
When the flow works end to end — address created, deposit detected, webhook verified, balance credited — delete the header. Nothing else changes. That symmetry is deliberate, and it is why going live is a config change rather than a second integration project.
Three integrations, walked through
Feature lists say little about integration effort, so here are three builds we see often, each reduced to its moving parts.
Deposits for an online shop
A store wants to accept USDT at checkout. When a customer picks crypto, your backend assigns an address for that order and displays it next to the amount. From there the webhook does the work. The notification arrives once the transfer settles on-chain; mark the order "payment detected" and show that to the customer, because fast feedback is what makes crypto checkout feel trustworthy. If your policy wants more depth for larger amounts, check the transaction with GET /api/v2/{chain}/transactions/{txid} until your threshold is reached, then mark the order paid and start fulfillment.
Two edge cases decide whether this build is production-grade. Underpayment: customers sometimes send slightly less than the invoice, usually because their wallet deducted network fees from the entered amount. Decide the tolerance up front — absorb a small shortfall, or hold the order and request the difference. Overpayment is rarer and easier: credit it or refund it, but log it either way. Both cases fall out of comparing the notified amount against the invoice amount instead of treating any callback as "paid".
Batch payouts
An affiliate platform pays hundreds of partners in stablecoins every month, on Polygon because fees there stay small relative to the payout amounts. The build is a queue and a loop:
import requests
payouts = load_pending_payouts() # [{"address": ..., "amount": ...}, ...]
for p in payouts:
r = requests.post(
"https://app.chaingateway.io/api/v2/polygon/transactions/erc20",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"contractaddress": "0xTokenContract...",
"from": "0xTreasuryWallet...",
"to": p["address"],
"amount": p["amount"],
"password": "treasury-wallet-password",
},
)
record_result(p, r.json()) # persist before the next iteration
The queue matters more than the loop. Persist each payout's state before you send it, store the API response immediately, and never retry a send just because the HTTP call timed out — the transaction may have gone through anyway. Check your stored results and GET /api/v2/polygon/transactions, which lists every transaction created through the API, then re-send only what verifiably never happened. That one rule separates payout systems that survive audits from payout systems that end in spreadsheet archaeology.
On-chain billing for a SaaS
A B2B tool bills customers monthly in stablecoins because card processors keep declining its merchant category. The build reuses the shop pattern with one twist: a fresh deposit address per invoice, not per customer. Address-per-invoice makes matching trivial — any amount arriving on invoice 4711's address belongs to invoice 4711 — and it removes the guesswork of matching payments by amount when two invoices happen to total the same sum. The webhook marks invoices paid; a scheduled job expires stale ones and sends reminders. Nothing in this flow requires a wallet UI, a browser extension or any crypto knowledge on the customer's side beyond the ability to send a transfer.
Supported blockchains
Each chain has its own page with endpoints and code samples:
- Bitcoin API — the original chain. Native BTC transfers from password-encrypted wallets, plus deposit webhooks for incoming payments.
- Ethereum API — the most widely adopted smart contract platform, with ERC-20 token transfers and ERC-721 NFT support.
- TRON API — TRC-10 and TRC-20 transactions, staking via freeze and delegate, and self-signing build/broadcast routes. Estimate transfer costs upfront with the TRON fee calculator.
- Solana API — address creation and SPL token transactions on a high-throughput chain.
- BNB Smart Chain API — BEP-20 transfers with the same route pattern you use on Ethereum.
- Polygon API — ERC-20 transfers on Ethereum's scaling chain, at a fraction of mainnet gas costs. This is the Polygon blockchain API, not the Polygon.io stock-data service.
- Arbitrum API — Ethereum L2 for high throughput, sharing the mainnet endpoint layout.
Migrating from JSON-RPC to REST
A blockchain API replaces raw JSON-RPC calls with one authenticated REST request per action. Where JSON-RPC needs several round trips per transfer, plus manual ABI encoding, nonce tracking and signing, a call like POST /api/v2/{chain}/transactions/erc20 (bep20 on BNB Smart Chain) collapses all of that into a single request.
Plenty of teams arrive here with an integration already running: web3.js against a paid RPC endpoint, or a hand-rolled JSON-RPC client from an earlier era of the codebase. The migration is less dramatic than it sounds, because the API absorbs whole categories of code rather than replacing it call for call.
Take the canonical EVM send path. Over JSON-RPC, a token transfer is a sequence: eth_getTransactionCount for the nonce, eth_gasPrice or a fee-history call for pricing, eth_estimateGas against ABI-encoded calldata, local signing, then eth_sendRawTransaction to broadcast. Each step has failure modes your code currently handles — or silently doesn't. All five collapse into one authenticated POST to /api/v2/{chain}/transactions/erc20, and the nonce bookkeeping, the usual source of "stuck transaction" tickets, leaves your codebase entirely.
Event detection changes shape more than it changes logic. Where you polled eth_getLogs with a block cursor or held a WebSocket subscription open through every reconnect bug, you now register a webhook and delete the poller. Your downstream logic — parse the transfer, match the customer, credit the balance — stays as it is; only the input side flips from pull to push.
What does not map: consensus tooling, custom indexers, anything that needs raw block access. Keep an RPC endpoint for those jobs; the two coexist without friction. Payments are usually the first workload worth moving, because they carry the most operational risk per line of code. The longer comparison, including the cases where a node wins, is in blockchain API vs. blockchain node.
When a request fails
Error handling for a payments API deserves more than a generic catch block, because a failed request and a failed transaction are different events.
The HTTP layer follows REST conventions. A 401 means the Bearer token is missing, wrong or expired — fix the credential, don't retry. Other responses in the 4xx range say the request itself is at fault: a malformed address, a missing field, a validation error. Log the response body, which names the specific problem, and treat these as bugs to fix rather than transient conditions to retry. The 5xx range and network-level timeouts form the transient class, where a retry with exponential backoff is the right reflex.
With one exception, and it is the exception that matters. Never blind-retry a request that moves funds. A timeout tells you that you did not receive the response — not that the transaction failed. The safe sequence: check whether the transfer went out, using your stored results and GET /api/v2/{chain}/transactions (the list of transactions your key created), and re-send only when you can show it never happened. Idempotency keys on your side, tied to your own payout or order IDs, make that check cheap.
Build observability in from day one. Log request and response pairs for every money-moving call, and alert on 4xx rates rather than only on 5xx — a sudden burst of validation errors usually means a deploy broke your request format. Catching that in minutes instead of days is the difference between an incident and a footnote.
Run your own nodes or use an API?
Running nodes yourself gives you full control and no third-party dependency. It also means one machine per chain, disk and bandwidth budgets, sync monitoring and version upgrades — multiplied by seven if you want the coverage described above. Our comparison of blockchain API vs. blockchain node walks through that trade-off. The short version: run a node when you need consensus-level control, use the API when you need payments working this week.
Frequently asked questions
Ready to accept crypto payments?
Create an account at app.chaingateway.io/register, pick a chain from the seven above and send a testnet transfer. The full endpoint reference is in the docs, and plans and rate limits are listed on their own page.