Table of contents
TL;DR - Imagine you have a list of information about people. This list contains the person's name, age, email address, and interests. JSON is a way of presenting this information in a structured and somewhat easy-to-read way. In Power Automate, technically speaking, all actions whose inputs and outputs are processed in JSON.
The basics and the structure
Lets imagine a list of information about people.
- A list (of people) is called Array. You can recognize an array when you see the square brackets.
- Data (of a person) within the array in called Object. You can recognize an object by the curly brackets.
- An object is further defined by its properties. The properties contain the actual data of that person. Properties always contain data following a data type (string, number, object, array, boolean or null, which is empty). Property names and their values are put into double quotes and separated by a colon (:).
Arrays, Objects and Properties are separated by commas. Within an array all objects have the same set of properties, even if they don’t contain values. Strings or dates are written in double quotes, numbers without and a point as the decimal separator, boolean values (true or false) and null also without.
Here is another good explanation: https://www.w3schools.com/js/js_json_syntax.asp

In Power Automate
In Power Automate JSON is the underlying code for a flow. Every trigger, every action and the flow itself is stored and written in JSON. The designer simply translates the code into UI and therefore, clickable elements.
Input example
In the UI
We use the create item action to create an item in a SharePoint list. In the UI we select the site address and list from dropdown and enter the values we want to create the item with.

Backend code as JSON
Using the code view we can see that the inputs via the UI reflect in the JSON code of that action. Dataset corresponds to the site address and table is the ID of the list we have selected.Remember: Each actions inputs are described in JSON. We configure inputs by using the parameters tab in the UI and we can view the underlying code using the code view.

Output example
This is an action to get an item by its ID from s SharePoint list. We want to read the items value from the text column and send it in an email.

In the UI
We use the Send email action and add the textColumn from the Get item action by using the UI.

Backend code as JSON
Using the code view or by hovering over the dynamic input with the mouse, we get to see the underlying JSON.

outputs('Get_item')?['body/textColumn']What you need to learn
Expressions like the one below are simply a method of navigating through the JSON and return arrays, objects or a properties value. The output of each action is always split into to parts: Headers and Body. While the headers contain technical information, the body contains data (we want).
The complete output including header and body is returned by using
- outputs('Action Name')
Usually, each action will have a body property as an output. It can be returned by using
- outputs(’Action Name’)?[’body’]
From there you will try navigate across the path that you need to take in order to reach your destination array, object or value. If there is a property within the body of this JSON called birthday it can be returned using
- outputs(’Action Name’)?[’body’]?[’birthday’]
I encourage you to always check the outputs of an action once your flow has run. You can show the raw outputs of any action and take a look at the JSON it returned.

Deconstructing some examples
Action: Get item
Getting the value from the text column
outputs('Get_item')?['body']?['textColumn']Getting the value from the date column
outputs('Get_item')?['body']?['dateColumn']Getting the Email value of the author column
outputs('Get_item')?['body']?['Author']?['Email']
//OR
outputs('Get_item')?['body/Author/Email']Although both versions to get the email of the author work, the second version is prone to error. If for some reason there is no author and the path cannot be completed your action using that expression will fail. I always recommend to use the first version.
Output of the Get item action (shortened for better readability)
Action: Create and wait for an approval
A very commonly used action belongs to the standard approvals connector.
Getting the value of the outcome
outputs('Start_and_wait_for_an_approval')?['body']?['outcome']Getting the approval completion date
outputs('Start_and_wait_for_an_approval')?['body']?['completionDate']Getting the approvers email
The approvers email is within the responses array, where each response object describes the approver. When selecting this directly in the UI the flow designer will automatically turn this into a loop.
Lets just imagine that this approval always has exactly one approver, the responses will still be stored as an array. We can apply the following expression(s) to get the approvers email:
first(outputs('Start_and_wait_for_an_approval')?['body']?['responses'])?['responder']?['email']We are using first to simply take the first object inside the responses array. The first is wrapped around the path to the responses array. From there we use our usual way of navigation through the json.
Output of the Create and wait for an approval action (shortened for better readability)
Action: Get items
As the name of that action suggests, the output is a list of items. As you already know a list of items is called array. Get items returns an array. Once you use outputs in your loop from that action, the flow designer will automatically create a for each action for you.
We will take a closer look at the for each action being added automatically.

Inside the for each action
A for each action always needs an array to work through. In that case it automatically selected the value from our Get items action.
outputs('Get_items')?['body']?['value']Inside the compose action
The for each now goes through all objects inside the array, one after the other. As a reminder, each object is surrounded by curly brackets. We can use either version below to tell all actions inside the for each that we need the textColumn value of the current object that the for each is processing.
items('For_each')?['textColumn']
//OR
item()?['textColumn']Getting only the first objects textColumn value
Just as we did above for the approval action, we can use the expression first() to access the very first object in the array. Instead we can also use Last() to get the last object.
first(outputs('Get_items')?['body']?['value'])?['textColumn']
//OR by using an index
outputs('Get_items')?['body']?['value'][0]?['textColumn']
//This can also get us the third or the object in any position
outputs('Get_items')?['body']?['value'][3]?['textColumn']When you are using the index to get a certain object, the first object is always the index value 0. If you try to select a position that does not exist, for example 5, then the flow will fail as there is only four objects in our array.
Output of the Get items action (shortened for better readability)
When should you use your own expressions
- Get items is a very common use case. It always returns an array which the flow designer interprets into a loop once you are using outputs from it. In some cases you might already know that the array will only contain one object. You can use the expression first() to avoid an unnecessary loop action being added to your flow.
- Working with data from the HTTP Request to SharePoint Connector,
- Office 365 … HTTP Connector
- Working with custom or external APIs
I do not recommend using the Parse JSON action as this does not help you to understand JSON. You give that action the output you want to continue to work with, then its parses the data and return it to the UI. Sometimes, it will fail your flow if the output schema changes or property values that where filled before are suddenly empty.
Changelog
Date | Changes |
28.02.2026 | Initial version |
❤️ Thanks for reading.