Schema · sensors/binding
Sensor binding
The tenant a sensor's readings are written into: the one account and the one Decisions space the Atlas writer scopes itself to when it turns that sensor's readings into observations and evidence. A sensor with no binding is not written to Atlas (readings stay in the sensors store); removing the binding stops the writing. The writer reads sensor_id as the key, requires account_id to equal the account the sensor itself belongs to (a binding never moves a sensor across accounts), converts space_id to the Atlas space and opens a store authority scoped to that account and space, so one sensor writes into exactly one tenant. bound_by and bound_at are the audit record of who made the binding and when; the writer does not act on them. A binding names its tenant and nothing else: no content, prompt or credential, and the object is closed so a field outside these is refused. Draft line: it may still be corrected.
https://schemas.inorbit.hr/sensors/binding/v0.jsonEach version is a file at its own address. The raw file is plain JSON, served without a sign-in.
- v0draftMay still be corrected; kept for five minutes.schemas.inorbit.hr/sensors/binding/v0.json ↗
Fields of v0, the newest version, by path. A name ending in [] is each item of a list. Every field not listed is refused.
sensor_idanyrequiredThe sensor, as SensorsService names it. Defined here the same way as in https://schemas.inorbit.hr/sensors/reading/v0.json#/$defs/sensor_id so the two can be read together; this schema does not refer to it so that it stands alone.
account_idstringrequiredThe account the sensor belongs to and the writer scopes to: a UUID, as accounts are written everywhere (accounts have no prefix).
pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$space_idstringrequiredThe Decisions space the observations are written into: lab_ and a ULID, as decisions_list_spaces names it. Never the bare ULID or the Atlas space UUID derived from it.
pattern ^lab_[0-9A-HJKMNP-TV-Z]{26}$bound_bystringrequiredWho made the binding: the verified subject (a person's or an agent's), 1 to 128 characters, no spaces or control characters.
pattern ^[^\s\u0000-\u001f\u007f-\u009f]{1,128}$bound_atanyrequiredWhen it was made.
Valid documents with made-up values, as the repository's tests check them.
{
"sensor_id": "builtin.incidents.open",
"account_id": "2779ba0b-df69-4cfc-89fe-101441554413",
"space_id": "lab_01M5FVHEWEWZZ1A66W0PCGZSWV",
"bound_by": "user:legal@example.org",
"bound_at": "2026-10-23T16:09:26+02:00"
}The repository's tests also check 20 documents that this schema must refuse.
Replace the file name with yours.
"json.schemas": [
{ "fileMatch": ["my-file.json"], "url": "https://schemas.inorbit.hr/sensors/binding/v0.json" }
]check-jsonschema --schemafile https://schemas.inorbit.hr/sensors/binding/v0.json my-file.jsonajv validate --spec=draft2020 -s <(curl -s https://schemas.inorbit.hr/sensors/binding/v0.json) -d my-file.jsoncurl -s https://schemas.inorbit.hr/sensors/binding/v0.jsonThe raw file of v0, as published.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://schemas.inorbit.hr/sensors/binding/v0.json",
"title": "Sensor binding",
"description": "The tenant a sensor's readings are written into: the one account and the one Decisions space the Atlas writer scopes itself to when it turns that sensor's readings into observations and evidence. A sensor with no binding is not written to Atlas (readings stay in the sensors store); removing the binding stops the writing. The writer reads sensor_id as the key, requires account_id to equal the account the sensor itself belongs to (a binding never moves a sensor across accounts), converts space_id to the Atlas space and opens a store authority scoped to that account and space, so one sensor writes into exactly one tenant. bound_by and bound_at are the audit record of who made the binding and when; the writer does not act on them. A binding names its tenant and nothing else: no content, prompt or credential, and the object is closed so a field outside these is refused. Draft line: it may still be corrected.",
"type": "object",
"additionalProperties": false,
"required": ["sensor_id", "account_id", "space_id", "bound_by", "bound_at"],
"properties": {
"sensor_id": {
"description": "The sensor, as SensorsService names it. Defined here the same way as in https://schemas.inorbit.hr/sensors/reading/v0.json#/$defs/sensor_id so the two can be read together; this schema does not refer to it so that it stands alone.",
"$ref": "#/$defs/sensor_id"
},
"account_id": {
"description": "The account the sensor belongs to and the writer scopes to: a UUID, as accounts are written everywhere (accounts have no prefix).",
"type": "string",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
},
"space_id": {
"description": "The Decisions space the observations are written into: lab_ and a ULID, as decisions_list_spaces names it. Never the bare ULID or the Atlas space UUID derived from it.",
"type": "string",
"pattern": "^lab_[0-9A-HJKMNP-TV-Z]{26}$"
},
"bound_by": {
"description": "Who made the binding: the verified subject (a person's or an agent's), 1 to 128 characters, no spaces or control characters.",
"type": "string",
"pattern": "^[^\\s\\u0000-\\u001f\\u007f-\\u009f]{1,128}$"
},
"bound_at": {
"description": "When it was made.",
"$ref": "#/$defs/timestamp"
}
},
"$defs": {
"sensor_id": {
"description": "A sensor's id: sen_ and a ULID for a sensor a producer registered; builtin.<name> for a built-in count (builtin.incidents.open); mon_ and a ULID for a monitor, which is a built-in sensor too. Never a bare UUID: every id carries its prefix.",
"type": "string",
"maxLength": 64,
"oneOf": [
{ "pattern": "^sen_[0-9A-HJKMNP-TV-Z]{26}$" },
{ "pattern": "^mon_[0-9A-HJKMNP-TV-Z]{26}$" },
{ "pattern": "^builtin\\.[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$" }
]
},
"timestamp": {
"description": "RFC 3339 with a T and a Z or an offset, at most nine fractional digits. The API writes UTC with milliseconds (2026-10-23T14:09:26.123Z).",
"type": "string",
"minLength": 20,
"maxLength": 40,
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,9})?(Z|[+-][0-9]{2}:[0-9]{2})$"
}
}
}