{"id":13775920,"url":"https://github.com/shadowsocks/shadowsocks-hub-api","last_synced_at":"2025-10-19T14:32:20.461Z","repository":{"id":65979121,"uuid":"140085984","full_name":"shadowsocks/shadowsocks-hub-api","owner":"shadowsocks","description":"A set of open and standard restful APIs for managing shadowsocks users, servers, nodes, products, accounts, and traffic.","archived":false,"fork":false,"pushed_at":"2018-10-03T10:29:00.000Z","size":107,"stargazers_count":28,"open_issues_count":1,"forks_count":27,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-01-29T18:45:41.358Z","etag":null,"topics":["accounts","management","restful-api","servers","shadowsocks","traffic","users"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shadowsocks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-07T13:17:56.000Z","updated_at":"2024-11-11T15:13:58.000Z","dependencies_parsed_at":"2023-02-19T18:45:21.440Z","dependency_job_id":null,"html_url":"https://github.com/shadowsocks/shadowsocks-hub-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shadowsocks%2Fshadowsocks-hub-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shadowsocks%2Fshadowsocks-hub-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shadowsocks%2Fshadowsocks-hub-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shadowsocks%2Fshadowsocks-hub-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shadowsocks","download_url":"https://codeload.github.com/shadowsocks/shadowsocks-hub-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237152832,"owners_count":19263792,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accounts","management","restful-api","servers","shadowsocks","traffic","users"],"created_at":"2024-08-03T17:01:54.503Z","updated_at":"2025-10-19T14:32:20.140Z","avatar_url":"https://github.com/shadowsocks.png","language":"JavaScript","funding_links":[],"categories":["\u003ca id=\"d03d494700077f6a65092985c06bf8e8\"\u003e\u003c/a\u003e工具"],"sub_categories":["\u003ca id=\"cb16466a31a167bb61f39e2a4a85f449\"\u003e\u003c/a\u003eShadowsocks"],"readme":"# Shadowsocks Hub API\nShadowsocks Hub API provides a set of open and standard restful APIs for managing shadowsocks users, servers, nodes, products, accounts, and traffic. It is best suitable for companies, organizations, and groups of people to manage their internal shadowsocks infrastructures. \n\nIts web app (including graphic UI) can be found from [shadowsocks-hub](https://github.com/shadowsocks/shadowsocks-hub). Alternatively, you may choose to develop your own shadowsocks management UI by utilizing this set of API. All common features have been made available in the form of restful APIs.\n\nShadowsocks Hub API is developed using Nodejs. It uses MySQL as its underlying database and shadowsocks-libev as its shadowsocks implementation. \n\n## Install (Ubuntu 16.04)\n\n1. Install Nodejs 6 or above (8 preferred).\n2. Install MySQL.\n3. Download and install Shadowsocks Hub API:\n    ```\n    cd ~\n    git clone https://github.com/shadowsocks/shadowsocks-hub-api.git\n    cd ~/shadowsocks-hub-api\n    npm i\n    ```\n4. Create a MySQL database `sshub`:\n    ```\n    CREATE DATABASE sshub;\n    ```\n5. Create an environment file `.env`:\n    ```\n    cd ~/shadowsocks-hub-api\n    touch .env\n    ```\n6. Add the following configuration key value pairs to `.env`:\n    ```\n    JWT_SECRET = 2wk0M@ow094B^\u00269k3==~o2soejd$sEEo@2(\n    LISTEN_PORT = 8000\n\n    DATABASE_HOST = localhost\n    DATABASE_PORT = 3306\n    DATABASE_USER = root\n    DATABASE_PASSWORD = d4f889df22769f54\n    ```\n\n   Change the values about the database connection to your local configuration.  \n   Change the value of `JWT_SECRET` with a long and random string.  \n   Change the value `LISTEN_PORT` to your preferred port for Shadowsocks Hub API to listen to.  \n\n7. Initialize database:\n    ```\n    cd ~/shadowsocks-hub-api\n    knex migrate:latest --env production\n    ```\n8. Setup digital certificate\n\n   All requests and responses are encrypted using https. It requires you to set up a digital certificate. You may create your own self-signed certificate:  \n    ```\n    cd ~/shadowsocks-hub-api\n    openssl req -nodes -x509 -newkey rsa:4096 -keyout server.key -out server.cert -days 365\n    ```\n\n   Alternatively, you may copy your digital certificate and key pair that you obtained from a Certificate Authority (e.g. Let's Encrypt) to `~/shadowsocks-hub-api` with the certificate named as `server.cert` and the key named as `server.key`.  \n\n9. Shadowsocks Hub API utilize [shadowsocks-restful-api](https://github.com/shadowsocks/shadowsocks-restful-api) to manage shadowsocks protocol. Install it on every server that you would like to use as a shadowsocks node.\n\n## Update\nIf you have updated Shadowsocks Hub API from an older version to the latest version, run:\n```\ncd ~/shadowsocks-hub-api\nknex migrate:latest --env production\n```\n\n## Run\n1. Run Shadowsocks Hub API:\n    ```\n    cd ~/shadowsocks-hub-api\n    node api.js\n    ```\n\n2. Change admin credential\n\n   For the sake of security, you should change the default admin user credential as soon as possible. This can be done by using the `login` API to obtain a token, and then using the `update user` API to change the username and password of the admin user. The default username and password for admin user are `admin@email.com` and `pleaseChangePassword`, respectively.\n\n3. Run [shadowsocks-restful-api](https://github.com/shadowsocks/shadowsocks-restful-api) on every server that you would like to use as a shadowsocks node.\n\n## Authentication\n\nAll the APIs except for the `login` API require an Authorization header. The header pattern is: `Authorization: Bearer \u003ctoken\u003e`. The token can be obtained from the `login` or `refresh token` API. The authentication is compatiable with [OAuth 2](https://oauth.net/2/). There are 3 APIs relating to authentication: `login`, `refresh token`, and `invalidate refresh token`.\n\nAccess token expires in 15 minutes while refresh token exipires in 1 week. Both `login` and `refresh token` APIs will produce a pair of new access token and refresh token. The difference is that `login` API requires `username` and `password` while `refresh token` API requires a valid refresh token to be provided in the `Authorization Bearer` header.\n\nThe `invalidate refresh token` API can be used to invalidate all previously obtained refresh tokens.\n\n## Rate limit\n\nYou may enforce a rate limit by setting the maximum number of requests allowed within 15-minute window from the same ip address. Requests exceeding the limit will be refused with HTTP status code `429 Too Many Requests`. This setting can be done by add the following config to the `.env` file.\n    ```\n    RATE_LIMIT = 50\n    ```\n\n   Change the number to your choice.\n\n\n## Bug report and feature request\n\nBug report and feature request are welcome. Bugs have a high priority to get addressed. Feature requests will be considered depending on their popularity and importance.\n\n## APIs\n\n### 1. User APIs\nThere are two type of users: `admin user` and `normal user`. This API is [OAuth 2](https://oauth.net/2/) compatiable. Admin user has priviliege to make any API requests. Normal user has priviliege to make API requests relating to themselves only.\n\n#### Login\nBoth `admin user` and `normal user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/user/login                            |\n| Request Header:               |  Content-Type: application/json                                   |\n| Request Body:                 |  {\"username\":\"your_username\", \"password\":\"your_login_password\"}   |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {\"token\":\"new_authentication_token\", \"refreshToken\":\"new_refresh_token\"} |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -X POST -d '{\"username\":\"admin@email.com\",\"password\":\"pleaseChangePassword\"}' https://localhost:8000/api/user/login\n```\nResponse example:  \n```json\n{\"token\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWVmYjQ3LTI4YzYtNDA1OC1hMDBiLTc1ZGI1MTQ0OGJkNyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMTIyNDMzMiwiZXhwIjoxNTMxMjI1MjMyfQ.h82mSltnLua-XLPHyV7X2-lqe94O7dYE7Ujachg3NDY\",\"refreshToken\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWVmYjQ3LTI4YzYtNDA1OC1hMDBiLTc1ZGI1MTQ0OGJkNyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMTIyNDMzMiwiZXhwIjoxNTMxODI5MTMyfQ.PIL-thIdKr2ji5LDOelLXPfIZQUvo3II1KrOG0-lLx4\"}\n```\n\n#### Refresh Token\nBoth `admin user` and `normal user` can call this API. This API is [OAuth 2](https://oauth.net/2/) compatiable. You will get a set of new `token` and `refreshToken`. Note that you need supply `refreshToken` instead of `token` to `Authorization Bearer` header.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/user/refresh_token                    |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_refresh_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  {\"token\":\"new_authentication_token\", \"refreshToken\":\"new_refresh_token\"} |\n| Response Error Status Code:   |  401 Unauthorized \u003cbr\u003e 500 Internal Server Error                  |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWVmYjQ3LTI4YzYtNDA1OC1hMDBiLTc1ZGI1MTQ0OGJkNyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMTIyNDMzMiwiZXhwIjoxNTMxODI5MTMyfQ.PIL-thIdKr2ji5LDOelLXPfIZQUvo3II1KrOG0-lLx4\" https://localhost:8000/api/user/refresh_token\n```\nResponse example:  \n```json\n{\"token\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWVmYjQ3LTI4YzYtNDA1OC1hMDBiLTc1ZGI1MTQ0OGJkNyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMTIyNDM4NSwiZXhwIjoxNTMxMjI1Mjg1fQ.U_A74GyZy9xGZsj49weYaPK99iZeBaIFkCX9GVx9_dE\",\"refreshToken\":\"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWVmYjQ3LTI4YzYtNDA1OC1hMDBiLTc1ZGI1MTQ0OGJkNyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMTIyNDM4NSwiZXhwIjoxNTMxODI5MTg1fQ.6OoLLVmTAsHMtDsLWPl9lS19w1WMQeyNyL9WLReEjaQ\"}\n```\n\n#### Invalidate Refresh Token\nBoth `admin user` and `normal user` can call this API. This API is [OAuth 2](https://oauth.net/2/) compatiable. You will invalidate all previously obtained `refreshToken`. Note that you need supply `refreshToken` instead of `token` to `Authorization Bearer` header.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/user/invalidate_refresh_token         |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_refresh_token |\n| Request Body:                 |  {}                                                               |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {}                                                               |\n| Response Error Status Code:   |  401 Unauthorized \u003cbr\u003e 500 Internal Server Error                  |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYWVmYjQ3LTI4YzYtNDA1OC1hMDBiLTc1ZGI1MTQ0OGJkNyIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMTIyNDMzMiwiZXhwIjoxNTMxODI5MTMyfQ.PIL-thIdKr2ji5LDOelLXPfIZQUvo3II1KrOG0-lLx4\" -X POST -d '{\"username\":\"admin@email.com\",\"password\":\"pleaseChangePassword\"}' https://localhost:8000/api/user/invalidate_refresh_token\n```\nResponse example:  \n```json\n{}\n```\n\n#### Create User\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/user                                  |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"role\":\"user\", \"email\":\"email_address\", \"password\":\"userPassword\"} |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {\"id\",\"user_id\"}                                                 |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 409 Conflict (user already exists) \u003cbr\u003e 500 Internal Server Error                  |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X POST -d '{\"role\":\"user\",\"email\":\"user@email.com\",\"password\":\"somePassword\"}' https://localhost:8000/api/user\n```\nResponse example:  \n```json\n{\"id\":\"7768be69-b707-4111-a15c-84b7278bc588\"}\n```\n\n#### Delete User\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  DELETE                                                           |\n| Request URL:                  |  https://host_name:port/api/user?id=user_id                      |\n| Request Header:               |  Authorization: Bearer your_authentication_token                  |\n| Response HTTP Status Code:    |  204 No Content                                                   |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X DELETE https://localhost:8000/api/user?id=7768be69-b707-4111-a15c-84b7278bc588\n```\n\n#### Get User\nBoth `admin user` and `normal user` can call this API. But `normal user` can get user about themselves. The `admin user` can get user about anyone.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/user?id=user_id                      |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  {\"id\":\"user_id\", \"type\":\"EmailUser\", \"role\":\"admin\", \"email\":\"email_address\", \"createdTime\":epoch_time, \"username\":\"email_address\", \"lastLoginTime\":epoch_time} |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (user does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" https://localhost:8000/api/user?id=e2da99e0-7d47-4ce2-b8c8-3088e0132459\n```\nResponse example:  \n```json\n{\"id\":\"e2da99e0-7d47-4ce2-b8c8-3088e0132459\",\"type\":\"EmailUser\",\"role\":\"admin\",\"email\":\"admin@email.com\",\"createdTime\":1530753369303,\"username\":\"admin@email.com\",\"lastLoginTime\":1530759474686}\n```\n\n#### Update User\nBoth `admin user` and `normal user` can call this API. But `normal user` can get user about themselves. The `admin user` can get user about anyone.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  PUT                                                              |\n| Request URL:                  |  https://host_name:port/api/user                                  |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"id\":\"user_id\", \"role\":\"user_role\", \"email\":\"new_email_address\", \"password\":\"new_password\"} |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (user does not exist) \u003cbr\u003e 409 Conflict (new email address already exists) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X PUT -d '{\"id\":\"e2da99e0-7d47-4ce2-b8c8-3088e0132459\", \"role\":\"admin\",\"email\":\"admin@new.email.com\",\"password\":\"newPassword\"}' https://localhost:8000/api/user\n```\n\n\n### 2. Server APIs\n\nServers are physical shadowsocks servers. Multiple servers are supported. Each server must have an external ip address or domain name that can be used to be connected by user shadowsocks clients.\n\n#### Create Server\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/server                                |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"ipAddressOrDomainName\":\"server_ip_address_or_domain_name\"}     |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {\"id\",\"server_id\"}                                               |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 409 Conflict (server already exists) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X POST -d '{\"ipAddressOrDomainName\":\"127.0.0.1\"}' https://localhost:8000/api/server\n```\nResponse example:  \n```json\n{\"id\":\"d0ee089d-f43d-4bae-b408-02f59db04e9c\"}\n```\n\n#### Delete Server\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  DELETE                                                           |\n| Request URL:                  |  https://host_name:port/api/server?id=server_id                  |\n| Request Header:               |  Authorization: Bearer your_authentication_token                  |\n| Response HTTP Status Code:    |  204 No Content                                                   |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 409 Conflict (server is in use) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X DELETE https://localhost:8000/api/server?id=d0ee089d-f43d-4bae-b408-02f59db04e9c\n```\n\n#### Get Server\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/server?id=server_id                  |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  {\"id\":\"server_id\", \"ipAddressOrDomainName\":\"server_ip_address_or_domain_name\", \"createdTime\":epoch_time} |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (server does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" https://localhost:8000/api/server?id=c9be32dd-e2d6-4af4-876f-f086e82af20c\n```\nResponse example:  \n```json\n{\"id\":\"c9be32dd-e2d6-4af4-876f-f086e82af20c\",\"ipAddressOrDomainName\":\"127.0.0.1\",\"createdTime\":1530773538890}\n```\n\n#### Update Server\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  PUT                                                              |\n| Request URL:                  |  https://host_name:port/api/server                                |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"id\":\"server_id\", \"ipAddressOrDomainName\":\"new_server_ip_address_or_domain_name\"} |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (server does not exist) \u003cbr\u003e 409 Conflict (new ip address or domain name already exists) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X PUT -d '{\"id\":\"c9be32dd-e2d6-4af4-876f-f086e82af20c\",\"ipAddressOrDomainName\":\"127.0.0.2\"}' https://localhost:8000/api/server\n```\n\n### 3. Node APIs\n\nNodes are logical shadowsocks servers. A node has to reside in one and only one server. A server may have multiple nodes. All nodes within a server appear like different shadowsocks servers to users, but they share the same resources of the server. A node must have a unique name, a port number and password that is used by [shadowsocks-restful-api](https://github.com/shadowsocks/shadowsocks-restful-api).\n\n#### Create Node\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/node                                  |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"serverId\":\"server_id\", \"port\":port_number, \"password\":\"somePassword\", \"name\":\"someName\"} |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {\"id\",\"node_id\"}                                                 |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (server does not exist) \u003cbr\u003e 409 Conflict (node already exists) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X POST -d '{\"serverId\":\"c9be32dd-e2d6-4af4-876f-f086e82af20c\", \"port\":4001, \"password\":\"pleaseChangeThisPassword\", \"name\":\"New York\"}' https://localhost:8000/api/node\n```\nResponse example:  \n```json\n{\"id\":\"5daefb47-28c6-4058-a00b-75db51448bd7\"}\n```\n\n#### Delete Node\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  DELETE                                                           |\n| Request URL:                  |  https://host_name:port/api/node?id=node_id                      |\n| Request Header:               |  Authorization: Bearer your_authentication_token                  |\n| Response HTTP Status Code:    |  204 No Content                                                   |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 409 Conflict (node is in use) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X DELETE https://localhost:8000/api/node?id=5daefb47-28c6-4058-a00b-75db51448bd7\n```\n\n#### Get Node\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/node?id=node_id                      |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  {\"id\":\"node_id\", \"server\":{\"id\":\"server_id\", \"ipAddressOrDomainName\":\"server_ip_address_or_domain_name\", \"createdTime\":server_created_time}, \"password\":\"some_password\", \"port\":node_management_port_number, \"name\":\"node_name\", \"comment\":\"come_comment\", \"createdTime\":node_createdTime} |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (node does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" https://localhost:8000/api/node?id=075a74fd-d8ab-4313-bde3-f9cb99d7215d\n```\nResponse example:  \n```json\n{\"id\":\"075a74fd-d8ab-4313-bde3-f9cb99d7215d\",\"server\":{\"id\":\"7b15f7ba-ee6c-452d-8264-0657f202590d\",\"ipAddressOrDomainName\":\"127.0.0.1\",\"createdTime\":1530790525902},\"password\":\"pleaseChangeThisPassword\",\"port\":4001,\"name\":\"New York\",\"comment\":null,\"createdTime\":1530790577846}\n```\n\n#### Update Node\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  PUT                                                              |\n| Request URL:                  |  https://host_name:port/api/node                                  |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"id\":\"node_id\", \"port\":new_port_number, \"password\":\"newPassword\", \"name\":\"newName\"} |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (node does not exist) \u003cbr\u003e 409 Conflict (new name already exists) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X PUT -d '{\"id\":\"075a74fd-d8ab-4313-bde3-f9cb99d7215d\", \"port\":4002, \"password\":\"newPassword\", \"name\":\"newName\", \"comment\":\"some comment\"}' https://localhost:8000/api/node\n```\n\n### 4. Product APIs\n\nProducts are different types of shadowsocks services. A product must have a unique name, traffic, and period. The period of a product defines the life span of an account associated with this product. The traffic of a product defines the maximum amount of traffic allowed for an account associated with this product with in its period.\n\n#### Create Product\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/product                               |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"name\":\"some name\", \"traffic\":max_traffic_allowed, \"period\":\"valid_period\"} |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {\"id\",\"product_id\"}                                              |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 409 Conflict (product already exists) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X POST -d '{\"name\":\"dimond\", \"traffic\":1000000000, \"period\":\"monthly\"}' https://localhost:8000/api/product\n```\nResponse example:  \n```json\n{\"id\":\"66c5a883-f729-498b-9442-f3d0bbca9345\"}\n```\n\n#### Delete Product\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  DELETE                                                           |\n| Request URL:                  |  https://host_name:port/api/product?id=product_id                |\n| Request Header:               |  Authorization: Bearer your_authentication_token                  |\n| Response HTTP Status Code:    |  204 No Content                                                   |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 409 Conflict (product is in use) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X DELETE https://localhost:8000/api/product?id=66c5a883-f729-498b-9442-f3d0bbca9345\n```\n\n#### Get Product\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/product?id=product_id                |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  {\"id\":\"server_id\", \"ipAddressOrDomainName\":\"server_ip_address_or_domain_name\", \"createdTime\":epoch_time} |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (product does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" https://localhost:8000/api/product?id=b35aa689-756c-4752-bb7a-9b3e8e0dd699\n```\nResponse example:  \n```json\n{\"id\":\"b35aa689-756c-4752-bb7a-9b3e8e0dd699\",\"name\":\"dimond\",\"traffic\":1000000000,\"period\":\"monthly\",\"createdTime\":1530793170070}\n```\n\n#### Update Product\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  PUT                                                              |\n| Request URL:                  |  https://host_name:port/api/node                                  |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"id\":\"product_id\", \"name\":\"newName\", \"traffic\":newTraffic, \"period\":\"newPeriod\"} |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (product does not exist) \u003cbr\u003e 409 Conflict (new name already exists) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X PUT -d '{\"id\":\"b35aa689-756c-4752-bb7a-9b3e8e0dd699\", \"name\":\"newName\", \"traffic\":5000000000, \"period\":\"annual\"}' https://localhost:8000/api/product\n```\n\n### 5. Account APIs\n\nAccounts contain all information needed for a shadowsocks client to connect to a node. A user has to obtain an account before being able to use a product. An account contains data of its owner, the node and product associated with the account.\n\n#### Request Account\n\nBoth `admin user` and `normal user` can call this API. But `normal user` can request account for themselves only. The `admin user` can do so for anyone.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/account/request                       |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"userId\":\"user_id\", \"productId\":\"product_id\"}                   |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {\"id\",\"approval_id\"}                                             |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (user does not exist) \u003cbr\u003e 420 (product does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X POST -d '{\"userId\":\"5daefb47-28c6-4058-a00b-75db51448bd7\", \"productId\":\"b35aa689-756c-4752-bb7a-9b3e8e0dd699\"}' https://localhost:8000/api/account/request\n```\nResponse example:  \n```json\n{\"id\":\"480e723d-6e61-4440-a6dd-6ae624342a8e\"}\n```\n\n\n#### Approve Request (create accounts)\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  POST                                                             |\n| Request URL:                  |  https://host_name:port/api/account/approve                       |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Request Body:                 |  {\"id\",\"approval_id\"}                                             |\n| Response HTTP Status Code:    |  201 Created                                                      |\n| Response Body:                |  {\"id\",\"approval_id\"}                                             |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (approval_id does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X POST -d '{\"id\":\"0e3f59ac-693c-4fbf-a286-6a9de41d3a74\"}' https://localhost:8000/api/account/approve\n```\nResponse example:  \n```json\n{\"id\":\"0e3f59ac-693c-4fbf-a286-6a9de41d3a74\"}\n```\n\n#### Delete Account\n\nOnly `admin user` can call this API.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  DELETE                                                           |\n| Request URL:                  |  https://host_name:port/api/account?id=account_id                |\n| Request Header:               |  Authorization: Bearer your_authentication_token                  |\n| Response HTTP Status Code:    |  204 No Content                                                   |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 409 Conflict (account is in use) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" -X DELETE https://localhost:8000/api/account?id=66c5a883-f729-498b-9442-f3d0bbca9345\n```\n\n#### Get Account\n\nBoth `admin user` and `normal user` can call this API. But `normal user` can get account belonging to themselves only. The `admin user` can get any account.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/account?id=account_id                |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  {\"id\":\"account_id\", \"node\":{\"id\":\"node_id\", \"server\":{\"id\":\"server_id\", \"ipAddressOrDomainName\":\"server_ip_address_or_domain_name\", \"createdTime\":server_created_time}, \"port\":node_management_port_number, \"name\":\"node_name\", \"comment\": \"noe_comment\", \"createdTime\":node_created_time},\"port\":account_port_number, \"createdTime\":account__created_time, \"password\":\"account_password\", \"method\":\"encryption_method\", \"approval\":{\"id\":\"approval_id\", \"state\":\"approval_state\", \"createdTime\":approval_created_time}, \"request\":{\"id\":\"request_id\", \"user\":{\"id\":\"user_id\", \"role\":\"user_role\", \"email\":\"user_email_address\", \"createdTime\":user_created_time, \"username\":\"user_email_address\"}, \"product\":{\"id\":\"product_id\", \"name\":\"product_name\", \"traffic\":product_traffic, \"period\":\"product_period\", \"createdTime\":product_created_time}, \"createdTime\":request_created_time}} |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (account does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" https://localhost:8000/api/account?id=b35aa689-756c-4752-bb7a-9b3e8e0dd699\n```\nResponse example:  \n```json\n{\"id\":\"c2e5a807-9525-4c23-b121-6024e2d1eebb\",\"node\":{\"id\":\"cd41dc00-2e53-4d7f-8374-b44e82caaeaa\",\"server\":{\"id\":\"aec2a2ad-ecb4-4a12-b90d-4acaeb8ec676\",\"ipAddressOrDomainName\":\"127.0.0.1\",\"createdTime\":1530838310353},\"port\":4001,\"name\":\"New York\",\"comment\":null,\"createdTime\":1530838367312},\"port\":50647,\"createdTime\":1530847875199,\"password\":\"ee60fe5cf97433e9\",\"method\":\"aes-256-cfb\",\"approval\":{\"id\":\"1ab123d0-92d6-4c6d-991e-c82cd03182f2\",\"state\":\"completed\",\"createdTime\":1530842543004},\"request\":{\"id\":\"4da6972a-2e10-4f20-8cc0-4ad66e886607\",\"user\":{\"id\":\"ad5ceb7f-4a6d-4577-8ed6-01e3acb2604c\",\"role\":\"user\",\"email\":\"user@email.com\",\"createdTime\":1530838144205,\"username\":\"user@email.com\"},\"product\":{\"id\":\"48e6a637-f94e-4d8e-b71c-9793a37e7e2c\",\"name\":\"dimond\",\"traffic\":1000000000,\"period\":\"monthly\",\"createdTime\":1530838417112},\"createdTime\":1530842543116}}\n```\n\n#### Get Accounts by User Id\n\nBoth `admin user` and `normal user` can call this API. But `normal user` can get accounts for themselves only. The `admin user` can accounts for any users.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/account/accounts_by_user_id?id=user_id                |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  [{\"id\":\"account_id\", \"node\":{\"id\":\"node_id\", \"server\":{\"id\":\"server_id\", \"ipAddressOrDomainName\":\"server_ip_address_or_domain_name\", \"createdTime\":server_created_time}, \"port\":node_management_port_number, \"name\":\"node_name\", \"comment\": \"noe_comment\", \"createdTime\":node_created_time},\"port\":account_port_number, \"createdTime\":account__created_time, \"password\":\"account_password\", \"method\":\"encryption_method\", \"approval\":{\"id\":\"approval_id\", \"state\":\"approval_state\", \"createdTime\":approval_created_time}, \"request\":{\"id\":\"request_id\", \"user\":{\"id\":\"user_id\", \"role\":\"user_role\", \"email\":\"user_email_address\", \"createdTime\":user_created_time, \"username\":\"user_email_address\"}, \"product\":{\"id\":\"product_id\", \"name\":\"product_name\", \"traffic\":product_traffic, \"period\":\"product_period\", \"createdTime\":product_created_time}, \"createdTime\":request_created_time}},...] |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (account does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" https://localhost:8000/api/account/accounts_by_user_id?id=3ec1072e-e6e3-438d-99ad-2f891b877697\n```\nResponse example:  \n```json\n[{\"id\":\"c2e5a807-9525-4c23-b121-6024e2d1eebb\",\"node\":{\"id\":\"cd41dc00-2e53-4d7f-8374-b44e82caaeaa\",\"server\":{\"id\":\"aec2a2ad-ecb4-4a12-b90d-4acaeb8ec676\",\"ipAddressOrDomainName\":\"127.0.0.1\",\"createdTime\":1530838310353},\"port\":4001,\"name\":\"New York\",\"comment\":null,\"createdTime\":1530838367312},\"port\":50647,\"createdTime\":1530847875199,\"password\":\"ee60fe5cf97433e9\",\"method\":\"aes-256-cfb\",\"approval\":{\"id\":\"1ab123d0-92d6-4c6d-991e-c82cd03182f2\",\"state\":\"completed\",\"createdTime\":1530842543004},\"request\":{\"id\":\"4da6972a-2e10-4f20-8cc0-4ad66e886607\",\"user\":{\"id\":\"ad5ceb7f-4a6d-4577-8ed6-01e3acb2604c\",\"role\":\"user\",\"email\":\"user@email.com\",\"createdTime\":1530838144205,\"username\":\"user@email.com\"},\"product\":{\"id\":\"48e6a637-f94e-4d8e-b71c-9793a37e7e2c\",\"name\":\"dimond\",\"traffic\":1000000000,\"period\":\"monthly\",\"createdTime\":1530838417112},\"createdTime\":1530842543116}}]\n```\n\n### 6. Traffic APIs\n\nTraffic is the amount of data transmitted by a node for an account.\n\n#### Get Account Latest Traffic\n\nBoth `admin user` and `normal user` can call this API. But `normal user` can get latest traffic belonging to themselves only. The `admin user` can do so for any account.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/traffic/account?id=account_id                |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  {\"usage\":latest_usage}         |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 404 Not Found (account does not exist) \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\"  https://localhost:8000/api/traffic/account?id=766341be-bc67-49e2-bc44-1c9ac485a56b\n```\nResponse example:  \n```json\n{\"usage\":298270232}\n```\n\n#### Get Account Traffic History\n\nBoth `admin user` and `normal user` can call this API. But `normal user` can get traffic history belonging to themselves only. The `admin user` can do so for any account.\n\n|                               |                                                                   |\n| :---------------------------- | :---------------------------------------------------------------- |\n| Request method:               |  GET                                                              |\n| Request URL:                  |  https://host_name:port/api/traffic/history?id=account_id    |\n| Request Header:               |  Content-Type: application/json \u003cbr\u003e Authorization: Bearer your_authentication_token |\n| Response HTTP Status Code:    |  200 OK                                                           |\n| Response Body:                |  [{\"usage\":accumulative_usage, \"createdTime\":epoch_time}...] |\n| Response Error Status Code:   |  400 Bad Request \u003cbr\u003e 401 Unauthorized \u003cbr\u003e 500 Internal Server Error |\n\nRequest example (curl):  \n```\ncurl -ik -H \"Content-Type: application/json\" -H \"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImUyZGE5OWUwLTdkNDctNGNlMi1iOGM4LTMwODhlMDEzMjQ1OSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTUzMDc1OTQ3NCwiZXhwIjoxNTMwODQ1ODc0fQ.XqS8UBj7hWNeKjaGlXjrZDHuVZWM_8thw__ojAkBG0A\" https://localhost:8000/api/traffic/history?id=b12bd8d0-5943-48c4-9016-d45a654c5a1c\n```\nResponse example:  \n```json\n[{\"usage\":0,\"createdTime\":1530840202934},{\"usage\":19380263,\"createdTime\":1530840300014}]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshadowsocks%2Fshadowsocks-hub-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshadowsocks%2Fshadowsocks-hub-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshadowsocks%2Fshadowsocks-hub-api/lists"}