Personal builds only. The launcher API is compiled only into the maintainer's personal build (
wails build -tags personal). It isn't part of the public release (v1.0.0 and later) and there the named pipe isn't opened and--apiexits at once. It may come back as an add-on.
A local API for game launchers (such as Seaglass): show a game's save status, sync saves before a game starts, back them up after it exits, and deal with conflicts.
- Transport: the named pipe
\\.\pipe\syncer. Only the current Windows user can connect (the pipe's DACL grants access to that user alone), and remote clients are refused. - Who serves it: the Syncer window, while it runs (including in the tray). Otherwise start
Syncer.exe --api: it serves the same pipe without a window and exits after a minute without connections (after any backup it started has finished). When the pipe is already served,--apiexits right away. - Finding Syncer.exe: the
DisplayIconvalue ofHKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\ApolloFSyncer, or%LOCALAPPDATA%\Programs\Syncer\Syncer.exe. - Clients should check the server:
GetNamedPipeServerProcessId, then compare the owner of that process with the current user, so another account can't pose as Syncer.
JSON-RPC 2.0, one JSON object per line (UTF-8, \n-terminated, at most 1 MB). Requests on one connection may overlap; answers carry the request's id. A request without id is a notification and gets no answer.
{"jsonrpc":"2.0","id":1,"method":"gameStatus","params":{"title":"Elden Ring"}}
{"jsonrpc":"2.0","id":1,"result":{"known":true,"folders":[{"id":"elden-ring","label":"Elden Ring","state":"idle", …}]}}Errors use the standard codes (-32700 parse error, -32600 invalid request, -32601 unknown method, -32602 bad params) and -32000 for a valid call that didn't work, with the reason in message.
status returns protocol (now 1). New methods and fields can be added within a version; clients ignore fields they don't know. A change that breaks clients raises the version. Clients should check it and treat an unknown or missing Syncer as "not available".
| Method | Params | Result |
|---|---|---|
status |
– | {protocol, version, window, syncthing, paused, pausedUntil?, backingUp, lastBackup?, games, conflicts} |
games |
– | every save folder, as Folder objects |
gameStatus |
{title?, dir?, steamAppId?, gogId?} (at least one of the first three) |
{known, folders: [Folder]} |
syncNow |
{ids: [folder id], timeoutMs?} (default 30 s, at most 2 min) |
[{id, done, state, needBytes}] |
backupNow |
{wait?, timeoutMs?} (default 2 min, at most 30 min) |
{started, finished, ok, at?, copied, errors?} |
conflicts |
{id} |
[{rel, copy, device, deviceName, size, modified, missing, copySize, copyModified}] |
resolveConflict |
{id, copy, useCopy} |
true |
getNewer |
{id} |
{files} |
open |
– | true (shows the Syncer window, starting it if needed) |
registerGames |
{games: [{title, dir?, steamAppId?, gogId?}]} (at most 20,000) |
{games: n} |
subscribe |
– | true, then changed notifications on this connection |
accounts |
– | {enabled, active?, accounts: [{id, name, color?, active}], split: [{game, label, accounts}]} |
switchAccount |
{id} |
true once that account's saves are in place on this PC |
launcherData |
{launcher, path} |
{id?, label?, sync, backup, added, dismissed, error?, repaired?} |
Folder: {id, label, path, sync, backup, state, needBytes, errors, problem?, conflicts, exists, modified?, backedUp?, newerOn?, newerAt?, newerCanGet?, kind?, account?}.
-
problem: what keeps Syncthing from syncing the folder, in plain words (it stopped the folder, or some files can't be synced). Set exactly when Syncer counts the folder as having an issue. -
sync: synced with other PCs;falsemeans only backed up. -
state: Syncthing's state (idle,scanning,syncing, …), orbackup-only,off,paused. -
newerOn: another PC backed up a newer save that hasn't arrived here yet. Syncer takes it from that PC's backup by itself when it safely can (the saves here are exactly what this PC last backed up, no game runs, and that PC's whole backup has arrived through Google Drive).newerCanGet: it wasn't, butgetNewercan take it now. -
kind: set for mod folders:mods(Vortex's installed mods),mods-profiles(its load orders),mods-deployed(mods deployed into the game's folder).gameStatusnever returns deployed-mods folders, andsyncNowdoesn't apply their updates: that only happens from Syncer's window. -
account: the game has separate saves per account and this folder holds this account's (the one playing on this PC). Itsidis<game>.u-<account>; the other accounts' saves aren't listed.
- gameStatus matches folders by the game's title, the names the game database (Ludusavi manifest) has for its Steam app or install folder, and the title a launcher registered for that install folder. Emulator save folders (
Game (RUNE saves)) count as their game.known: falsemeans Syncer has no saves for it. - syncNow asks Syncthing to rescan each synced folder and waits until the folder is idle with nothing left to fetch.
done: falseafter the timeout means it's still catching up (for example, the other PC is offline). Backup-only folders reportdone: true, state: "not-synced"; paused folders reportstate: "paused". - backupNow runs the same incremental backup as Back up now. With
wait, it returns once the backup has finished or the timeout has passed (finished: false). - resolveConflict keeps one version: with
useCopythe conflict copy replaces the file, otherwise the current file stays. The other version goes to backup history, never deleted. - getNewer takes a game's newer save from the other PC's backup (see
newerCanGet), after keeping the saves here as a restore point.filesis how many files changed. A launcher can call it before starting the game. - registerGames replaces the previous list. Syncer keeps it in
%APPDATA%\Syncer\launcher-games.json. - subscribe: Syncer checks folder states every 3 seconds while someone is subscribed and sends
{"jsonrpc":"2.0","method":"changed","params":{}}when something changed. CallgamesorgameStatusagain for the details. - launcherData has Syncer sync and back up a launcher's own data folder (Seaglass: playtime, achievements and settings) like a game's saves, shared with every paired PC at the same place under AppData.
pathmust be an existing subfolder of the launcher's own folder in%APPDATA%or%LOCALAPPDATA%(%APPDATA%\Seaglass\ProfileforSeaglass), and a real folder (no link or junction on the way). Only launchers Syncer knows can ask (for nowSeaglass): any program running as the user can reach the API, and a made-up name must not get another program's data synced. Other PCs learn from Syncer's shared list that the folder is a launcher's data, so none of them splits it per account or removes it as an uninstalled game. Asking again is harmless: it reports how the folder is doing (added: false). Once the user stops syncing it (removes it, or keeps it backed up only), it stays that way (dismissed: true) until they add it again in Syncer. Such a folder can't be split per account: the launcher keeps each account's data apart itself (one file per PC and account, so PCs never write the same file). The launcher must add up every file in the folder (playtime summed, achievements joined, the newest settings win) and skip Syncthing's conflict copies (.sync-conflict-).sync: falsewitherrormeans Syncthing can't sync the folder right now;errorsays why, in plain words. When the folder was emptied or replaced outside Syncer (Syncthing stops such a folder, so the other PCs keep their copies), the call repairs it (repaired: true): files the backup has that are missing come back as they were; for a file the launcher already started again, the backup's copy is put next to it as<name>.restored-<YYYYMMDD-HHMMSS><ext>(the time is the copy's), never over it; then the folder joins again like a new PC, takes what the other PCs have and deletes nothing on them. The background task does the same. An older Syncer answers-32601(unknown method). - accounts / switchAccount: with Accounts on in Syncer, several people can keep their own saves of the same game. A launcher can ask who's playing before it starts a game and call
switchAccountto put that person's saves in place. Switching fails (nothing changed) while a game is running or when that account's saves haven't reached this PC yet. A split game's folderidchanges with the account (<game>.u-<account>), so callgamesorgameStatusagain after switching, beforesyncNow.enabled: falsemeans accounts are off; then every game has one set of saves.