JSON Schema for Parse JSON
Stop Parse JSON failing at run time. The exact schema dialect behind the Parse JSON action and the "When a HTTP request is received" trigger — types, properties, required, items, and the nullable patterns that survive messy real-world payloads. Paste a sample into the generator for a ready-to-use schema, complete with required-array switches and a "never fails" nullable mode.
{
"type": "object",
"properties": {
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"displayName": {
"type": "string"
},
"mail": {
"type": "string"
},
"accountEnabled": {
"type": "boolean"
},
"signInActivity": {
"type": "object",
"properties": {
"lastSignIn": {
"type": "string"
}
},
"required": [
"lastSignIn"
]
},
"assignedLicenses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"skuId": {
"type": "string"
}
},
"required": [
"skuId"
]
}
},
"department": {},
"directReports": {
"type": "integer"
}
},
"required": [
"id",
"displayName",
"mail",
"accountEnabled",
"signInActivity",
"assignedLicenses",
"department",
"directReports"
]
}
},
"@odata.count": {
"type": "integer"
}
},
"required": [
"value",
"@odata.count"
]
}Paste the result into the Parse JSON action’s Schema box. Everything runs in your browser.
What Parse JSON needs
The Parse JSON data operation and the When a HTTP request is received trigger both take a schema that describes the payload. The designer uses it for two jobs: to emit typed dynamic-content tokens for every property, and to validate the shape of the content at run time. The schema is a JSON Schema document in the draft-4-era vocabulary Logic Apps uses — a tree of nodes built from type, properties, items, and required.
Generate from sample, then edit
You rarely hand-write a schema. Under the Schema box choose Generate from sample (Parse JSON) or Use sample payload to generate schema (the Request trigger), paste a *representative* response — ideally one where every optional field is populated — and the designer infers the schema. Then edit it (see below). The generator on this page does the same, with extra switches.
The same schema, in several places
This dialect shows up beyond Parse JSON: the Request trigger's Request Body JSON Schema, custom-connector request/response definitions, and anywhere the designer turns JSON into tokens. Learn the schema once and it pays off across all of them. For where Parse JSON sits in a real HTTP flow, see the HTTP Requests & APIs guide.
Anatomy of a schema
Every schema is a tree of nodes. Each node declares a type; container nodes then describe their children — an object node carries a properties map, an array node carries an items schema. The root is almost always an object.
{
"type": "object",
"properties": {
"status": { "type": "string" },
"orders": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"total": { "type": "number" }
},
"required": [ "id" ]
}
}
},
"required": [ "status" ]
}| Keyword | Applies to | Purpose |
|---|---|---|
| type | Every node | The JSON type: string, integer, number, boolean, object, array, null. |
| properties | object | Map of key → child schema. Drives the typed tokens. |
| items | array | Schema for each element of the array. |
| required | object | Keys that must be present, or the action fails. |
| additionalProperties | object | Whether keys beyond properties are allowed (usually omitted). |
Types: JSON value → schema type → token
Each JSON value maps to one schema type, which in turn decides the kind of dynamic-content token you get downstream.
| JSON value | Schema type | Token | Notes |
|---|---|---|---|
| "hello" | `"string"` | Text | The default for most fields. |
| 42 | `"integer"` | Integer | Whole numbers only — mind the integer/number trap below. |
| 3.14 | `"number"` | Float | Any real number — JSON has a single numeric type. |
| true / false | `"boolean"` | Boolean | Yes/No values. |
| { … } | `"object"` | expands to fields | Carries `properties`; drill in for child tokens. |
| [ … ] | `"array"` | Array | Carries `items`; feed an Apply to each or Select. |
| null | `{}` or `["…","null"]` | Any / nullable | A bare `{}` node matches any type. |
The integer vs. number trap
If a sample shows a whole number (4), the generator infers "integer". If that field can ever be fractional (4.5), the value fails the "integer" node at run time — Microsoft's own docs call this out. When a number might have decimals, change "integer" to "number". Money, rates, and averages are the usual offenders.
Empty schema = any type
A node of {} (no type) matches anything. The generator emits it for a null sample, because it can't infer a type from null. It's also a deliberate escape hatch for a node whose shape is volatile or that you simply don't read — see the cookbook.
Nullability: the #1 Parse JSON failure
By far the most common Parse JSON error is a field that is null or absent in real data but typed as a non-null required value in the schema. APIs routinely omit empty fields or send null — and a node typed "string" rejects null, while a required key that's missing fails the whole action.
// fails when "department" comes back null
"department": { "type": "string" }
// tolerates null
"department": { "type": [ "string", "null" ] }- Allow null — change
"type": "string"to"type": ["string", "null"]so a null value parses. - Make it optional — remove the key from the node's
requiredarray so an absent field doesn't fail. - Belt and braces — do both for any field you don't fully control; the action then never fails on that property.
Let the generator do it
The generator above has a Make all fields nullable switch: it adds "null" to every type and drops all required arrays, producing a schema that won't fail on missing or null data. Tighten it back up only for the fields you genuinely depend on.
Objects: properties & required
An object node lists each key under properties and (optionally) names mandatory keys in required. The generator's default — matching the designer — is to mark every key it saw as required, which is exactly why generated schemas are brittle.
{
"type": "object",
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"note": { "type": [ "string", "null" ] }
},
"required": [ "id" ],
"additionalProperties": false
}Trim required to what matters
Over-broad required arrays are the usual cause of "Invalid type. Expected … but got Null" and missing-property failures. Keep in required only the keys your downstream actions actually read; let everything else be optional.
additionalProperties
Left out (the generator's default), extra keys in the payload are simply ignored — usually what you want. Set "additionalProperties": false only when you must reject any unexpected key. "additionalProperties": { "type": "string" } types a bag of arbitrary string-valued keys (see the cookbook).
Arrays: items, list vs. tuple
An array node describes its elements with items. A single schema under items means a homogeneous list — every element has the same shape. This is the form Power Automate generates and the one you almost always want.
"orders": {
"type": "array",
"items": {
"type": "object",
"properties": { "id": { "type": "string" } },
"required": [ "id" ]
}
}
"tags": {
"type": "array",
"items": { "type": "string" }
}The designer samples only the first element
Built-in "Generate from sample" infers an array's items from the first element alone — so optional keys that appear only on later elements are missed, and you get null-token surprises. The generator on this page is stricter: it merges the keys across all sampled elements and marks as required only the keys present in every one.
Skip tuple validation
JSON Schema also allows a tuple form — items as an *array* of schemas, one per position. It's valid, but Power Automate's generator never emits it and tooling support is patchy. Stick to the single-schema list form.
Validation keywords (and what Parse JSON enforces)
JSON Schema has a rich constraint vocabulary, but Parse JSON is a parser, not a validator. It enforces the structural keywords (type, required) and uses properties/items to build tokens; the rest are valid schema but effectively documentation here.
| Keyword | Constrains | Enforced by Parse JSON? |
|---|---|---|
| type | The JSON type of the value | Yes — strict; a mismatch fails the action. |
| required | Keys that must be present | Yes — a missing key fails the action. |
| properties | An object's child schemas | Yes — drives the typed tokens. |
| items | Schema for array elements | Yes — drives the array tokens. |
| enum / const | Value must be one of a set | Not reliably — treat as advisory. |
| pattern / format | Regex or semantic string format | Not reliably — date-time stays plain text. |
| minimum / maximum | Numeric bounds | Not enforced. |
| minLength / maxLength | String length bounds | Not enforced. |
| minItems / uniqueItems | Array size / uniqueness | Not enforced. |
| additionalProperties | Allow / forbid extra keys | Partial — generally tolerant; safest omitted. |
Don’t rely on Parse JSON for real validation
If you need to *reject* bad input — enforce an enum, a regex, a numeric range — do it yourself: a Condition, a Filter array, an Office Scripts call, or schema validation upstream. Parse JSON will happily pass a value your constraint keywords say is invalid.
String formats & special values
The format keyword annotates strings (date-time, email, uri…). Parse JSON keeps them as plain string tokens — format doesn't change the type or get enforced, so you reshape values yourself with expressions.
| format | Example value | Treat it as |
|---|---|---|
| date-time | 2026-06-16T09:30:00Z | A plain string — reshape with `formatDateTime()`. |
| date | 2026-06-16 | Plain string. |
| ada@contoso.com | Plain string. | |
| uri | https://contoso.com | Plain string. |
| uuid | 7c1f…e9 | Plain string (a GUID). |
| byte / binary | U29tZSBkYXRh… | Plain string; decode with `base64ToBinary()`. |
Numbers that arrive as strings
Plenty of APIs quote their numbers ("amount": "123.45"). That's a "string", not a number — type it as such and cast in an expression with int(), float(), or decimal() when you need to do maths. See the Expressions guide.
Schema cookbook
Copy-paste starting points for the payloads you meet most. All are pre-relaxed where a field is commonly null — tighten required to taste.
Microsoft Graph collection (value array + nextLink)
{
"type": "object",
"properties": {
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string" },
"displayName": { "type": "string" },
"mail": { "type": [ "string", "null" ] }
},
"required": [ "id" ]
}
},
"@odata.nextLink": { "type": "string" }
},
"required": [ "value" ]
}SharePoint / Dataverse rows (annotated OData)
{
"type": "object",
"properties": {
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"@odata.etag": { "type": "string" },
"accountid": { "type": "string" },
"name": { "type": "string" },
"revenue": { "type": [ "number", "null" ] }
}
}
}
}
}Webhook trigger body (When a HTTP request is received)
{
"type": "object",
"properties": {
"event": { "type": "string" },
"timestamp": { "type": "string" },
"data": {
"type": "object",
"properties": {
"id": { "type": "string" },
"amount": { "type": "number" }
},
"required": [ "id" ]
}
},
"required": [ "event", "data" ]
}A root-level array
{
"type": "array",
"items": {
"type": "object",
"properties": {
"first": { "type": "string" },
"last": { "type": "string" }
},
"required": [ "first", "last" ]
}
}A dynamic key/value bag
{
"type": "object",
"additionalProperties": { "type": "string" }
}An unpredictable sub-tree
"metadata": {}Editing a generated schema
Treat the generated output as a first draft. A few quick edits turn a brittle schema into a robust one:
- Relax null-prone fields — add
"null"to the type of anything optional or sometimes-empty. - Trim `required` — keep only the keys you actually read downstream.
- Fix integer → number — for any value that can be fractional.
- Collapse volatile nodes to `{}` — sub-trees that change shape, or that you don't read.
- Delete the noise — drop
@odata.*and other keys you'll never reference to keep the token list clean. - Sample richly — paste a record where optional fields are populated, so the generator sees them at all.
Common gotchas
- Null on a non-null type —
"Invalid type. Expected String but got Null"means add"null"to that node's type. - Missing required key — a
requiredfield absent from the payload fails the action; remove it fromrequired. - integer vs. number — a decimal value fails an
"integer"node; widen to"number". - First-element sampling — the designer only reads array element [0]; optional keys on later items are missed (this generator merges them).
- Constraint keywords don't validate —
enum,pattern,format,minimumare advisory in Parse JSON; validate critical rules yourself. - Don't double-parse — connector actions usually return parsed objects already; only run Parse JSON /
json()on raw strings. - Quoted numbers are strings —
"123"is a"string"; cast withint()/float()when you need maths. - Secure the Request trigger — generating a schema from a sample doesn't authenticate callers; validate and gate the trigger (see the HTTP guide).