# Microsoft Power Automate

> Send records from Microsoft Forms, SharePoint, Dynamics 365 and other Power Automate connectors to Dimension Labs with a cloud flow and the universal API.

Power Automate connects to Microsoft 365, Dynamics 365 and many other apps ([Microsoft's Power Automate page](https://www.microsoft.com/en-us/power-platform/products/power-automate/) states more than 1,400 prebuilt, certified connectors as of 2026-10-26). If a tool you use has a Power Automate trigger, such as a new Microsoft Forms response, a new SharePoint list item or a new Dynamics 365 case, a cloud flow can send each new record to the [universal API](/api/tracker). There's no server to run: Power Automate runs the flow each time the trigger fires.

Power Automate fits sources where one trigger event is one piece of customer text: a form or survey response, a review, a feedback submission, the first message of a ticket. For full multi-message conversations, or to load history, use the app's own guide or [Any other system](/integrations/other-sources), which pull every message in order.

## What you need

- **A Power Automate license that includes premium connectors.** The flow sends with the HTTP action, and Microsoft describes HTTP as a premium connection ([Overview of HTTP connectors in Power Automate](https://learn.microsoft.com/en-us/training/modules/http-connectors/1-introduction)). Users on the free plan or a Microsoft 365 license can only use standard connectors ([licensing FAQ](https://learn.microsoft.com/en-us/power-platform/admin/power-automate-licensing/faqs)). A Power Automate Premium license for the flow's owner, or a Process license assigned to the flow, covers it ([license types](https://learn.microsoft.com/en-us/power-platform/admin/power-automate-licensing/types)).
- A trigger for your app that returns the customer's text and a date.
- A Dimension Labs API key for a new **Universal API** source. See [Your API key](/api/tracker#your-api-key).

Without a premium license, export your records from the app and [upload a file](/data/upload-a-file) instead.

## 1. Choose the trigger

1. Create an automated cloud flow and choose the trigger for your app, for example a new form response, a new list item or a new case. Some triggers return only an id: add the app's "get details" action after it to fetch the full record.
2. Test the flow and check the trigger's output has three things: the customer's text, an id for the record, and when it was written.

Use one source in Dimension Labs per app, so its data is easy to filter later.

In the steps below, `TEXT`, `RECORD_ID` and `WRITTEN_AT` stand for your trigger's fields. Wherever they appear, insert that field from **Dynamic content** in its place.

## 2. Skip empty text

Add a **Condition** ([Add a condition to a cloud flow](https://learn.microsoft.com/en-us/power-automate/add-condition)). In the left box, enter the expression `empty(trim(TEXT))`. Set the middle box to **is equal to** and the right box to the expression `false`. Add the next two actions under **If yes**.

## 3. Build the message with Compose

Add a **Compose** action and rename it `Message`. In **Inputs**, type this JSON, putting your trigger's fields in place of `TEXT` and `RECORD_ID`:

```json
{
  "text": "TEXT",
  "userId": "@{replace(concat('forms-', string(RECORD_ID)), ':', '-')}",
  "incoming": true,
  "sessionId": "@{replace(concat('forms-', string(RECORD_ID)), ':', '-')}",
  "conversationId": "@{replace(concat('forms-', string(RECORD_ID)), ':', '-')}",
  "platformJson": { "source": "forms" }
}
```

- `forms-` prefixes the record's id with the app's name. Change it to match your app. `replace` turns any colon into a dash, because ids can't contain colons.
- `userId` is the `sessionId` here. If the trigger has your internal customer id, use `replace(string(CUSTOMER_ID), ':', '-')` instead. Never an email address or name.
- Add other fields you want to filter or join on later (a rating, a location id, a form name) inside `platformJson`.

Build the message in Compose, never by joining text with `concat` into a JSON string. Compose keeps the message as an object and the HTTP action turns it into JSON, escaping quotes and line breaks in the customer's text. Microsoft's own [expression cookbook](https://learn.microsoft.com/en-us/power-automate/expression-cookbook) warns that JSON built with `concat` is malformed when a value contains quotes: a review with a quotation mark in it would break the request.

## 4. Send it with the HTTP action

Add an **HTTP** action after Compose and set:

- **Method:** `POST`
- **URI:** the address below. The part in `@{...}` picks the endpoint: a record written more than an hour ago goes to `/trackhistorical`, as every guide does. Replace `YOUR_API_KEY` with your Dimension Labs API key.

```
https://tracker.dimensionlabs.io/@{if(less(ticks(WRITTEN_AT), ticks(addHours(utcNow(), -1))), 'trackhistorical', 'track')}?platform=universal&v=11.1.0-rest&type=incoming&apiKey=YOUR_API_KEY
```

- **Headers:** `Content-Type` = `application/json`
- **Body:** this expression, which adds the timestamp in Unix milliseconds to the message:

```
setProperty(outputs('Message'), 'dimensionlabs_timestamp', div(sub(ticks(WRITTEN_AT), ticks('1970-01-01T00:00:00Z')), 10000))
```

`ticks` counts 100-nanosecond intervals, so the difference from 1 January 1970, divided by 10,000, is Unix time in milliseconds. These functions are in Microsoft's [expression functions reference](https://learn.microsoft.com/en-us/azure/logic-apps/expression-functions-reference), which covers Power Automate.

Test the flow. A `200` status on the HTTP action means the message reached Dimension Labs.

## 5. Turn it on

- **Save** the flow and make sure it is on. Each new record is sent as it arrives, to `/track`, and is enriched automatically every day.
- **If the flow runs late** (more than an hour after the record was written), the URI sends it to `/trackhistorical`. Run a [backfill](/dimensions/backfill) from the **Backfill** tab to enrich those.
- **History:** a trigger only sees new records. Export your history from the app and [upload a file](/data/upload-a-file) (check it with the [file checker](/data/check-a-file)), then run a backfill.
- **Re-runs are safe:** if you resubmit a run, duplicates are removed automatically.
- **Action limits:** every action, including HTTP, counts toward your license's daily action limit ([licensing FAQ](https://learn.microsoft.com/en-us/power-platform/admin/power-automate-licensing/faqs)). This flow uses a few actions per record.

**Personal data.** Don't put email addresses, names or phone numbers into the message: everything in `platformJson` is kept as metadata. Redact the text if customers include personal details. See [PII redaction](/data/pii-redaction).

## A record with several messages

If the trigger returns a whole conversation (a ticket with replies, a chat transcript), each message needs its own `POST`, in order, at least one second apart, with replies from your side marked `incoming: false` and `type=outgoing`. That is easier and more reliable in a script: see the app's guide, or [Any other system](/integrations/other-sources).

## Power Automate reference

- [Power Automate](https://www.microsoft.com/en-us/power-platform/products/power-automate/)
- [Power Automate license types](https://learn.microsoft.com/en-us/power-platform/admin/power-automate-licensing/types)
- [Power Automate licensing FAQ](https://learn.microsoft.com/en-us/power-platform/admin/power-automate-licensing/faqs)
- [Overview of HTTP connectors in Power Automate](https://learn.microsoft.com/en-us/training/modules/http-connectors/1-introduction)
- [Add a condition to a cloud flow](https://learn.microsoft.com/en-us/power-automate/add-condition)
- [Expression cookbook](https://learn.microsoft.com/en-us/power-automate/expression-cookbook)
- [Expression functions reference](https://learn.microsoft.com/en-us/azure/logic-apps/expression-functions-reference)

Checked against Microsoft's documentation on 2026-10-26.
