Aerovy Platform logo

Templates

Map external payloads into platform telemetry.

Templates are in beta.

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:

AxisMeaning
TargetThe internal entity or pipeline the template produces.
FormatThe 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

FormatUse it to
JsonPointerMap values from JSON payloads with RFC 6901 JSON Pointer selectors.
JavaScriptHandlerAuthor custom JavaScript conversion logic for payloads that need code-driven parsing or transformation.
DbcDecode CAN bus payloads with DBC signal definitions.

Supported target types

TargetProduces
ThingDataTime-series metric readings for Things.
TransactionsTransaction records for business or operational events.
IntegrationsIntegration 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 to mdef_ 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.

FieldMeaning
pointerAn RFC 6901 JSON Pointer. An empty pointer "" resolves to the current record root.
scoperecord 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:

  • iso8601
  • epoch_ms
  • epoch_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.

CaseBehavior
Source is absent or JSON nullWrite default if configured. Otherwise skip that metric.
Source is present but cannot be parsedSkip that metric and report invalid_value.
Source resolves to an object or arraySkip that metric and report invalid_value.
Enum source has no enumMap entrySkip that metric and report invalid_value.
Metric is not on the Thing's active typeSkip 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:

TransformUse withNotes
transformNumeric metricsApplies value * scale + offset to present values.
enumMapEnum-shaped Int metricsMaps 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.

MethodPathPurpose
GET/v2/templatesList templates. Supports target, format, status, continuationToken, and pageLimit.
GET/v2/templates/{templateId}Get one template.
POST/v2/templatesCreate a template.
PUT/v2/templates/{templateId}Update name, description, spec, and tags.
DELETE/v2/templates/{templateId}Soft-delete a template.
POST/v2/templates/{templateId}/testDry-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.

  • target and format must be known values with a registered handler.
  • Every JSON Pointer must be valid RFC 6901.
  • timestamp.format must be iso8601, epoch_ms, or epoch_s.
  • Every mapped metricId must exist and must not be deleted.
  • A template cannot map the same metric twice.
  • Numeric transforms only apply to numeric metrics.
  • enumMap only applies to enum-shaped Int metrics.
  • 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.

  • 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.