Workflow
End-to-end API workflow for creating, testing, and subscribing to a data model in Prelude Collector — request and response shapes for every step.
This page walks through the API calls to take a model from "doesn't exist yet" to "actively collecting data". After this first mention, the rest of this page refers to Prelude Collector as "the collector". Models are stored in the database, loaded into the collection engine at startup, and hot-reloaded within ~500 ms of any change to their fields or mappings — active subscriptions are re-configured automatically without a restart.
This page is the data-shape reference. For a narrative walk-through of building a multi-vendor model, see the interface counters tutorial.
End-to-end data shape
A complete, ready-to-use custom model goes through five API steps:
- Create the model definition.
- Add typed fields.
- Add one or more protocol mappings.
- Run a live collection test against a real device.
- Create a subscription to start continuous collection.
The rest of this page documents the request and response shapes for each step. For the exact endpoint paths and full schemas, see the API reference.
Step 1 — Create the model
export BASE="https://collector.example.com"
export TOKEN="<your-api-token>"
curl -s -X POST "$BASE/api/v1/models" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-bgp-summary",
"description": "BGP summary table via SNMP",
"version": "1.0"
}'
Bruno: 04 Models / Create model
UI: https://collector.example.com/models/new
Validation rules:
nameis required, max 100 characters, and must match^[a-zA-Z0-9][a-zA-Z0-9._-]*$.namemust be globally unique (case-insensitive).descriptionmax 500 characters.
Response 201 Created:
{
"id": 7,
"name": "my-bgp-summary",
"description": "BGP summary table via SNMP",
"version": "1.0",
"is-active": true,
"fields": [],
"mappings": []
}
You can also inline fields in the create body. The API validates
each field's type and format before saving.
Step 2 — Add fields
curl -s -X POST "$BASE/api/v1/models/7/fields" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "neighbor-address",
"field-type": "string",
"format": "ip-address",
"required": true,
"description": "BGP neighbor IP (row key)",
"position": 0
}'
Bruno: 04 Models / Add field
UI: https://collector.example.com/models/7
Repeat for each field. The supported field-type values are:
string int32 int64 uint32 uint64 float32 float64 boolean
To change the display order after adding all fields, send an array of field IDs in the desired order to the reorder endpoint:
curl -s -X POST "$BASE/api/v1/models/7/fields/reorder" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '[12, 10, 11, 13]'
Bruno: 04 Models / Reorder fields
The engine assigns position values from the array index. For the
update and delete endpoints, see the API reference.
Step 3 — Add a protocol mapping
curl -s -X POST "$BASE/api/v1/models/7/mappings" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"protocol": "snmp",
"netos": "ios-xr",
"key-field": "neighbor-address",
"snmp-walk-oids": ["1.3.6.1.2.1.15.3"],
"field-mappings": {
"bgpPeerRemoteAddr": "neighbor-address",
"bgpPeerState": "session-state",
"bgpPeerRemoteAs": "peer-as"
},
"value-transforms": {
"session-state": {
"1": "idle",
"2": "connect",
"3": "active",
"4": "opensent",
"5": "openconfirm",
"6": "established"
}
}
}'
Bruno: 04 Models / Add mapping
UI: https://collector.example.com/models/7/mappings/new
Protocol-specific path fields
Use exactly one set of path fields for the chosen protocol:
| Protocol | Path fields |
|---|---|
gnmi |
gnmi-paths (array), optional gnmi-path-filter |
snmp |
snmp-walk-oids and / or snmp-scalar-oids |
netconf |
netconf-filter-paths (array of XML subtree filter strings) |
cli |
cli-commands (array, may use {param} placeholders), cli-template (TTP template), cli-discovery-params |
Version constraints
To target a specific firmware range, add version-constraints:
{
"protocol": "gnmi",
"netos": "ios-xr",
"version-constraints": [">=7.5", "<8.0"],
"key-field": "neighbor-address"
}
The engine picks the matching mapping with the highest specificity (most constraints) for the device's reported version. If two equally-specific mappings match, both are skipped and an error is recorded.
Uniqueness constraint
The combination (model, protocol, netos, version-constraints)
must be unique. Adding a second mapping with the same protocol,
NetOS, and version constraints returns 409 Conflict.
Path syntax warnings
After saving a mapping, the API may include a warnings array on the
response if it detects path syntax issues — for example, an invalid
gNMI path format. These are non-blocking; the mapping is saved
regardless.
{
"id": 3,
"protocol": "gnmi",
"warnings": ["gnmi-paths[0]: path does not begin with a module prefix"]
}
Step 4 — Run a live collection test
Before subscribing, validate the model against a real device:
curl -s -X POST "$BASE/api/v1/models/7/test" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device-id": 3,
"mapping-id": 5
}'
Bruno: 04 Models / Test mapping
UI: https://collector.example.com/models/7/test
The engine connects to the device using the protocol configured for the mapping and collects data for up to 8 seconds, returning early once 1.5 seconds elapse with no new updates (the initial burst has settled).
Response 200 OK:
{
"device": "router-core-01",
"protocol": "snmp",
"raw-data-received": true,
"results": [
{
"key": "192.0.2.1",
"model-name": "my-bgp-summary",
"data": {
"neighbor-address": "192.0.2.1",
"session-state": "established",
"peer-as": 65001
}
}
],
"raw-updates": []
}
resultscontains parsed, field-mapped data.raw-updatesshows the raw protocol output before any mapping is applied — useful when debugging field-mapping keys.
Tip
If raw-data-received is true but results is empty, the
parser received data but could not extract the key field. Check
that key-field matches an actual leaf name in raw-updates.
Step 5 — Create a subscription
Once the test passes, activate the model on a device:
curl -s -X POST "$BASE/api/v1/subscriptions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"device-id": 3,
"model-name": "my-bgp-summary",
"protocol": "snmp",
"interval": 60
}'
Bruno: 05 Subscriptions / Create subscription
UI: https://collector.example.com/subscriptions/new
device-id, model-name, and protocol are required. The
collector defaults interval to 60 seconds and forces enabled to
true on creation; the new subscription starts in the stopped
status and transitions on its first poll. The collection engine
resolves the correct mapping at each poll cycle based on the
device's NetOS and firmware version.
Import / export format
Models can be exported and imported as self-contained JSON files, which makes it easy to move a working model between environments or to seed a starter catalogue.
Export
curl -s -X GET "$BASE/api/v1/models/7/export" \
-H "Authorization: Bearer $TOKEN" \
-o my-bgp-summary.json
Bruno: 04 Models / Export model
UI: https://collector.example.com/models/7
The response is a JSON document with
Content-Disposition: attachment.
Import
curl -s -X POST "$BASE/api/v1/models/0/import" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data-binary @my-bgp-summary.json
Bruno: 04 Models / Import model
UI: https://collector.example.com/models
The path takes a model ID for routing consistency but the import
handler ignores it — every imported model is created from the JSON
body. Import fails with 400 if a model with the same name already
exists.
Export schema
{
"name": "my-bgp-summary",
"description": "BGP summary table via SNMP",
"version": "1.0",
"fields": [
{
"name": "neighbor-address",
"field-type": "string",
"format": "ip-address",
"required": true,
"description": "BGP neighbor IP (row key)",
"position": 0
},
{
"name": "session-state",
"field-type": "string",
"required": false,
"description": "BGP session state",
"position": 1
}
],
"mappings": [
{
"protocol": "snmp",
"netos": "ios-xr",
"version-constraints": [],
"key-field": "neighbor-address",
"snmp-walk-oids": ["1.3.6.1.2.1.15.3"],
"field-mappings": {
"bgpPeerRemoteAddr": "neighbor-address",
"bgpPeerState": "session-state"
},
"value-transforms": {
"session-state": {
"6": "established"
}
}
}
]
}
All array and map fields (version-constraints, gnmi-paths,
field-mappings, field-transforms, value-transforms,
ignore-values, cli-discovery-params) are optional and are omitted
when empty.
Hot-reload behaviour
After any field or mapping change (create, update, delete), the collector debounces the event and fires a reload ~500 ms after the last change. The reload:
- Re-reads the model from the database.
- Rebuilds the in-memory model registry.
- Re-subscribes every active device collector that uses the model with the new configuration.
If you delete the model or set is-active to false, it is removed
from the registry immediately and all associated collectors are
torn down.