> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kodelabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Apply a templating plan

> Applies ontology fields and enum maps to the points of the devices you select. The call validates the plan and starts an operation that you poll until it finishes. Send `validateOnly` as `true` to check the plan without changing anything.

> [!WARNING]
>
> Applying a plan rewrites live data on every matched point: its name, display name, unit, ontology fields, and enum maps. It also sets the canonical type on the devices. There is no undo call. [Clear a templating plan](https://docs.kodelabs.com/products/kode-api/api-reference/templating/clear-a-templating-plan.md) removes the ontology fields and restores the connector name and unit, but it does not restore other values. Always validate first, check `summary.matchedPoints`, and test on a non-critical device.

A plan has a `canonicalType`, the `deviceIds` it covers (1 to 2,000), and up to 1,000 `mappings`. Each mapping has:

* `match`: The points to change. Send exactly one of `groupKey`, a tuple (`name`, `kind`, `unitSymbol`, `writable`, `pointEnum`), or `pointIds`.
* `field`: The catalog field to apply, from [List fields for a canonical type](https://docs.kodelabs.com/products/kode-api/api-reference/ontology/list-fields-for-a-canonical-type.md).
* `overrides`: Optional changes to the field's defaults, such as `displayName`, `unit`, `precision`, `covTolerance`, `defaultInGraph`, `prefix`, `suffix`, and `dataInterval`.
* `enumMapping`: Optional enum maps for `Bool` and `Str` points. `action` is `SET` to replace the maps, `UNSET` to remove them, or `KEEP` to leave them as they are. `KEEP` is the default.

A point-level mapping (`pointIds`) takes precedence over a group mapping that covers the same point. A plan can cover at most 5,000 distinct point ids.

**Validate first**

With `validateOnly` set to `true`, the response holds `validationReport` and nothing is written. Read:

* `valid`: `true` when no issue has `ERROR` severity.
* `summary`: How many points and devices the apply would reach, with counts of errors and warnings.
* `mappings[]`: The outcome of each mapping, in request order, with its own `issues`.
* `issues`: Findings about the whole plan, such as devices that are already templated under another canonical type.
* `unmappedGroups`: Groups in your device selection that no mapping covers.
* `etag`: A fingerprint of the resolved plan.

Each issue has a `code`, a `pointer` to the part of your request it concerns, and a `message`. `ERROR` issues stop the apply. Warnings, such as `NO_MATCH` or `ENUM_MAPPING_RECOMMENDED`, do not.

**Start the run**

Send the same body with `validateOnly` removed (or `false`), a `requestId` of your choice, and the `etag` from the report. The response holds `operation`. Keep the last segment of `operation.name` as the `operationId` and poll [Get a templating operation](https://docs.kodelabs.com/products/kode-api/api-reference/templating/get-a-templating-operation.md).

* Only `validateOnly: true` makes a dry run. If you leave `validateOnly` out, the call starts a real run.
* The `requestId` is unique per building. Sending the same `requestId` with the same body again returns the operation it already started. Sending it with a different body returns `400`.
* If the plan changed since you validated it, the `etag` no longer matches and the call returns `400`. Validate again to get a new `etag`. Leave `etag` out to skip the check.
* The API does not stop two runs from touching the same points. The last write wins.

> [!NOTE]
>
> Your service account needs the permission to manage device and point templating, including for a dry run.


## OpenAPI

````yaml /openapi/kode-api.yaml post /api/v1/buildings/{buildingId}/templating:apply
openapi: 3.1.0
info:
  title: KODE API
  version: 1.0.0
  summary: Programmatic access to KODE OS resources and operations.
  description: >
    Use the KODE API to work with buildings, data sources, connectors, devices,
    points, virtual devices,

    timeseries data, schedules, the ontology, templating, mass writes, spaces,
    space assignments, tenants, meters, users, actions,

    and AssetOps work orders.
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
servers:
  - url: https://api.kodelabs.com/kodeos
    description: KODE API
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: OAuth 2.0 discovery, token, and revocation endpoints.
  - name: Buildings
    description: Buildings and their areas.
  - name: Data sources
    description: Data sources connected to a building.
  - name: Devices
    description: Devices and their points.
  - name: Points
    description: Point queries and point writes.
  - name: Timeseries
    description: Current and historical point values.
  - name: Actions
    description: Actions exposed by building data sources.
  - name: Work orders
    description: AssetOps work orders, lookups, comments, and attachments.
  - name: Connectors
    description: KODE API connectors and the devices and points ingested through them.
  - name: Schedules
    description: Schedules discovered on building data sources.
  - name: Templating
    description: Apply ontology templates to groups of points.
  - name: Virtual devices
    description: Virtual devices that group points from other devices.
  - name: Ontology
    description: Canonical types, fields, units, and connections of the KODE ontology.
  - name: Users
    description: Users of the organization and their app access.
  - name: Mass write
    description: Write values to many points across buildings, and follow each run.
  - name: Spaces
    description: Levels and space units of a building, and the meters located in them.
  - name: Space assignments
    description: Assign tenants to leasable spaces of a building for a period.
  - name: Tenants
    description: Tenants of a building, the people or companies that lease its spaces.
  - name: Meters
    description: >-
      Meters of a building, their space assignments, parent and child links, and
      readings.
paths:
  /api/v1/buildings/{buildingId}/templating:apply:
    post:
      tags:
        - Templating
      summary: Apply a templating plan
      description: >-
        Applies ontology fields and enum maps to the points of the devices you
        select. The call validates the plan and starts an operation that you
        poll until it finishes. Send `validateOnly` as `true` to check the plan
        without changing anything.
      operationId: applyTemplatingPlan
      parameters:
        - $ref: '#/components/parameters/BuildingId'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplatingRunRequestBody'
        required: true
      responses:
        '200':
          description: >-
            The started operation in `operation`, or the validation report in
            `validationReport` when `validateOnly` is `true`. Exactly one of the
            two is present.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TemplatingRunResultPublic'
        '400':
          description: >-
            The body is not valid, the plan has an `ERROR` issue, the `etag` is
            stale, or the `requestId` was already used for a different plan. For
            a plan error, the `fields` list in the error names the part of the
            plan and the reason. Validate with `validateOnly` to see every
            issue.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: >-
            The service account lacks permission to manage templating, or the
            building does not exist or is not assigned to it. KODE API answers
            `403` in both cases so that building ids cannot be probed.
        '404':
          description: The building was not found.
        '429':
          $ref: '#/components/responses/TooManyRequests'
components:
  parameters:
    BuildingId:
      name: buildingId
      in: path
      required: true
      description: Building identifier from List buildings.
      schema:
        type: string
      example: 67c960faffaa42223163099e
  schemas:
    TemplatingRunRequestBody:
      type: object
      required:
        - canonicalType
        - deviceIds
        - requestId
      properties:
        canonicalType:
          type: string
          description: Canonical type this plan is scoped to.
          examples:
            - AHU
          pattern: (?s)(?=.*[^\p{C}\p{Z}])[\P{Cc}\n\r\t]*
          maxLength: 255
        deviceIds:
          type: array
          items:
            type: string
            pattern: '[^\p{C}\p{Z}]{1,128}'
            maxLength: 255
          description: Explicit device ids to scope this plan to.
          maxItems: 2000
          minItems: 1
        mappings:
          type: array
          items:
            $ref: '#/components/schemas/TemplatingMappingPublic'
          description: >-
            The plan's mappings. Empty or omitted on :clear clears the whole
            device selection for this canonical type.
          maxItems: 1000
        requestId:
          type: string
          description: >-
            Client-chosen idempotency key, unique per building. Repeating it
            with the same plan returns the existing operation; with a different
            plan it is rejected.
          examples:
            - ahu-1-apply-2026-09-30
          pattern: '[^\p{C}\p{Z}]{1,128}'
          maxLength: 128
        etag:
          type: string
          description: >-
            Etag from a previous validation. If it no longer matches, the
            request fails with 400; validate again for a fresh etag. Omitted
            means no check.
          examples:
            - sha256:9f86d0818...
          pattern: '[^\p{C}\p{Z}]{1,128}'
          maxLength: 128
        validateOnly:
          type: boolean
          description: 'Dry run: true returns the validation report and writes nothing.'
          examples:
            - false
    TemplatingRunResultPublic:
      type: object
      properties:
        validationReport:
          $ref: '#/components/schemas/TemplatingValidationReportPublic'
          description: >-
            Present only for validateOnly: true. The plan's validation report;
            nothing was written.
          type: object
        operation:
          $ref: '#/components/schemas/TemplatingOperationEnvelopePublic'
          description: >-
            Present only when validateOnly is false. The started operation, or
            the existing one when the requestId is replayed with the same plan.
          type: object
    TemplatingMappingPublic:
      type: object
      properties:
        match:
          $ref: '#/components/schemas/TemplatingGroupMatchPublic'
          description: The mapping's target - exactly one of groupKey, tuple or pointIds.
          type: object
        field:
          type: string
          description: Catalog field name to apply. Omitted for a CLEAR mapping.
          examples:
            - dischargeAirTemp
          maxLength: 255
        overrides:
          $ref: '#/components/schemas/TemplatingFieldOverridesPublic'
          description: Overrides of the catalog field's defaults.
          type: object
        enumMapping:
          $ref: '#/components/schemas/TemplatingEnumMappingPublic'
          description: Enum-map instruction for this mapping.
          type: object
    TemplatingValidationReportPublic:
      type: object
      properties:
        valid:
          type: boolean
          description: Whether the plan has no ERROR-severity issue anywhere.
          examples:
            - false
        etag:
          type: string
          description: >-
            Etag of the resolved plan. Send it as etag on :apply/:clear to
            reject a stale plan.
          examples:
            - sha256:9f86d081...
        summary:
          $ref: '#/components/schemas/TemplatingValidationSummaryPublic'
          description: Plan-wide counters.
          type: object
        mappings:
          type: array
          items:
            $ref: '#/components/schemas/TemplatingMappingResultPublic'
          description: Per-mapping outcomes, in the same order as the request's mappings.
        issues:
          type: array
          items:
            $ref: '#/components/schemas/TemplatingValidationIssuePublic'
          description: >-
            Plan-level findings not tied to one mapping (canonical-type
            conflicts, plan size, ...).
        unmappedGroups:
          type: array
          items:
            $ref: '#/components/schemas/TemplatingUnmappedGroupPublic'
          description: Groups in the device selection that no mapping targets.
    TemplatingOperationEnvelopePublic:
      type: object
      properties:
        name:
          type: string
          description: Operation resource name.
          examples:
            - >-
              buildings/66f1a2b3c4d5e6f7a8b9c0d1/templating/operations/66f1a2b3c4d5e6f7a8b9c0d3
        done:
          type: boolean
          description: Whether the operation has finished (successfully or not).
          examples:
            - false
        metadata:
          $ref: '#/components/schemas/Metadata3'
          description: Progress and identifying metadata, always present.
          type: object
        response:
          $ref: '#/components/schemas/Response1'
          description: Present only once done and successful.
          type: object
        error:
          $ref: '#/components/schemas/Error1'
          description: Present only once done and failed.
          type: object
    TemplatingGroupMatchPublic:
      type: object
      properties:
        groupKey:
          type: string
          description: Match by a groupKey issued by the point-groups query endpoint.
          examples:
            - pg1.Yz3kR1a2B3c4D5e6F7g8H9
          pattern: '[^\p{C}\p{Z}]{1,128}'
          maxLength: 64
        name:
          type: string
          description: 'Tuple match: the group''s connector name, case-sensitive.'
          examples:
            - SA-T
          maxLength: 255
        kind:
          type: string
          description: >-
            Tuple match: point kind, exactly as returned by the point-groups
            query (Number, Bool or Str).
          examples:
            - Number
          maxLength: 16
        unitSymbol:
          type: string
          description: 'Tuple match: unit symbol (Number kind only).'
          examples:
            - °F
          maxLength: 64
        writable:
          type: boolean
          description: >-
            Tuple match: writable tri-state (null, true and false are all
            distinct).
          examples:
            - false
        pointEnum:
          type: array
          items:
            type: string
            maxLength: 255
          description: >-
            Tuple match: the point enum values, in stored order (non-Number
            kinds only).
          examples:
            - - 'Off'
              - 'On'
          maxItems: 256
        pointIds:
          type: array
          items:
            type: string
            pattern: '[^\p{C}\p{Z}]{1,128}'
            maxLength: 255
          description: Match specific points by id instead of a group.
          examples:
            - - 66f1a2b3c4d5e6f7a8b9c0d1
          maxItems: 5000
    TemplatingFieldOverridesPublic:
      type: object
      properties:
        displayName:
          type: string
          description: Overrides the catalog field's display name.
          examples:
            - Supply Air Temp
          pattern: (?s)(?=.*[^\p{C}\p{Z}])[\P{Cc}\n\r\t]*
          maxLength: 255
        precision:
          type: integer
          format: int32
          description: Overrides the catalog field's display precision.
          examples:
            - 1
        unit:
          type: string
          description: >-
            Overrides the field's unit. Must be in the field's unit category and
            the building's unit system.
          examples:
            - °F
          maxLength: 64
        covTolerance:
          type: number
          format: double
          description: Overrides the catalog field's default COV tolerance.
          examples:
            - 0.5
        defaultInGraph:
          type: boolean
          description: >-
            Whether points templated with this field default to being shown in
            graphics.
          examples:
            - true
        prefix:
          type: integer
          format: int32
          description: Explicit field-instance prefix. Null lets the server number it.
          examples:
            - 0
        suffix:
          type: integer
          format: int32
          description: Explicit field-instance suffix. Null lets the server number it.
          examples:
            - 1
        dataInterval:
          type: string
          description: Overrides the trending interval for this field's points.
          examples:
            - 15m
          maxLength: 32
    TemplatingEnumMappingPublic:
      type: object
      properties:
        action:
          $ref: '#/components/schemas/TemplatingEnumMappingActionPublic'
          description: >-
            SET replaces the matched points' enum maps; UNSET removes both; KEEP
            (the default when omitted) leaves them untouched.
          type: string
          examples:
            - SET
        readMap:
          type: array
          items:
            $ref: '#/components/schemas/TemplatingEnumMapEntryPublic'
          description: Read-map pairs (point's own enum label -> mapped canonical label).
          maxItems: 256
        writeMap:
          type: array
          items:
            $ref: '#/components/schemas/TemplatingEnumMapEntryPublic'
          description: >-
            Write-map pairs (canonical label -> point's own enum label); only
            accepted when the matched group/points are writable.
          maxItems: 256
    TemplatingValidationSummaryPublic:
      type: object
      properties:
        mappings:
          type: integer
          format: int32
          description: Number of mappings in the plan.
          examples:
            - 42
        matchedGroups:
          type: integer
          format: int32
          description: Distinct groups actually resolved by a groupKey or tuple mapping.
          examples:
            - 41
        matchedPoints:
          type: integer
          format: int32
          description: Sum of matched points across every mapping.
          examples:
            - 8120
        devicesAffected:
          type: integer
          format: int32
          description: Distinct devices touched by at least one resolved mapping.
          examples:
            - 212
        errors:
          type: integer
          format: int32
          description: Total ERROR-severity issues, plan-level plus every mapping's.
          examples:
            - 1
        warnings:
          type: integer
          format: int32
          description: Total WARNING-severity issues, plan-level plus every mapping's.
          examples:
            - 2
    TemplatingMappingResultPublic:
      type: object
      properties:
        index:
          type: integer
          format: int32
          description: The mapping's position in the plan's mappings list.
          examples:
            - 0
        groupKey:
          type: string
          description: >-
            The resolved group's key, for a groupKey/tuple match; null for a
            pointIds match or an unresolved match.
          examples:
            - pg1.Yz3kR1a2B3c4D5e6F7g8H9
        field:
          type: string
          description: The mapping's field, echoed back.
          examples:
            - dischargeAirTemp
        matchedPoints:
          type: integer
          format: int32
          description: How many in-scope points this mapping resolved to.
          examples:
            - 212
        status:
          $ref: '#/components/schemas/TemplatingMappingStatusPublic'
          description: Worst severity among this mapping's issues.
          type: string
          examples:
            - OK
        issues:
          type: array
          items:
            $ref: '#/components/schemas/TemplatingValidationIssuePublic'
          description: Findings for this mapping.
    TemplatingValidationIssuePublic:
      type: object
      properties:
        code:
          type: string
          description: Stable issue code.
          examples:
            - FIELD_KIND_MISMATCH
        pointer:
          type: string
          description: JSON pointer into the plan this issue is about.
          examples:
            - /mappings/7/field
        message:
          type: string
          description: Human-readable message for this issue.
          examples:
            - >-
              Field 'supplyFanRunCmd' requires a Bool/Str point; group kind is
              Number.
        details:
          type: object
          additionalProperties: {}
          description: Structured details for this issue (e.g. the offending device ids).
    TemplatingUnmappedGroupPublic:
      type: object
      properties:
        groupKey:
          type: string
          description: The group's key.
          examples:
            - pg1.Qa91mN2o3P4q5R6s7T8u9V0
        name:
          type: string
          description: The group's connector name.
          examples:
            - ZN-T
        pointsCount:
          type: integer
          format: int32
          description: Number of points in this group.
          examples:
            - 48
    Metadata3:
      type: object
      properties:
        operation:
          $ref: '#/components/schemas/TemplatingOperationPublic'
          description: Which verb started this operation.
          type: string
          examples:
            - APPLY
        canonicalType:
          type: string
          description: Canonical type this run is scoped to.
          examples:
            - AHU
        state:
          $ref: '#/components/schemas/TemplatingRunStatePublic'
          description: Run state. STALLED is derived on read, never stored.
          type: string
          examples:
            - RUNNING
        progress:
          type: number
          format: double
          description: >-
            Progress as a percentage, 0-100, updated after each batch. Use done,
            not progress, to detect completion.
          examples:
            - 62.5
        createdAt:
          $ref: '#/components/schemas/Date'
          description: When the run was created.
          type: string
        updatedAt:
          $ref: '#/components/schemas/Date'
          description: When the run was last updated.
          type: string
        actorId:
          type: string
          description: The calling service account's id.
          examples:
            - 66f1a2b3c4d5e6f7a8b9c0d4
        etag:
          type: string
          description: Etag of the resolved plan this run started from.
          examples:
            - sha256:9f86d081...
        requestId:
          type: string
          description: requestId this run was started with.
          examples:
            - 5f8a1b2c-3d4e-4f5a-8b6c-7d8e9f0a1b2c
    Response1:
      type: object
      properties:
        matchedPoints:
          type: integer
          format: int32
          description: Points matched and written by this run.
          examples:
            - 8120
        devicesAffected:
          type: integer
          format: int32
          description: Distinct devices affected by this run.
          examples:
            - 212
        notes:
          type: array
          items:
            type: string
          description: >-
            Run-level notices. On SUCCEEDED, states that downstream updates
            finish asynchronously.
    Error1:
      type: object
      properties:
        code:
          type: string
          description: Engine-reported error code.
          examples:
            - '13'
        message:
          type: string
          description: Engine-reported error message.
    TemplatingEnumMappingActionPublic:
      type: string
      enum:
        - TEMPLATING_ENUM_MAPPING_ACTION_UNSPECIFIED
        - SET
        - UNSET
        - KEEP
    TemplatingEnumMapEntryPublic:
      type: object
      required:
        - from
        - to
      properties:
        from:
          type: string
          description: The point's own raw enum label.
          examples:
            - 'Off'
          maxLength: 255
        to:
          type: string
          description: The mapped canonical label.
          examples:
            - 'off'
          maxLength: 255
    TemplatingMappingStatusPublic:
      type: string
      enum:
        - MAPPING_STATUS_UNSPECIFIED
        - OK
        - WARNING
        - ERROR
    TemplatingOperationPublic:
      type: string
      enum:
        - TEMPLATING_OPERATION_UNSPECIFIED
        - APPLY
        - CLEAR
    TemplatingRunStatePublic:
      type: string
      enum:
        - TEMPLATING_RUN_STATE_UNSPECIFIED
        - QUEUED
        - RUNNING
        - SUCCEEDED
        - FAILED
        - STALLED
    Date:
      type: string
      description: >-
        Date and time in UTC, with a numeric offset and no colon, for example
        `2026-10-28T13:51:31+0000`.
      examples:
        - 2026-10-28T13:51:31+0000
  responses:
    Unauthorized:
      description: The access token is missing, invalid, or expired. Request a new token.
    TooManyRequests:
      description: >-
        A rate-limit window is exhausted. Wait, then retry with increasing
        delays.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >
        Paste an access token from [Create an access
        token](/products/kode-api/api-reference/authentication/create-an-access-token).
        Tokens expire, so request a new one if you receive `401`.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.