Files
claudetools/.claude/skills/synology/references/dsm-api.md
Howard Enos 2a1a275511 sync: auto-sync from HOWARD-HOME at 2026-06-24 17:37:00
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-24 17:37:00
2026-06-24 17:37:35 -07:00

206 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DSM 7 Web API reference (for the `synology` skill)
Consolidated from primary sources — kwent's device-extracted DSM 7.x `_full.json`
(method/version dump from a real device = authoritative for **names + versions**),
N4S4/`synology-api` source (param detail), and Synology's official *DSM Login Web API*
and *FileStation API* guides. Confidence per row: **[docs]** authoritative · **[comm]**
community/library · **[inf]** inferred. **[W]** = mutating → gate behind `--confirm`.
**[PKG]** = the API only appears in the device's `SYNO.API.Info` map if that package is
installed.
> **Golden rules (why the client is shaped the way it is)**
> 1. **Discover, don't hardcode.** Call `SYNO.API.Info query=all` after login and route
> every call to the returned `path` (DSM 7 funnels most `SYNO.Core.*` through
> `entry.cgi`; DSM 6 used per-API `.cgi`) at the advertised `maxVersion` (FileStation
> `Upload` is the exception — use `minVersion`).
> 2. **CSRF is mandatory for writes.** Login with `enable_syno_token=yes`, then send the
> `synotoken` as both the `X-SYNO-TOKEN` header and a `SynoToken` param on every call.
> Without it, DSM 7 silently fails mutating calls. (The client does this.)
> 3. **Setters are read-modify-write.** Many `set` methods take a JSON blob (`conf`,
> `profile`, `rules`, `shareinfo`, firewall/DSM `**kwargs`). Always `get` first, mutate,
> push back — constructing from scratch wipes sibling settings.
> 4. **Param schemas are the weak spot.** Method names + versions below are
> device-authoritative; many *setter param keys* are community/inferred. Before a
> production write, capture the matching `get` and round-trip it, or run the call on-box
> via `synowebapi --exec api=<API> method=<m> version=<v> k=v` (the on-box binary
> validates params, sidestepping the gaps).
> 5. `format=sid` over `cookie` on DSM 7 (avoids cookie-jar/HTTPS issues).
## Auth & discovery — always present
| API | method | key params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.API.Info | query | `query=all` or CSV of API names | 1 | Discover APIs → `path`/`minVersion`/`maxVersion`. **Call first.** | docs |
| SYNO.API.Auth | login | `account`,`passwd`,`session`,`format=sid`,`enable_syno_token=yes`,`otp_code`,`enable_device_token=yes`,`device_id`,`device_name` | 7 (6/3 older) | Returns `data.sid` + `data.synotoken`. `device_id`/`enable_device_token` = trusted-device skip-OTP. | docs |
| SYNO.API.Auth | logout | `session` | 7 | End session. | docs |
**Auth error codes** (in `error.code` on login): 400 bad account/password · 401 disabled/guest ·
402 permission denied · **403 OTP code required** · **404 OTP code wrong** · 406 enforce-2FA (must
enable) · **407 IP auto-blocked** · 408 password expired (uncchangeable) · 409 password expired ·
410 password must change. Branch on 403/404/407 — the rest are hard failures.
**Generic codes** (any API): 100 unknown · 101 bad param · 102 API n/a · 103 method n/a · 104 version
unsupported · 105 insufficient permission · 106 session timeout · 107 dup-login interrupt · **119
invalid/missing SID or synotoken** → re-login. (Client re-logs in once on 106/119.)
## System / power / utilization — `SYNO.Core.System*`
| API | method | params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.Core.System | info | (none) | 12 | model, serial, firmware_ver/version_string, ram_size(MB), cpu_*, temperature, up_time, time/time_zone, ntp_server, sata_dev/usb_dev | comm |
| SYNO.Core.System | reboot | optional `force` | 1 | **[W]** reboot. *See 103 note.* | comm |
| SYNO.Core.System | shutdown | optional `force` | 1 | **[W]** power off. *See 103 note.* | comm |
| SYNO.Core.System.Utilization | get | — | 1 | live `cpu{*_load,1/5/15min}`, `memory{total_real,avail_real,real_usage,cached,...}`, `disk{total{read/write_byte},disk[]}`, `network[{device,tx,rx}]` | comm |
| SYNO.Core.System.Status | get | — | 1 | `is_system_crashed`,`is_disk_wcache_crashed`,`upgrade_ready` | comm |
| SYNO.Core.System.SystemHealth | get | — | 1 | aggregate health summary | comm |
| SYNO.Core.CurrentConnection | get *(some builds `list`)* | `offset`,`limit` | 1 | active user/file-service sessions | comm |
| SYNO.Core.System.Process / ProcessGroup | list | — | 1 | Resource Monitor processes | comm |
> **reboot/shutdown 103 regression:** confirmed API is `SYNO.Core.System` `reboot`/`shutdown`
> (NOT `Hardware.PowerSchedule` = *scheduled* on/off, NOT `Core.Upgrade`). Some DSM 7.2.x builds
> return **103 "method does not exist"** via the Web API. Mitigation: route via `entry.cgi` at
> `maxVersion` with the synotoken; on persistent 103 fall back to **SSH `synoshutdown -r|-s`**
> (the `syno-ssh.sh reboot|shutdown --confirm` recipes).
## Storage / shares / file services
| API | method | params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.Storage.CGI.Storage | load_info | — | 1 | one snapshot: `volumes[]`(id,fs_type,size.total/used,raid_type,vol_path), `disks[]`, `storagePools[]`, `ssdCaches[]`, `env`, `ha_info`. Parse defensively (sizes are byte-strings). | docs/comm |
| SYNO.Core.Share | list | `shareType`(all/dec/enc), `additional:=[…]`, `offset`,`limit` | 1 | shares + flags | docs |
| SYNO.Core.Share | get | `name`, `additional:=[…]` | 1 | one share | docs |
| SYNO.Core.Share | create / set | `name`, `shareinfo:={…}`(name,vol_path,desc,enable_recycle_bin,encryption,hidden,enable_share_quota,share_quota) | 1 | **[W]** create/modify share | comm |
| SYNO.Core.Share | delete | `name:=["s1",…]` | 1 | **[W]** delete | docs |
| SYNO.Core.Share.Permission | list | `name`,`action`(enum/find),`user_group_type`,`offset`,`limit` | 1 | per-user/group RW/RO/NA on a share | comm |
| SYNO.Core.Share.Permission | set / set_by_user_group | `name`,`user_group_type`,`permissions:=[…]` | 1 | **[W]** set share perms | comm |
| SYNO.Core.Share.Permission | list_by_group | `name`,`user_group_type`,`share_type` | 1 | shares a group can reach | comm |
| SYNO.Core.Share.Crypto | encrypt/decrypt/mount/unmount | `name`,`password` | 1 | **[W]** encryption (API partly gated → prefer CLI) | inf |
| SYNO.Core.FileServ.SMB / AFP / NFS / FTP | get / set | service config | 13 | **[W on set]** file-service protocol config | docs |
`Share.list` `additional` values (where perm/ACL/encryption/quota state is read):
`hidden, encryption, is_aclmode, is_support_acl, unite_permission, recyclebin, share_quota,
share_quota_used, is_sync_share, is_force_readonly, support_snapshot`. **Windows-ACL mode** is read
via `is_aclmode`+`is_support_acl`+`unite_permission` — but this only says a share *is* in ACL mode;
**the per-file ACE list is NOT in the Web API** (filesystem-only → use `synoacltool` over SSH).
## Users / groups / security / directory / certificates
| API | method | params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.Core.User | list / get | `additional:=["email","description","expired","cannot_chg_passwd","passwd_never_expire"]` | 1 | local users | docs |
| SYNO.Core.User | create / set / delete | `name`,`password`,`description`,`email`,`expired`,`cannot_chg_passwd` | 1 | **[W]** user CRUD (password set via `set`, no separate method) | docs |
| SYNO.Core.User.Group | join | `name`,`join_group:=[…]`,`leave_group:=[…]` | 1 | **[W]** add/remove user↔groups (async → `join_status task_id`) | docs |
| SYNO.Core.User.PasswordPolicy / PasswordExpiry | get / set | policy blob | 1 | **[W]** password strength/aging | docs |
| SYNO.Core.Group | list | `offset`,`limit`,`type` | 1 | groups | docs |
| SYNO.Core.Group | create / set / delete | `name`,`new_name`,`description` | 1 | **[W]** group CRUD | docs |
| SYNO.Core.Group.Member | list | `group`,`ingroup`(bool) | 1 | members | docs |
| SYNO.Core.Group.Member | change | `group`,`add_member:=[…]`,`remove_member:=[…]` | 1 | **[W]** add+remove in one call (**list-replace semantics — read first**) | docs |
| SYNO.Core.Quota | get / set | `name`,`group_quota` | 1 | **[W]** per-share group quota | docs |
| SYNO.Core.Security.Firewall | get / set | settings blob | max | **[W]** global firewall | docs |
| SYNO.Core.Security.Firewall.Rules | list / get / set / delete | `rules`(full JSON list) | max | **[W]** firewall rules (read-modify-write the whole set) | docs |
| SYNO.Core.Security.AutoBlock.Rules | get / list / set / delete | `rules` | max | **[W]** brute-force auto-block list + thresholds | docs |
| SYNO.Core.Security.DoS / Security.DSM | get / set | **kwargs | max | **[W]** DoS protect; DSM hardening (account-protection, HSTS, banner) | docs |
| SYNO.Core.OTP.EnforcePolicy / SmartBlock(.Trusted/.Untrusted/.User/.Device) | get/set | **kwargs | — | **[W]** force-2FA / Adaptive-MFA (account protection) | comm |
| SYNO.Core.Directory.Domain.Conf | get / set | `conf`(JSON: server,DNS,admin creds,NetBIOS) | max | **[W]** AD join (creds inside `conf` — capture a joined NAS's `get` first) | comm |
| SYNO.Core.Directory.LDAP.* | get / set | profile/base_dn | max | **[W]** LDAP join | comm |
| SYNO.Core.Certificate.CRT | list / set / delete | `cert_id`,`as_default`,`ids` | 1 | **[W on set/del]** list/select/delete certs | docs |
| SYNO.Core.Certificate | import / export | `serv_key`,`ser_cert`,`ca_cert`,`id`,`as_default` (multipart) | min | **[W]** upload/export cert | docs |
| SYNO.Core.Certificate.Service | set | `cert_id`,`service`,`old_id` | min | **[W]** bind cert to a service | docs |
## Packages — `SYNO.Core.Package*` (core)
| API | method | params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.Core.Package | list | `additional:=["status","installed_info"]` | 2 | installed packages + run status | comm |
| SYNO.Core.Package.Control | start / stop | `id=<pkgid>` (POST) | 1 | **[W]** start/stop a package. `id` = the package-ID **string** (`SynologyDrive`,`HyperBackup`,`LogCenter`,…) | docs |
| SYNO.Core.Package.Server | list | `blforcereload` | 2 | available catalog packages | comm |
| SYNO.Core.Package.Installation / Uninstallation | install / upload / uninstall | `url`/`name`/`id` | 1 | **[W]** install/remove | comm |
CLI fallback (most reliable): `synopkg list --name` · `synopkg status <pkgid>` · `synopkg
start|stop <pkgid>` (sudo).
## Log Center — syslog collector project [PKG: Log Center]
The **NAS-as-server** (receive pfSense/UniFi logs) is `SYNO.LogCenter.*` (needs the package). The
**NAS-forwarding-its-own-logs** is `SYNO.Core.SyslogClient.*` (core). For the on-site collector you
want the server side.
| API | method | params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.LogCenter.RecvRule | list | — | max | log-receiving rules (name, UDP/TCP/TLS, port 514, BSD/IETF format) = the "syslog server" objects | comm |
| SYNO.LogCenter.RecvRule | create / set / delete | `name`,`port`,`protocol`,`format`,`enable` | max | **[W]** create/enable a receive rule = turn the NAS into a syslog server. *Method names inferred — verify live via `apis SYNO.LogCenter.RecvRule`.* | inf |
| SYNO.LogCenter.Log | list | filter/paging | max | read received remote logs | comm |
| SYNO.LogCenter.Log | get_remotearch_subfolder | — | max | list remote-log archive subfolders | comm |
| SYNO.LogCenter.Setting.Storage | get / set | volume,retention,archive | max | **[W on set]** where received logs are stored + rotation | comm |
| SYNO.Core.SyslogClient.Status | cnt_get / eps_get | — | 1 | received-count / events-per-sec metrics | comm |
| SYNO.Core.SyslogClient.Setting(.Profile) | get / set | remote host,port,protocol,TLS,severity | 1 | **[W on set]** forward the NAS's OWN logs out | inf |
Log Center wraps **syslog-ng**; custom listeners can also be dropped in
`/etc/syslog-ng/patterndb.d/`. Prefer the RecvRule API/GUI for standup.
## Synology Drive — team-folder migration project [PKG: Synology Drive Server]
All read-only `list` (confirmed). `SYNO.C2FS.*` is C2 **cloud**, not on-prem — don't use it here.
| API | method | ver | what | conf |
|---|---|---|---|---|
| SYNO.SynologyDrive.Tasks | list | max | server-side sync tasks | comm |
| SYNO.SynologyDrive.TeamFolders | list | max | **Team Folders** (migration target) | comm |
| SYNO.SynologyDrive.Connection | list | max | connected Drive clients/devices | comm |
| SYNO.SynologyDrive.Profiles | list | max | per-user sync profiles (`user`,`start`,`limit`) | comm |
| SYNO.SynologyDrive.Settings | list | max | Drive Admin Console settings | comm |
| SYNO.SynologyDriveShareSync.Connection | list | max | server-to-server ShareSync connections | comm |
## Backup
| API | method | params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.Backup.Task | list / get / status | `task_id` | min | **[PKG: Hyper Backup]** backup tasks + run state | comm |
| SYNO.Backup.Task | backup | `task_id` | min | **[W]** run a backup task now | comm |
| SYNO.Backup.Repository | list / get | `task_id` | min | destinations/repositories (B2/Wasabi appear as target fields) | comm |
| SYNO.ActiveBackup.Task | list | `load_status`,`load_result`,`load_devices` | 1 | **[PKG: ABB — needs Btrfs]** task inventory | comm |
| SYNO.ActiveBackup.Task | backup / cancel / remove | `task_ids` | 1 | **[W]** run/cancel/delete | comm |
| SYNO.ActiveBackup.Log | list_log / list_result | `filter`,`offset`,`limit` | 1 | task logs + run history | comm |
> **ABB on ext4 — CORRECTED by live test 2026-06-24.** Active Backup for Business **is installed and
> running** on the Cascades DS718+ (ext4), and all 40 `SYNO.ActiveBackup.*` APIs are present. The
> Btrfs requirement applies only to certain ABB *features* (block-level dedup on the backup
> destination, file self-healing), NOT to installing/running the package. Don't assume absence —
> check `apis activebackup` on the device. Offsite copy still = **Hyper Backup → B2** (phase4 §6.4).
## Network / external access / services
| API | method | params | ver | what | conf |
|---|---|---|---|---|---|
| SYNO.Core.Network | get / set | hostname, dns(primary/secondary), gateway | 1 | **[W on set]** global net: hostname/DNS/default-gateway (single object — NOT per-NIC) | docs |
| SYNO.Core.Network.Interface | list | — | 1 | enumerate NICs + addrs (read-only) | docs |
| SYNO.Core.Network.Ethernet | get / set | `ifname`,`ip`,`mask`,`gateway`,`use_dhcp`,`mtu` | 12 | **[W on set]** per-NIC IPv4 (static/DHCP/jumbo) | docs |
| SYNO.Core.Network.Bond | list/get/create/set/delete | members, mode | 12 | **[W]** link-aggregation | docs |
| SYNO.Core.Network.Router.Static.Route | get / tablesget / set | route list[] | 1 | **[W on set]** static routes (there is NO `SYNO.Core.Network.Route`) | docs |
| SYNO.Core.Terminal | get / set | `enable_ssh`,`enable_telnet`,`ssh_port` | 3 | **[W on set]** enable SSH/Telnet, SSH port | docs |
| SYNO.Core.SNMP | get / set | `enable_snmp`,`community`,`snmp_port`,v3 user/auth/priv,trap | 1 | **[W on set]** SNMP | docs |
| SYNO.Core.QuickConnect | get / status / set | `enabled`,`quickconnect_id` | 13 | **[W on set]** QuickConnect | docs |
| SYNO.Core.DDNS.Record | list / create / set / delete / update_ip_address | provider,hostname,user,passwd | 1 | **[W on writes]** DDNS records | docs |
| SYNO.Core.PortForwarding.Rules | load / save | rules[] | 1 | **[W on save]** UPnP router port-forwards | docs |
| SYNO.Core.Notification.Mail.Conf / .Mail.Auth | get / set | mailserver,smtp_port,mailaddr,user,passwd,ssl | 1 | **[W on set]** SMTP for alerts | docs |
| SYNO.Core.Notification.Mail | send_test | — | 1 | **[W]** (actually emails) test mail | docs |
| SYNO.Core.Notification.Push.Conf | get / set / status | `enable_mobile`,`enable_mail`,`enable_webhook` | 1 | **[W on set]** push toggles | docs |
| SYNO.Core.Notification.Advance.FilterSettings | get / set / list | per-event rules | 1 | **[W on set]** alert rules (NOT `Notification.Rule`) | docs |
| SYNO.Core.TaskScheduler | list / get / run / set_enable / create / set / delete | id, real_owner, task object | 12 | **[W on writes]** scheduled tasks | docs |
| SYNO.Core.TaskScheduler.Root | create / set | `task_name`,`owner=root`,`script`,`run_days`,`start_time_h/m`,`same_day_repeat_*` | 1 | **[W]** root user-script task — **the way to schedule a syslog snapshotter as root** | comm |
| SYNO.Core.BandwidthControl | list/get/set | rules[] | 12 | **[W on set]** bandwidth rules | docs |
| SYNO.Backup.Service.NetworkBackup *(or SYNO.Core.FileServ.Rsync)* | get / set | `enable_network_backup` | 1 | **[W on set]** rsync server enable (probe which the device returns) | comm |
## SSH `syno*` CLI surface (what the Web API can't fully express)
- **`synoacltool -get <path>`** — per-file NTFS ACE list (the data Web API lacks). ACE format:
`[idx] <type>:<name>:<allow|deny>:<perm-bits rwxpdDaARWcCo>:<inherit fdin> (level: N)`; level 0 =
set on this path, ≥1 = inherited. `-add`/`-del <idx>`/`-enforce-inherit` to write.
- **`synoshare --enum ALL|ENC|DEC`** (list, incl. encrypted/plain split) · `--get <share>` ·
`--list_acl <share>` · `--enc_mount/--enc_unmount <share> <pw>` (the dependable encryption path).
- **`synouser`** / **`synogroup`** — local account CLI (line-oriented `key=value`, not JSON);
`--add` is **list-replace** for group members; run `--rebuild all` after manual edits.
- **`synopkg start|stop|status <pkgid>`** — package control fallback.
- **`synonet --get_all` / `--hostname` / `--gateway` / `--dns` / `--restart <iface>`** — network.
- **`synoservice --enable|--disable|--restart sshd|snmpd|rsyncd|crond`** — service toggles.
- **`synoschedtask --get | --run --id=<N>`** — scheduled tasks.
- **`synogetkeyvalue / synosetkeyvalue /etc/synoinfo.conf <key> [val]`** — raw config.
- **`synowebapi --exec api=<API> method=<m> version=<v> k=v`** — call ANY Web API on-box; the
binary validates params, so this is the most robust scripted path for setters whose param schema
isn't publicly documented. **Use this for production writes when unsure of param keys.**
- **`synoshutdown -r` (reboot) / `-s` (shutdown)** — power fallback when the Web API 103s.
## Sources
- kwent/syno `definitions/7.x/_full.json` (device-extracted method+version dump — authority for names/versions)
- N4S4/synology-api source + https://n4s4.github.io/synology-api/docs/apis (param detail)
- Synology *DSM Login Web API Guide* + *File Station API Guide* (PDFs)
- Synology KB: Log Center server, Terminal & SNMP, Task Scheduler, Key Manager (DSM 7 help tree)
- zub2/synoacl (synoacltool ACE format); ordinoscope.net (synoshare/synoacltool CLI)