Summary
The BNB Smart Chain (BSC) JSON-RPC endpoint is the HTTP or WebSocket URL your app points at to read chain state and submit transactions. For mainnet you need chain ID 56, the BNB native currency, and a reliable RPC URL; for testnet you use chain ID 97 and tBNB. This page covers the exact chain settings, wallet and code configuration, the JSON-RPC methods you will call most, and how to debug the errors that show up first. It also explains when a shared public endpoint is enough and when a dedicated BNB Chain node is the better fit.
If you are wiring a wallet, a script, or a backend service to BNB Smart Chain, the first thing you need is a working JSON-RPC endpoint plus the correct chain settings. Get those two right and most "it does not connect" problems disappear. Get them wrong and you will spend an afternoon chasing errors that are really just a mismatched chain ID or a stale endpoint.
This page gives you the settings first, then the methods, then the debugging path. It is written for developers who already know what JSON-RPC is and want the BSC-specific details without re-reading a generic intro.
Chain settings at a glance
Use these values when adding BNB Smart Chain to a wallet, a framework config, or a backend client. The mainnet and testnet values are different, and mixing them is the single most common setup mistake.
| Setting | BNB Smart Chain Mainnet | BNB Smart Chain Testnet |
|---|---|---|
| Chain ID | 56 | 97 |
| Chain name | BNB Smart Chain Mainnet | BNB Smart Chain Testnet |
| Native currency | BNB (18 decimals) | tBNB (18 decimals) |
| Block explorer | https://bscscan.com | https://testnet.bscscan.com |
| RPC URL | https://bnb.api.onfinality.io/public | https://bnb-testnet.api.onfinality.io/public |
| Transport | HTTP and WebSocket | HTTP |
Mainnet supports both HTTP and WebSocket transports on the OnFinality endpoint, which matters if you rely on subscriptions such as eth_subscribe for new blocks or pending logs. Testnet is HTTP-only, so polling is the right pattern there.
If you need a different network or want to compare options, the supported RPC networks page lists what is available, and BNB Chain RPC has the network-specific detail.
Pick the right endpoint for your workload
Before you copy a URL, decide what kind of traffic you are sending. The endpoint that works for a weekend prototype is not always the one you want behind a production service.
- Read-only scripts and dashboards. A shared public endpoint is usually fine. You are sending
eth_call,eth_getBalance, andeth_blockNumberat low volume. - Wallets and dApps with real users. You want predictable throughput and a URL that does not change under you. A managed RPC API with a stable hostname is the safer default.
- Indexers, bots, and backends that scan logs.
eth_getLogsover wide block ranges is the heaviest common call on BSC. This is where shared endpoints start to hurt and a dedicated node earns its place. - Anything that needs subscriptions. If you depend on WebSocket push instead of polling, confirm your endpoint actually supports
wsbefore you build around it.
A quick way to frame it: if your app fails when the endpoint rate-limits you, you have outgrown the shared tier. OnFinality offers both a managed RPC API service and dedicated nodes when you need isolated capacity. You can see how those map to cost on the RPC pricing page.
Configure a wallet or client
Most wallets accept a custom network. The fields map directly to the table above. In code, the same values go into your client constructor.
For a viem client pointed at BSC mainnet:
import { createPublicClient, http } from 'viem';
import { bsc } from 'viem/chains';
const client = createPublicClient({
chain: bsc,
transport: http('https://bnb.api.onfinality.io/public'),
});
const block = await client.getBlockNumber();
console.log('Latest BSC block:', block);
If you prefer raw JSON-RPC, the same call looks like this:
curl -s https://bnb.api.onfinality.io/public \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
Both return the latest block height as a hex string. If that works, your endpoint and chain settings are correct and you can move on to the methods your app actually needs.
The JSON-RPC methods you will call most
BSC is EVM-compatible, so the method set is the standard Ethereum JSON-RPC surface. In practice a handful of calls do most of the work.
| Method | What it is for | Watch out for |
|---|---|---|
eth_blockNumber | Health check and sync position | Cheap; good for a first connectivity test |
eth_getBalance | Native BNB balance | Pass the block tag you mean, not always latest |
eth_call | Read contract state without a transaction | Needs correct to, data, and block tag |
eth_getLogs | Pull events for an address or topic | Wide ranges are the top cause of timeouts |
eth_getTransactionReceipt | Confirm a tx and read its logs | Returns null until the tx is mined |
eth_sendRawTransaction | Broadcast a signed transaction | Needs a correctly signed, correctly nonced tx |
eth_subscribe | Push new blocks or logs over WebSocket | HTTP endpoints cannot do this |
For eth_getLogs, keep block ranges modest and paginate. A range of tens of thousands of blocks against a shared endpoint will often fail even when the endpoint is healthy, because the node has to scan a lot of state to answer.
Debugging the errors you will actually see
Most BSC JSON-RPC problems fall into a small set of symptoms. Match the symptom, then apply the fix.
| Symptom | Likely cause | Fix |
|---|---|---|
chainId mismatch in wallet | Wrong network selected | Set chain ID 56 (mainnet) or 97 (testnet) |
eth_getLogs times out | Block range too wide | Reduce range, paginate, or move to a dedicated node |
null receipt | Tx not mined yet | Poll eth_getTransactionReceipt until non-null |
nonce too low | Reused or stale nonce | Re-read eth_getTransactionCount with pending |
eth_subscribe fails | Endpoint is HTTP-only | Use a WebSocket-capable endpoint |
| 429 or throttling | Shared endpoint under load | Add retries/backoff or move to dedicated capacity |
| Connection refused | Wrong host or network | Re-check the URL and chain settings table |
Two of these deserve a closer look. First, the nonce errors: when you resend a transaction, read the account nonce with the pending block tag, not latest, or you will keep colliding with your own in-flight transaction. Second, throttling: a 429 is not a bug in your code, it is a capacity signal. Retry with exponential backoff for occasional bursts, but if it happens on normal traffic, the shared tier is the wrong tier for that workload.
For a deeper walkthrough of nonce behavior, see what a nonce is in blockchain transactions.
A minimal monitoring probe
Before you blame your application, confirm the endpoint is healthy. A short probe that checks block height and latency will tell you whether the problem is the endpoint or your code.
async function probe(url) {
const start = Date.now();
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0', id: 1, method: 'eth_blockNumber', params: [],
}),
});
const { result } = await res.json();
const height = parseInt(result, 16);
console.log('height', height, 'roundtrip', Date.now() - start, 'ms');
}
probe('https://bnb.api.onfinality.io/public');
Run this on a schedule and log the height. A height that stops advancing is a clear signal, and a roundtrip time that drifts upward tells you the endpoint is under pressure before your users notice.
When to move off a shared endpoint
There is no single number that says "switch now," but the signals are consistent. You are ready for dedicated capacity when:
- You hit throttling on normal, non-bursty traffic.
eth_getLogsover the ranges you need keeps timing out.- You need WebSocket subscriptions and want them isolated from other tenants.
- You want a stable, private endpoint rather than a shared public URL.
- Your compliance or reliability requirements mean you cannot depend on a best-effort shared tier.
A dedicated BNB Chain node gives you isolated throughput and a private endpoint. The tradeoff is cost and the fact that you now own more of the operational surface. If you would rather not run the node yourself, a managed dedicated option keeps the isolation without the maintenance. Compare the shapes on dedicated nodes and check RPC pricing before you commit.
Key Takeaways
- BSC mainnet uses chain ID 56 and BNB; testnet uses chain ID 97 and tBNB. Mixing them is the most common setup error.
- Mainnet supports HTTP and WebSocket; testnet is HTTP-only, so subscriptions need a
ws-capable endpoint. eth_getLogsover wide ranges is the heaviest common call and the top reason shared endpoints fail.- A 429 is a capacity signal, not a code bug. Retry with backoff for bursts, but move to dedicated capacity if it happens on normal traffic.
- A simple block-height probe separates endpoint problems from application problems in seconds.
Frequently Asked Questions
What is the BSC mainnet chain ID? 56. The testnet chain ID is 97. Always confirm which one your wallet or client is pointed at before debugging anything else.
Can I use the same endpoint for mainnet and testnet? No. They are separate networks with separate URLs and chain IDs. Use the mainnet URL for chain ID 56 and the testnet URL for chain ID 97.
Why does eth_getLogs fail on BSC?
Usually because the block range is too wide for the node to scan quickly. Reduce the range, paginate your queries, or use a dedicated node with more headroom.
Does BSC support WebSocket subscriptions?
Mainnet does on the OnFinality endpoint, which supports both HTTP and WebSocket. Testnet is HTTP-only, so poll there instead of using eth_subscribe.
How do I know if I need a dedicated node?
If you see throttling on normal traffic, repeated eth_getLogs timeouts, or a need for isolated WebSocket capacity, a dedicated node is the right next step. Otherwise a managed shared endpoint is usually enough.
Where do I find the current endpoint URLs? Use the BNB Chain RPC and BNB Chain Testnet RPC pages for the current URLs and settings, and the supported RPC networks page for everything else.