JSON-RPC Blockchain Nodes: PHP, Python & JS Guide
How JSON-RPC 2.0 works with blockchain nodes: request and response format, error codes and batching, with working PHP, Python and JavaScript examples.
Reviewed by Maurice Sobiera
JSON-RPC is a remote procedure call protocol that encodes requests and responses as JSON. An Ethereum node exposes it over HTTP or WebSocket, so a client can read blocks and balances or submit signed transactions by posting a small JSON object. The protocol is versioned and specified, which is why the same code shape works across most EVM nodes.
This article shows the request and response format, the error codes, batching, and one working example each in PHP, Python and JavaScript.
What is JSON-RPC?
JSON-RPC 2.0 is a stateless protocol defined in the JSON-RPC 2.0 specification. The client sends a request object. The server answers with a response object that has the same id.
A request has four members:
| Member | Meaning |
|---|---|
jsonrpc | The string "2.0" |
method | The name of the method to call, for example eth_blockNumber |
params | An array or object with the arguments. May be omitted if the method takes none |
id | A string, number or null. The response carries the same value |
A response contains either a result member or an error member, never both. A request without an id is a notification, and the server must not reply to it.
How do you send a JSON-RPC request to a node?
Send an HTTP POST request with the header Content-Type: application/json and the request object as the body. The node’s HTTP endpoint is usually port 8545 for Ethereum clients such as Geth. WebSocket connections work the same way, but keep one connection open.
The method names and parameters are defined by the blockchain, not by JSON-RPC. For Ethereum, the JSON-RPC API reference on ethereum.org lists them. eth_blockNumber takes no parameters and returns the current block number as a hex-encoded quantity.
Request:
{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}Response:
{"jsonrpc": "2.0", "id": 1, "result": "0x4b7"}Quantities are hex strings with a 0x prefix and no leading zeros. The result 0x4b7 is block 1207.
Example code in PHP, Python and JavaScript
All three examples send the request above to a local node and print the response. They use POST, because JSON-RPC over HTTP does not use GET.
PHP, with the curl extension:
<?php$request = json_encode([ 'jsonrpc' => '2.0', 'method' => 'eth_blockNumber', 'params' => [], 'id' => 1,]);
$curl = curl_init('http://localhost:8545');curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);curl_setopt($curl, CURLOPT_POST, true);curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
$response = json_decode(curl_exec($curl), true);curl_close($curl);
echo hexdec($response['result']); // block number as an integerPython, with the requests library:
import requests
payload = {"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}response = requests.post("http://localhost:8545", json=payload, timeout=10)body = response.json()
print(int(body["result"], 16)) # block number as an integerJavaScript, with fetch:
const response = await fetch('http://localhost:8545', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1, }),});const body = await response.json();console.log(parseInt(body.result, 16)); // block number as an integerHow do you read a balance?
Call eth_getBalance with an address and a block parameter. The block parameter can be a hex block number or a tag such as "latest", "safe" or "finalized". The result is the balance in wei, as a hex quantity.
{ "jsonrpc": "2.0", "method": "eth_getBalance", "params": ["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"], "id": 2}For payment systems the tag matters. "latest" can still be reorganized, while "finalized" cannot. Use "finalized" when you credit a deposit and "latest" only for display.
What do the error codes mean?
When a call fails, the response has an error object with a numeric code and a message. The specification reserves these codes:
| Code | Name | Typical cause |
|---|---|---|
| -32700 | Parse error | The body is not valid JSON |
| -32600 | Invalid Request | The JSON is not a valid request object |
| -32601 | Method not found | Wrong method name, or the node does not expose that namespace |
| -32602 | Invalid params | Wrong number or type of parameters |
| -32603 | Internal error | The node failed while processing the call |
Always check for error before you read result. JSON-RPC carries errors in the response body, so check the body no matter what the HTTP status is.
Can you send several calls in one request?
Yes. A batch is a JSON array of request objects, and the server answers with an array of responses. The responses may come in any order, so match them by id.
[ {"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}, {"jsonrpc": "2.0", "method": "eth_chainId", "params": [], "id": 2}]Batching saves round trips. Node operators may limit the batch size, so check the limit of the endpoint you use.
When should you use an API instead of a node?
Running your own node gives you raw JSON-RPC access, but you maintain the node. For wallet creation, token transfers and deposit notifications, Chaingateway offers a REST API instead; its endpoints are listed in the OpenAPI file. See how to set up a Tron node for what operating a node involves.
Ready to build this yourself? Get your API key — 7-day trial, no card required — or see the Blockchain API for the full endpoint reference.