Templates
Map external payloads into platform telemetry.
Templates let you map an external payload shape into an internal platform entity. They are external-to-internal adapters: they do not define your schema, and they do not decide which data persists. Your Thing Type Definition remains the gatekeeper for the metrics a Thing can write to its primary time-series record.
A common template maps JSON payloads into Thing telemetry. You create a template once, then use it with a generic ingestion endpoint for any Thing whose type includes the mapped metrics.
How templates work
A template has two independent parts:
| Axis | Meaning |
|---|---|
| Target | The internal entity or pipeline the template produces. |
| Format | The external input mechanism, selector type, and conversion logic. |
The target defines the output contract: available fields, validation rules, and the downstream sink. The format defines how the external payload is read and converted.
Supported formats
| Format | Use it to |
|---|---|
JsonPointer | Map values from JSON payloads with RFC 6901 JSON Pointer selectors. |
JavaScriptHandler | Author custom JavaScript conversion logic for payloads that need code-driven parsing or transformation. |
Dbc | Decode CAN bus payloads with DBC signal definitions. |
Supported target types
| Target | Produces |
|---|---|
ThingData | Time-series metric readings for Things. |
Transactions | Transaction records for business or operational events. |
Integrations | Integration events or commands for connected external systems. |
JSON Pointer ThingData templates
A ThingData + JsonPointer template maps an inbound JSON document to metric values for one Thing.
The spec includes:
recordsPointer: optional pointer to an array of readings. If omitted, the whole document is one reading.timestamp: the pointer and timestamp format for each reading.mappings: metric mappings from external values tomdef_metric ids.
Each mapping targets a Metric Definition by id. At apply time, the platform intersects those mappings with the Thing's active Thing Type Definition. Metrics that are not on the Thing's type are skipped and reported.
{
"name": "Acme Telemetry v1",
"target": "ThingData",
"format": "JsonPointer",
"spec": {
"recordsPointer": "/readings",
"timestamp": {
"source": { "pointer": "/ts" },
"format": "iso8601"
},
"mappings": [
{
"metricId": "mdef_voltage",
"source": { "pointer": "/v" },
"transform": { "scale": 0.1, "offset": 0 }
},
{
"metricId": "mdef_state",
"source": { "pointer": "/state" },
"enumMap": { "RUNNING": 1, "IDLE": 0, "FAULT": 2 }
},
{
"metricId": "mdef_mode",
"source": { "pointer": "/mode" },
"default": "auto"
},
{
"metricId": "mdef_fw",
"source": { "pointer": "/header/fw", "scope": "document" }
}
]
}
}
Selectors and records
Each source is a selector object.
| Field | Meaning |
|---|---|
pointer | An RFC 6901 JSON Pointer. An empty pointer "" resolves to the current record root. |
scope | record by default. Use document to resolve from the root document, such as a shared header value. |
If recordsPointer points to an array, each array item becomes one candidate reading. If it is
omitted or empty, the whole document is treated as one reading.
Timestamp formats
Every emitted reading needs a timestamp. The timestamp mapping supports:
iso8601epoch_msepoch_s
If a record has a missing or unparseable timestamp, the platform skips that record and reports it in the apply response.
Missing and invalid values
Templates distinguish missing values from invalid values.
| Case | Behavior |
|---|---|
Source is absent or JSON null | Write default if configured. Otherwise skip that metric. |
| Source is present but cannot be parsed | Skip that metric and report invalid_value. |
| Source resolves to an object or array | Skip that metric and report invalid_value. |
Enum source has no enumMap entry | Skip that metric and report invalid_value. |
| Metric is not on the Thing's active type | Skip that metric and report it as not on the Thing Type Definition. |
A default only applies when the source is absent or null. It does not rescue a present but invalid
value.
If a record produces no metric values after mapping and validation, the platform skips the whole
reading and reports no_metric_values.
Transforms
Templates support two transform styles:
| Transform | Use with | Notes |
|---|---|---|
transform | Numeric metrics | Applies value * scale + offset to present values. |
enumMap | Enum-shaped Int metrics | Maps a source label or code string to the target enum code. |
transform and enumMap are mutually exclusive. default is independent: it may coexist with
either one, but it is written as-is and is not transformed.
Current templates support scalar metric types: Double, Int, Bool, String, and enum-shaped Int
metrics. Json metrics are not supported by templates yet.
Create and manage templates
Use the Aerovy Platform API to create and manage templates.
| Method | Path | Purpose |
|---|---|---|
GET | /v2/templates | List templates. Supports target, format, status, continuationToken, and pageLimit. |
GET | /v2/templates/{templateId} | Get one template. |
POST | /v2/templates | Create a template. |
PUT | /v2/templates/{templateId} | Update name, description, spec, and tags. |
DELETE | /v2/templates/{templateId} | Soft-delete a template. |
POST | /v2/templates/{templateId}/test | Dry-run a sample payload without a Thing or write. |
Template ids use the tmpl_ prefix. target and format are immutable after creation. Updating a
template bumps its revision, and apply responses echo the revision that processed the payload.
Apply a template
Apply a ThingData template to a Thing with:
POST /v2/thing/{thingId}/data/template/{templateId}?previewOnly=false
X-Api-Key: avy...
Content-Type: application/json
The request body is the raw external JSON payload. The platform loads the Thing, resolves the active Thing Type Definition, maps the payload, writes valid readings, and returns a processing report.
Set previewOnly=true to preview the generated write without persisting it.
{
"previewOnly": false,
"templateId": "tmpl_abc123",
"templateRevision": 7,
"recordsParsed": 100,
"readingsWritten": 98,
"metricValuesWritten": 540,
"recordsSkipped": [
{ "index": 12, "reason": "invalid_timestamp", "value": "n/a" },
{ "index": 30, "reason": "no_metric_values" }
],
"metricsSkippedNotOnTtd": ["mdef_torque"],
"fieldsSkippedMissing": [
{ "metricId": "mdef_mode", "count": 3 }
],
"fieldsInvalid": [
{ "metricId": "mdef_voltage", "reason": "parse_failed", "count": 2 }
]
}
Validation and limits
Template create and update validates the spec before saving it.
targetandformatmust be known values with a registered handler.- Every JSON Pointer must be valid RFC 6901.
timestamp.formatmust beiso8601,epoch_ms, orepoch_s.- Every mapped
metricIdmust exist and must not be deleted. - A template cannot map the same metric twice.
- Numeric transforms only apply to numeric metrics.
enumMaponly applies to enum-shapedIntmetrics.- Defaults must be coercible to the target metric type.
- A template can have up to 100 mappings.
- The inline serialized spec must stay under 256 KB.
Apply requests are limited to 1 MB and 1,000 records per request.
Failure behavior
Structural problems fail the request and write nothing. Examples include an unknown template, an
unknown Thing, invalid JSON, a recordsPointer that does not resolve to an array, a Thing without a
Thing Type Definition, a deleted Thing Type Definition, or a missing time-series table.
Per-record and per-field problems do not fail the whole request. The platform skips the affected record or metric, writes the rest, and includes diagnostics in the apply report.
Related docs
- Data model explains Thing Type Definitions and Metric Definitions.
- Ingesting data covers the standard telemetry ingestion path.
- Querying data shows how to read telemetry after it is written.