JSON-RPC quickstart in Python
Here's the secret that makes Dogecoin development approachable: your node is already a JSON API server. Every dogecoin-cli command you ran in the last lesson was an HTTP request underneath. In this lesson you make those requests yourself – first with curl to see the wire format, then with a 20-line Python wrapper you'll reuse in every project on this site.
Prerequisites
- A synced (or syncing) testnet node from the node lesson, with
server=1and RPC credentials indogecoin.conf - Python 3.9+ and the
requestslibrary (pip install requests)
One raw call with curl
JSON-RPC is a single POST endpoint. The body names a method and its params – that's the whole protocol:
$ curl --user dogeuser:CHANGE_ME_long_random_string \
--data-binary '{"jsonrpc":"1.0","id":"dogecode","method":"getblockchaininfo","params":[]}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:44555/
{"result":{"chain":"test","blocks":7345120,...},"error":null,"id":"dogecode"}
Three things to notice: the credentials are your rpcuser/rpcpassword; the port is testnet's 44555 (mainnet would be 22555); and the reply always has result and error fields – exactly one of them is non-null.
The Python wrapper you'll reuse everywhere
import requests
class DogeRPC:
"""Minimal JSON-RPC client for Dogecoin Core."""
def __init__(self, user, password, host="127.0.0.1", port=44555):
self.url = f"http://{host}:{port}/"
self.auth = (user, password)
def call(self, method, *params):
payload = {"jsonrpc": "1.0", "id": "dogecode",
"method": method, "params": list(params)}
r = requests.post(self.url, json=payload, auth=self.auth, timeout=30)
data = r.json() # the node answers JSON even for errors
if data.get("error"):
err = data["error"]
raise RuntimeError(f"RPC {err['code']}: {err['message']}")
return data["result"]
rpc = DogeRPC("dogeuser", "CHANGE_ME_long_random_string")
info = rpc.call("getblockchaininfo")
print("chain:", info["chain"], "| height:", info["blocks"])
addr = rpc.call("getnewaddress")
print("fresh address:", addr)
print("balance:", rpc.call("getbalance"))
Run it:
$ python quickstart.py
chain: test | height: 7345120
fresh address: nXyz...
balance: 0.0
That DogeRPC class is deliberately boring – and that's the point. Any of the node's several hundred RPC methods is now one line of Python: rpc.call("validateaddress", some_string), rpc.call("listtransactions", "*", 10), rpc.call("sendtoaddress", addr, 25.0). When you outgrow it, python-bitcoinrpc offers the same idea with more conveniences; the wire format is identical because Dogecoin Core speaks Bitcoin Core's RPC dialect.
Error handling that will save you
Three failures you'll meet early, and what they mean:
| Symptom | Cause | Fix |
|---|---|---|
| Connection refused | Node not running, or wrong port | Start dogecoind; check testnet vs mainnet port |
| HTTP 401 | Wrong RPC credentials | Match rpcuser/rpcpassword in dogecoin.conf |
RPC -28: Loading block index... | Node still starting up | Wait and retry – your code should treat -28 as "try again shortly" |
Security posture from day one: RPC credentials are wallet credentials. Keep RPC bound to localhost, keep the password out of source control (environment variable or a config file outside the repo), and never expose the RPC port to the internet – not even "temporarily".
Key takeaways
- Dogecoin Core is an HTTP JSON-RPC server;
dogecoin-cliis just a client. - Every reply carries
resultorerror– raise onerror, returnresult. - One small wrapper class turns the entire node API into one-liners.
- RPC credentials = wallet access: localhost only, secrets out of the repo.