Table of contents:
- Data formats
- Public API
- Internal communication
Serval accounting service uses Protocol Buffers for internal communication with puppeteer service and collection service. Communication with public API is done with JSON objects through standard HTTP(S) protocol. All data is stored and used in UTF32 encoding.
When communicating with public API through POST
methods, both request and response body is in JSON form. GET
and DELETE
use standard NVP query strings for request, response body is then returned in JSON format. All NVP parameter values must be URL encoded.
Service can be extended to accept different formats through different protocols by adapting existing or creating new service extensions.
For internal communication Salsa20 encryption algorithm is used. Connections are stream-based and can be used for multiple requests. Upon opening new connection client must send 32 bytes long initialization vector along with client id. This IV will be used in encryption process for the currently active session. Keys used in encryption are never exchanged through the network and are considered known at the time of encryption.
Public API is primarily used by the Serval web application. However this API can be used to automate integration tasks and other use cases.
It is important to note that accounting service is separate from other services to ensure robustness of the infrastructure. Accounting service is designed to be used as a proxy to other services and to make operations on them easier. To retrieve actual data collected client has to connect to API of other services and directly request data from them.
Internal communication between services is done through secure and encrypted protocol.
For service to accept data, client must provide identifying information. To avoid integration complexity authentication data is sent per-request. Service does not support any sort of session based authentication.
Authentication for web application is done through basic HTTP authentication. Authentication is done by specifying Authorization
header with value set to Basic <code>
. Where code is BASE64 encoded pair of username:password
.
Example:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQK
For internal communication authentication is not required as keys are considered private and trusted. Identifying information for client is exchanged in first encrypted message.
Structure of API endpoint path for version 1.0 follows strict format (/<version>/json/<object>
). Objects are always included as a part of path and are case sensitive. They represent object of operation while request method (GET
, POST
, DELETE
) specifies operation itself.
For example, endpoint for creating new organization would be /v1/json/organization
while using POST
method. Organization information is transfered as request body in form of JSON object. Some objects support additional operations in their endpoint in format /v1/json/<object>/<action>
.
All service operations return standard HTTP 200
code on successful execution and 500
when error occurs with exception to 403
on failed authentication and 501
when endpoint path is malformed. Message following the code will give more insight in what kind of error occurred.
The following is a complete service request with headers and authentication:
POST /v1/json/organization HTTP/1.1
Host: ?????
Content-Type: application/json; charset=UTF-8
Content-Length: ???
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQK
Connection: close
{
"name": "Weirdo Inc.",
"web_site": "http://something.com"
}
Working with organizations is done through /v1/json/organization
and /v1/json/organization-access
endpoints. Organizations are entities used to organize and group data collection and users. They do not necessarily represent legal entities. System allows for user interface to be customized with organization colors and logo image.
Business plans are applied and billed per organization.
System recognizes the following actions, along with specified methods:
- Retrieving organization information -
GET /v1/json/organization
- Adding new organization -
POST /v1/json/organization
- Changing organization related data -
PATCH /v1/json/organization
- Removing organization -
DELETE /v1/json/organization
- Listing users with access to organization -
GET /v1/json/organization-access
- Assigning users to organization -
POST /v1/json/organization-access
- Changing user access to organization -
PATCH /v1/json/organization-access
- Removing users from organization -
DELETE /v1/json/organization-access
id
- Unique id of organization;name
- Full name of the organization;web_site
- URL to the company site without protocol;phone_number
- Contact phone number;address
- Office street address;city
- City where offices are located;zip
- ZIP code for city where offices are located;state
- State where organization is located;country
- Country where organization is located;colors
- Coma separated colors used for stylizing user interface;logo_url
- URL to organization logo.
All data, except for id
, can be changed.
This endpoint is used to create new organization associated with currently logged in user account. Response contains id
of newly created organization and result
of operation.
Method: POST
Endpoint: /v1/json/organization
Request body:
{
"name": "Company Inc.",
"web_site": "somesite.com",
"phone_number": "000-CALL-NOW",
"address": "Bruce Partington rd. 221b",
"city": "London",
"zip": "1000",
"state": "",
"country": "UK",
"colors": "#330033,white,#ff00ff",
"logo_url": "somesite.com/images/logo.png"
}
Response body:
{
"id": 213,
"result": true
}
This endpoint is used to change specified organization data. Only fields specified in request will be modified. Fields which can't be modified will be silently ignored.
Response body contains id
of affected organization and result
of operation. If operation fails, id
will be set to 0.
Method: PATCH
Endpoint: /v1/json/organization
Request body:
{
"id": 213,
"name": "New Name Inc."
}
Response body:
{
"id": 213,
"result": true
}
Schedules organization and all of its services for permanent removal. User accounts associated with the organization will not be affected. Removing organization is a manual process and will not happen automatically. After one month since organization was marked for removal has passed calling this endpoint again organization and all the data associated with it will be permanently removed.
During this waiting period services assigned to organization will continue to operate normally and can be transfered to other organizations. Owners can cancel removal process at any time.
Method: DELETE
Endpoint: /v1/json/organization
organization=213
Response body:
{
"scheduled": "2016-10-10",
"result": true
}
Get list of all users with access to organization
specified in request parameter. This endpoint is only available to users which have ability to modify user access in organization.
Method: GET
Endpoint: /v1/json/organization-access
Request body:
organization=213
Response body:
{
"users": [11, 1450, 234],
"result": true
}
Endpoint used to allow existing users to access organization and its data with specified restrictions. This endpoint can not be used to create new user account.
Response object contains result
of the operation.
Method: POST
Endpoint: /v1/json/organization-access
Request body:
{
"organization": 213,
"user": 12,
"access": 0
}
Response body:
{
"result": true
}
Change access for user in organization. This endpoint allows you to promote or demote users withing organization. It is also used in ownership transfers. It's important to note that organization can have more than one owner account and in fact an advisable situation to be in as it will make sure bus factor is higher.
Response object contains result
of the operation.
Method: PATCH
Endpoint: /v1/json/organization-access
Request body:
{
"organization": 213,
"user": 12,
"access": 0
}
Response body:
{
"result": true
}
Remove user from the organization. This operation does not affect data associated with the user.
Response object contains result
of the operation.
Method: DELETE
Endpoint: /v1/json/organization-access
Request body:
{
"organization": 213,
"user": 12
}
Response body:
{
"result": true
}