JSON-RPC Reference
TrustRelay exposes a JSON-RPC 2.0 endpoint that lets authenticated clients execute SQL queries directly against published data products. Queries run through TrustRelay’s DuckDB connection pool — no separate data-access credentials are needed by the caller.
The JSON-RPC endpoint has a 60-second timeout (vs. the standard 30s for REST endpoints) to accommodate longer-running analytical queries.
Query engine
The query engine powering TrustRelay’s data access layer is DuckDB. All SQL queries sent through the JSON-RPC endpoint are executed by DuckDB, so your queries should follow standard ANSI SQL syntax or DuckDB-specific syntax where needed.
DuckDB supports a rich SQL dialect including window functions, lateral joins, STRUCT, LIST, and MAP types, geospatial extensions, and format-specific readers (Parquet, CSV, JSON). Refer to the DuckDB SQL documentation for the full language reference.
Endpoint
POST /api/jsonrpc
Content-Type: application/json Authentication
The JSON-RPC endpoint accepts two authentication mechanisms:
Session cookie
For browser-based or session-authenticated callers, include the session cookie obtained at login:
POST /api/jsonrpc
Content-Type: application/json
Cookie: session=<session-token> Personal Access Token (PAT)
For programmatic access (scripts, CI pipelines, backend services), pass a PAT as a Bearer token in the Authorization header:
POST /api/jsonrpc
Content-Type: application/json
Authorization: Bearer <your-pat-here> PATs can be created in User Settings → Developer or via the REST API. See Personal Access Tokens for details.
Requests with no valid session or token return 401 Unauthorized.
Request payload
The request body follows the JSON-RPC 2.0 specification.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
jsonrpc | string | Yes | Must be "2.0" |
method | string | Yes | "query" for positional params; the query code from Usage Info for named params |
params | array or object | Yes | Positional (array) or named (object) — see below |
id | string | Yes | Client-supplied identifier echoed back in the response |
Reference the data product by its slug as the table name in the SQL query.
Positional parameters
Use method: "query" and pass params as a single-element array containing the SQL string:
{
"id": "1",
"jsonrpc": "2.0",
"method": "query",
"params": [
"SELECT transaction_id, timestamp, location, water_flow_rate FROM CHWaterFlow_v1"
]
} Named parameters
Use a query code from the product’s Usage Info as the method, and pass params as an object with sql, limit, and offset:
{
"id": "1",
"jsonrpc": "2.0",
"method": "querySample",
"params": {
"sql": "SELECT transaction_id, timestamp, location, water_flow_rate FROM CHWaterFlow_v1",
"limit": 5,
"offset": 1
}
} | Param | Type | Description |
|---|---|---|
sql | string | The SQL query to execute |
limit | number | Maximum number of rows to return |
offset | number | Number of rows to skip before returning results |
Response
Success
{
"id": "1",
"jsonrpc": "2.0",
"result": {
"columns": [
"object_id",
"address",
"type",
"mail",
"name",
"town",
"zip",
"phone",
"geometry",
"geometry_wgs84"
],
"count": 52,
"data": [
{
"address": "Grünmattstrasse 4",
"geometry": "POINT (2680440 1246275)",
"geometry_wgs84": "POINT(8.503485797047611, 47.36241114274159)",
"mail": "gruenmatt@almacasa.ch",
"name": "Almacasa Grünmatt",
"object_id": 1,
"phone": "+41 58 100 80 70",
"town": "Zürich",
"type": "Private Alters- und Pflegeheime",
"zip": 8055
}
]
}
} The result object contains:
| Field | Type | Description |
|---|---|---|
columns | string[] | Ordered list of column names returned by the query |
count | number | Total number of rows in the result set |
data | object[] | Array of result rows, each as a key-value object keyed by column name |
Error
When a query fails or the request is malformed, the response includes an error object instead of result:
{
"jsonrpc": "2.0",
"error": {
"code": -32603,
"message": "Internal error"
},
"id": "1"
} Standard JSON-RPC error codes apply:
| Code | Meaning |
|---|---|
-32700 | Parse error — invalid JSON |
-32600 | Invalid request — missing required fields |
-32602 | Invalid params — params must be a non-empty array |
-32603 | Internal error — query execution failed |
Predefined queries
A data product’s Usage Info section may list example SQL queries provided by the data owner. You can retrieve them via:
GET /api/products/{productversionid}/usage-info {
"value": {
"queries": [
{
"code": "recent_records",
"name": "Recent Records",
"description": "Returns records from the last 30 days",
"sql": "SELECT * FROM my-product-slug WHERE created_at >= now() - INTERVAL 30 DAY"
},
{
"code": "summary_by_region",
"name": "Summary by Region",
"description": "Aggregated totals grouped by region",
"sql": "SELECT region, count(*) AS total FROM my-product-slug GROUP BY region"
}
]
}
} These are plain SQL statements — no different from any query you would write yourself. The data provider has simply included them as examples to help consumers get started. You execute them exactly the same way as any other query, by passing the SQL string in params:
{
"id": "1",
"jsonrpc": "2.0",
"method": "query",
"params": [
"SELECT * FROM my-product-slug WHERE created_at >= now() - INTERVAL 30 DAY"
]
} Access requirement
A consumer must have an active (GRANTED) access agreement for the target data product before their JSON-RPC calls will be authorised. Calls from users without a valid agreement are rejected with 403 Forbidden.
See Access Management for details on the access request workflow.