Exploring the Synology PhotoStation API

I've started to use PhotoStation on my Synology NAS device at home to organize my photos and provide easy means to access remotely. I have been quite pleased overall, especially with the integration with the DS Photo app which can sync photos from an iPhone's camera roll to the Synology NAS.

I was looking for an automated way to sort my photos into a hierarchy of folders by date. Unable to find a built-in way to do this or any public documentation for the PhotoStation API, I set about to explore the API and see what I could figure out.

Synology API Structure

While the Synology developer documentation site does not have any API reference for PhotoStation, it does contain information on some of the other REST APIs from Synology which proved useful to understanding the basic workings of the PhotoStation API. For example, in the documentation for FileStation one can see how the general request/response workflow is for a Synology application.

Each application has several named APIs (eg. SYNO.FileStation.Info or SYNO.FileStation.List) that provide different functionality. To make a request against one of these APIs, one must first find its endpoint (the path portion of the URL) and then send an HTTP request with the following parameters:

The API endpoints and available versions can be found by querying the SYNO.API.Info API at http://mysynology:5000/webapi/query.cgi. Sending a request with the above parameters (sans sid) and additional parameter query=all will return a list of all available APIs from the NAS device.

Unfortunately, there are no PhotoStation APIs listed in the response. This, as it turns out, is because the PhotoStation API is handled differently, as we see below.

Listening on the Wire

Since the FileStation documentation didn't lead to the list of APIs as I hoped, the next step was to examine the network traffic between the browser and NAS when running PhotoStation. Since the web interface for PhotoStation does not use HTTPS by default, it is rather easy to use a packet tracing tool like wireshark to examine the network traffic between my browser and the NAS system. By setting a capture filter to "host 10.20.30.40 and port 80" (the IP of my NAS device) and then using a display filter "http", I could start to see the HTTP traffic between the javascript UI running in my browser and the PhotoStation backend.

Alternatively, one could use developer tools in the browser itself to show the network requests and responses being sent from a particular session. The built-in browser tools can be easier to understand than wireshark but only works (obviously) when using that browser. Later on, when doing testing from the command line with curl wireshark is useful (though curl too can display some additional info with the -v flag)

The first thing to notice when looking at the network traffic from a browser is that the all the requests are going to port 80 on the NAS and not port 5000 where the DSM GUI operates. Secondly, there appeared to be two broad sets of requests - those going to files in /photo and those accessing files in /photo/webapi. The first are all the files for displaying and running the PhotoStation GUI. The latter set are requests to the backend API. Finally, the observed /photo/webapi calls all (or mostly all) appeared to have .php suffixes.

Given this, a quick trial shows that there is a separate API info endpoint for PhotoStation that can be accessed as follows:

curl 'http://mysynology/photo/webapi/query.php?api=SYNO.API.Info&version=1&method=query&query=all'`

The response (truncated below, see full response here) lists approximately 30 separate APIs along with their path (endpoint) and versions:

{
  "success": true,
  "data": {
    "SYNO.PhotoStation.Auth": {
      "path": "auth.php",
      "minVersion": 1,
      "maxVersion": 1
    },
    "SYNO.PhotoStation.Info": {
      "path": "info.php",
      "minVersion": 1,
      "maxVersion": 2
    },
    "SYNO.PhotoStation.Album": {
      "path": "album.php",
      "minVersion": 1,
      "maxVersion": 1
    },
    ... truncated ...
    "SYNO.API.Info": {
      "path": "query.php",
      "minVersion": 1,
      "maxVersion": 1
    }
  }
}

Understanding Authentication

Having made some progress, the next step was to tackle authentication. None of the backend requests I observed had a sid or session parameter mentioned in the FileStation documentation, so it was unclear how an authenticated session was communicated to the backend.

I experimented some with curl to try to mimic the queries that were being sent by my browser but would get different results or errors because it did not recognize my session. Even copying the SynoToken parameter that was sent on some backend queries did not help.

In the end, I discovered that session ID was being sent as a cookie (with the key PHPSESSID) on each request. Once I started to send a similar cookie in curl (with the -b KEY=VALUE option), I could start getting the same responses via curl as from the browser.

However, I still needed to understand how to start a session (ie. login) rather than piggyback on an existing session. The login method of SYNO.PhotoStation.Auth certainly seemed promising but without knowing the parameters to send, it doesn't do much good. Fortunately, I was able to log out of PhotoStation and then login again while tracing the network and was able to see the needed parameters (username and password).

Sending my credentials to this API returned (among other items) a session ID that I could use to send in cookie form on subsequent requests.

Diving into the Code

Tracing requests and responses can be informative but does not always give insight into the meaning of parameters or even the existence of parameters not being used by the GUI. Thankfully, I was able to also dig into the PhotoStation code some.

Synology's NAS products are based on Linux and they provide local shell access through ssh. With this, one can log into the NAS and explore what is going on. Unfortunately it takes a while to find where things are.

Synology Packaging

Synology applications are distributed in packages, bundled archives of files that provide the necessary code and data to run an application. When installed on a Synology machine these packages are unpacked into a subfolder in /var/packages named for the application, for instance /var/packages/PhotoStation. Within this package directory there are a number of files and directories that pertain to the packaging itself (eg. versioning, install/upgrade/remove scripts, etc…) while the core application code and data are saved in a target directory.

Synology only allocates a few GB to its operating system, so this target directory is typically a symlink to another directory within one of the storage volumes, /volume1/@appstore/PhotoStation in this case. Within this directory are all the files used by PhotoStation – all 3700+ of them! While a daunting number to examine, there is a silver lining … one reason why there are so many files is that the backend REST API is written in PHP, and thus is present in readable code on the NAS device (unlike other applications that might have only compiled binaries installed).

Exploring photo/webapi Directory

The photo/webapi directory within /var/packages/PhotoStation/target contains the bulk of the PHP code used in the backend of PhotoStation. These are the files that the webserver calls to handle requests. For instance, a request to http://mysynology/photo/webapi/auth.php will run the PHP script contained in photo/webapi/auth.php. Knowing this, one can explore the individual code for each command.

In addition to these PHP files, there are additional files located in photo/include and photo/webapi/sdk that may be referenced by the PHP files in photo/webapi.

Finally, there is a file named photo/webapi/PhotoStation.api that provides the same information as the SYNO.API.Info query (API name, path and versions) but also provides a list of all the methods associated with an API!

Here is a small subset of the APIs defined in photo/webapi/PhotoStation.api:

{
  "SYNO.PhotoStation.Auth": {
    "path": "auth.php",
    "minVersion": 1,
    "maxVersion": 1,
    "methods": {
      "1": [
        "login",
        "photo_login",
        "logout",
        "checkauth"
      ]
    }
  },
  "SYNO.PhotoStation.Info": {
    "path": "info.php",
    "minVersion": 1,
    "maxVersion": 2,
    "methods": {
      "2": [
        "getinfo",
        "getexternalip"
      ],
      "1": [
        "getinfo"
      ]
    }
  },
  "SYNO.PhotoStation.Album": {
    "path": "album.php",
    "minVersion": 1,
    "maxVersion": 1,
    "methods": {
      "1": [
        "list",
        "getinfo",
        "create",
        "edit",
        "delete",
        "arrangeitem",
        "move",
        "cleararrangeitem",
        "cancel"
      ]
    }
  },
  ...
}

Documenting the API

With this information, wireshark and time to experiment and test, I was able to gradually understand some of the key parts of the PhotoStation API - notably those parts associated with creating albums, moving photos and the like. Initially, I was taking notes in a small text file but soon I was inspired to take it a step further and started my own unofficial Synology PhotoStation API documentation using the wonderful TechDoc Hugo theme.

I've tried to lay out the basics for using the API in the Getting Started section. This should, hopefully, allow others to get up to speed with accessing the API directly. The API Reference section provides detailed information on a limited number of APIs (as I have been able to examine and document them). Within this section, I provide information on the request parameters and the responses for various methods of the APIs.

I don't expect I will completely document the entire API, as frankly there are only a limit subset of calls required for my immediate project. However, I as I understand the API more, I will try to update this documentation for others. I've hosted the documentation on GitHub at https://github.com/jamesbo13/syno-photostation-api and would be open to any pull request improvements.