Home/Knowledge Base/Integrations & IoT/Connecting Azure IoT Hub to UniAsset
Back to Integrations & IoT

Connecting Azure IoT Hub to UniAsset

10 min readadvancedLast updated: January 2, 2026

Overview

Azure IoT Hub is Microsoft's cloud-scale message broker for IoT devices. UniAsset's IoT Signal ingestion endpoint accepts the telemetry that IoT Hub forwards, recording every signal against the asset it belongs to.

This article walks through:

  1. The prerequisites
  2. Creating an API key in UniAsset
  3. Configuring an Azure IoT Hub message route
  4. The payload format UniAsset expects
  5. Verifying signals are arriving
  6. Troubleshooting common errors

Plan required: Enterprise

Note: Phase 1 of the IoT Signal foundation stores and displays signals. It does not yet trigger automation, work orders, or notifications. Those capabilities ship in a later phase on top of the same ingestion contract.

Prerequisites

Before you begin, confirm you have:

  • A UniAsset organization on the Enterprise plan
  • The Owner role in UniAsset (required to create integration API keys)
  • An active Azure subscription with an Azure IoT Hub instance
  • Permission in Azure to add a custom endpoint to IoT Hub and to create a message route
  • HTTPS connectivity from Azure to https://<your-uniasset-domain>

Step 1 — Create a UniAsset API key

  1. Sign in to UniAsset as the Owner.
  2. Click Settings in the left sidebar.
  3. Open the Integrations tab.
  4. Click API Keys → Create API Key.
  5. Give it a descriptive name (for example, Azure IoT Hub — Production).
  6. Grant only the iot:signal:ingest permission. Avoid adding write permissions that this integration does not need.
  7. Click Generate. The full key is shown once — copy it now and store it in Azure Key Vault. UniAsset only persists a bcrypt hash; the plaintext key cannot be recovered.

The key format is ua_live_<64-hex-chars>. The first 12 characters are an unencrypted prefix used for lookup.

Step 2 — Add UniAsset as a custom endpoint in Azure IoT Hub

In the Azure portal:

  1. Open your IoT Hub instance.
  2. Under Hub settings, select Message routing.
  3. Switch to the Custom endpoints tab and click + Add → Webhook.
  4. Name the endpoint UniAsset.
  5. Set the URI to https://<your-uniasset-domain>/api/integrations/iot/signals.
  6. Under Custom headers, add:
    • Authorization: Bearer ua_live_<your-key>
    • Content-Type: application/json
  7. Save the endpoint.

Step 3 — Create the message route

  1. In Message routing, switch to the Routes tab and click + Add.
  2. Name the route forward-to-uniasset.
  3. Data source: Device Telemetry Messages.
  4. Endpoint: the UniAsset endpoint you just created.
  5. Routing query: leave as true to forward everything, or scope it (for example, signalType = 'temperature.high') if your devices already emit a signalType property.
  6. Save.

Step 4 — Shape the payload

UniAsset expects each signal as a JSON object with at least source, signalType, and payload. Devices that emit raw sensor messages should transform them either at the edge or via an Azure Function bridge.

{
  "assetId": "ckxyz123abc",
  "deviceId": "azure-device-001",
  "source": "AzureIoTHub",
  "signalType": "temperature.high",
  "severity": "HIGH",
  "numericValue": 92.5,
  "payload": {
    "temperature": 92.5,
    "unit": "C",
    "messageId": "12fa..."
  }
}
FieldRequiredNotes
sourceYesAlways "AzureIoTHub" for this integration.
signalTypeYesFree-form, e.g. temperature.high, vibration.spike. Use a dotted-path convention so future rules can pattern-match.
payloadYesRaw payload object. Stored verbatim — keep the original device fields here.
assetIdNoUniAsset asset id. If your IoT Hub device twins already store this, include it.
deviceIdNoStable Azure device identifier. Useful for reconciliation.
severityNoOne of INFO, LOW, MEDIUM, HIGH, CRITICAL. Free text allowed but normalized to upper case server-side.
numericValue / textValue / booleanValueNoTyped projections for charting and filtering. The raw payload is always the source of truth.

Edge transformation with an Azure Function

If your devices emit a raw schema, the simplest pattern is an HTTP-triggered Azure Function that receives the IoT Hub message, transforms it, and POSTs to UniAsset. A starting point:

export async function azureIoTBridge(req: { body: any }) {
  const raw = req.body;
  const uniassetPayload = {
    deviceId: raw.systemProperties["iothub-connection-device-id"],
    source: "AzureIoTHub",
    signalType: raw.properties.signalType ?? "telemetry.raw",
    severity: raw.properties.severity,
    numericValue: raw.body.value,
    payload: raw.body,
  };

  await fetch("https://<your-uniasset-domain>/api/integrations/iot/signals", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.UNIASSET_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(uniassetPayload),
  });
}

Step 5 — Verify signals are arriving

  1. In UniAsset, open IoT Signals in the left sidebar (only visible on Enterprise).
  2. The timeline should show messages within seconds of devices publishing.
  3. If you mapped assetId, open the corresponding asset in Assets → <name> and scroll to the IoT Signals section.

Best practices

  • Store the API key in Azure Key Vault. Do not check it into source control or paste it into the IoT Hub UI without a Key Vault reference.
  • Use one API key per environment. Production and staging should have distinct keys so revocation is surgical.
  • Adopt a dotted-path signalType convention. It future-proofs rule patterns: temperature.high, temperature.low, vibration.spike, door.open, motor.runtime.
  • Send severities as upper case enumsCRITICAL, HIGH, MEDIUM, LOW, INFO. UniAsset will normalize anything else, but consistency simplifies your downstream rules later.
  • Keep payloads under 1 MB. UniAsset rejects larger bodies with a 413 PAYLOAD_TOO_LARGE. For aggregate uploads, split at the IoT Hub side.

Troubleshooting

SymptomLikely causeResolution
401 INVALID_KEYKey revoked or mistypedRegenerate the key in UniAsset and update the IoT Hub endpoint header.
403 ENTERPRISE_REQUIREDPlan downgradedRestore the Enterprise plan.
403 FORBIDDENKey missing iot:signal:ingestEdit the key's permissions in UniAsset.
404 NOT_FOUND on a signalSupplied assetId doesn't belong to the tenantRemove the assetId or correct the mapping. The signal will still be stored without an asset link if you drop the field.
422 VALIDATION_ERRORMissing source / signalType / payload, or signalType contains invalid charactersCheck the response details[] for the offending field and fix the transformation function.
413 PAYLOAD_TOO_LARGEBody above 1 MBSplit the payload upstream.
Signals visible globally but not on an asset detail pageMissing or wrong assetIdAdd assetId to the payload before posting.

Related articles

Need Help?

If you have questions not covered in this article, our support team is here to help.

Contact Support