Litmus Edge 4.4.x - Digital Twins

Dynamic attributes and transformations bind to live tag data, which arrives as a flat DeviceHub/DataHub message (fields value, tagName, deviceID, datatype, timestamp, ... no payload wrapper). Full shape and field types: /reference/devicehub-message-format.md.

List Static Attributes

POST {{edgeUrl}}/digital-twins/v2

Updated in 4.3.x. This item replaces its 4.2.x counterpart.

The query itself is unchanged. What changed is AttributeType, which gains a third member: it is now Regular | UNS | AssetHierarchy.

Value Meaning
Regular An ordinary static attribute
UNS Derived from the Unified Namespace
AssetHierarchy New in 4.3.x. Derived from the asset hierarchy set by SetInstanceAssetHierarchy

This is the read path for asset hierarchy placement, and the reason this item sits in this folder.

Worth checking in client code: any switch or if/else over AttributeType written against 4.2.x handled two values and will now meet a third. The schema change is additive, but an exhaustive match that assumed two members is where it shows up. Make sure the default branch does something sensible.

Request Body

GraphQL Query

query ListStaticAttributes($input: ListStaticAttributeRequest!) {
    ListStaticAttributes(input: $input) {
        ID
        ModelID
        InstanceID
        Key
        Value
        AttributeType
        CreatedAt
        UpdatedAt
    }
}

Variables

{
  "input": {
    "ModelID": "{{dt_model_id}}",
    "InstanceID": "{{dt_instance_id}}",
    "Limit": 100,
    "Offset": 0
  }
}

Create Static Attribute

POST {{edgeUrl}}/digital-twins

Create Static Attribute

Requires: an existing model. The ModelID is not checked: an unknown ID still returns a new attribute that belongs to no model. Confirm the model with List Models before creating attributes.

Creates a new static attribute on a model. The attribute is part of the model's schema and is inherited by every instance unless overridden.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation CreateStaticAttributes($input: CreateStaticAttributesRequest!) {
  CreateStaticAttributes(input: $input) {
    ID
    ModelID
    InstanceID
    Key
    Value
    CreatedAt
    UpdatedAt
  }
}

The singular CreateStaticAttribute mutation is deprecated in the schema ("No longer supported"). It still executes, but use the batch form above.

Variables (input: CreateStaticAttributesRequest!)

Field Type Required Description
Items [Item!]! Yes One entry per attribute to create.
Items[].ModelID ID Yes UUID of the model to attach the attribute to.
Items[].Key String Yes Attribute name. Must be unique within the model.
Items[].Value String Yes Attribute value.
{
  "input": {
    "Items": [
      {
        "ModelID": "{{digital_twins_model_id}}",
        "Key": "Model",
        "Value": "New API Model"
      }
    ]
  }
}

Response

200 OK -- application/json. An array, one element per item submitted, each the same shape as one element of List Static Attributes.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation CreateStaticAttributes ($input: CreateStaticAttributesRequest!) {
    CreateStaticAttributes(input: $input) {
        ID
        ModelID
        InstanceID
        Key
        Value
        CreatedAt
        UpdatedAt
    }
}

Variables

{
    "input": {
        "Items": [
            {
                "ModelID": "{{digital_twins_model_id}}",
                "Key": "Model",
                "Value": "New API Model"
            }
        ]
    }
}

Response

Status: 200 OK

{
    "data": {
        "CreateStaticAttributes": [
            {
                "ID": "63E4BD05-CE85-41CD-99A6-F69CCD171240",
                "ModelID": "3A923971-5DFC-4633-B5AF-A6BF8C0B60E9",
                "InstanceID": null,
                "Key": "Model",
                "Value": "New API Model",
                "CreatedAt": "2023-08-16T00:13:38.224123983Z",
                "UpdatedAt": "2023-08-16T00:13:38.224126007Z"
            }
        ]
    }
}

Update Static Attribute

POST {{edgeUrl}}/digital-twins

Update Static Attribute

Updates the Key or Value of an existing static attribute. Pass the attribute's ID plus the new values. Identical schema is used to update both model-level definitions and instance-level overrides -- the endpoint behaves the same in either case.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation UpdateStaticAttributes($input: UpdateStaticAttributesRequest!) {
  UpdateStaticAttributes(input: $input) {
    ID
    ModelID
    InstanceID
    Key
    Value
    CreatedAt
    UpdatedAt
  }
}

The singular UpdateStaticAttribute mutation is deprecated in the schema ("No longer supported"). It still executes, but use the batch form above.

Variables (input: UpdateStaticAttributesRequest!)

Field Type Required Description
Items [Item!]! Yes One entry per attribute to update.
Items[].ID ID Yes UUID of the static attribute.
Items[].ModelID ID Yes UUID of the parent model.
Items[].Key String Yes New attribute name. Must be unique within the model.
Items[].Value String Yes New attribute value.
{
  "input": {
    "Items": [
      {
        "ID": "{{digital_twins_static_attribute_id}}",
        "ModelID": "{{digital_twins_model_id}}",
        "Key": "Model",
        "Value": "Updated Value API Model"
      }
    ]
  }
}

Response

200 OK -- application/json. An array, one element per item submitted, same shape as List Static Attributes, reflecting the post-update values and a refreshed UpdatedAt.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation UpdateStaticAttributes($input:UpdateStaticAttributesRequest!) {
    UpdateStaticAttributes(input: $input) {
        ID
        ModelID
        InstanceID
        Key
        Value
        CreatedAt
        UpdatedAt
    }
}

Variables

{
    "input": {
        "Items": [
            {
                "ID": "{{digital_twins_static_attribute_id}}",
                "ModelID": "{{digital_twins_model_id}}",
                "Key": "Model",
                "Value": "Updated Value API Model"
            }
        ]
    }
}

Response

Status: 200 OK

{
    "data": {
        "UpdateStaticAttributes": [
            {
                "ID": "63E4BD05-CE85-41CD-99A6-F69CCD171240",
                "ModelID": "3A923971-5DFC-4633-B5AF-A6BF8C0B60E9",
                "InstanceID": null,
                "Key": "Model",
                "Value": "Updated Value API Model",
                "CreatedAt": "2023-08-16T00:13:38.224123983Z",
                "UpdatedAt": "2023-08-16T00:23:12.872714078Z"
            }
        ]
    }
}

Delete Static Attribute

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: DeleteStaticAttributeRequest.ID is now required (UUID!).

Delete Static Attribute

Deletes one or more static attributes by ID. Despite the singular name, the mutation accepts a list -- pass any number of items in the Items array.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation DeleteStaticAttributes($input: DeleteStaticAttributesRequest!) {
  DeleteStaticAttributes(input: $input)
}

Variables

Field Type Required Description
Items [Item!]! Yes List of {ID} objects -- one per attribute to delete.
Items[].ID ID Yes UUID of the static attribute.
{
  "input": {
    "Items": [
      { "ID": "{{digital_twins_static_attribute_id}}" }
    ]
  }
}

Response

200 OK -- application/json. The mutation returns no data on success.

{ "data": { "DeleteStaticAttributes": null } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation DeleteStaticAttributes($input: DeleteStaticAttributesRequest!) {
    DeleteStaticAttributes(input: $input)
}

Variables

{
    "input": {
        "Items": [
            {
                "ID": "{{digital_twins_static_attribute_id}}"
            }
        ]
    }
}

Response

Status: 200 OK

{
    "data": {
        "DeleteStaticAttributes": null
    }
}

Upload an Image

POST {{edgeUrl}}/digital-twins

Upload an Image

Uploads an image to associate with a digital twin model (e.g. a photo or diagram of the asset). Multipart form-data request following the GraphQL multipart request spec.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body (form-data parts)

Form key Type Description
operations text GraphQL envelope describing the mutation, with null placeholder for the file.
map text JSON mapping form file keys to placeholder locations within operations.
1 file The image file (binary). The form key (1) must match what appears in map.

operations value

{
  "operationName": "UploadImage",
  "variables": { "input": { "ObjectID": "{{digital_twins_model_id}}", "File": null } },
  "query": "mutation UploadImage($input: ImageRequest!) { UploadImage(input: $input) }"
}

map value

{ "1": ["variables.input.File"] }

The ObjectID is the model UUID; the same endpoint is reused on instances by passing an instance UUID.

Response

200 OK -- application/json

Field Type Description
data.UploadImage Boolean true on success.
{ "data": { "UploadImage": true } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

Response

Status: 200 OK

{
    "data": {
        "UploadImage": true
    }
}

Delete an Image

POST {{edgeUrl}}/digital-twins

Delete an Image

Removes the image previously uploaded by Upload an Image from a model (or instance). Idempotent -- deleting when there is no image is a no-op.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation DeleteImage($input: DeleteImageRequest!) {
  DeleteImage(input: $input)
}

Variables

Field Type Required Description
ObjectID ID Yes UUID of the model (or instance) whose image to delete.
{
  "input": {
    "ObjectID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json

Field Type Description
data.DeleteImage Boolean true on success.
{ "data": { "DeleteImage": true } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation DeleteImage($input: DeleteImageRequest!) {
    DeleteImage(input: $input)
}

Variables

{
    "input": {
        "ObjectID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "DeleteImage": true
    }
}

Get an Image

POST {{edgeUrl}}/digital-twins

Get an Image

Returns the image stored for one model or one instance, as a data URI ready to drop into an <img src>. This is how the Digital Twins UI shows the picture on a model or instance page. Upload with Upload an Image, remove with Delete an Image.

ObjectID takes a model UUID or an instance UUID. Instances hold their own image, which can differ from their model's.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query GetImage($input: GetImageRequest!) {
  GetImage(input: $input) {
    ObjectID
    Content
  }
}

Variables (input: GetImageRequest!)

Field Type Required Description
ObjectID UUID! Yes Model or instance UUID.
{
  "input": {
    "ObjectID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json. data.GetImage is an Image:

Field Type Description
ObjectID UUID! The model or instance the image belongs to.
Content String! Data URI, e.g. data:image/png;base64, ... or data:image/svg+xml;base64, ... (truncated in the examples).
{
  "data": {
    "GetImage": {
      "ObjectID": "05B0972B-CAEF-40C8-BE69-0CCB21C0E523",
      "Content": "data:image/svg+xml;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIC4uLg=="
    }
  }
}

An object with no image, or an unknown UUID, returns key not found. To fetch several images in one call, and skip the missing ones instead of failing, use Get Images.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query GetImage($input: GetImageRequest!) {
    GetImage(input: $input) {
        ObjectID
        Content
    }
}

Variables

{
    "input": {
        "ObjectID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "GetImage": {
            "ObjectID": "05B0972B-CAEF-40C8-BE69-0CCB21C0E523",
            "Content": "data:image/svg+xml;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTIiIGhlaWdodD0iMTU2IiB2aWV3Qm94PSIwIDAgMjUyIDE1NiI+PHBhdGggZD0iTTU0IDUwIFE1NCA0NiA1OCA0NiBMMTEyIDQ2IFExMTYgNDYgMTE2IDUwIEwxMTYgNTggTDU0IDU4IFoiIGZpbGw9IiMzMTc4NWIiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNNzggNDggTDg4IDI2IEw4NCAyMCBRODMgMTIgOTEgMTIgTDEyNiAxMCBRMTMzIDEwIDEzMyAxNiBMMTMzIDIxIFExMzMgMjYgMTI3IDI2IEwxMDEgMjggTDkzIDQ4IFoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cmVjdCB4PSIxMjgiIHk9IjEyIiB3aWR0aD0iNiIgaGVpZ2h0PSIxMiIgcng9IjEiIGZpbGw9IiNiZGZmY2MiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48Y2lyY2xlIGN4PSIxMDQiIGN5PSIxMiIgcj0iMi41IiBmaWxsPSIjMzJkZDg5IiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTk2IDMwIEwxMDAgMzYiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48Y2lyY2xlIGN4PSI4NiIgY3k9IjUyIiByPSIyLjUiIGZpbGw9IiMzMmRkODkiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMTM1IDE0IEwxODAgNiBMMTgwIDQyIEwxMzUgMjIgWiIgZmlsbD0iI2JkZmZjYyIgZmlsbC1vcGFjaXR5PSIwLjc1Ii8+PHJlY3QgeD0iMTgwIiB5PSI0IiB3aWR0aD0iNTAiIGhlaWdodD0iNTIiIHJ4PSIyIiBmaWxsPSIjMzJkZDg5IiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHJlY3QgeD0iMTg2IiB5PSIxMiIgd2lkdGg9IjM4IiBoZWlnaHQ9IjI2IiByeD0iMSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjMDAxOTE0IiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxyZWN0IHg9IjE5MSIgeT0iMTYiIHdpZHRoPSIyIiBoZWlnaHQ9IjE2IiBmaWxsPSIjMDAxOTE0Ii8+PHJlY3QgeD0iMTk2IiB5PSIxNiIgd2lkdGg9IjMiIGhlaWdodD0iMTYiIGZpbGw9IiMwMDE5MTQiLz48cmVjdCB4PSIyMDIiIHk9IjE2IiB3aWR0aD0iMiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzAwMTkxNCIvPjxyZWN0IHg9IjIwNyIgeT0iMTYiIHdpZHRoPSIxIiBoZWlnaHQ9IjE2IiBmaWxsPSIjMDAxOTE0Ii8+PHJlY3QgeD0iMjEzIiB5PSIxNiIgd2lkdGg9IjIiIGhlaWdodD0iMTYiIGZpbGw9IiMwMDE5MTQiLz48cGF0aCBkPSJNMTg2IDI0IEwyMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yNCA1OCBMMjI4IDU4IiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PC9zdmc+"
        }
    }
}

Get Images

POST {{edgeUrl}}/digital-twins

Get Images

Batch form of Get an Image: returns the images for a list of models and instances in one call. The Digital Twins UI uses it to draw the thumbnails on the model and instance grids.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query GetImages($input: GetImagesRequest!) {
  GetImages(input: $input) {
    Images {
      ObjectID
      Content
    }
  }
}

Variables (input: GetImagesRequest!)

Field Type Required Description
ObjectIDs [UUID!]! Yes Model and instance UUIDs, in any mix.
{
  "input": {
    "ObjectIDs": [
      "{{digital_twins_model_id}}",
      "{{digital_twins_instance_id}}"
    ]
  }
}

Response

200 OK -- application/json. data.GetImages.Images holds one Image (ObjectID, Content as a data URI) per requested object that has an image. Objects without an image, and unknown UUIDs, are left out rather than raising an error, so match results on ObjectID instead of by position.

{
  "data": {
    "GetImages": {
      "Images": [
        {
          "ObjectID": "05B0972B-CAEF-40C8-BE69-0CCB21C0E523",
          "Content": "data:image/svg+xml;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIC4uLg=="
        }
      ]
    }
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query GetImages($input: GetImagesRequest!) {
    GetImages(input: $input) {
        Images {
            ObjectID
            Content
        }
    }
}

Variables

{
    "input": {
        "ObjectIDs": [
            "{{digital_twins_model_id}}",
            "{{digital_twins_instance_id}}"
        ]
    }
}

Response

Status: 200 OK

{
    "data": {
        "GetImages": {
            "Images": [
                {
                    "ObjectID": "05B0972B-CAEF-40C8-BE69-0CCB21C0E523",
                    "Content": "data:image/svg+xml;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTIiIGhlaWdodD0iMTU2IiB2aWV3Qm94PSIwIDAgMjUyIDE1NiI+PHBhdGggZD0iTTU0IDUwIFE1NCA0NiA1OCA0NiBMMTEyIDQ2IFExMTYgNDYgMTE2IDUwIEwxMTYgNTggTDU0IDU4IFoiIGZpbGw9IiMzMTc4NWIiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNNzggNDggTDg4IDI2IEw4NCAyMCBRODMgMTIgOTEgMTIgTDEyNiAxMCBRMTMzIDEwIDEzMyAxNiBMMTMzIDIxIFExMzMgMjYgMTI3IDI2IEwxMDEgMjggTDkzIDQ4IFoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cmVjdCB4PSIxMjgiIHk9IjEyIiB3aWR0aD0iNiIgaGVpZ2h0PSIxMiIgcng9IjEiIGZpbGw9IiNiZGZmY2MiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48Y2lyY2xlIGN4PSIxMDQiIGN5PSIxMiIgcj0iMi41IiBmaWxsPSIjMzJkZDg5IiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTk2IDMwIEwxMDAgMzYiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48Y2lyY2xlIGN4PSI4NiIgY3k9IjUyIiByPSIyLjUiIGZpbGw9IiMzMmRkODkiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMTM1IDE0IEwxODAgNiBMMTgwIDQyIEwxMzUgMjIgWiIgZmlsbD0iI2JkZmZjYyIgZmlsbC1vcGFjaXR5PSIwLjc1Ii8+PHJlY3QgeD0iMTgwIiB5PSI0IiB3aWR0aD0iNTAiIGhlaWdodD0iNTIiIHJ4PSIyIiBmaWxsPSIjMzJkZDg5IiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHJlY3QgeD0iMTg2IiB5PSIxMiIgd2lkdGg9IjM4IiBoZWlnaHQ9IjI2IiByeD0iMSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjMDAxOTE0IiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxyZWN0IHg9IjE5MSIgeT0iMTYiIHdpZHRoPSIyIiBoZWlnaHQ9IjE2IiBmaWxsPSIjMDAxOTE0Ii8+PHJlY3QgeD0iMTk2IiB5PSIxNiIgd2lkdGg9IjMiIGhlaWdodD0iMTYiIGZpbGw9IiMwMDE5MTQiLz48cmVjdCB4PSIyMDIiIHk9IjE2IiB3aWR0aD0iMiIgaGVpZ2h0PSIxNiIgZmlsbD0iIzAwMTkxNCIvPjxyZWN0IHg9IjIwNyIgeT0iMTYiIHdpZHRoPSIxIiBoZWlnaHQ9IjE2IiBmaWxsPSIjMDAxOTE0Ii8+PHJlY3QgeD0iMjEzIiB5PSIxNiIgd2lkdGg9IjIiIGhlaWdodD0iMTYiIGZpbGw9IiMwMDE5MTQiLz48cGF0aCBkPSJNMTg2IDI0IEwyMjQgMjQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yNCA1OCBMMjI4IDU4IiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PC9zdmc+"
                },
                {
                    "ObjectID": "37A85041-81D8-4FC6-97E5-02BAEF438CFF",
                    "Content": "data:image/svg+xml;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTIiIGhlaWdodD0iMTU2IiB2aWV3Qm94PSIwIDAgMjUyIDE1NiI+PHJlY3QgeD0iMzAiIHk9IjQ4IiB3aWR0aD0iMTcwIiBoZWlnaHQ9IjgiIHJ4PSIyIiBmaWxsPSIjMzE3ODViIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHJlY3QgeD0iNDAiIHk9IjE4IiB3aWR0aD0iNTgiIGhlaWdodD0iMzAiIHJ4PSI1IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTUyIDIyIEw1MiA0NCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAxOTE0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik02MiAyMiBMNjIgNDQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNNzIgMjIgTDcyIDQ0IiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTgyIDIyIEw4MiA0NCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAxOTE0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxyZWN0IHg9Ijk4IiB5PSIyOCIgd2lkdGg9IjEyIiBoZWlnaHQ9IjEwIiByeD0iMiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjMDAxOTE0IiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxjaXJjbGUgY3g9IjEzNyIgY3k9IjMzIiByPSIxNyIgZmlsbD0iIzMxNzg1YiIgc3Ryb2tlPSIjMDAxOTE0IiBzdHJva2Utd2lkdGg9IjMiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxjaXJjbGUgY3g9IjEzNyIgY3k9IjMzIiByPSI2IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTEzNyAxNiBMMTM3IDggTDIxNCA4IiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iNSIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTIxNCAyIEwyMTQgMTQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMTU0IDMzIEwyMTQgMzMiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSI1IiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjE0IDI3IEwyMTQgMzkiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMTkxNCIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMTgwIDggbDYgMCBNMTgzIDUgbDMgMyBsLTMgMyIgc3Ryb2tlPSIjMDAxOTE0IiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yMCA2MiBMMjIwIDYyIiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDE5MTQiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PC9zdmc+"
                }
            ]
        }
    }
}

Get Transformations

POST {{edgeUrl}}/digital-twins

Get Transformations

Lists every transformation defined on a model. A transformation is a named JSON Schema that dynamic attributes can reference to validate or shape their payload before it is published.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ListTransformations($input: ListTransformationRequest!) {
  ListTransformations(input: $input) {
    ID
    Name
    Schema
  }
}

Variables

Field Type Required Description
ModelID ID Yes UUID of the model.
{
  "input": {
    "ModelID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json

Field Type Description
data.ListTransformations [Transformation!]! All transformations on the model.
data.ListTransformations[].ID ID Transformation UUID.
data.ListTransformations[].Name String Display name.
data.ListTransformations[].Schema String JSON Schema as a string. Parse client-side.
{
  "data": {
    "ListTransformations": [
      {
        "ID": "ABF0E58E-2D3C-4E85-A42F-18CFE9D94C91",
        "Name": "apiTransformation",
        "Schema": "{\"key\": \"value\"}"
      }
    ]
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ListTransformations ($input:ListTransformationRequest!){
    ListTransformations(input: $input) {
        ID
        Name
        Schema
    }
}

Variables

{
    "input": {
        "ModelID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "ListTransformations": [
            {
                "ID": "ABF0E58E-2D3C-4E85-A42F-18CFE9D94C91",
                "Name": "apiTransformation",
                "Schema": "{\"key\": \"value\"}"
            },
            {
                "ID": "30D86400-D103-4C5C-95E4-AB6F02FB00EE",
                "Name": "Transformation",
                "Schema": "{\n  \"key\": \"value\"\n}"
            }
        ]
    }
}

Create Transformation

POST {{edgeUrl}}/digital-twins

Create Transformation

Creates a new transformation on a model. The Schema is a JSON Schema document represented as a string.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation CreateTransformation($input: CreateTransformationRequest!) {
  CreateTransformation(input: $input) {
    ID
    Name
    Schema
  }
}

Variables

Field Type Required Description
ModelID ID Yes UUID of the parent model.
Name String Yes Transformation name. Must be unique in the model.
Schema String Yes JSON Schema as a string.
{
  "input": {
    "ModelID": "{{digital_twins_model_id}}",
    "Name": "apiTransformation",
    "Schema": "{\"key\": \"value\"}"
  }
}

Response

200 OK -- application/json. Returns the new transformation.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation CreateTransformation($input: CreateTransformationRequest!) {
  CreateTransformation(input: $input) {
    ID
    Name
    Schema
  }
}

Variables

{
  "input": {
    "ModelID": "{{digital_twins_model_id}}",
    "Name": "apiTransformation",
    "Schema": "{\"key\": \"value\"}"
  }
}

Response

Status: 200 OK

{
    "data": {
        "CreateTransformation": {
            "ID": "ABF0E58E-2D3C-4E85-A42F-18CFE9D94C91",
            "Name": "apiTransformation",
            "Schema": "{\"key\": \"value\"}"
        }
    }
}

Update Transformation

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: UpdateTransformationRequest.ID is now required (UUID!).

Update Transformation

Updates the Name and/or Schema of an existing transformation.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation UpdateTransformation($input: UpdateTransformationRequest!) {
  UpdateTransformation(input: $input) {
    ID
    Name
    Schema
  }
}

Variables

Field Type Required Description
ID ID Yes UUID of the transformation.
Name String Yes New transformation name.
Schema String Yes New JSON Schema (as a string).
{
  "input": {
    "ID": "{{digital_twins_transformation_id}}",
    "Name": "updatedTransformation",
    "Schema": "{\"updatedKey\": \"updatedValue\"}"
  }
}

Response

200 OK -- application/json. Returns the updated transformation.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation UpdateTransformation ($input: UpdateTransformationRequest!) {
    UpdateTransformation(input: $input) {
        ID
        Name
        Schema
    }
}

Variables

{
    "input": {
        "ID": "{{digital_twins_transformation_id}}",
        "Name": "updatedTransformation",
        "Schema": "{\"updatedKey\": \"updatedValue\"}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "UpdateTransformation": {
            "ID": "ABF0E58E-2D3C-4E85-A42F-18CFE9D94C91",
            "Name": "updatedTransformation",
            "Schema": "{\"updatedKey\": \"updatedValue\"}"
        }
    }
}

Delete Transformation

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: DeleteTransformationRequest.ID is now required (UUID!).

Delete Transformation

Deletes a single transformation by ID. Dynamic attributes that referenced the deleted transformation will fall back to no validation.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation DeleteTransformation($input: DeleteTransformationRequest!) {
  DeleteTransformation(input: $input)
}

Variables

Field Type Required Description
ID ID Yes UUID of the transformation.
{
  "input": {
    "ID": "{{digital_twins_transformation_id}}"
  }
}

Response

200 OK -- application/json. No data returned on success.

{ "data": { "DeleteTransformation": null } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation DeleteTransformation ($input: DeleteTransformationRequest!){
    DeleteTransformation(input: $input)
}

Variables

{
    "input": {
        "ID": "{{digital_twins_transformation_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "DeleteTransformation": null
    }
}

Validate Transformation

POST {{edgeUrl}}/digital-twins

Validate Transformation

Checks that a transformation expression compiles before you save it with Create Transformation or Update Transformation. The Digital Twins UI runs it as you type in the transformation editor. Nothing is stored.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ValidateTransformation($input: ValidateTransformationRequest!) {
  ValidateTransformation(input: $input)
}

Variables (input: ValidateTransformationRequest!)

Field Type Required Description
Expression String! Yes The expression to check.
SchemaType SchemaType! Yes jsonata for a JSONata expression, json for a JSON document.
{
  "input": {
    "Expression": "$.temperature * 1.8 + 32",
    "SchemaType": "jsonata"
  }
}

Response

200 OK -- application/json. data.ValidateTransformation is true when the expression is valid.

{ "data": { "ValidateTransformation": true } }

An invalid expression does not return false; it returns an error carrying the parser's message, which the UI shows under the editor:

{
  "errors": [
    {
      "message": "failed to compile jsonata expression: JSONata error S0201 at token \"EOF\": unexpected end of expression",
      "path": ["ValidateTransformation"]
    }
  ],
  "data": null
}

With SchemaType: json the message starts schema validation failed: json parsing error.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ValidateTransformation($input: ValidateTransformationRequest!) {
    ValidateTransformation(input: $input)
}

Variables

{
    "input": {
        "Expression": "$.temperature * 1.8 + 32",
        "SchemaType": "jsonata"
    }
}

Response

Status: 200 OK

{
    "data": {
        "ValidateTransformation": true
    }
}

List Parameters

POST {{edgeUrl}}/digital-twins

List Parameters

Returns the parameters defined on the given owner. OwnerID is the UUID of either a model or an instance. Parameters are free-form Name/Value strings used by integrations and the LE UI for ad-hoc configuration that isn't surfaced as static/dynamic attributes.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ListParameters($input: ListParametersRequest) {
  ListParameters(input: $input) {
    ID
    Name
    Value
  }
}

Variables

Field Type Required Description
OwnerID ID Yes UUID of the model or instance that owns the parameters.
{
  "input": {
    "OwnerID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json

Field Type Description
data.ListParameters [Parameter!]! All parameters on the owner.
data.ListParameters[].ID ID Parameter UUID.
data.ListParameters[].Name String Parameter name.
data.ListParameters[].Value String Parameter value.
{
  "data": {
    "ListParameters": [
      { "ID": "51D2E713-6150-4800-8779-9A1825BE19D7", "Name": "Updated key", "Value": "Updated value" },
      { "ID": "8FA45411-ECA0-44C0-BD2F-60341D55C581", "Name": "key1",        "Value": "value1" }
    ]
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ListParameters($input: ListParametersRequest) {
  ListParameters(input: $input) {
    ID
    Name
    Value
  }
}

Variables

{
    "input": {
        "OwnerID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "ListParameters": [
            {
                "ID": "51D2E713-6150-4800-8779-9A1825BE19D7",
                "Name": "Updated key",
                "Value": "Updated value"
            },
            {
                "ID": "8FA45411-ECA0-44C0-BD2F-60341D55C581",
                "Name": "key1",
                "Value": "value1"
            }
        ]
    }
}

Set Parameters

POST {{edgeUrl}}/digital-twins

Set Parameters (transactional)

Applies a set of parameter changes to a model atomically using the transactional model update mutation. The same mutation is used to create, update, and delete parameters in one call; Delete Parameters uses a payload that includes only the delete portion.

This is the same endpoint used by the LE UI to commit edits to a model's schema in one round-trip.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation TransactionalModelUpdate($input: TransactionalModelUpdateRequest!) {
  TransactionalModelUpdate(input: $input)
}

Variables

The input is an envelope of per-operation arrays. Send only the arrays you need; the others can be empty Items: [].

Field Type Description
modelID ID UUID of the target model.
createStaticAttributes { Items } List of CreateStaticAttribute payloads to apply.
updateStaticAttributes { Items } List of UpdateStaticAttribute payloads.
delStaticAttributes { Items } List of {ID} objects for static attributes to delete.
createDynamicAttributes { Items } List of CreateDynamicAttribute payloads.
updateDynamicAttributes { Items } List of UpdateDynamicAttribute payloads.
delDynamicAttributes { Items } List of {ID} objects.
createParameters { Items } List of {Name, Value, OwnerID} parameter payloads to create.
updateParameters { Items } List of {ID, Name, Value} parameter payloads to update.
delParameters { Items } List of {ID} objects for parameters to delete.

For the parameter-only use case, leave every attribute-related array empty and populate just createParameters / updateParameters / delParameters.

{
  "input": {
    "modelID": "{{digital_twins_model_id}}",
    "createStaticAttributes":  { "Items": [] },
    "updateStaticAttributes":  { "Items": [] },
    "delStaticAttributes":     { "Items": [] },
    "createDynamicAttributes": { "Items": [] },
    "updateDynamicAttributes": { "Items": [] },
    "delDynamicAttributes":    { "Items": [] }
  }
}

Response

200 OK -- application/json. The mutation returns no data; failures surface in the GraphQL errors array.

{ "data": { "TransactionalModelUpdate": null } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation TransactionalModelUpdate($input: TransactionalModelUpdateRequest!) {
    TransactionalModelUpdate(input: $input)
}

Variables

{
    "input": {
        "modelID": "{{digital_twins_model_id}}",
        "createStaticAttributes": {
            "Items": []
        },
        "updateStaticAttributes": {
            "Items": []
        },
        "delStaticAttributes": {
            "Items": []
        },
        "createDynamicAttributes": {
            "Items": []
        },
        "updateDynamicAttributes": {
            "Items": []
        },
        "delDynamicAttributes": {
            "Items": []
        },
        "createTransformations": [],
        "updateTransformations": [],
        "deleteTransformations": [],
        "setParameters": {
            "Items": [
                {
                    "ID": "8fa45411-eca0-44c0-bd2f-60341d55c581",
                    "Name": "key1",
                    "Value": "value1"
                },
                {
                    "ID": "51d2e713-6150-4800-8779-9a1825be19d7",
                    "Name": "Updated key",
                    "Value": "Updated value"
                }
            ]
        },
        "deleteParameters": {
            "Items": []
        }
    }
}

Response

Status: 200 OK

{
    "data": {
        "TransactionalModelUpdate": null
    }
}

Delete Parameters

POST {{edgeUrl}}/digital-twins

Delete Parameters (transactional)

Variant of Set Parameters for the delete-only case. The mutation is identical (TransactionalModelUpdate); only the populated arrays differ.

To delete one or more parameters, populate delParameters.Items with {ID} objects.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation TransactionalModelUpdate($input: TransactionalModelUpdateRequest!) {
  TransactionalModelUpdate(input: $input)
}

Variables (delete-only example)

{
  "input": {
    "modelID": "{{digital_twins_model_id}}",
    "createStaticAttributes":  { "Items": [] },
    "updateStaticAttributes":  { "Items": [] },
    "delStaticAttributes":     { "Items": [] },
    "createDynamicAttributes": { "Items": [] },
    "updateDynamicAttributes": { "Items": []  }
  }
}

The above example shows the envelope without any deletions populated -- in practice you would fill delParameters.Items: [{ID: "..."}] with the parameter UUIDs to remove. See Set Parameters for the full set of arrays the envelope supports.

Response

200 OK -- application/json. No data returned on success.

{ "data": { "TransactionalModelUpdate": null } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

    mutation TransactionalModelUpdate($input: TransactionalModelUpdateRequest!) {
        TransactionalModelUpdate(input: $input)
    }

Variables

{
  "input": {
    "modelID": "{{digital_twins_model_id}}",
    "createStaticAttributes": {
      "Items": []
    },
    "updateStaticAttributes": {
      "Items": []
    },
    "delStaticAttributes": {
      "Items": []
    },
    "createDynamicAttributes": {
      "Items": []
    },
    "updateDynamicAttributes": {
      "Items": []
    },
    "delDynamicAttributes": {
      "Items": []
    },
    "createTransformations": [],
    "updateTransformations": [],
    "deleteTransformations": [],
    "setParameters": {
      "Items": [
        {
          "ID": "56daf3aa-bdec-4e7e-8d6a-a5229eaa2988",
          "Name": "hi",
          "Value": "hello"
        }
      ]
    },
    "deleteParameters": {
      "Items": [
        {
          "ID": "51D2E713-6150-4800-8779-9A1825BE19D7"
        },
        {
          "ID": "56DAF3AA-BDEC-4E7E-8D6A-A5229EAA2988"
        }
      ]
    }
  }
}

Response

Status: 200 OK

{
    "data": {
        "TransactionalModelUpdate": null
    }
}

Get Hierarchy

POST {{edgeUrl}}/digital-twins

Get Hierarchy

Returns the current hierarchy of a model as a nested tree. The hierarchy defines how attributes are organized into folders inside the model -- the same structure the LE UI shows in the model editor's tree view.

Each node references either an attribute (via AttributeID) or is a folder (IsFolder: true). Nodes may have child nodes via Childs.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query GetHierarchy($input: GetHierarchyRequest!) {
  GetHierarchy(input: $input)
}

Variables

Field Type Required Description
ModelID ID Yes UUID of the model.
{
  "input": {
    "ModelID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json. data.GetHierarchy is a single root node:

Field Type Description
Name String Node display name. "root" for the synthetic root.
Node Node? Backing node record (null for the synthetic root).
Node.ID ID Node UUID.
Node.ModelID ID Parent model.
Node.Position Int Display order among siblings (0-indexed).
Node.ParentID ID? UUID of the parent node, or null for top-level nodes.
Node.IsFolder Boolean true for organizational folders; false for attribute references.
Node.AttributeID ID? UUID of the referenced static or dynamic attribute. Empty for folders.
Attr object? Resolved attribute record (denormalized for UI convenience).
Childs [Node] Child nodes (recursive).
{
  "data": {
    "GetHierarchy": {
      "Name": "root",
      "Node": null,
      "Attr": null,
      "Childs": [
        {
          "Name": "Manufacturer",
          "Node": {
            "ID": "d476d3df-8794-4d57-a991-623e8811fb6b",
            "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
            "Position": 0,
            "ParentID": null,
            "Name": "Manufacturer",
            "IsFolder": false,
            "AttributeID": "189edb70-1029-4ebf-ab40-27e5423c12ce"
          }
        }
      ]
    }
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query GetHierarchy ($input : GetHierarchyRequest!){
    GetHierarchy(input: $input)
}

Variables

{
    "input": {
        "ModelID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "GetHierarchy": {
            "Name": "root",
            "Node": null,
            "Attr": null,
            "Childs": [
                {
                    "Name": "Manufacturer",
                    "Node": {
                        "ID": "d476d3df-8794-4d57-a991-623e8811fb6b",
                        "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "Position": 0,
                        "ParentID": null,
                        "Name": "Manufacturer",
                        "IsFolder": false,
                        "AttributeID": "189edb70-1029-4ebf-ab40-27e5423c12ce",
                        "AttributeType": "static",
                        "CreatedAt": "2023-08-17T17:31:55.670316457Z",
                        "IndexUniqueAttrID": "root189edb70-1029-4ebf-ab40-27e5423c12ce",
                        "IndexType": "hierarchy_nodes",
                        "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
                    },
                    "Attr": {
                        "ID": "189edb70-1029-4ebf-ab40-27e5423c12ce",
                        "ParentID": "00000000-0000-0000-0000-000000000000",
                        "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "InstanceID": "00000000-0000-0000-0000-000000000000",
                        "Key": "Manufacturer",
                        "Value": "API Manufacturer",
                        "CreatedAt": "2023-08-16T00:03:50.174589529Z",
                        "UpdatedAt": "2023-08-16T00:23:38.740405183Z",
                        "IndexType": "static_attributes",
                        "IndexModelID": "static_attributes3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "IndexInstanceID": "static_attributes00000000-0000-0000-0000-000000000000",
                        "IndexUniqueModelIDName": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9Manufacturer"
                    },
                    "Childs": []
                },
                {
                    "Name": "New_Node",
                    "Node": {
                        "ID": "2562cb6d-36c1-47b2-bfac-1495377db3a5",
                        "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "Position": 1,
                        "ParentID": null,
                        "Name": "New_Node",
                        "IsFolder": true,
                        "AttributeID": null,
                        "AttributeType": null,
                        "CreatedAt": "2023-08-17T17:31:55.670579242Z",
                        "IndexUniqueAttrID": "root2562cb6d-36c1-47b2-bfac-1495377db3a5",
                        "IndexType": "hierarchy_nodes",
                        "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
                    },
                    "Attr": null,
                    "Childs": [
                        {
                            "Name": "Model",
                            "Node": {
                                "ID": "e028e1d1-9212-4e5b-8290-46104491ce93",
                                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                                "Position": 0,
                                "ParentID": "2562cb6d-36c1-47b2-bfac-1495377db3a5",
                                "Name": "Model",
                                "IsFolder": false,
                                "AttributeID": "3f44c811-d8cc-4735-b337-a0f30826641e",
                                "AttributeType": "static",
                                "CreatedAt": "2023-08-17T17:31:55.670918962Z",
                                "IndexUniqueAttrID": "2562cb6d-36c1-47b2-bfac-1495377db3a53f44c811-d8cc-4735-b337-a0f30826641e",
                                "IndexType": "hierarchy_nodes",
                                "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
                            },
                            "Attr": {
                                "ID": "3f44c811-d8cc-4735-b337-a0f30826641e",
                                "ParentID": "00000000-0000-0000-0000-000000000000",
                                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                                "InstanceID": "00000000-0000-0000-0000-000000000000",
                                "Key": "Model",
                                "Value": "New API Model",
                                "CreatedAt": "2023-08-16T17:29:11.461961315Z",
                                "UpdatedAt": "2023-08-16T17:29:11.461962629Z",
                                "IndexType": "static_attributes",
                                "IndexModelID": "static_attributes3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                                "IndexInstanceID": "static_attributes00000000-0000-0000-0000-000000000000",
                                "IndexUniqueModelIDName": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9Model"
                            },
                            "Childs": []
                        }
                    ]
                }
            ]
        }
    }
}

Save All Hierarchy

POST {{edgeUrl}}/digital-twins

Save All Hierarchy

Replaces the entire hierarchy of a model in a single call. The mutation accepts the same nested tree shape that Get Hierarchy returns (with arrays of {Node, Childs} entries). Existing hierarchy nodes are reconciled; missing ones are deleted; new ones are created.

Use this when programmatically building or editing a model's tree -- it is much cheaper than per-node mutations.

Updated in 4.1.x: UpdateHierarchyNodeRequest.ID / DeleteHierarchyNodeRequest.ID is now required (UUID!).

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation SaveAllHierarchy($modelId: UUID!, $input: [SaveAllHierarchyRequest]!) {
  SaveAllHierarchy(modelId: $modelId, input: $input)
}

Variables

Field Type Required Description
modelId UUID! Yes UUID of the model whose hierarchy to replace.
input [SaveAllHierarchyRequest]! Yes Top-level nodes. Each node has Node (a {AttributeID, AttributeType, IsFolder, Name, Position} payload) and Childs (recursive).
{
  "modelId": "{{digital_twins_model_id}}",
  "input": [
    {
      "Node": {
        "AttributeID": "189edb70-1029-4ebf-ab40-27e5423c12ce",
        "AttributeType": "static",
        "IsFolder": false,
        "Name": "Manufacturer",
        "Position": 0
      },
      "Childs": []
    }
  ]
}

AttributeType is "static" or "dynamic" and must match the kind of the attribute referenced by AttributeID.

Node.Name character rules

Node names are validated server-side and reject on a notAllowedCharacters tag.

Effective allowlist: Unicode letters, digits, space, _, - and .

Spaces and dots are permitted here, unlike Model.Name. Rejected: / & ( ) % , : + ' ° * ! ? @ # $ ^ ~ ; = [ ] { } | \ " < >. Unicode letters such as µ and Ω pass; the Unicode symbol ° does not.

The ampersand is the common trip-up: folder names like Motor & Drive or Process & Quality are rejected and have to be written Motor and Drive.

Response

200 OK -- application/json. Returns the persisted nodes with their freshly-assigned/refreshed UUIDs.

{
  "data": {
    "SaveAllHierarchy": [
      {
        "ID": "71ae472d-b2d5-43fd-8824-80aee150791b",
        "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
        "Position": 0,
        "ParentID": "8cd29a23-816e-4f53-bd88-aed2a0564724",
        "Name": "Model",
        "IsFolder": false,
        "AttributeID": "3f44c811-d8cc-4735-b337-a0f30826641e",
        "AttributeType": "static",
        "CreatedAt": "2023-08-18T21:57:49.16464345Z"
      }
    ]
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation SaveAllHierarchy($modelId: UUID!, $input: [SaveAllHierarchyRequest]!) {
  SaveAllHierarchy(modelId: $modelId, input: $input)
}

Variables

{
  "modelId": "{{digital_twins_model_id}}",
  "input": [
    {
      "Node": {
        "AttributeID": "189edb70-1029-4ebf-ab40-27e5423c12ce",
        "AttributeType": "static",
        "IsFolder": false,
        "Name": "Manufacturer",
        "Position": 0
      },
      "Childs": []
    },
    {
      "Node": {
        "AttributeID": null,
        "AttributeType": null,
        "IsFolder": true,
        "Name": "New_Node",
        "Position": 1
      },
      "Childs": [
        {
          "Node": {
            "AttributeID": "3f44c811-d8cc-4735-b337-a0f30826641e",
            "AttributeType": "static",
            "IsFolder": false,
            "Name": "Model",
            "Position": 0
          },
          "Childs": []
        },
        {
          "Node": {
            "AttributeID": "31A6EDDC-A455-4126-981C-0A6313915A89",
            "AttributeType": "dynamic",
            "IsFolder": false,
            "Name": "Speed",
            "Position": 1
          },
          "Childs": []
        },
        {
          "Node": {
            "AttributeID": null,
            "AttributeType": null,
            "IsFolder": true,
            "Name": "New_Node",
            "Position": 2
          },
          "Childs": [
            {
              "Node": {
                "AttributeID": "3F44C811-D8CC-4735-B337-A0F30826641E",
                "AttributeType": "static",
                "IsFolder": false,
                "Name": "Model",
                "Position": 0
              },
              "Childs": []
            }
          ]
        }
      ]
    }
  ]
}

Response

Status: 200 OK

{
    "data": {
        "SaveAllHierarchy": [
            {
                "ID": "71ae472d-b2d5-43fd-8824-80aee150791b",
                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                "Position": 0,
                "ParentID": "8cd29a23-816e-4f53-bd88-aed2a0564724",
                "Name": "Model",
                "IsFolder": false,
                "AttributeID": "3f44c811-d8cc-4735-b337-a0f30826641e",
                "AttributeType": "static",
                "CreatedAt": "2023-08-18T21:57:49.16464345Z",
                "IndexUniqueAttrID": "8cd29a23-816e-4f53-bd88-aed2a05647243f44c811-d8cc-4735-b337-a0f30826641e",
                "IndexType": "hierarchy_nodes",
                "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
            },
            {
                "ID": "8424515e-a7f8-4cf4-b577-8ef999388538",
                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                "Position": 0,
                "ParentID": null,
                "Name": "Manufacturer",
                "IsFolder": false,
                "AttributeID": "189edb70-1029-4ebf-ab40-27e5423c12ce",
                "AttributeType": "static",
                "CreatedAt": "2023-08-18T21:57:49.163896372Z",
                "IndexUniqueAttrID": "root189edb70-1029-4ebf-ab40-27e5423c12ce",
                "IndexType": "hierarchy_nodes",
                "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
            },
            {
                "ID": "d0d06af4-be65-4d2b-943c-4b2487f7e365",
                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                "Position": 0,
                "ParentID": "92c483ac-5949-4a55-84c5-4e55c281ff87",
                "Name": "Model",
                "IsFolder": false,
                "AttributeID": "3f44c811-d8cc-4735-b337-a0f30826641e",
                "AttributeType": "static",
                "CreatedAt": "2023-08-18T21:57:49.165856053Z",
                "IndexUniqueAttrID": "92c483ac-5949-4a55-84c5-4e55c281ff873f44c811-d8cc-4735-b337-a0f30826641e",
                "IndexType": "hierarchy_nodes",
                "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
            },
            {
                "ID": "14ce6813-11b7-41d0-b785-ce1fdcdaf6b0",
                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                "Position": 1,
                "ParentID": "8cd29a23-816e-4f53-bd88-aed2a0564724",
                "Name": "Speed",
                "IsFolder": false,
                "AttributeID": "31a6eddc-a455-4126-981c-0a6313915a89",
                "AttributeType": "dynamic",
                "CreatedAt": "2023-08-18T21:57:49.165069353Z",
                "IndexUniqueAttrID": "8cd29a23-816e-4f53-bd88-aed2a056472431a6eddc-a455-4126-981c-0a6313915a89",
                "IndexType": "hierarchy_nodes",
                "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
            },
            {
                "ID": "8cd29a23-816e-4f53-bd88-aed2a0564724",
                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                "Position": 1,
                "ParentID": null,
                "Name": "New_Node",
                "IsFolder": true,
                "AttributeID": null,
                "AttributeType": null,
                "CreatedAt": "2023-08-18T21:57:49.164185815Z",
                "IndexUniqueAttrID": "root8cd29a23-816e-4f53-bd88-aed2a0564724",
                "IndexType": "hierarchy_nodes",
                "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
            },
            {
                "ID": "92c483ac-5949-4a55-84c5-4e55c281ff87",
                "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                "Position": 2,
                "ParentID": "8cd29a23-816e-4f53-bd88-aed2a0564724",
                "Name": "New_Node",
                "IsFolder": true,
                "AttributeID": null,
                "AttributeType": null,
                "CreatedAt": "2023-08-18T21:57:49.165520481Z",
                "IndexUniqueAttrID": "8cd29a23-816e-4f53-bd88-aed2a056472492c483ac-5949-4a55-84c5-4e55c281ff87",
                "IndexType": "hierarchy_nodes",
                "IndexModelID": "hierarchy_nodes3a923971-5dfc-4633-b5af-a6bf8c0b60e9"
            }
        ]
    }
}

Download Hierarchy CSV

POST {{edgeUrl}}/digital-twins

Download Hierarchy CSV

Exports a model's attribute hierarchy as CSV: one row per folder or attribute node. This is the Export CSV action on the model's Hierarchy tab, which saves the result as hierarchy-<ModelID>.csv. Use it to back up a hierarchy or edit it offline.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query DownloadHierarchyCSV($input: DownloadCSVRequest!) {
  DownloadHierarchyCSV(input: $input)
}

Variables (input: DownloadCSVRequest!)

Field Type Required Description
ModelID UUID! Yes Model whose hierarchy to export.
InstanceID UUID No Accepted, but on LE 4.0.x the output is the model's hierarchy either way.
{
  "input": {
    "ModelID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json. data.DownloadHierarchyCSV is the CSV as one string (type Any), header row first. Write it to a file as-is.

Column Description
ID Node UUID.
ModelID Owning model.
Position Order among siblings, from 0.
ParentID Parent node UUID; empty for a top-level folder.
Name Node name.
IsFolder true for a folder, false for an attribute.
AttributeID Attribute UUID; the nil UUID for a folder.
AttributeType static or dynamic for an attribute; empty for a folder.
NodeType folder or attribute.
{
  "data": {
    "DownloadHierarchyCSV": "ID,ModelID,Position,ParentID,Name,IsFolder,AttributeID,AttributeType,NodeType\n10796e93-725f-417e-9b75-957b6e32b90f,139fabdc-5ab1-461c-b231-5fb69c47ef77,1,c7a18a59-8b29-4749-8399-fbf75d98f492,LocationId,false,38e78057-60c1-4f21-9683-10693c49feeb,static,attribute\n...\nc7a18a59-8b29-4749-8399-fbf75d98f492,139fabdc-5ab1-461c-b231-5fb69c47ef77,0,,Properties,true,00000000-0000-0000-0000-000000000000,,folder\n"
  }
}

Rows are not sorted by hierarchy; rebuild the tree from ParentID and Position. An unknown ModelID is not an error: it returns the header row only.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query DownloadHierarchyCSV($input: DownloadCSVRequest!) {
    DownloadHierarchyCSV(input: $input)
}

Variables

{
    "input": {
        "ModelID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "DownloadHierarchyCSV": "ID,ModelID,Position,ParentID,Name,IsFolder,AttributeID,AttributeType,NodeType\n10796e93-725f-417e-9b75-957b6e32b90f,139fabdc-5ab1-461c-b231-5fb69c47ef77,1,c7a18a59-8b29-4749-8399-fbf75d98f492,LocationId,false,38e78057-60c1-4f21-9683-10693c49feeb,static,attribute\n5597b5cd-4b14-4c31-8a88-1c6c1b98d285,139fabdc-5ab1-461c-b231-5fb69c47ef77,4,c7a18a59-8b29-4749-8399-fbf75d98f492,UpdatedAt,false,e8aeda58-b04f-4447-a859-51be459aa469,static,attribute\n609e32dd-730b-4739-bb8e-475e0df8e8b7,139fabdc-5ab1-461c-b231-5fb69c47ef77,2,c7a18a59-8b29-4749-8399-fbf75d98f492,GlobalUuid,false,593b3aab-afb6-42dd-ad90-cbc2188c52a6,static,attribute\nb968782d-8c4b-4065-96a2-7b0a75663af9,139fabdc-5ab1-461c-b231-5fb69c47ef77,3,c7a18a59-8b29-4749-8399-fbf75d98f492,CreatedAt,false,b2e7155f-41cf-4e47-bc71-4e01126111bd,static,attribute\nc7a18a59-8b29-4749-8399-fbf75d98f492,139fabdc-5ab1-461c-b231-5fb69c47ef77,0,,Properties,true,00000000-0000-0000-0000-000000000000,,folder\ncaf9472b-75bb-4394-b9bc-13c0ec2a18eb,139fabdc-5ab1-461c-b231-5fb69c47ef77,0,c7a18a59-8b29-4749-8399-fbf75d98f492,Status,false,0d047dc4-50f3-45af-97dc-a71842738b59,static,attribute\n"
    }
}

List all Dynamic Attributes

POST {{edgeUrl}}/digital-twins/v2

Updated in 4.2.x. ListDynamicAttributeRequest gained Limit and Offset.

The replacement path for the removed Model.DynamicAttributes field. Same scoping and paging contract as ListStaticAttributes.

AttrDataType is json | string | number | boolean | array.

Request Body

GraphQL Query

query ListDynamicAttributes($input: ListDynamicAttributeRequest!) {
    ListDynamicAttributes(input: $input) {
        ID
        ModelID
        InstanceID
        Name
        Topic
        Unit
        DataType
        AttrDataType
        SkipParentKey
        SchemaID
        TopicExpression
        TopicExpressionConverted
        CreatedAt
        UpdatedAt
    }
}

Variables

{
  "input": {
    "ModelID": "{{dt_model_id}}",
    "InstanceID": null,
    "Limit": 100,
    "Offset": 0
  }
}

Create Dynamic Attribute

POST {{edgeUrl}}/digital-twins/v2

Requires: an existing model. The ModelID is not checked: an unknown ID still returns a new attribute that belongs to no model, so confirm the model with List Models first. DataType must be one of json, string, number, boolean or array; anything else, such as float, fails with DT_VALIDATION_FAILED.

Updated in 4.3.x. This item replaces its 4.2.x counterpart.

CreateDynamicAttributeRequest gains NestedModelID and NestedInstanceID, and DynamicAttributeType gains a nestedModel member. Together they let one model reference another instead of restating its attributes.

New field Meaning
AttrDataType Now json
NestedModelID The model this attribute embeds
NestedInstanceID The instance this attribute embeds

Set NestedModelID to compose a model definition, or NestedInstanceID to point at one specific instance. They are alternatives: populate one, leave the other null. Both are ignored unless AttrDataType is nestedModel.

Both new fields are optional, so a 4.2.x request body still works unchanged and produces the same non-nested attribute it did before. The selection set above adds AttrDataType, NestedModelID and NestedInstanceID so the nesting is visible in the response; drop them if you do not use nesting.

Keep an eye on what you point at. Nothing stops a model from nesting a chain that leads back to itself, and a cycle only shows up when the twin is resolved, not when the attribute is created.

Topic, Name, Unit and DataType are NON_NULL in the schema: the request fails validation if any of them is absent, even though Unit and Topic are routinely empty strings. Send "" when there is no unit or topic.

Creating a Name that already exists on the model fails with dynamic attribute id is not unique: operation not permitted. The message says id, but the collision is on Name -- ID is server-assigned on create. Names must be unique across the whole model, not per hierarchy node.

Name and Unit character rules

Neither field is a free-form string. Both are validated server-side and reject on a notAllowedCharacters tag with no indication of the allowed set.

Field Allowed Rejected
Name any character none observed
Unit Unicode letters, digits, space, _, -, . everything else, listed below

Unit rejects / & ( ) % , : + ' ° * ! ? @ # $ ^ ~ ; = [ ] { } | \ " < >. It accepts µ and Ω (Unicode letters) but rejects ° (Unicode symbol). Because the solidus is rejected, rate and ratio units such as mm/s, m/s2, L/min and count/min cannot be stored as written, and neither can % or °C. Rewrite them (mm per s) or store the unit elsewhere.

Request Body

GraphQL Query

mutation CreateDynamicAttribute ($input: CreateDynamicAttributeRequest!) {
    CreateDynamicAttribute(input: $input) {
        ID
        ModelID
        InstanceID
        Topic
        Name
        Unit
        DataType
        AttrDataType
        NestedModelID
        NestedInstanceID
        SchemaID
        CreatedAt
        UpdatedAt
    }
}

Variables

{
  "input": {
    "ModelID": "{{dt_model_id}}",
    "InstanceID": null,
    "Topic": "line/1/motor",
    "Name": "motor",
    "Unit": "",
    "DataType": "object",
    "AttrDataType": "nestedModel",
    "NestedModelID": "{{dt_nested_model_id}}",
    "NestedInstanceID": null
  }
}

Update Dynamic Attribute

POST {{edgeUrl}}/digital-twins/v2

Updated in 4.3.x. This item replaces its 4.2.x counterpart.

UpdateDynamicAttributeRequest gains the same NestedModelID and NestedInstanceID fields as the create mutation, so an existing attribute can be converted into a nested-model reference in place.

Set NestedModelID to compose a model definition, or NestedInstanceID to point at one specific instance. They are alternatives: populate one, leave the other null. Both are ignored unless AttrDataType is nestedModel.

This is a full update, not a patch: send the complete attribute. Omitting NestedModelID on an attribute that currently has one clears it, which silently turns a nested reference back into a plain attribute. Read the attribute first if you are updating only one field.

ID, Topic, Name, Unit and DataType are NON_NULL in the schema. Unit follows the same character rules as on create (see Name and Unit character rules under Create Dynamic Attribute).

Request Body

GraphQL Query

mutation UpdateDynamicAttribute ($input: UpdateDynamicAttributeRequest!) {
    UpdateDynamicAttribute(input: $input) {
        ID
        ModelID
        InstanceID
        Topic
        Name
        Unit
        DataType
        AttrDataType
        NestedModelID
        NestedInstanceID
        SchemaID
        CreatedAt
        UpdatedAt
    }
}

Variables

{
  "input": {
    "ID": "{{dt_dynamic_attribute_id}}",
    "ModelID": "{{dt_model_id}}",
    "InstanceID": null,
    "Topic": "line/1/motor",
    "Name": "motor",
    "Unit": "",
    "DataType": "object",
    "AttrDataType": "nestedModel",
    "NestedModelID": "{{dt_nested_model_id}}",
    "NestedInstanceID": null
  }
}

Download Dynamic Attributes

POST {{edgeUrl}}/digital-twins

Download Dynamic Attributes

Exports the dynamic attributes of a model as a CSV string. The CSV is compatible with Upload Dynamic Attribute CSV for round-trip workflows: download, edit in a spreadsheet, re-upload.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query DownloadDynamicAttributesCSV($input: DownloadCSVRequest!) {
  DownloadDynamicAttributesCSV(input: $input)
}

Variables

Field Type Required Description
ModelID ID Yes UUID of the model to export.
{
  "input": {
    "ModelID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json. data.DownloadDynamicAttributesCSV is a CSV-formatted string with header row ID,ModelName,InstanceName,Topic,Name,Unit,DataType,SchemaID.

{
  "data": {
    "DownloadDynamicAttributesCSV": "ID,ModelName,InstanceName,Topic,Name,Unit,DataType,SchemaID\n68280ec1-1c12-4b0d-a7ea-5a9d5ac32092,apiImportModel,,,Speed,kmph,string,4c67a3e1-d442-4b39-b0f6-eb07cc200066\n"
  }
}

Parse the string client-side (it is not a separate file download). To get a true file download, take the string and write it to disk yourself.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query DownloadDynamicAttributesCSV($input: DownloadCSVRequest!) {
    DownloadDynamicAttributesCSV(input: $input)
}

Variables

{
    "input": {
        "ModelID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "DownloadDynamicAttributesCSV": "ID,ModelName,InstanceName,Topic,Name,Unit,DataType,SchemaID\n68280ec1-1c12-4b0d-a7ea-5a9d5ac32092,apiImportModel,,,Speed,kmph,string,4c67a3e1-d442-4b39-b0f6-eb07cc200066\n"
    }
}

Upload Dynamic Attribute CSV

POST {{edgeUrl}}/digital-twins

Upload Dynamic Attribute CSV

Imports dynamic attributes from a CSV file. Uses the GraphQL multipart spec, identical in shape to Models > Static Attributes > Upload an Image.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body (form-data parts)

Form key Type Description
operations text GraphQL envelope describing the mutation, with null placeholder for the file.
map text JSON mapping form file keys to placeholder locations within operations.
1 file The CSV file. The form key (1) must match the key referenced in map.

operations value

{
  "operationName": "UploadDynamicAttributesCSV",
  "variables": { "input": { "ModelID": "{{digital_twins_model_id}}", "File": null } },
  "query": "mutation UploadDynamicAttributesCSV($input: UploadCSVRequest!) { UploadDynamicAttributesCSV(input: $input) { Errors { Line Column Error } } }"
}

map value

{ "1": ["variables.input.File"] }

The CSV format must match what Download Dynamic Attributes produces (see that endpoint for the header row).

Response

200 OK -- application/json

Field Type Description
data.UploadDynamicAttributesCSV.Errors [CSVError!]! One entry per error row, plus a summary row.
data.UploadDynamicAttributesCSV.Errors[].Line Int? 1-indexed CSV line number with the error. null for the summary.
data.UploadDynamicAttributesCSV.Errors[].Column Int? 1-indexed column number with the error. null for the summary.
data.UploadDynamicAttributesCSV.Errors[].Error String Error text (or created: N updated: N skipped: N summary).
{
  "data": {
    "UploadDynamicAttributesCSV": {
      "Errors": [
        {
          "Line": null,
          "Column": null,
          "Error": "created: 0 updated: 1 skipped: 0"
        }
      ]
    }
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

Response

Status: 200 OK

{
    "data": {
        "UploadDynamicAttributesCSV": {
            "Errors": [
                {
                    "Line": null,
                    "Column": null,
                    "Error": "created: 0 updated: 1 skipped: 0",
                    "__typename": "CSVError"
                }
            ],
            "__typename": "UploadCSVResponse"
        }
    }
}

Remove Dynamic Attribute

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: DeleteDynamicAttributeRequest.ID is now required (UUID!).

Remove Dynamic Attribute

Deletes one or more dynamic attributes by ID. Despite the singular name, the underlying mutation accepts a list -- but the example below shows the single-ID form taken by the Postman item.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation DeleteDynamicAttributes($input: DeleteDynamicAttributesRequest!) {
  DeleteDynamicAttributes(input: $input)
}

The singular DeleteDynamicAttribute mutation is deprecated in the schema ("No longer supported"). It still executes, but use the batch form above.

Variables (input: DeleteDynamicAttributesRequest!)

Field Type Required Description
Items [Item!]! Yes List of {ID} objects -- one per attribute to delete.
Items[].ID ID Yes UUID of the dynamic attribute to delete.
{
  "input": {
    "Items": [
      { "ID": "{{digital_twins_dynamic_attribute_id}}" }
    ]
  }
}

Response

200 OK -- application/json. No data returned on success.

{ "data": { "DeleteDynamicAttributes": null } }

An attribute that is referenced by a hierarchy node cannot be deleted:

attribute in use by hierarchy

Remove the node first with Save All Hierarchy (submit the tree without that node), then delete the attribute.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation DeleteDynamicAttributes ($input: DeleteDynamicAttributesRequest!) {
    DeleteDynamicAttributes(input: $input)
}

Variables

{
    "input": {
        "Items": [
            { "ID": "{{digital_twins_dynamic_attribute_id}}" }
        ]
    }
}

Response

Status: 200 OK

{
    "data": {
        "DeleteDynamicAttributes": null
    }
}

Digital Twins Version

POST {{edgeUrl}}/digital-twins

Digital Twins Version

Returns the running version and git revision of the Digital Twins service. Use as a fast liveness probe or to record the build version for support tickets.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query Version {
  Version {
    Git
    Version
  }
}

Response

200 OK -- application/json

Field Type Description
data.Version.Git String Short git commit hash of the deployed build.
data.Version.Version String Semantic version of the Digital Twins service.
{
  "data": {
    "Version": {
      "Git": "20e4e53e40",
      "Version": "1.2.4"
    }
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ListModels {
    Version {
        Git
        Version
    }
}

Response

Status: 200 OK

{
    "data": {
        "Version": {
            "Git": "20e4e53e40",
            "Version": "1.2.4"
        }
    }
}

List Models

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: Model now exposes four count fields (InstanceCount, StaticAttributeCount, DynamicAttributeCount, ParameterCount) and full nested lists (Instances, StaticAttributes, DynamicAttributes) -- see List Models with Nested Data.

List Models

Returns every model defined on the device, projected to a minimal {ID, Name} shape. Use as the source for a model picker, or to enumerate models when iterating over instances. For full schema, extend the GraphQL selection (e.g. add Description, Assets, IsUNS, ConnectorName).

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ListModels {
  ListModels {
    ID
    Name
  }
}

Response

200 OK -- application/json

Field Type Description
data.ListModels [Model!]! All models on the device.
data.ListModels[].ID ID Model UUID.
data.ListModels[].Name String Display name. Unique across models.
{
  "data": {
    "ListModels": [
      { "ID": "D9117AE5-3F3E-4436-9A2A-6DD725FBD8FB", "Name": "Digital-Twin-1" }
    ]
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ListModels {
    ListModels {
        ID
        Name
        DynamicAttributeCount
        StaticAttributeCount
        ParameterCount
        InstanceCount
    }
}

Response

Status: 200 OK

{
    "data": {
        "ListModels": [
            {
                "ID": "D9117AE5-3F3E-4436-9A2A-6DD725FBD8FB",
                "Name": "Digital-Twin-1"
            }
        ]
    }
}

List Models with Nested Data

POST {{edgeUrl}}/digital-twins/v2

BREAKING in 4.2.x. This item replaces its 4.1.x counterpart.

Model no longer has StaticAttributes or DynamicAttributes. A query that still selects either field fails validation outright, so this is a hard break, not a silent change.

What to do

Keep using StaticAttributeCount and DynamicAttributeCount for counts, which are unchanged. When you need the attributes themselves, fetch them per model with ListStaticAttributes / ListDynamicAttributes, passing the model's ID and paging with Limit and Offset.

Before (4.1.x, now invalid)

query ListModels {
    ListModels {
        ID Name
        StaticAttributes  { ID Key Value AttributeType }
        DynamicAttributes { ID Name AttrDataType Topic Unit }
    }
}

After (4.2.x)

query ListModels {
    ListModels { ID Name StaticAttributeCount DynamicAttributeCount }
}

query ListStaticAttributes($input: ListStaticAttributeRequest!) {
    ListStaticAttributes(input: $input) { ID Key Value AttributeType }
}

Why it changed

Embedding every attribute in every model made ListModels grow without bound on installations with large models: listing ten models pulled back their entire attribute sets whether or not the caller wanted them. Splitting the two apart keeps ListModels a cheap, predictable call and puts attribute fetching under explicit paging.

Expect one extra round trip per model whose attributes you actually need. If you were listing models purely to read counts, you now do strictly less work.

Request Body

GraphQL Query

query ListModels {
    ListModels {
        ID
        Name
        Description
        Version
        Assets
        IsUNS
        ConnectorName
        Source
        IsTopicExpressionEnabled
        InstanceCount
        StaticAttributeCount
        DynamicAttributeCount
        ParameterCount
        Instances {
            ID
            Name
            Topic
            Interval
            Version
            StaticAttributeCount
            DynamicAttributeCount
        }
    }
}

Create Model

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: CreateModelRequest.Name and .Assets are now required (String!) -- omitting either returns a GraphQL validation error. The response also exposes the new count fields.

Create Model

Creates a new digital twin model with the minimum properties needed for the LE UI to show it on the Models page. After creation, populate the schema via the Static Attributes, Dynamic Attribute, Transformation, and Hierarchy subfolders.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation CreateModel($input: CreateModelRequest!) {
  CreateModel(input: $input) {
    ID
    Name
    Assets
    Description
    IsUNS
    ConnectorName
  }
}

Variables (input: CreateModelRequest!)

Field Type Required Description
Name String Yes Display name. Must be unique across all models. Restricted character set -- see Name character rules below.
Assets String Yes Asset category for organising models. Default ASSET. Free-form, used for grouping in the UI.
Description String Yes Free-form description. May be empty ("") but the field must be present.
IsUNS Boolean No Default false. true if this model participates in the Unified Namespace via a UNS connector.
ConnectorName String No UNS connector to publish under when IsUNS: true (e.g. LitmusEdge).

Two required fields behave differently when omitted, and neither failure is self-explanatory:

Name character rules

Model.Name is validated by three separate server-side validators, each reporting a different tag:

Value Result
abc def rejected -- noWhitespaces
abc.def rejected -- noDots
abc/def rejected -- notAllowedCharacters

Effective allowlist: Unicode letters, digits, _ and -. Everything else is rejected, including space, ., and / & ( ) % , : + ' ° * ! ? @ # $ ^ ~ ; = [ ] { } | \ " < >. Unicode letters outside ASCII pass (µ, Ω), Unicode symbols do not (°).

A human-readable line name such as Line 1Z is therefore rejected; use Line_1Z.

A duplicate name fails with an internal index identifier rather than a field name:

index name xNm: unique constraint violation
unique constraint violation
{
  "input": {
    "Name": "{{digital_twins_model}}",
    "Assets": "ASSET",
    "Description": "",
    "IsUNS": true,
    "ConnectorName": "{{uns_connector_name}}"
  }
}

Response

200 OK -- application/json

Field Type Description
data.CreateModel.ID ID UUID of the newly created model. Save as {{digital_twins_model_id}}.
data.CreateModel.Name String Model name echoed back.
data.CreateModel.Assets String Asset category echoed back.
data.CreateModel.Description String Description echoed back.
{
  "data": {
    "CreateModel": {
      "ID": "9C01CCFC-7A94-4554-AFAD-BB14942D5190",
      "Name": "apiTest",
      "Assets": "ASSET",
      "Description": "",
      "__typename": "Model"
    }
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation CreateModel($input: CreateModelRequest!) {
    CreateModel(input: $input) {
        ID
        Name
        Assets
        Description
        IsUNS
        ConnectorName
        DynamicAttributeCount
        StaticAttributeCount
        ParameterCount
        InstanceCount
    }
}

Variables

{
  "input": {
    "Name": "{{digital_twins_model}}",
    "Assets": "ASSET",
    "Description": "",
    "IsUNS": true,
    "ConnectorName": "{{uns_connector_name}}"
  }
}

Response

Status: 200 OK

{
    "data": {
        "CreateModel": {
            "ID": "9C01CCFC-7A94-4554-AFAD-BB14942D5190",
            "Name": "apiTest",
            "Assets": "ASSET",
            "Description": "",
            "__typename": "Model"
        }
    }
}

Update Model

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: UpdateModelRequest.ID is now required (UUID!). The response also exposes the new count fields.

Update Model

Updates the mutable top-level fields of a model. To edit the model's schema (attributes, hierarchy, transformations), use the sub-folder endpoints rather than this one.

UpdateModel is a full replacement of the input shape -- include every field you want to keep.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation UpdateModel($input: UpdateModelRequest!) {
  UpdateModel(input: $input) {
    ID
    Name
    Assets
    Description
    IsUNS
    ConnectorName
    __typename
  }
}

Variables (input: UpdateModelRequest!)

Same fields as Create Model, plus:

Field Type Required Description
ID ID Yes UUID of the model to update.
{
  "input": {
    "ID": "{{digital_twins_model_id}}",
    "Name": "{{digital_twins_model}}",
    "Assets": "ASSET",
    "Description": "",
    "IsUNS": true,
    "ConnectorName": "{{uns_connector_name}}"
  }
}

Response

200 OK -- application/json. Echoes the model's new state.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation UpdateModel($input: UpdateModelRequest!) {
    UpdateModel(input: $input) {
        ID
        Name
        Assets
        Description
        IsUNS
        ConnectorName
        DynamicAttributeCount
        StaticAttributeCount
        ParameterCount
        InstanceCount
        __typename
    }
}

Variables

{
    "input": {
        "Name": "{{digital_twins_model}}",
        "Assets": "ASSET",
        "Description": "",
        "ID": "{{digital_twins_model_id}}",
        "IsUNS": true,
        "ConnectorName": "{{uns_connector_name}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "UpdateModel": {
            "ID": "5CF29323-A2C7-48E3-A356-6A046AF99B7F",
            "Name": "apiTest",
            "Assets": "ASSET",
            "Description": "",
            "IsUNS": true,
            "ConnectorName": "LitmusEdge",
            "__typename": "Model"
        }
    }
}

Delete Model

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: DeleteModelRequest.ID is now required (UUID!).

Delete Model

Deletes a model together with its attributes, transformations and hierarchy. A model that still has instances cannot be deleted: the call fails with DT_MODEL_HAS_INSTANCES (Model '<name>' can't be deleted while 1 instance still uses it. Delete that instance first, then delete the model.). Delete its instances first (List Instances with the ModelID, then Delete Instance). Destructive and not idempotent: deleting a missing ID returns a BAD_USER_INPUT error.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation DeleteModel($input: DeleteModelRequest!) {
  DeleteModel(input: $input)
}

Variables (input: DeleteModelRequest!)

Field Type Required Description
ID ID Yes UUID of the model to delete.
{
  "input": {
    "ID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json. No data returned on success.

{ "data": { "DeleteModel": null } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation DeleteModel($input: DeleteModelRequest!) {
  DeleteModel(input: $input)
}

Variables

{
  "input": {
    "ID": "{{digital_twins_model_id}}"
  }
}

Response

Status: 200 OK

{
    "data": {
        "DeleteModel": null
    }
}

Clone a Model

POST {{edgeUrl}}/digital-twins

Clone a Model

Creates a deep copy of an existing model: static attributes, dynamic attributes, transformations, parameters, and hierarchy are all duplicated. Instances are not cloned -- the new model starts with no instances.

Use this to template new asset types from an existing definition without re-entering the schema.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation CloneModel($input: CloneModelRequest!) {
  CloneModel(input: $input) {
    ID
    Assets
    Name
    Description
  }
}

Variables (input: CloneModelRequest!)

Field Type Required Description
ID ID Yes UUID of the source model to clone.
Name String Yes Display name for the new model. Must be unique across models.
{
  "input": {
    "ID": "{{digital_twins_model_id}}",
    "Name": "{{digital_twins_clone}}"
  }
}

Response

200 OK -- application/json

Field Type Description
data.CloneModel.ID ID UUID of the newly created clone.
data.CloneModel.Assets String Asset category copied from the source.
data.CloneModel.Name String Name as supplied.
data.CloneModel.Description String Description copied from the source.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation CloneModel ($input: CloneModelRequest!) {
    CloneModel(input: $input) {
        ID
        Assets
        Name
        Description
    }
}

Variables

{
    "input": {
        "ID": "{{digital_twins_model_id}}",
        "Name": "{{digital_twins_clone}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "CloneModel": {
            "ID": "46946ABE-2235-4B27-833D-CC335DDFCB4C",
            "Assets": "ASSET",
            "Name": "apiTest2",
            "Description": "Digital Twin example 1"
        }
    }
}

Export Model

POST {{edgeUrl}}/digital-twins

Export Model

Serializes a model and its full schema (static attributes, dynamic attributes, transformations, hierarchy, image) to a JSON document suitable for Import Model on another device. Use this to move models between devices, source-control them, or take backups.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation ExportModel($input: ExportModelRequest!) {
  ExportModel(input: $input)
}

Variables (input: ExportModelRequest!)

Field Type Required Description
ModelID ID Yes UUID of the model to export.
{
  "input": {
    "ModelID": "{{digital_twins_model_id}}"
  }
}

Response

200 OK -- application/json. data.ExportModel is an array of model documents (typically of length 1) containing every nested entity. Each document includes:

Persist the response verbatim for re-import.

{
  "data": {
    "ExportModel": [
      {
        "id": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
        "assets": "ASSET",
        "name": "apiTest",
        "description": "updated model",
        "image": "",
        "dynamicAttributes": [
          {
            "id": "31a6eddc-a455-4126-981c-0a6313915a89",
            "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
            "parentId": "00000000-0000-0000-0000-000000000000"
          }
        ]
      }
    ]
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation ExportModel ($input: ExportModelRequest!) {
    ExportModel(input: $input)
}

Variables

{
    "input": {
        "ModelID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "ExportModel": [
            {
                "id": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                "assets": "ASSET",
                "name": "apiTest",
                "description": "updated model",
                "image": "",
                "dynamicAttributes": [
                    {
                        "id": "31a6eddc-a455-4126-981c-0a6313915a89",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "topic": "",
                        "name": "Speed",
                        "unit": "kmph",
                        "dataType": "string",
                        "schemaId": "30d86400-d103-4c5c-95e4-ab6f02fb00ee"
                    }
                ],
                "staticAttributes": [
                    {
                        "id": "189edb70-1029-4ebf-ab40-27e5423c12ce",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "key": "Manufacturer",
                        "value": "API Manufacturer"
                    },
                    {
                        "id": "3f44c811-d8cc-4735-b337-a0f30826641e",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "key": "Model",
                        "value": "New API Model"
                    },
                    {
                        "id": "3af47815-bb4f-4288-84da-02b259a75edb",
                        "parentId": "00000000-0000-0000-0000-000000000000",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "instanceId": "00000000-0000-0000-0000-000000000000",
                        "key": "Model1",
                        "value": "New API Model1"
                    }
                ],
                "hierarchyNodes": [
                    {
                        "id": "60c1f5d0-25ab-4bc0-93a8-52a60a7087d0",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "position": 0,
                        "parentId": "4c224618-4e24-4bf7-af8b-d87188fdc413",
                        "name": "Model",
                        "isFolder": false,
                        "attributeId": "3f44c811-d8cc-4735-b337-a0f30826641e",
                        "attributeType": "static",
                        "CreatedAt": "2023-11-29T00:54:35.953112543Z"
                    },
                    {
                        "id": "81d4226b-12f9-4d89-957d-2f01a8e5bf12",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "position": 0,
                        "parentId": "a6a8cb25-ba33-41ca-8d2c-6f657949b849",
                        "name": "Model",
                        "isFolder": false,
                        "attributeId": "3f44c811-d8cc-4735-b337-a0f30826641e",
                        "attributeType": "static",
                        "CreatedAt": "2023-11-29T00:54:35.954122264Z"
                    },
                    {
                        "id": "997ed034-52de-4ce4-9f7d-731294f70e6a",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "position": 0,
                        "parentId": null,
                        "name": "Manufacturer",
                        "isFolder": false,
                        "attributeId": "189edb70-1029-4ebf-ab40-27e5423c12ce",
                        "attributeType": "static",
                        "CreatedAt": "2023-11-29T00:54:35.951975424Z"
                    },
                    {
                        "id": "4c224618-4e24-4bf7-af8b-d87188fdc413",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "position": 1,
                        "parentId": null,
                        "name": "New_Node",
                        "isFolder": true,
                        "attributeId": null,
                        "attributeType": null,
                        "CreatedAt": "2023-11-29T00:54:35.952255779Z"
                    },
                    {
                        "id": "a6a8cb25-ba33-41ca-8d2c-6f657949b849",
                        "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "position": 2,
                        "parentId": "4c224618-4e24-4bf7-af8b-d87188fdc413",
                        "name": "New_Node",
                        "isFolder": true,
                        "attributeId": null,
                        "attributeType": null,
                        "CreatedAt": "2023-11-29T00:54:35.953579776Z"
                    }
                ],
                "transformationBackup": [
                    {
                        "ID": "30d86400-d103-4c5c-95e4-ab6f02fb00ee",
                        "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
                        "Name": "Transformation",
                        "Schema": "{\n  \"key\": \"value\"\n}"
                    }
                ]
            }
        ]
    }
}

Import Model

POST {{edgeUrl}}/digital-twins

Import Model

Imports one or more model documents previously produced by Export Model (or hand-authored to the same shape). The mutation accepts the document verbatim -- pass an array of model objects.

Imported models keep their original UUIDs from the source export. If a matching ID already exists on the device, the import fails -- delete or clone the existing one first.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation ImportModel($input: Any!) {
  ImportModel(input: $input)
}

The Any! scalar accepts the same JSON structure that Export Model returns. The example below imports a single, minimal model:

{
  "input": [
    {
      "id": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
      "assets": "ASSET",
      "name": "apiImportModel",
      "description": "updated model",
      "image": "",
      "dynamicAttributes": [],
      "staticAttributes": []
    }
  ]
}

Response

200 OK -- application/json

Field Type Description
data.ImportModel Boolean true on success.
{ "data": { "ImportModel": true } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation ImportModel($input: Any!) {
    ImportModel(input: $input)
}

Variables

{
    "input": [
      {
        "id": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
        "assets": "ASSET",
        "name": "apiImportModel",
        "description": "updated model",
        "image": "",
        "dynamicAttributes": [],
        "staticAttributes": [
          {
            "id": "189edb70-1029-4ebf-ab40-27e5423c12ce",
            "parentId": "00000000-0000-0000-0000-000000000000",
            "modelId": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
            "instanceId": "00000000-0000-0000-0000-000000000000",
            "key": "Manufacturer",
            "value": "API Manufacturer"
          }
        ],
        "hierarchyNodes": [],
        "transformationBackup": [
          {
            "ID": "30d86400-d103-4c5c-95e4-ab6f02fb00ee",
            "ModelID": "3a923971-5dfc-4633-b5af-a6bf8c0b60e9",
            "Name": "Transformation",
            "Schema": "{\n  \"key\": \"value\"\n}"
          }
        ]
      }
    ]
  }

Response

Status: 200 OK

{
    "data": {
        "ImportModel": true
    }
}

Upgrade Instances

POST {{edgeUrl}}/digital-twins

Upgrade Instances

Reconciles one or more instances with the current state of their parent model. Use this after editing a model's schema (adding/removing attributes, changing hierarchy) so that existing instances pick up the change without being deleted and recreated.

Without Upgrade Instances, existing instances continue to operate against the model schema they were created against.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation UpgradeInstances($input: [UUID!]) {
  UpgradeInstances(input: $input)
}

Variables

Field Type Required Description
input [UUID!] Yes Instance UUIDs to upgrade. Pass a single-element array for one.
{
  "input": [
    "{{digital_twins_instance_id}}"
  ]
}

Response

200 OK -- application/json

Field Type Description
data.UpgradeInstances Boolean true on success.
{ "data": { "UpgradeInstances": true } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation UpgradeInstances($input: [UUID!]) {
    UpgradeInstances(input: $input)
}

Variables

{
    "input": [
        "{{digital_twins_instance_id}}"
    ]
}

Response

Status: 200 OK

{
    "data": {
        "UpgradeInstances": true
    }
}

List UNS Connectors

POST {{edgeUrl}}/digital-twins

List UNS Connectors

Lists the Litmus UNS connectors a model can publish through. The Digital Twins UI calls this to fill the connector picker when a model is created or edited with UNS publishing turned on. Pass the chosen connector's Name as ConnectorName (with IsUNS: true) to Create Model or Update Model.

A connector is an Integration instance of the Litmus UNS provider. The list is empty until one exists, which is what this example device returns.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ListUNSConnectors {
  ListUNSConnectors {
    Name
    ConnectorID
  }
}

No variables.

Response

200 OK -- application/json. data.ListUNSConnectors is a list of UNSConnector:

Field Type Description
Name String! Connector name, as used in ConnectorName.
ConnectorID String! ID of the Integration instance behind it.
{ "data": { "ListUNSConnectors": [] } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ListUNSConnectors {
    ListUNSConnectors {
        Name
        ConnectorID
    }
}

Response

Status: 200 OK

{
    "data": {
        "ListUNSConnectors": []
    }
}

List Static Attributes

POST {{edgeUrl}}/digital-twins/v2

Updated in 4.3.x. This item replaces its 4.2.x counterpart.

Instance-scoped form. The 4.2.x version of this item did not select AttributeType at all; it is added here because the enum gained a member that matters for instances specifically.

AttributeType is now Regular | UNS | AssetHierarchy.

Value Meaning
Regular An ordinary static attribute
UNS Derived from the Unified Namespace
AssetHierarchy New in 4.3.x. Derived from the asset hierarchy set by SetInstanceAssetHierarchy

This is the read path for asset hierarchy placement. SetInstanceAssetHierarchy returns Empty, so this query is how you confirm a placement actually landed.

Any exhaustive match on AttributeType in client code was written against two members and will now meet a third. Check the default branch.

Request Body

GraphQL Query

query ListStaticAttributes($input: ListStaticAttributeRequest!) {
    ListStaticAttributes(input: $input) {
        ID
        ModelID
        InstanceID
        Key
        Value
        AttributeType
        CreatedAt
        UpdatedAt
    }
}

Variables

{
  "input": {
    "ModelID": null,
    "InstanceID": "{{dt_instance_id}}"
  }
}

Update Static Attribute

POST {{edgeUrl}}/digital-twins

Update Static Attribute (instance scope)

Identical to Models > Static Attributes > Update Static Attribute. The endpoint is reused for both model-level and instance-level updates -- when the static attribute UUID belongs to an instance override, the override is what's written; otherwise the model-level definition is updated.

See the Models-side endpoint for the request shape and field reference.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation UpdateStaticAttributes($input: UpdateStaticAttributesRequest!) {
  UpdateStaticAttributes(input: $input) {
    ID
    ModelID
    InstanceID
    Key
    Value
    CreatedAt
    UpdatedAt
  }
}

The singular UpdateStaticAttribute mutation is deprecated in the schema ("No longer supported"). It still executes, but use the batch form above.

Variables (input: UpdateStaticAttributesRequest!)

Field Type Required Description
Items [Item!]! Yes One entry per attribute to update.
Items[].ID ID Yes UUID of the static attribute (model or instance override).
Items[].ModelID ID Yes UUID of the parent model.
Items[].Key String Yes New attribute name.
Items[].Value String Yes New attribute value.
{
  "input": {
    "Items": [
      {
        "ID": "{{digital_twins_static_attribute_id}}",
        "ModelID": "{{digital_twins_model_id}}",
        "Key": "Model",
        "Value": "Updated Value API Model"
      }
    ]
  }
}

Response

Same shape as Models > Static Attributes > Update Static Attribute.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation UpdateStaticAttributes($input:UpdateStaticAttributesRequest!) {
    UpdateStaticAttributes(input: $input) {
        ID
        ModelID
        InstanceID
        Key
        Value
        CreatedAt
        UpdatedAt
    }
}

Variables

{
    "input": {
        "Items": [
            {
                "ID": "{{digital_twins_static_attribute_id}}",
                "ModelID": "{{digital_twins_model_id}}",
                "Key": "Model",
                "Value": "Updated Value API Model"
            }
        ]
    }
}

Response

Status: 200 OK

{
    "data": {
        "UpdateStaticAttributes": [
            {
                "ID": "63E4BD05-CE85-41CD-99A6-F69CCD171240",
                "ModelID": "3A923971-5DFC-4633-B5AF-A6BF8C0B60E9",
                "InstanceID": null,
                "Key": "Model",
                "Value": "Updated Value API Model",
                "CreatedAt": "2023-08-16T00:13:38.224123983Z",
                "UpdatedAt": "2023-08-16T00:23:12.872714078Z"
            }
        ]
    }
}

List all Dynamic Attributes

POST {{edgeUrl}}/digital-twins

List all Dynamic Attributes (instance scope)

Same shape as Models > Dynamic Attribute > List all Dynamic Attributes -- the endpoint is reused. Pass the parent ModelID to scope. The response includes per-instance overrides if InstanceID is non-zero on the returned records.

See the Models-side endpoint for the full field reference.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ListDynamicAttributes($input: ListDynamicAttributeRequest!) {
  ListDynamicAttributes(input: $input) {
    ID
    ModelID
    InstanceID
    Topic
    Name
    Unit
    DataType
    SchemaID
    CreatedAt
    UpdatedAt
  }
}

Variables

Field Type Required Description
ModelID ID Yes UUID of the parent model.
{
  "input": {
    "ModelID": "{{digital_twins_model_id}}"
  }
}

Response

Same shape as Models > Dynamic Attribute > List all Dynamic Attributes.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ListDynamicAttributes ($input: ListDynamicAttributeRequest!) {
    ListDynamicAttributes(input:$input) {
        ID
        ModelID
        InstanceID
        Topic
        Name
        Unit
        DataType
        SchemaID
        CreatedAt
        UpdatedAt
    }
}

Variables

{
    "input": {
        "ModelID": "{{digital_twins_model_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "ListDynamicAttributes": [
            {
                "ID": "77990102-3613-4D2B-ABFC-EE761383E631",
                "ModelID": "3A923971-5DFC-4633-B5AF-A6BF8C0B60E9",
                "InstanceID": "00000000-0000-0000-0000-000000000000",
                "Topic": "",
                "Name": "Dynamic attribute 1",
                "Unit": "test1",
                "DataType": "Dictionary",
                "SchemaID": "30D86400-D103-4C5C-95E4-AB6F02FB00EE",
                "CreatedAt": "2023-08-16T19:13:13.808757635Z",
                "UpdatedAt": "2023-08-16T20:17:31.074886398Z"
            }
        ]
    }
}

Update Dynamic Attribute

POST {{edgeUrl}}/digital-twins/v2

Updated in 4.3.x. This item replaces its 4.2.x counterpart.

Instance-scoped form: set InstanceID and leave ModelID null. The model-scoped form of the same mutation is under Models > Dynamic Attribute.

UpdateDynamicAttributeRequest gains NestedModelID and NestedInstanceID, and DynamicAttributeType gains a nestedModel member.

Set NestedModelID to compose a model definition, or NestedInstanceID to point at one specific instance. They are alternatives: populate one, leave the other null. Both are ignored unless AttrDataType is nestedModel.

NestedInstanceID is the one that matters most here: it points this attribute at a specific instance rather than at a model definition, which is what you usually want when the attribute itself belongs to an instance.

This is a full update, not a patch. Send the complete attribute: omitting NestedInstanceID on an attribute that currently has one clears it and silently turns a nested reference back into a plain attribute.

Request Body

GraphQL Query

mutation UpdateDynamicAttribute ($input: UpdateDynamicAttributeRequest!) {
    UpdateDynamicAttribute(input: $input) {
        ID
        ModelID
        InstanceID
        Topic
        Name
        Unit
        DataType
        AttrDataType
        NestedModelID
        NestedInstanceID
        SchemaID
        CreatedAt
        UpdatedAt
    }
}

Variables

{
  "input": {
    "ID": "{{dt_dynamic_attribute_id}}",
    "ModelID": null,
    "InstanceID": "{{dt_instance_id}}",
    "Topic": "line/1/motor",
    "Name": "motor",
    "Unit": "",
    "DataType": "object",
    "AttrDataType": "nestedModel",
    "NestedModelID": null,
    "NestedInstanceID": "{{dt_nested_instance_id}}"
  }
}

Upload Dynamic Attribute CSV

POST {{edgeUrl}}/digital-twins

Upload Dynamic Attribute CSV (instance scope)

Same multipart mutation as Models > Dynamic Attribute > Upload Dynamic Attribute CSV. The endpoint is reused; the difference is that the CSV typically contains per-instance overrides (with InstanceID set).

See the Models-side endpoint for the form-data shape, CSV format, and response field reference.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body (form-data parts)

Form key Type Description
operations text GraphQL envelope, see Models-side endpoint.
map text {"1": ["variables.input.File"]}
1 file The CSV file.

The operations value uses $input.ModelID from the parent model -- the service applies overrides to the appropriate instance based on rows in the CSV.

Response

Same shape as Models > Dynamic Attribute > Upload Dynamic Attribute CSV.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

Response

Status: 200 OK

{
    "data": {
        "UploadDynamicAttributesCSV": {
            "Errors": [
                {
                    "Line": null,
                    "Column": null,
                    "Error": "created: 0 updated: 1 skipped: 0",
                    "__typename": "CSVError"
                }
            ],
            "__typename": "UploadCSVResponse"
        }
    }
}

List Parameters

POST {{edgeUrl}}/digital-twins

List Parameters (instance scope)

Same query as Models > Parameters > List Parameters -- pass the instance UUID as OwnerID to scope to the instance. See the Models-side endpoint for the request shape and field reference.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ListParameters($input: ListParametersRequest) {
  ListParameters(input: $input) {
    ID
    Name
    Value
  }
}

Variables

Field Type Required Description
OwnerID ID Yes UUID of the instance.
{
  "input": {
    "OwnerID": "{{digital_twins_instance_id}}"
  }
}

Response

Same shape as Models > Parameters > List Parameters.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ListParameters($input: ListParametersRequest) {
  ListParameters(input: $input) {
    ID
    Name
    Value
  }
}

Variables

{
    "input": {
        "OwnerID": "{{digital_twins_instance_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "ListParameters": [
            {
                "ID": "51D2E713-6150-4800-8779-9A1825BE19D7",
                "Name": "Updated key",
                "Value": "Updated value"
            },
            {
                "ID": "8FA45411-ECA0-44C0-BD2F-60341D55C581",
                "Name": "key1",
                "Value": "value1"
            }
        ]
    }
}

Get Instances

POST {{edgeUrl}}/digital-twins/v2

Updated in 4.3.x. This item replaces its 4.2.x counterpart.

Instance gains Source (local | external), added to the selection set here.

Filter on it client-side to separate instances defined on this device from those that came in from elsewhere. ListInstancesRequest still takes only ModelID, so there is no server-side filter by source in this release.

Everything else about this query is unchanged from 4.2.x. Removing Source from the selection gives you exactly the 4.2.x response.

Request Body

GraphQL Query

query ListInstances($input: ListInstancesRequest) {
    ListInstances(input: $input) {
        ID
        ModelID
        Name
        Topic
        Interval
        FlatHierarchy
        Source
        DynamicAttributeCount
        StaticAttributeCount
        ParameterCount
    }
}

Variables

{
  "input": {
    "ModelID": "{{dt_model_id}}"
  }
}

Create Instance

POST {{edgeUrl}}/digital-twins/v2

Requires: an existing model (ModelID from Create Model or List Models). An unknown ID fails with DT_NOT_FOUND.

Updated in 4.3.x. This item replaces its 4.2.x counterpart.

CreateInstanceRequest gains an optional Source field, and Instance returns it. InstanceSource is local | external.

Value Meaning
local The instance is defined and owned on this device
external The instance originates outside this device

The field is optional, so a 4.2.x request body still works and the server applies its default. Send it explicitly once you have instances arriving from more than one place, since Source is what tells them apart afterwards.

Select Source in the response, as above, to confirm what was actually recorded rather than what you asked for.

Request Body

GraphQL Query

mutation CreateInstance($input: CreateInstanceRequest!) {
    CreateInstance(input: $input) {
        ID
        ModelID
        Name
        Topic
        Interval
        FlatHierarchy
        Source
    }
}

Variables

{
  "input": {
    "ModelID": "{{dt_model_id}}",
    "Name": "line-1-press",
    "Topic": "plant/line1/press",
    "Interval": 1000,
    "FlatHierarchy": false,
    "Source": "local"
  }
}

Delete Instance

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: DeleteInstanceRequest.ID is now required (UUID!).

Delete Instance

Note: a model cannot be deleted while any instance still uses it, so delete instances before their model.

Deletes an instance and all of its per-instance attribute overrides. The parent model is not affected.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation DeleteInstance($input: DeleteInstanceRequest!) {
  DeleteInstance(input: $input)
}

Variables

Field Type Required Description
ID ID Yes UUID of the instance to delete.
{
  "input": {
    "ID": "{{digital_twins_instance_id}}"
  }
}

Response

200 OK -- application/json. No data returned on success.

{ "data": { "DeleteInstance": null } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation DeleteInstance ($input: DeleteInstanceRequest!) {
    DeleteInstance(input:$input)
}

Variables

{
    "input": {
        "ID":"AB89BC5A-3E72-4CFD-B5FA-3F216BB33601"
    }
}

Response

Status: 200 OK

{
    "data": {
        "DeleteInstance": null
    }
}

Update Instance

POST {{edgeUrl}}/digital-twins

Updated in 4.1.x: UpdateInstanceRequest.ID is now required (UUID!). The response also exposes the new count fields.

Update Instance

Updates the top-level fields of an instance (Name, Topic, Interval, FlatHierarchy). The ModelID is not re-assignable -- delete and recreate to change models.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation UpdateInstance($input: UpdateInstanceRequest!) {
  UpdateInstance(input: $input) {
    ID
    ModelID
    Name
    Topic
    Interval
    FlatHierarchy
  }
}

Variables

Same fields as Create Instance, plus:

Field Type Required Description
ID ID Yes UUID of the instance to update.
{
  "input": {
    "ID": "{{digital_twins_instance_id}}",
    "ModelID": "{{digital_twins_model_id}}",
    "Name": "updated_{{digital_twins_instance}}",
    "Interval": 1,
    "Topic": "digitaltwins_updated_{{digital_twins_instance}}",
    "FlatHierarchy": false
  }
}

Response

200 OK -- application/json. Returns the updated instance.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation UpdateInstance($input: UpdateInstanceRequest!) {
    UpdateInstance(input: $input) {
        ID
        ModelID
        Name
        Topic
        Interval
        FlatHierarchy
        DynamicAttributeCount
        StaticAttributeCount
        ParameterCount
  }
}

Variables

{
    "input": {
        "ID": "{{digital_twins_instance_id}}",
        "ModelID": "{{digital_twins_model_id}}",
        "Name": "updated_{{digital_twins_instance}}",
        "Interval": 1,
        "Topic": "digitaltwins_updated_{{digital_twins_instance}}",
        "FlatHierarchy": false
    }
}

Response

Status: 200 OK

{
    "data": {
        "UpdateInstance": {
            "ID": "D0C8844D-EF72-4933-BB5E-B74372B33F4B",
            "ModelID": "D9117AE5-3F3E-4436-9A2A-6DD725FBD8FB",
            "Name": "Instance1",
            "Topic": "digitaltwins_Instance1",
            "Interval": 1,
            "FlatHierarchy": false
        }
    }
}

Set Instance State

POST {{edgeUrl}}/digital-twins

Set Instance State

Enables or disables an instance. A disabled instance is configured but does not publish to its topic; enabled instances actively run.

Use this to pause/resume publishing without deleting and recreating the instance.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation SetInstanceState($input: SetInstanceStateRequest!) {
  SetInstanceState(input: $input)
}

Variables

Field Type Required Description
InstanceID ID Yes UUID of the instance.
IsEnabled Boolean Yes true to enable, false to disable.
{
  "input": {
    "InstanceID": "{{digital_twins_instance_id}}",
    "IsEnabled": true
  }
}

Response

200 OK -- application/json

Field Type Description
data.SetInstanceState Boolean true on success.
{ "data": { "SetInstanceState": true } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation SetInstanceState ($input: SetInstanceStateRequest!) {
    SetInstanceState(input: $input)
}

Variables

{
    "input": {
        "InstanceID": "{{digital_twins_instance_id}}", 
        "IsEnabled": true
    }
}

Response

Status: 200 OK

{
    "data": {
        "SetInstanceState": true
    }
}

Save Instance/ Add Topic to Dynamic Attribute

POST {{edgeUrl}}/digital-twins/

Save Instance / Add Topic to Dynamic Attribute (transactional)

Applies one or more updates to an instance's per-instance static and dynamic attribute overrides in a single transaction. This is the same shape as Models > Parameters > Set Parameters, but scoped to instance overrides instead of model schema.

The most common use case is adding a topic to a dynamic attribute override -- this is the step that actually binds the dynamic attribute to a live data source (typically a DeviceHub tag topic).

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

mutation TransactionalInstanceUpdate($input: TransactionalInstanceUpdateRequest!) {
  TransactionalInstanceUpdate(input: $input)
}

Variables

The input is an envelope of per-operation arrays. Send only the arrays you need; the others can be empty Items: [].

Field Type Description
updateStaticAttributes { Items } List of per-instance static attribute payloads to update.
updateDynamicAttributes { Items } List of per-instance dynamic attribute payloads to update (e.g. set Topic).
{
  "input": {
    "updateStaticAttributes":  { "Items": [] },
    "updateDynamicAttributes": {
      "Items": [
        {
          "__typename": "DynamicAttribute",
          "ID": "{{digital_twins_dynamic_attribute_id}}",
          "ModelID": "{{digital_twins_model_id}}",
          "InstanceID": "{{digital_twins_instance_id}}",
          "Topic": "<devicehub-tag-topic>",
          "Name": "Speed",
          "Unit": "kmph",
          "DataType": "string",
          "SchemaID": "30D86400-D103-4C5C-95E4-AB6F02FB00EE"
        }
      ]
    }
  }
}

To discover the right Topic value for a DeviceHub-backed signal, list the device's registers via DeviceHub > Tags > List Registers from Single Device and inspect Topics[].Topic.

Response

200 OK -- application/json. No data returned on success.

{ "data": { "TransactionalInstanceUpdate": null } }

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

mutation TransactionalInstanceUpdate($input: TransactionalInstanceUpdateRequest!) {
    TransactionalInstanceUpdate(input: $input)
}

Variables

{
  "input": {
    "updateStaticAttributes": {
      "Items": []
    },
    "updateDynamicAttributes": {
      "Items": [
        {
          "__typename": "DynamicAttribute",
          "ID":"{{digital_twins_dynamic_attribute_id}}",
          "ModelID": "{{digital_twins_model_id}}",
          "InstanceID": "{{digital_twins_instance_id}}",
          "Topic": "devicehub.raw.779F42F3-54FC-4A87-B9A6-CD39CFA4A97D.1A5572B2-8242-40C8-BC63-FFEBC7DAF1E4",
          "Name": "Speed",
          "Unit": "kmph",
          "DataType": "string",
          "AttrDataType": "string",
          "SchemaID": "4C67A3E1-D442-4B39-B0F6-EB07CC200066"
        }
      ]
    }
  }
}

Response

Status: 200 OK

{
    "data": {
        "TransactionalInstanceUpdate": null
    }
}

Subscribe Instance Status

POST {{edgeUrl}}/digital-twins

Subscribe Instance Status

Streams the enabled/disabled state of every instance on the device. The Digital Twins UI subscribes to it to keep the status badges on the instance list current. Change a state with Set Instance State.

Endpoint

GET wss://{{edgeHost}}/digital-twins
Sec-WebSocket-Protocol: graphql-transport-ws

WebSocket subscription. Run it over the graphql-transport-ws protocol at wss://{{edgeHost}}/digital-twins: send connection_init, then a subscribe message carrying the document below. A plain HTTP POST does not stream. After importing this item, convert it to a Postman WebSocket request.

Authentication

HTTP Basic Auth on the WebSocket upgrade request. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Subscription

subscription InstanceStatus {
  InstanceStatus {
    InstanceID
    Status
  }
}

No variables.

Messages

Each next message carries data.InstanceStatus, a list of InstanceStatusEvent:

Field Type Description
InstanceID UUID! The instance.
Status InstanceStatus! Enabled or Disabled.

The first message arrives right after subscribe and lists every instance, so it doubles as a snapshot. With no state changes, no further message followed in 25 seconds on LE 4.0.x.

{
  "id": "1",
  "type": "next",
  "payload": {
    "data": {
      "InstanceStatus": [
        { "InstanceID": "0304E96A-F646-47A6-BDBC-D5F83A144A17", "Status": "Enabled" },
        { "InstanceID": "08F772EF-4EAC-5610-AB59-6D0E3C56052B", "Status": "Enabled" }
      ]
    }
  }
}

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

subscription InstanceStatus {
    InstanceStatus {
        InstanceID
        Status
    }
}

Response

Status: 200 OK

{
    "data": {
        "InstanceStatus": [
            {
                "InstanceID": "0304E96A-F646-47A6-BDBC-D5F83A144A17",
                "Status": "Enabled"
            },
            {
                "InstanceID": "08F772EF-4EAC-5610-AB59-6D0E3C56052B",
                "Status": "Enabled"
            },
            {
                "InstanceID": "09AF1BB5-CABC-5889-A331-5BF91AE3A12E",
                "Status": "Enabled"
            }
        ]
    }
}

Subscribe Instance Data

POST {{edgeUrl}}/digital-twins

Subscribe Instance Data

Streams the live payload of one instance: its static attribute values and the latest value of each dynamic attribute, laid out in the instance's hierarchy. This is what the instance page in the Digital Twins UI shows. Export Instance Schema returns the JSON Schema this payload follows.

Endpoint

GET wss://{{edgeHost}}/digital-twins
Sec-WebSocket-Protocol: graphql-transport-ws

WebSocket subscription. Run it over the graphql-transport-ws protocol at wss://{{edgeHost}}/digital-twins: send connection_init, then a subscribe message carrying the document below. A plain HTTP POST does not stream. After importing this item, convert it to a Postman WebSocket request.

Authentication

HTTP Basic Auth on the WebSocket upgrade request. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Subscription

subscription DataAccess($input: DataAccessRequest!) {
  DataAccess(input: $input)
}

Variables (input: DataAccessRequest!)

Field Type Required Description
InstanceID UUID! Yes Instance to stream.

input is optional in the 4.0.x schema and required from 4.4.x, so always send it.

{
  "input": {
    "InstanceID": "{{digital_twins_instance_id}}"
  }
}

Messages

Each next message carries data.DataAccess (type Any), the whole instance payload rather than a delta:

The example is trimmed to one tag. Several messages arrive right after subscribe, sometimes repeating the same payload. Later messages follow as the instance publishes new data; none arrived in 20 seconds on instances whose source tags were idle.

{
  "id": "1",
  "type": "next",
  "payload": {
    "data": {
      "DataAccess": {
        "Identification": {
          "AssetType": "Capper",
          "Line": "Bottling Line 1",
          "Site": "bottling-plant-01"
        },
        "PackML": {
          "CurMachSpeed": {
            "tagName": "CurMachSpeed",
            "deviceName": "BL1_Capper",
            "deviceID": "41E8271E-7E54-52D0-A9A8-0AB2DA882120",
            "registerId": "943315E3-B6E5-50D2-A2F7-3817D7EC02FF",
            "datatype": "float32",
            "value": null,
            "success": false,
            "timestamp": 1791650818402
          }
        }
      }
    }
  }
}

An unknown InstanceID returns key not found in the first message, followed by complete.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

subscription DataAccess($input: DataAccessRequest!) {
    DataAccess(input: $input)
}

Variables

{
    "input": {
        "InstanceID": "{{digital_twins_instance_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "DataAccess": {
            "Identification": {
                "AssetType": "Capper",
                "Line": "Bottling Line 1",
                "ModbusUnitId": "2",
                "Site": "bottling-plant-01",
                "Standard": "ISA-TR88.00.02 PackML"
            },
            "PackML": {
                "CurMachSpeed": {
                    "datatype": "float32",
                    "description": "",
                    "deviceID": "41E8271E-7E54-52D0-A9A8-0AB2DA882120",
                    "deviceName": "BL1_Capper",
                    "metadata": {
                        "asset_type": "capper",
                        "line": "Bottling Line 1",
                        "plant": "Bottling Plant 01"
                    },
                    "registerId": "943315E3-B6E5-50D2-A2F7-3817D7EC02FF",
                    "success": false,
                    "tagName": "CurMachSpeed",
                    "timestamp": 1791650818402,
                    "value": null
                }
            }
        }
    }
}

Export Instance Schema

POST {{edgeUrl}}/digital-twins

Export Instance Schema

Returns a JSON Schema (draft-07) describing the payload an instance publishes: its static attributes and its dynamic attributes, laid out in the instance's hierarchy. Use it to validate instance messages in a downstream consumer, or to generate typed models for them. Read-only.

This is the call behind Export JSON Schema on an instance card in the Digital Twins UI (Export Schema in the table view), which saves the result as a file.

Endpoint

POST {{edgeUrl}}/digital-twins
Content-Type: application/json

The operation is chosen by the GraphQL query body, not the URL path.

Authentication

HTTP Basic Auth. Username is your API token, password is empty. The same token is valid across /devicehub/v2, /analytics/v2, /cc, /opcua, and the other LE services.

Request body

query ExportInstanceSchema($input: ExportInstanceSchemaRequest!) {
  ExportInstanceSchema(input: $input) {
    Schema
    Filename
    ContentType
  }
}

Variables (input: ExportInstanceSchemaRequest!)

Field Type Required Description
InstanceID UUID! Yes Instance to describe. Take it from Get Instances.
{
  "input": {
    "InstanceID": "{{digital_twins_instance_id}}"
  }
}

Response

200 OK -- application/json. data.ExportInstanceSchema is a JSONSchemaResponse:

Field Type Description
Schema String! The JSON Schema, serialized as a string. Parse it before use.
Filename String! Suggested file name. Currently always instance.schema.json.
ContentType String! Media type for the file. Currently application/schema+json.

Parsed, the schema is an object with name set to the instance name and one property per top-level group:

Every listed property is also required.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "name": "Pump_P101",
  "description": "Instance schema",
  "type": "object",
  "properties": {
    "Nameplate": {
      "type": "object",
      "properties": {
        "Nameplate.ManufacturerName": { "type": "object" },
        "Nameplate.SerialNumber": { "type": "object" }
      },
      "required": ["Nameplate.ManufacturerName", "Nameplate.SerialNumber"]
    },
    "Properties": {
      "type": "object",
      "properties": {
        "AssetKind": { "type": "string" },
        "EquipmentTag": { "type": "string" }
      },
      "required": ["AssetKind", "EquipmentTag"]
    }
  },
  "required": ["Nameplate", "Properties"]
}

An unknown InstanceID returns instance not found; a malformed one returns invalid UUID length: <n>.

Errors

GraphQL endpoints return 200 OK even on logical errors. Inspect the errors array in the response body:

{ "errors": [ { "message": "...", "path": ["..."], "extensions": { "code": "..." } } ] }
extensions.code Meaning
UNAUTHENTICATED Missing or invalid API token.
FORBIDDEN Token lacks permission for this operation.
BAD_USER_INPUT Invalid argument (wrong type, missing required field, malformed UUID, unknown ID, etc.).
NOT_FOUND The targeted entity does not exist.
INTERNAL_SERVER_ERROR DeviceHub fault. Retry, then escalate via System > Support.

A non-200 HTTP response means DeviceHub itself is unreachable. See Dashboard > DeviceHub Status.

TLS note: edge devices use a self-signed certificate by default. Either install the device CA in your client trust store or disable certificate verification when calling this endpoint directly.

Request Body

GraphQL Query

query ExportInstanceSchema($input: ExportInstanceSchemaRequest!) {
    ExportInstanceSchema(input: $input) {
        Schema
        Filename
        ContentType
    }
}

Variables

{
    "input": {
        "InstanceID": "{{digital_twins_instance_id}}"
    }
}

Response

Status: 200 OK

{
    "data": {
        "ExportInstanceSchema": {
            "Schema": "{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"name\": \"Pump_P101\",\n  \"description\": \"Instance schema\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"Nameplate\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"Nameplate.CompanyLogo\": {\n          \"type\": \"object\"\n        },\n        \"Nameplate.ManufacturerName\": {\n          \"type\": \"object\"\n        },\n        \"Nameplate.SerialNumber\": {\n          \"type\": \"object\"\n        },\n        \"Nameplate.YearOfConstruction\": {\n          \"type\": \"object\"\n        }\n      },\n      \"required\": [\n        \"Nameplate.CompanyLogo\",\n        \"Nameplate.ManufacturerName\",\n        \"Nameplate.SerialNumber\",\n        \"Nameplate.YearOfConstruction\"\n      ]\n    },\n    \"OperationalData\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"AlarmHistory\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"0\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"OperationalData.AlarmHistory.0.Code\": {\n                  \"type\": \"object\"\n                },\n                \"OperationalData.AlarmHistory.0.Message\": {\n                  \"type\": \"object\"\n                }\n              },\n              \"required\": [\n                \"OperationalData.AlarmHistory.0.Code\",\n                \"OperationalData.AlarmHistory.0.Message\"\n              ]\n            },\n            \"1\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"OperationalData.AlarmHistory.1.Code\": {\n                  \"type\": \"object\"\n                },\n                \"OperationalData.AlarmHistory.1.Message\": {\n                  \"type\": \"object\"\n                }\n              },\n              \"required\": [\n                \"OperationalData.AlarmHistory.1.Code\",\n                \"OperationalData.AlarmHistory.1.Message\"\n              ]\n            }\n          },\n          \"required\": [\n            \"0\",\n            \"1\"\n          ]\n        },\n        \"Measurements\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"OperationalData.Measurements.FlowRate\": {\n              \"type\": \"object\"\n            },\n            \"OperationalData.Measurements.RunningState\": {\n              \"type\": \"object\"\n            },\n            \"OperationalData.Measurements.TemperatureRange\": {\n              \"type\": \"object\"\n            }\n          },\n          \"required\": [\n            \"OperationalData.Measurements.FlowRate\",\n            \"OperationalData.Measurements.RunningState\",\n            \"OperationalData.Measurements.TemperatureRange\"\n          ]\n        },\n        \"MotorAssembly\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"OperationalData.MotorAssembly.MotorPower\": {\n              \"type\": \"object\"\n            }\n          },\n          \"required\": [\n            \"OperationalData.MotorAssembly.MotorPower\"\n          ]\n        }\n      },\n      \"required\": [\n        \"AlarmHistory\",\n        \"Measurements\",\n        \"MotorAssembly\"\n      ]\n    },\n    \"Properties\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"AssetKind\": {\n          \"type\": \"string\"\n        },\n        \"EquipmentTag\": {\n          \"type\": \"string\"\n        },\n        \"GlobalAssetId\": {\n          \"type\": \"string\"\n        },\n        \"IdShort\": {\n          \"type\": \"string\"\n        },\n        \"ShellId\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"AssetKind\",\n        \"EquipmentTag\",\n        \"GlobalAssetId\",\n        \"IdShort\",\n        \"ShellId\"\n      ]\n    }\n  },\n  \"required\": [\n    \"Nameplate\",\n    \"OperationalData\",\n    \"Properties\"\n  ]\n}",
            "Filename": "instance.schema.json",
            "ContentType": "application/schema+json"
        }
    }
}

Subscribe Playground Messages

POST {{edgeUrl}}/digital-twins/v2

New in 4.2.x. Streams live messages from a subject so a transformation can be tried against real traffic before it is saved to an attribute.

Input Meaning
Subject Required. The topic or subject to watch.
Expression Optional. Transformation to apply to each message.
SchemaType json | jsonata.

Each event carries the raw Payload, the Transformed result of applying Expression, and an Error when the expression fails on that message. Sending no Expression gives a plain topic tap.

DroppedSinceLast counts messages skipped since the previous event because the stream outran the consumer. A steadily rising value means what you are seeing is a sample, not the full feed.

WebSocket subscription. Convert to a Postman WebSocket request after import (URL: wss://.../digital-twins/v2).

Request Body

GraphQL Query

subscription PlaygroundMessages($input: PlaygroundSubscribeRequest!) {
    PlaygroundMessages(input: $input) {
        Topic
        ReceivedAt
        Payload
        Transformed
        Error
        DroppedSinceLast
    }
}

Variables

{
  "input": {
    "Subject": "{{dt_playground_subject}}",
    "Expression": null,
    "SchemaType": "jsonata"
  }
}

Set Instance Asset Hierarchy

POST {{edgeUrl}}/digital-twins/v2

New in 4.3.x. Place one or more instances in an asset hierarchy. Returns Empty.

Request field Meaning
Items List of assignments. Required, and the only field on the request
Items[].InstanceID The instance being placed. Required
Items[].HierarchyPath Its position in the hierarchy. Optional
Items[].HierarchyMetadata Free-form metadata, typed Any. Optional

The mutation is batch-first: Items is a list, so several instances can be placed in one call, which is the efficient way to build or restructure a hierarchy.

HierarchyMetadata is the Any scalar, so the server does not constrain its shape. That flexibility cuts both ways: a typo in a key is accepted silently. Settle on a metadata shape and validate it before sending.

The return type is Empty, so the response confirms nothing beyond the absence of an error. Read the placement back through the instance's static attributes, where hierarchy-derived entries carry AttributeType: AssetHierarchy.

Related: AttributeType gains AssetHierarchy in 4.3.x. See List Static Attributes in this folder.

Request Body

GraphQL Query

mutation SetInstanceAssetHierarchy($input: SetInstanceAssetHierarchyRequest!) {
    SetInstanceAssetHierarchy(input: $input)
}

Variables

{
  "input": {
    "Items": [
      {
        "InstanceID": "{{dt_instance_id}}",
        "HierarchyPath": "plant/line1/press",
        "HierarchyMetadata": {
          "area": "stamping",
          "criticality": "high"
        }
      }
    ]
  }
}

View this page as Markdown