---
title: "Data model"
description: "How to define your device types and the data they report."
icon: "sitemap"
---

> **For AI agents:** the complete documentation index is at [llms.txt](/llms.txt). Append `.md` to any page URL for its markdown version.

## Why this exists

Before the platform can accept telemetry from a device, it needs to know **what kind of device
it is and what data to expect**. We call this the *ontology*, the platform's
vocabulary to describe your devices.

You define the ontology yourself, through the API. It's data, not hard-coded: each
organization owns its own definitions, and they're versioned so they can evolve over time.

There's no single "ontology" object. Instead, the ontology is three cooperating pieces:

- A **Thing Type Definition** is the type of a device, e.g. "Battery".
- It references **Metric Definitions**: what the device measures (`soc`, `soh`, `latitude`, etc.).
- It includes **Property Definitions**: static attributes (`capacity`, reporting interval, etc.).

A simple way to think about this: **Things are instances of Thing Type Definitions**.

## Metric Definition

A **Metric Definition** describes a single measurable quantity. You create these first,
then reference them from your Thing Types.

| Field | Meaning |
|-------|---------|
| `name` *(required)* | Machine identifier (e.g. `soc`). |
| `dataType` *(required)* | `Int`, `Double`, `String`, `Bool`, or `Json`. |
| `defaultAggregation` *(required)* | How queries roll the metric up over time: `Last`, `Avg`, `Sum`, `Count`, `First`. |
| `displayName` | UI-friendly name. |
| `unitLabel` | Unit of measure (`%`, `V`, `A`, `C`…). |
| `description`, `tags` | Documentation and categorization. |
| `enumValues` | Optional. For `Int` metrics that represent coded states (see below). |

Two things to know:

- **`defaultAggregation` is how the data reads back.** A state-of-charge metric uses `Last`
  (you want the most recent value in a window); an energy total might use `Sum`. Choose it
  to match the physical meaning of the metric.
- **Enum-shaped metrics**: when `dataType` is `Int` and you supply `enumValues`, the metric
  represents discrete states (e.g. `0 = Idle`, `1 = Charging`). Codes are append-only and
  immutable. Labels can change. Aggregation is limited to `First`/`Last`/`Count`.

> Each metric is identified by a stable id (`mdef_…`) and a `name`. The name is what you put
> in telemetry payloads and query strings, so treat it as part of your contract. Renaming a
> metric is not a casual change.

## Thing Type Definition

A **Thing Type Definition** ties metrics and properties together into a named device type.

| Field | Meaning |
|-------|---------|
| `displayName` *(required)* | Human-readable type name (e.g. "Battery"). |
| `metricIds` *(required)* | The metrics a device of this type reports (references to Metric Definitions). |
| `propertyDefinitions` | Static properties a device of this type can carry (see below). |
| `description`, `tags` | Documentation and categorization. |

Key ideas:

- **Types reference metrics, they don't own them.** Because `metricIds` is a list of
  references, the *same* metric can be shared across multiple types (see
  [Metric reuse](#metric-reuse) below).
- **Types are scoped to your organization.** Your "Battery" type is yours; another org's
  "Battery" can have entirely different metrics.

## Property Definition

Where a metric is a *time-series measurement*, a **Property Definition** is a *static
attribute* of a device, configured once, like a battery's capacity or its reporting
interval. Property definitions live inline on the Thing Type.

| Field | Meaning |
|-------|---------|
| `name` *(required)* | Property name (e.g. `capacity`). |
| `valueType` *(required)* | `string`, `int`, `double`, or `bool`. |
| `unit` | Unit of measure (`kWh`, `min`…). |
| `description` | What it means. |
| `constraints` | Optional validation rules: each is an `operator` + `value` (e.g. `>` `0`, `<=` `100`). |

When you set a property on a Thing, the platform validates it against that Thing's type:
an unknown property name is rejected, and constraints define the allowed range. This is how
you keep device configuration consistent.

## Versioning

Thing Types are **immutably versioned**, which gives each type a two-part identity:

- A **stable id** (`tdefi_…`) identifies the type itself, "the Battery type". It never changes.
- A **version id** (`tdef_…`) identifies one immutable snapshot of that type's metrics and
  properties. Creating a "new version" adds a new snapshot; earlier versions are untouched.

A Thing records **both**: the stable type it is, and the exact version it was created
against. That version fixes which metric set applies to it. Devices created under v1 and v2
of a type coexist cleanly. Old data stays readable as your schema evolves.

## Metric reuse

Because a Thing Type references metrics by id, the *same* Metric Definition can be shared
across types. Define `soc` (state of charge) once and reference it from both **Battery** and
**SwapStation**; define `latitude`/`longitude` once and share them across **Battery** and a
**Scooter** type.

Defining a metric once and reusing it makes data **comparable across device kinds**: a query
for `soc` means the same thing whether the reading came from a Battery or a SwapStation.

## Managing the ontology

These live under the `v2` definitions endpoints of the Aerovy Platform API.

**Metric Definitions**

| Method & path | Purpose |
|---------------|---------|
| `POST /v2/definitions/metrics` | Create a metric definition. |
| `GET  /v2/definitions/metrics` | List metric definitions. |
| `GET  /v2/definitions/metrics/{metricId}` | Get one. |

**Thing Type Definitions**

| Method & path | Purpose |
|---------------|---------|
| `POST   /v2/definitions/thing-types` | Create a new type (and its first version). |
| `GET    /v2/definitions/thing-types` | List your types. |
| `GET    /v2/definitions/thing-types/{thingTypeId}` | Get one type. |
| `PUT    /v2/definitions/thing-types/{thingTypeId}` | Update type metadata. |
| `DELETE /v2/definitions/thing-types/{thingTypeId}` | Remove a type. |
| `GET    /v2/definitions/thing-types/{thingTypeId}/versions` | Version history. |
| `POST   /v2/definitions/thing-types/{thingTypeId}/versions` | Create a new version. |
| `GET    /v2/definitions/thing-types/versions/{thingTypeDefId}` | Get a specific version. |

> Exact request/response fields are documented in the API Reference. The
> [Ingesting data](/platform/ingesting-data) guide shows these in a worked example.

## Recap

| Layer | Concept | Analogy |
|-------|---------|---------|
| Schema | Thing Type (stable, `tdefi_…`) | The name of a class (`Battery`) |
| Schema | Thing Type Definition (version, `tdef_…`) | A specific version of that class |
| Schema | Metric Definition (`mdef_…`) | A typed, reusable field with units & aggregation |
| Schema | Property Definition | A static, constrained attribute |
| Instance | Thing (`<thingId>`) | An object of the class |
| Data | Telemetry data points | The values that object reports over time |

Devices aren't hard-coded; they're *defined*: per organization, versioned, with units,
aggregation rules, validation, and reuse.
