Learn Aria2 - RPC: JSON-RPC & XML-RPC
Series/Learn Aria2/Episode 15
Episode 15 of 23

Learn Aria2 - RPC: JSON-RPC & XML-RPC

In this episode we'll open the language behind the RPC door: the JSON-RPC 2.0 request and response structure, core methods like addUri and tellStatus, event notifications, and direct interaction via curl and jq for script integration.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 14 the RPC door was locked with a token. Now it's time to learn the language spoken behind that door: JSON-RPC. Until now you've controlled aria2 through the command line; from this episode on, you control it through commands sent as data — and that's the foundation of the entire frontend ecosystem, automation scripts, and download server we'll build in the coming episodes.

Episode 15 dissects the RPC interface from the bottom up: starting the daemon, understanding the JSON-RPC 2.0 request and response structure, meeting the core methods, leveraging event notifications, then practicing it all with curl and jq from the terminal.

Starting the RPC Daemon

RPC isn't active by default — it must be turned on explicitly:

enable-rpc.sh
aria2c --enable-rpc \
  --rpc-secret="rahasia-panjang-acak" \
  --rpc-listen-port=6800

--enable-rpc turns on the RPC daemon, --rpc-secret locks it down (episode 14), and --rpc-listen-port=6800 ensures it listens on the standard port — 6800. Once the daemon runs, the JSON-RPC endpoint lives at http://127.0.0.1:6800/jsonrpc.

Two Dialects: JSON-RPC and XML-RPC

aria2 speaks two RPC protocols at once: JSON-RPC 2.0 on the /jsonrpc path and XML-RPC on the /xmlrpc path. JSON is more concise, easier to read, and the default choice of every modern tool; XML-RPC is the legacy dialect still supported for compatibility. We'll focus on JSON-RPC, and touch XML-RPC briefly at the end of the episode.

Anatomy of a JSON-RPC 2.0 Request

Every request is a single JSON object with four keys: jsonrpc, id, method, and params. A real example of adding a new download:

request-adduri.json
{
  "jsonrpc": "2.0",
  "id": "add-1",
  "method": "aria2.addUri",
  "params": [
    "token:rahasia-panjang-acak",
    ["https://example.com/file.zip", "https://mirror.example.com/file.zip"]
  ]
}

The four keys have clear roles:

  • jsonrpc — the protocol version, always "2.0".
  • id — the request marker so responses can be matched; its value is free-form, string or number.
  • method — the name of the function being called, always starting with aria2..
  • params — the method's arguments; when RPC is protected by a token, the first element is a token string prefixed with token:.

Each request is answered by one response carrying the same id. For aria2.addUri, the result is a gid — the download's unique identity:

response.json
{
  "id": "add-1",
  "jsonrpc": "2.0",
  "result": "2089b05ecca3d829"
}

The result of aria2.addUri is a 16-character gid string. Every subsequent operation on that download — checking status, pausing, removing — uses this gid as its address.

Core Methods

A few methods you'll use almost daily:

| Method | Purpose | | aria2.addUri | Adds a new download from one or more URLs | | aria2.tellStatus | Shows detailed status of a download by gid | | aria2.remove | Removes a download from the list | | aria2.pause | Pauses a running download | | aria2.getGlobalStat | Global daemon statistics: speed and download counts | | aria2.tellActive | Lists currently active downloads |

All methods follow the same pattern: params contain the token (first element), then the arguments as needed. aria2.tellStatus asks for a gid, aria2.getGlobalStat takes no arguments besides the token, and both aria2.remove and aria2.pause ask for a gid. Memorize these method-gid pairs — they'll become your everyday language with the daemon.

curl + jq: RPC from the Terminal

The fastest way to test and use RPC is curl. Add a new download:

rpc-add.sh
curl -s http://127.0.0.1:6800/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":"add-1","method":"aria2.addUri","params":["token:rahasia-panjang-acak",["https://example.com/file.zip"]]}'

The response is raw JSON. To read a download's status by gid, send aria2.tellStatus and process the result with jq — the favorite pipeline in the scripting world:

rpc-status-jq.sh
curl -s http://127.0.0.1:6800/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":"s-1","method":"aria2.tellStatus","params":["token:rahasia-panjang-acak","2089b05ecca3d829"]}' \
  | jq '.result | {gid, status, totalLength, completedLength, downloadSpeed}'

The jq filter picks only the interesting fields: gid, status, total and completed sizes, and the current speed. For whole-daemon statistics:

rpc-global.sh
curl -s http://127.0.0.1:6800/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":"g-1","method":"aria2.getGlobalStat","params":["token:rahasia-panjang-acak"]}' \
  | jq '.result'

This curl and jq combination is the basis of almost every integration: the daemon is controlled through data, not human interaction — and that data is easy for any script to process.

Notifications and Events

Polling constantly is wasteful. aria2 provides a more elegant path: notifications. When certain events happen, the daemon pushes the event to connected clients — for example aria2.onDownloadStart, aria2.onDownloadComplete, and aria2.onDownloadError. Notifications are sent over a WebSocket connection at the same endpoint (/jsonrpc); for pure HTTP connections, clients usually poll with aria2.tellActive or aria2.tellStatus.

This event-driven pattern flips your way of thinking: instead of asking the daemon "are you done yet?" every two seconds, the client simply waits to be told "it's done". For a single download, simple polling is enough; for a system managing hundreds of downloads, notifications are the difference between a noisy machine and a quiet one.

Script Integration

All the pieces above come together in a complete monitoring script: add a download, record the gid, then poll until it finishes.

rpc-monitor.sh
#!/usr/bin/env bash
set -euo pipefail
 
SECRET="rahasia-panjang-acak"
URL="https://example.com/file.zip"
RPC="http://127.0.0.1:6800/jsonrpc"
 
GID=$(curl -s "$RPC" -H "Content-Type: application/json" \
  -d "{\"jsonrpc\":\"2.0\",\"id\":\"add\",\"method\":\"aria2.addUri\",\"params\":[\"token:$SECRET\",[\"$URL\"]]}" \
  | jq -r '.result')
echo "download dimulai: $GID"
 
while :; do
  STATUS=$(curl -s "$RPC" -H "Content-Type: application/json" \
    -d "{\"jsonrpc\":\"2.0\",\"id\":\"s\",\"method\":\"aria2.tellStatus\",\"params\":[\"token:$SECRET\",\"$GID\"]}" \
    | jq -r '.result.status')
  echo "status: $STATUS"
  [ "$STATUS" = "complete" ] && break
  sleep 2
done
 
echo "selesai: $URL"

Notice the patterns used: the JSON-RPC request is built with an escaped string inside double quotes, variable values are inserted when the request is made, and jq -r extracts a single value. A script like this can grow into a download queue, chat notifications, or a trigger for post-download processing — we'll go deeper in the scripting episode later.

XML-RPC at a Glance

For completeness, here's what the same old dialect looks like at the /xmlrpc endpoint:

xmlrpc-getversion.xml
<?xml version="1.0"?>
<methodCall>
  <methodName>aria2.getVersion</methodName>
  <params>
    <param>
      <value>
        <string>token:rahasia-panjang-acak</string>
      </value>
    </param>
  </params>
</methodCall>

The same structure — method and params — just wrapped in noisier XML markup. That's why almost the entire modern ecosystem chooses JSON-RPC, and we'll keep using it in the coming episodes too.

Closing

Episode 15 opened the language behind the RPC door: starting the daemon with --enable-rpc, understanding the JSON-RPC 2.0 request and response structure, meeting core methods like aria2.addUri and aria2.tellStatus, leveraging event notifications, and practicing curl and jq for direct interaction and script integration.

The key thing to remember: RPC changes aria2 from a tool you type into a service you call — and anyone who can call it can control it. This language is the bridge to the entire ecosystem around it.

In the next episode, episode 16, we make use of that bridge: Web UI & frontend ecosystem — installing AriaNg as a browser-based dashboard, connecting it with a token, and integrating browser extensions so download clicks get routed to aria2. See you then!

Learn Aria2 - RPC: JSON-RPC & XML-RPC | Learn Aria2