Before you start
PolarisLink has two parts. The protocol and the client libraries are open under the Apache License 2.0, and anyone can read the specification, run the clients or implement a gateway. The hosted gateway operated by Forticia Research Institute requires an approved API key. Keys are issued to authorised researchers, desks and counterparties; to ask for one, use request access.
You need three things for the examples below:
- A gateway address. The clients default to
https://forticia.uk. SetFORTICIA_API_URLto point at another gateway, for example a local development gateway onhttp://localhost:8787. - An API key with the scope each call needs. The clients read it from
FORTICIA_API_KEY. - Python 3.9 or later for the Python client, or a C++20 compiler and CMake 3.20 or later for the C++ client.
Keep the key out of source control and out of command-line arguments, where it would show up in a process list. The examples read it from the environment.
export FORTICIA_API_KEY="paste-your-key-here"Without a key you can still confirm that the hosted gateway is reachable. The status probe is public:
curl -s https://forticia.uk/api/polarislink/statusPython client
The Python client uses only the standard library. Pandas support is optional.
Install
A package on the Python Package Index is not published yet. Install the client from the repository:
pip install "git+https://github.com/Forticia/polarislink.git#subdirectory=python"To add the optional pandas integration, install from a local clone instead:
git clone https://github.com/Forticia/polarislink.git
pip install "./polarislink/python[pandas]"First call
Read the gateway telemetry. The key needs the ops:agent:telemetry scope.
import os
from polarislink import PolarisLinkClient
client = PolarisLinkClient(api_key=os.environ["FORTICIA_API_KEY"])
telemetry = client.get_telemetry()
print(telemetry["status"], telemetry["protocolVersion"])If the key and the address are right, this prints the gateway status and the protocol version.
Record a run
The run sink stores an immutable record of a job together with its provenance. Pass the source revision and an input digest so that the run can be reproduced.
result = client.log_run(
strategy_name="nightly-evaluation",
git_commit="9f8a7c2b",
provenance_hash="sha256:4a8b7c9e",
metrics={"examples_checked": 0},
workspace="research",
)
print(result["run"]["id"])The key needs a scope that allows writing run records. List recent runs with client.get_runs(workspace="research", limit=10).
Report an issue
Issues are how agents and people ask for data, report faults and raise requests. A workspace-bound key files into its own workspace automatically.
client.report_issue(
title="Missing input file",
description="The nightly job could not find its input for 2026-01-01.",
category="Data Gap",
priority="Normal",
workspace="research",
)Stream events
The event stream replaces polling. Each event arrives as a dictionary with the event name and its data.
for event in client.stream_polaris_events(max_events=10):
print(event["event"], event["data"])Command-line interface
Installing the package adds a polarislink command. Global options go before the sub-command.
polarislink polaris telemetry
polarislink polaris issues --status Open
polarislink polaris report-issue "Missing input file" "Nightly job found no input" --priority High
polarislink polaris streamC++20 client
The C++ client is one header. It uses libcurl when it is available and otherwise falls back to a transport that keeps credentials out of the process argument list.
Add it to a CMake project
Clone the repository, or add it as a submodule, and add the cpp directory:
add_subdirectory(polarislink/cpp)
target_link_libraries(your_target PRIVATE polarislink::polarislink)Install libcurl development files first if you want the in-process transport. On Debian or Ubuntu the package is libcurl4-openssl-dev. The repository's continuous-integration job builds with Clang and runs the header tests with CTest.
First call
#include <polarislink/polarislink.hpp>
#include <iostream>
int main() {
polarislink::Client client;
polarislink::TelemetryStatus telemetry = client.get_telemetry();
std::cout << telemetry.status << " " << telemetry.protocol_version << "\n";
return 0;
}With no arguments, Client reads FORTICIA_API_KEY and FORTICIA_API_URL from the environment. You can also pass them: polarislink::Client client(key, base_url).
Record a run
polarislink::BacktestRunMetrics run;
run.strategy_name = "nightly-evaluation";
run.workspace_id = "research";
run.git_commit = "9f8a7c2b";
run.provenance_hash = "sha256:4a8b7c9e";
std::string run_id = client.log_run(run);
std::cout << "Recorded run " << run_id << "\n";The numeric result fields are optional values, so a job that has nothing to report for them simply leaves them unset.
Build and run
cmake -B build -S .
cmake --build build
./build/your_targetTroubleshooting
| Symptom | Likely cause |
|---|---|
401 Unauthorized |
The key is missing, mistyped or revoked. Check FORTICIA_API_KEY. |
403 Forbidden |
The key lacks the scope for this route, or it is bound to another workspace. |
404 Not Found |
The route or entity does not exist. Compare the path with the specification. |
429 Too Many Requests |
The key exceeded its per-minute ceiling. Back off and retry. |
| Connection error | Check the gateway address, or whether FORTICIA_API_URL points somewhere unreachable. |
Next steps
- Read the protocol specification for every route, scope and event.
- See the clients overview for what each library covers.
- Follow the changelog for new releases.
- Browse the source and file issues in the GitHub repository.
Get started
The protocol and the clients are open. The hosted Forticia gateway needs an approved key.