JSON-RPC quickstart in Python

Lesson 5 of 11 15 min read Your First Dogecoin App

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=1 and RPC credentials in dogecoin.conf
  • Python 3.9+ and the requests library (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:

SymptomCauseFix
Connection refusedNode not running, or wrong portStart dogecoind; check testnet vs mainnet port
HTTP 401Wrong RPC credentialsMatch rpcuser/rpcpassword in dogecoin.conf
RPC -28: Loading block index...Node still starting upWait 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-cli is just a client.
  • Every reply carries result or error – raise on error, return result.
  • One small wrapper class turns the entire node API into one-liners.
  • RPC credentials = wallet access: localhost only, secrets out of the repo.
On the map

Built something on Dogecoin? Put it on the map.

The directory is the page people link when someone says Dogecoin has no developers. If you maintain a library, wallet, tool, or app – even a small one – it belongs here.