RadiatorDB REST API
Read and write RadiatorDB documents through the management API
RadiatorDB exposes document collections through Radiator Management API. Use the REST API when an external tool or service needs to browse, create, update, rename, or delete RadiatorDB documents.
Access Control
RadiatorDB REST API uses management API authentication. A request must authenticate with Basic authentication.
Collection access also depends on the RadiatorDB roles configured for the authenticated user. In the management authentication policy, set user.radiatordb_role to the list of roles that the user has.
These roles are separate from the management API privilege level in user.privilege. Collection document routes do not require a management API privilege level.
After the request is authenticated, collection access requires a matching user.radiatordb_role value. The API matches the user's RadiatorDB roles against the collection roles block.
For example, a user backend query can map a roles array into user.radiatordb_role:
backends {
jsonfile "MGMT_USERS" {
query "FIND_USER" {
mapping {
user.username = doc | jsonpath("$.users[?(@.username == '%{aaa.identity}')].username");
user.password = doc | jsonpath("$.users[?(@.username == '%{aaa.identity}')].password");
user.radiatordb_role = doc | jsonpath("$.users[?(@.username == '%{aaa.identity}')].roles[*]");
}
}
}
}
In the user backend data, store the role names that must match the collection role names:
{
"users": [
{
"username": "alice",
"password": "{argon2}...",
"roles": ["support", "ops"]
}
]
}
The collection roles block grants access by matching these user.radiatordb_role values:
readroles can list collections, read documents, and read revision history.writeroles can create, update, rename, and delete documents. Awriterole also grants read access.- Action
allowroles can invoke the matching action when the user can read the collection. - Backup export and import require
user.privilegewriteorall. Collectionrolesdo not restrict backup operations.
For example, a user whose user.radiatordb_role contains support can read the DEVICES collection shown above. A user whose user.radiatordb_role contains ops can also write to it.
If the authenticated user does not have a matching collection role, the request returns 403 Forbidden.
Routes
This .radconf example defines a RadiatorDB backend named RADIATORDB and a collection named DEVICES:
backends {
radiatordb "RADIATORDB" {
collection "DEVICES" {
roles {
read "support";
write "ops";
}
key {
field {
name "Site";
type text;
}
field {
name "Device";
type text;
}
}
}
}
}
In the routes below, this configuration maps placeholders as follows:
| Route placeholder | Value from the configuration | Example value |
|---|---|---|
:db_name | radiatordb "RADIATORDB" | RADIATORDB |
:collection | collection "DEVICES" | DEVICES |
:key | Ordered key fields | helsinki~edge-1 |
The example key helsinki~edge-1 represents a document whose Site key part is helsinki and whose Device key part is edge-1.
For example, the configuration above produces these management API routes:
GET /api/v1/backends/radiatordb/RADIATORDB/collections
GET /api/v1/backends/radiatordb/RADIATORDB/collections/DEVICES/documents
GET /api/v1/backends/radiatordb/RADIATORDB/collections/DEVICES/documents/helsinki~edge-1
PUT /api/v1/backends/radiatordb/RADIATORDB/collections/DEVICES/documents/helsinki~edge-1
POST /api/v1/backends/radiatordb/RADIATORDB/collections/DEVICES/documents/helsinki~edge-1/rename
DELETE /api/v1/backends/radiatordb/RADIATORDB/collections/DEVICES/documents/helsinki~edge-1
POST /api/v1/backends/radiatordb/RADIATORDB/collections/DEVICES/documents/helsinki~edge-1/actions/send-coa
GET /api/v1/backends/radiatordb/RADIATORDB/collections/DEVICES/documents/helsinki~edge-1/revisions
POST /api/v1/backends/radiatordb/RADIATORDB/backups/export
POST /api/v1/backends/radiatordb/RADIATORDB/backups/import
List Collections
List collections in a RadiatorDB backend:
GET /api/v1/backends/radiatordb/:db_name/collections
Returns 200 OK with an array of collection summary objects:
| Field | Type | Description |
|---|---|---|
name | string | Collection name from the .radconf collection block |
displayName | string | Display name configured with name, or the collection name |
description | string or null | Description configured with description, or null when omitted |
documentCount | number | Number of active documents currently visible in the collection |
Example response:
[
{
"name": "DEVICES",
"displayName": "Devices",
"description": "Managed network devices",
"documentCount": 2
}
]
List Documents
List documents in a collection:
GET /api/v1/backends/radiatordb/:db_name/collections/:collection/documents
The list endpoint accepts these query parameters:
| Parameter | Description |
|---|---|
cursor | Continue from a cursor returned in nextCursor |
limit | Limit the number of returned documents. Default: 50, maximum: 200 |
search | Search documents for matching text |
includeDoc | Set to false to return metadata without document payloads |
state | Select active, deleted, or all documents. Default: active |
Returns 200 OK with a paginated document list:
| Field | Type | Description |
|---|---|---|
documents | object[] | Returned documents for the current page |
nextCursor | string or null | Cursor for the next page, or null when no page remains |
total | number | Total number of documents matching the request |
When includeDoc=false, each returned document has doc set to null.
Example response:
{
"documents": [
{
"key": ["helsinki", "edge-1"],
"collection": "DEVICES",
"doc": {
"hostname": "edge-1",
"enabled": true
},
"createdAt": "2026-06-12T10:00:00Z",
"updatedAt": "2026-06-12T10:15:00Z",
"updatedBy": "alice",
"rev": "00000000-0000-0000-0000-000000000000",
"deleted": false
}
],
"nextCursor": null,
"total": 1
}
Get Document
Get one document:
GET /api/v1/backends/radiatordb/:db_name/collections/:collection/documents/:key
The get endpoint accepts the state query parameter with the same values as the list endpoint.
Returns 200 OK with a document object:
| Field | Type | Description |
|---|---|---|
key | string[] | Ordered key parts for the document |
collection | string | Collection name |
doc | object or null | JSON document payload. Tombstones and metadata-only reads use null |
createdAt | string | Creation time in RFC 3339 format |
updatedAt | string | Last update time in RFC 3339 format |
updatedBy | string or null | Authenticated management user that last updated the document |
rev | string | Document revision identifier |
deleted | boolean | Whether this response represents a deleted document |
Example response:
{
"key": ["helsinki", "edge-1"],
"collection": "DEVICES",
"doc": {
"hostname": "edge-1",
"enabled": true
},
"createdAt": "2026-06-12T10:00:00Z",
"updatedAt": "2026-06-12T10:15:00Z",
"updatedBy": "alice",
"rev": "00000000-0000-0000-0000-000000000000",
"deleted": false
}
Create or Update Document
Create or update one document:
PUT /api/v1/backends/radiatordb/:db_name/collections/:collection/documents/:key
Content-Type: application/json
{
"doc": {
"hostname": "edge-1",
"enabled": true
}
}
The doc value must be a JSON object. When a collection defines fields, the request must match the collection schema.
Returns 201 Created when the API creates a new document. Returns 200 OK when the API updates an existing document. The response body is a document object with the same fields as the get endpoint.
Rename Document
Rename one active document:
POST /api/v1/backends/radiatordb/:db_name/collections/:collection/documents/:key/rename
Content-Type: application/json
{
"newKey": "helsinki~edge-2",
"rev": "00000000-0000-0000-0000-000000000000"
}
Use the current document rev from a previous read. The API rejects stale rename requests when the document changed before the rename.
Returns 200 OK with a document object for the renamed document. The key field contains the new key parts.
Delete Document
Delete one document:
DELETE /api/v1/backends/radiatordb/:db_name/collections/:collection/documents/:key
Delete is a soft delete. You can read deleted documents by using state=deleted or state=all.
Returns 200 OK with a status message:
| Field | Type | Description |
|---|---|---|
code | number | HTTP status code |
message | string | Operation result text |
Example response:
{
"code": 200,
"message": "RadiatorDB document deleted"
}
Invoke Action
Invoke a configured action for one active or soft-deleted document:
POST /api/v1/backends/radiatordb/:db_name/collections/:collection/documents/:key/actions/:action_id
Content-Type: application/json
{
"input": {
"reason": "operator request"
}
}
The authenticated user must have collection read access and one of the action's
roles allow roles. Hidden actions return 404 Not Found.
The request body has these fields:
| Field | Type | Description |
|---|---|---|
input | object | Values for the action input fields. Use {} when the action has no inputs. |
target | object or null | Nested list target. Omit or set to null for top-level actions. |
For nested list actions, include a target object:
{
"input": {
"reason": "stale session"
},
"target": {
"path": [
{
"fieldName": "sessions",
"parentItemIndex": null
}
],
"itemIndex": 0
}
}
path identifies the nested list field path. itemIndex identifies the list
item for the action. For deeper nested lists, each path segment includes the
list field name and the parent list item index.
The API validates input against the action input fields. Unknown fields,
missing required fields, and invalid values return 400 Bad Request.
The server fetches the document and nested item by key, path, and item index.
Do not send document payloads in the request body. For deleted documents, the
action pipeline receives deleted as true and doc as the latest
non-tombstone payload when one exists.
Returns 200 OK when the action pipeline accepts:
| Field | Type | Description |
|---|---|---|
actionId | string | Invoked action identifier |
message | string | Optional public message from aaa.message |
Example response:
{
"actionId": "send-coa",
"message": "Disconnect queued."
}
If the pipeline accepts without setting aaa.message, the response contains
only actionId. The API does not return aaa.reason or pipeline errors to the
caller because those values can contain sensitive operational details.
If the action pipeline rejects or ignores the request, the API returns
400 Bad Request.
List Revision History
List revision history for one document key:
GET /api/v1/backends/radiatordb/:db_name/collections/:collection/documents/:key/revisions
The revision endpoint accepts these query parameters:
| Parameter | Description |
|---|---|
cursor | Continue from a cursor returned in nextCursor |
limit | Limit the number of returned revisions |
Returns 200 OK with a paginated revision history:
| Field | Type | Description |
|---|---|---|
history | object[] | Revision history entries for the requested document key |
nextCursor | string or null | Cursor for the next page, or null when no page remains |
Each revision history entry has these fields:
| Field | Type | Description |
|---|---|---|
rev | string | Revision identifier |
kind | string | document for content revisions, or rename for rename events |
key | string[] | Ordered key parts for this revision |
previousKey | string[] or null | Previous key parts for rename events, or null otherwise |
updatedAt | string | Revision update time in RFC 3339 format |
updatedBy | string or null | Authenticated management user that made the change |
doc | object or null | JSON payload stored for this revision |
deleted | boolean | Whether this revision is a delete tombstone |
Example response:
{
"history": [
{
"rev": "00000000-0000-0000-0000-000000000000",
"kind": "document",
"key": ["helsinki", "edge-1"],
"previousKey": null,
"updatedAt": "2026-06-12T10:15:00Z",
"updatedBy": "alice",
"doc": {
"hostname": "edge-1",
"enabled": true
},
"deleted": false
}
],
"nextCursor": null
}
Backup Routes
RadiatorDB backup export and import use these routes:
POST /api/v1/backends/radiatordb/:db_name/backups/export
POST /api/v1/backends/radiatordb/:db_name/backups/import
Backup export and import require user.privilege write or all. Backup streams can use raw JSON Lines or gzip-compressed JSON Lines. Import accepts importRevisions, strategy, batchSize, and validateFields query parameters. For request fields, response fields, strategy behavior, curl examples, and the backup file format, see RadiatorDB Backup.
Shared Error Responses
Error responses use a JSON status message body:
| Field | Type | Description |
|---|---|---|
code | number | HTTP status code |
message | string | Human-readable error |
Common status codes are:
| Status | Meaning |
|---|---|
400 | Invalid request body, key, cursor, revision, or schema |
401 | Missing or invalid management API authentication |
403 | Authenticated user lacks the required RadiatorDB role or privilege |
404 | Database, collection, document, or visible action was not found |
409 | Rename conflict or stale rename revision |
Multipart Keys
Multipart keys allow hierarchical document organization. Key parts are separated by ~ in management API URLs. Escape a literal ~ inside a key part as ~~.
For example, a document stored with two key parts helsinki and edge-1 has the composite key helsinki~edge-1 and is accessible through the management API at:
GET /api/v1/backends/radiatordb/:db_name/collections/:collection/documents/helsinki~edge-1
Multipart keys enable partial key matching through at and contains filters in RadiatorDB backend queries. This allows lookups by any subset of key parts without knowing the full key.
Related Documentation
About Radiator software development security
Architecture Overview
Backend Load Balancing
Basic Installation
Built-in Environment Variables
Byte Size Units
Certificate Revocation Lists
Comparison Operators
Configuration Editor
Configuration Import and Export
Containers
Cron and interval timers
Data Types
Duration Units
Environment Variables
Execution Context
Execution Pipelines
Filters
Getting a Radiator License
Health check /live and /ready
High Availability and Load Balancing
High availability identifiers
HTTP Basic Authentication
Introduction
Linux systemd support
Local AAA Backends
Log storage and formatting
Management API privilege levels
Namespaces
Password Hashing
Password Rehashing During Login
Probabilistic Sampling
Prometheus scraping
PROXY Protocol Support
Radiator server health and boot up logic
Radiator sizing
Radiator software releases
RadiatorDB
RadiatorDB Backup
RadiatorDB CLI
RadiatorDB Installation
RadiatorDB REST API
Rate Limiting
Rate Limiting Algorithms
Reverse Dynamic Authorization
Service Level Objective
TACACS+ Authentication, Authorization, and Accounting
Template Rendering CLI
Timestamp Format
Timestamps
Tools radiator-client
TOTP/HOTP Authentication
What is Radiator?
YubiKey Authentication
YubiKey Context Variables
About Radiator software development security
Architecture Overview
Backend Load Balancing
Basic Installation
Built-in Environment Variables
Byte Size Units
Certificate Revocation Lists
Comparison Operators
Configuration Editor
Configuration Import and Export
Containers
Cron and interval timers
Data Types
Duration Units
Environment Variables
Execution Context
Execution Pipelines
Filters
Getting a Radiator License
Health check /live and /ready
High Availability and Load Balancing
High availability identifiers
HTTP Basic Authentication
Introduction
Linux systemd support
Local AAA Backends
Log storage and formatting
Management API privilege levels
Namespaces
Password Hashing
Password Rehashing During Login
Probabilistic Sampling
Prometheus scraping
PROXY Protocol Support
Radiator server health and boot up logic
Radiator sizing
Radiator software releases
RadiatorDB
RadiatorDB Backup
RadiatorDB CLI
RadiatorDB Installation
RadiatorDB REST API
Rate Limiting
Rate Limiting Algorithms
Reverse Dynamic Authorization
Service Level Objective
TACACS+ Authentication, Authorization, and Accounting
Template Rendering CLI
Timestamp Format
Timestamps
Tools radiator-client
TOTP/HOTP Authentication
What is Radiator?
YubiKey Authentication
YubiKey Context Variables