User Guide 19.11 documentation

This Page

Using the PVX API

Introduction

The PVX API exposes multiple functions for the following tasks:

  • querying the collected data,
  • managing the user interface (including dashboards and widgets),
  • configuring the software.

To access most of these functions, you will need some sort of token (such as an API key or a Session ID). See API Keys.

In this documentation, <SERVER> refers to the hostname or IP address of the server hosting the API.

This URI is the root of the currently available protocols:

The documentation of the API functions is available at:

https://<SERVER>/api/doc

Warning

The PVX API is served over TLS (hence the https:// and wss:// prefixes).

For security reasons, it is strongly recommended that you install your own SSL certificate into PVX instead of using the pre-installed one.

For more information on security considerations, please read the related section.

Response Format of API Calls

The API responses are formatted as JSON.

The response is composed of messages. A single message is returned, except when streaming is enabled (see below).

A message contains a type attribute:

{
    "type": "<message_type>",
    "<message_type>": <result>,
    "<extra_attribute>": <value>,
    "<extra_attribute>": <value>,
    ...
}

When a request succeeds, a message of type result is returned.

{
    "type": "result",
    "result": <return_value>
}

When a request fails, a message of type error is returned. The errors are meant to be self-explanatory. For instance, calling a function with less arguments than expected will return something similar to:

{
    "type": "error",
    "error": "TOO-FEW-ARGUMENTS",
    "names": ["title", "queries"],
    "count": 2
}

The API is also able to stream chunks instead of returning a single response. This method is described in API Streaming.

Querying the API

The echo function will be used to show how the PVX API interprets requests. This function has no real interest in itself other than for testing purposes. As its name suggests, it simply echoes back the passed arguments.

It will be used to show some of the available input formats.

Using HTTP

Accessing the PVX API through HTTP should be straightforward with common HTTP clients.

All the API functions can be called with either the GET or POST HTTP methods. The function arguments are usually passed through the query string.

The simplest API function invocation over HTTP is to specify its name followed by the arguments.

The arguments and their values are delimited by =. The values are interpreted as JSON.

https://<SERVER>/api/function?argument1=value1&argument2=value2&...

To use the streaming mode (see API Streaming), use the stream/ prefix before the function’s name.

https://<SERVER>/api/stream/function?argument1=value1&argument2=value2&...

Querying with Curl

curl is a well-known tool to access different kind of URLs. It should be available on most UNIX-like systems.

The following commands are executed in a POSIX shell.

$ curl 'https://<SERVER>/api/echo?an_integer=42&a_string="the%20answer"&an_array=\["to%20life","the%20universe","and%20everything"\]'
{
     "type": "result",
     "result": {
         "an_integer": 42
         "a_string": "the answer",
         "an_array": [
             "to life",
             "the universe",
             "and everything"
         ]
     }
}

Notice how the arguments must be escaped to both satisfy curl and the URL encoding scheme.

Alternative ways to make a similar invocation include:

curl --get 'https://<SERVER>/api/echo' --data-urlencode 'an_integer=42' --data-urlencode 'a_string="the answer"' --data-urlencode 'an_array=["to life", "the universe", "and everything"]'
curl -X POST 'https://<SERVER>/api/echo' --data-urlencode 'an_integer=42' --data-urlencode 'a_string="the answer"' --data-urlencode 'an_array=["to life", "the universe", "and everything"]'
curl -X POST ' https://<SERVER>/api/echo' --form-string 'an_integer=42' --form-string 'a_string="the answer"' --form-string 'an_array=["to life", "the universe", "and everything"]'
curl -H 'Content-Type: application/json' https://<SERVER>/api/echo --data-raw '{"an_integer": 42, "a_string": "the answer", "an_array": ["to life", "the universe", "and everything"]}'

Querying with Invoke-WebRequest

Invoke-WebRequest is PowerShell cmdlet used to retrieve HTTP pages.

The following commands are executed in PowerShell.

Warning

The curl command may be automatically aliased to Invoke-WebRequest and is not compatible with the curl presented above.

Get-Alias curl | Select-Object -Property DisplayName

DisplayName
-----------
curl -> Invoke-WebRequest
Invoke-WebRequest 'https://<SERVER>/api/echo?an_integer=42&a_string="the%20answer"&an_array=["to%20life","the%20universe","and%20everything"]'
StatusCode        : 200
StatusDescription : OK
Content           : {
                        "result": {
                            "an_array": [
                                "to life",
                                "the universe",
                                "and everything"
                            ],
                            "a_string": "the answer",
                            "an_integer": 42
                        },
                        "...
RawContent        : HTTP/1.1 200 OK
# result truncated for brevity

Easier ways to make a similar invocation include:

Invoke-WebRequest -Method Post 'https://<SERVER>/api/echo' -Form @{an_integer=42; a_string="the answer"; an_array='["to life", "the universe", "and everything"]'}

You could also interpret the JSON content directly, using Invoke-RestMethod (but this may not work with streaming methods):

$(Invoke-RestMethod -Method Post 'https://<SERVER>/api/echo' -Form @{an_integer=42; a_string="the answer"; an_array='["to life", "the universe", "and everything"]'}).result

an_array                                a_string   an_integer
--------                                --------   ----------
{to life, the universe, and everything} the answer         42

Using WebSocket

PVX’s WebSocket API is largely similar to the HTTP API but the query format has to be adapted to the transport. It is mostly destined to a programmatic usage but the following examples will show a basic utilisation from the CLI.

All communication is done via JSON messages.

A call must be in the following format:

{
    "id": "<call_id>",
    "<call_type>": "<function_name>",
    "args": {"<argument1>": <value1>, "<argument2>": <value2>, ...}
}

Where call_type is either call for standard calls or stream for streaming calls.

The id attribute must be an unique value for each call. For example, you can use a number that is increased at each call, or an UUID. This id can be used to cancel an unfinished call.

Wscat

wscat is a small WebSocket client.

wscat -c 'wss://<SERVER>/api/ws'
connected (press CTRL+C to quit)
> {"id": "example1", "call": "echo", "args": {"an_integer": 42, "a_string": "the answer", "an_array": ["to life", "the universe", "and everything"]}}
< {
    "id": "example1",
    "type": "result",
    "result": {
        "an_integer": 42,
        "a_string": "the answer",
        "an_array": [
            "to life",
            "the universe",
            "and everything"
        ]
    }
}

API Versioning

API URLs should indicate a desired version. This is recommended to ensure that programs using the API will not break when upgrading. For example:

https://<SERVER>/api/0.1/<function>

https://<SERVER>/api/0.1/doc

wss://<SERVER>/api/0.1/ws

If a version is not specified, the API will choose the latest version available.

When upgrading PVX, the meaning of the API version number is as follow:

  • an unchanged version means the API is still the same or only received maintenance patches and is fully compatible with the previous one,
  • an increment of MINOR (e.g. API 1.2 → API 1.3) means the API only added functionalities and is compatible with the previous one (e.g. a new function or optional arguments have been added),
  • an increment of MAJOR (e.g. API 1.3 → API 2.0) means the API introduced breaking changes and is most likely incompatible with the previous one (e.g. a function has been removed or may require different arguments).

API Streaming

In addition to simple calls, the API provides a method to get a stream of results. Each partial result is returned with a message of type chunk, and terminated by a message of type end. When an error is encountered, the stream is interrupted with a message of type error.

When using HTTP, add stream/ before the function name in the URL. For example:

https://<SERVER>/api/1.0/stream/query

Example of messages received:

{
    "type": "chunk",
    "chunk": <partial_result1>
}
{
    "type": "chunk",
    "chunk": <partial_result2>
}
{
    "type": "end",
}

The exact content of the chunks are described by the documentation of each function. A chunk can contains a combination of:

  • new values (to be added to the already accumulated ones),
  • updated values (that replace previously given values),
  • informative values (that are specific to the chunk itself).

Note

Every function can stream its results. Likewise, every functions can be queried without streaming. In this case, if the function is producing several values, they are all accumulated and send all at once when the function terminates.

API Usage Overview

API Keys

API keys are the preferred way to programmatically authenticate to the API.

Note

The current GUI (PVX 5.0) doesn’t provide a way to create an API key. You need to use the API itself to create more keys.

In a future release, it will be possible to manage the API keys directly from the GUI.

Warning

An API key provides a full access to the API. Future enhancement will allow greater granularity on their authorized utilisation.

Creation of the First API Key

Creating an API key can be done in two steps:

  • creating a session from an user account
  • creating an API key from this session.

Warning

This method is temporary, and will be replaced by an easier one in a future version.

Creating the session is done with the login function that expects a user and password argument. In this example we will use the default user admin with the password admin. (In a standard installation, this account has a different password.)

The resulting HTTP URL is:

https://<SERVER>/api/login?user=admin&password=admin

Querying it will return something similar to:

{
    "type": "result",
    "result": "session:907c70c2-a78d-43ec-b577-a26b11ab586c"
}

Here, result contains our session ID, a reusable temporary token granting access to the API for a certain amount of time.

If something goes wrong, a response of type error will be returned instead.

Now that we have a session, we can create an API key. This is done with the create-api-key function. For that, we will need to pass the session ID in the special _session argument.

Note

It is perfectly fine to use a session ID to use the API, but this is mainly for user interfaces that need to be based on login/password, with a notion of short-lived sessions. So this is not appropriate for program that use the API.

Querying the following URL:

https://<SERVER>/api/create-api-key?name=example&_session=session:907c70c2-a78d-43ec-b577-a26b11ab586c

will generate an API key named example and return it in the result:

{
    "type": "result",
    "result": "secret:ce8e68ec-9048-4c71-87ef-1b7a96dd7567"
}

The result, secret:ce8e68ec-9048-4c71-87ef-1b7a96dd7567, is your API key and must be kept secret.

Using an API Key

Once you have an API key, it is usable permanently (until you revoke it) for authenticated calls by passing it as the argument _key.

For example, to perform a PVQL query such as traffic (which is the total traffic that occurred on the last hour by default), combined with the API key, we get:

https://<SERVER>/api/query?expr=traffic&_key=secret:ce8e68ec-9048-4c71-87ef-1b7a96dd7567

This will return a result containing a list of objects, including one with a data entry, that will look as follow:

{
    "data": [[[], [136308984336]]],
    "meta": {
        "accumulated_time": 0.16814637184143066,
        "elapsed": 0.16814422607421875,
        "sorted": true
    }
}

See query for an explanation of the format used.

If the authentication is invalid (because the credentials are revoked or expired), the result would have been something like this:

{
    "type": "error",
    "error": "API-AUTHENTICATION-NEEDED",
    "path": "query"
}

Authentication Methods

The session ID and API key can be provided in different way.

The following authentication tokens can be used in HTTP requests:

  • session IDs:
    • in a cookie, as “PVX-Session=<Session>”,
    • in the query string, as “_session=<Session>”.
  • API keys:
    • in the headers of the request, as “PVX-Authorization: <API_key>”,
    • in the query string, as “_key=<API_key>”.

Security Considerations

The PVX authentication mechanism prevents anybody from getting PVX access without a secret (account credentials, session ID or API key) shared between the client (anyone requesting the PVX API, including the related PVX graphical interface) and the server.

However, the current authentication mechanism needs this secret to be embedded in clear-text in every authentication-needing requests, and the uniqueness of each request is not verified.

This means that, if the communications between the client and the server are not properly encrypted, any eavesdropper can acquire this secret, forge valid requests and exploit the privileges it grants.

This is why PVX server force the use of TLS (aka SSL).

To ensure optimal security, company-specific TLS certificates should be deployed on the server and used by the client to ensure the communication are encrypted and the server identity is verified.

At your own risk, on a testing installation, you could circumvent certificate verification, but it is mostly system or tool dependent.

For example, with curl this is done with the --insecure option:

curl --insecure 'https://<SERVER>/api/...'

And with Invoke-WebRequest this is done with the -SkipCertificateCheck option:

Invoke-WebRequest -SkipCertificateCheck 'https://<SERVER>/api/...'