Skip to content

The REST API

Nothing in the previous chapters used the web GUI — deliberately. The GUI is a client of Syncthing's REST API, and everything it can show or do, a script can show or do with curl. This chapter is the API as the lab actually used it, which for most home purposes is the whole of it.

The key, and the shape of a call

Every request carries the API key from config.xml (chapter 2) in an X-API-Key header, to the same address the GUI lives on. Without the key, chapter 2 showed the answer: CSRF Error, HTTP 403. With it:

$ curl -s -X GET -H "X-API-Key: $KEY" http://127.0.0.1:8385/rest/system/status
{
  "myID": "VDKRCPU-UXHNS6G-4QRZCAS-TINLZ4I-UTXP2E6-37KQF7N-JTCRUFC-RRVUGAM",
  "uptime": 169
}

Answers are JSON throughout — the guide pipes several through jq, and so should you. For plain reading in a terminal, add the HTTP status line with -w '\n[HTTP %{http_code}]' as the transcripts do; several useful calls (puts, posts) answer with an empty body and a 200, and the status is the reply.

The endpoints the lab lived on

System. Who am I, who am I talking to:

GET  /rest/system/ping          {"ping": "pong"}
GET  /rest/system/status        myID, uptime, paths, versions
GET  /rest/system/connections   per peer: connected, address,
                                type, crypto, isLocal
POST /rest/system/pause         pause syncing (all folders,
                                or ?folder=<id> for one)
POST /rest/system/resume        and resume it
POST /rest/system/shutdown      {"ok": "shutting down"}

Config. Read it, replace pieces of it — this is how the lab paired devices (PUT /rest/config/devices/<id>), created folders (PUT /rest/config/folders/<id>), and switched versioning on (same PUT, one field changed), all on running instances:

GET  /rest/config               the whole config, as JSON
GET  /rest/config/folders/<id>  one folder, exactly as stored
GET  /rest/config/defaults/folder
                                the template a new folder
                                starts from
GET  /rest/config/options       the behaviour switches

That last one repays a look in the lab, where it reads back the hermetic setup from chapter 2 — proof the switches are really off, from the running program rather than the file:

{
  "globalAnnounceEnabled": false,
  "localAnnounceEnabled": false,
  "relaysEnabled": false,
  "natEnabled": false,
  "listenAddresses": [
    "tcp://127.0.0.1:22005"
  ]
}

Database. The state of the folders themselves — the gauge cluster from chapters 3 and 8:

GET  /rest/db/status?folder=<id>
     state, needFiles, needBytes, localFiles,
     globalFiles, localBytes, globalBytes
GET  /rest/db/ignores?folder=<id>
     the device's .stignore lines for the folder
POST /rest/db/revert?folder=<id>
     receive-only folders: discard local changes

On ignores, one honest wrinkle from the capture: the endpoint handed back the folder's .stignore lines —

{
  "ignore": [
    "#include .stglobalignore"
  ],
  "patterns": null
}

— the include directive as written, not the patterns it pulls in. The lab's proof that *.tmp and scratch were in force is the behavioural one in chapter 5 (files that never travelled); treat this endpoint as "show me the ignore file," and the filesystem as the appeal court.

Pause, used properly

The lab's last experiment is the one you will reach for in real life. Pause juniper's gazette folder, write a file on willow, wait, look:

$ curl -s -X POST -H "X-API-Key: $KEY" "http://127.0.0.1:8395/rest/system/pause?folder=gazette"
[HTTP 200]
…
$ test ! -e share-b/late-addition.txt
[exit 0]

Eight seconds — an eternity at lab speeds — and the file is not there. Pausing is not a suggestion; the folder simply stops. Resume, and the backlog flows:

$ curl -s -X POST -H "X-API-Key: $KEY" "http://127.0.0.1:8395/rest/system/resume?folder=gazette"
[HTTP 200]

$ cat share-b/late-addition.txt
A late addition, written while B was paused.

That pair of calls is the whole basis of polite automation: pause a folder before a backup snapshot, resume it after; pause the media folder before the video call, resume it at midnight.

The command-line client

One more door into the same API ships with the binary: syncthing cli reads the address and key from a home's config and formats the calls for you:

$ ./bin/syncthing cli --home=home-a show system
{
  …
  "guiAddressUsed": "127.0.0.1:8385",
  "myID": "VDKRCPU-UXHNS6G-4QRZCAS-TINLZ4I-UTXP2E6-37KQF7N-JTCRUFC-RRVUGAM",
  …
}

It is the same data — one excerpt shows the lab's fingerprints, guiAddressUsed naming willow's port — with subcommands for showing state, editing config, and running operations. Between the GUI for looking, curl for scripting, and syncthing cli for one-off questions at a terminal, there is no fourth thing you need to learn to run Syncthing without a browser.

Check: curl a /rest/db/status for a folder on your own setup and find the four numbers from chapter 3. If you can read that one response, you can read every gauge this guide uses — the GUI is only ever showing you the same numbers with better typography.