Blog • AI / App Intents
After iOS 27 Opens More Siri Actions, How Does App Action JSON Actually Flow? From the Spoken Request to the API Call
A Siri request runs because it first becomes App Intent parameters, then AppIntent decides inside perform() whether to stay on device or call your API. The system does not forward the raw utterance to your server.
Whether Siri counts as an agent is in the previous article. This one follows a single request: how a phrase selects an Intent, how parameters become JSON, and why the API runs only after validation.
- A phrase matches an App Shortcut. The utterance is not executed as free text
- Three parameter kinds: built-in types, a compile-time AppEnum, and an AppEntity that must be queried
- An entity contributes a stable id. The query loads your data with that id
- You keep your own parameter JSON. It is not Apple's wire format
- If resolved is false or the schema fails, do not call the API. Hand the dialog back to Siri
Hold this first: Speech is not the request body. The filled Intent parameters are. The sections below follow phrase, parameter type, entity id, your JSON, then the API.
Five steps in one request
The official entry is App Intents. See Getting started with App Intents. Siri, Shortcuts, and an in-app button share one Intent. They differ in who fills the parameters.
- 1Match the phrase
You register spoken phrases on
AppShortcutsProvider. The system uses that phrase to select an Intent. It does not hand the raw sentence to a model to improvise. - 2Fill parameters
Each
@Parameteron the Intent tells the system which value it needs and whether it is required. A missing value prompts the person. It does not guess and send. - 3Resolve the entity
User data is resolved through
EntityQuerybyid. The parameter holds the entity, not a paragraph that describes it. - 4Run
perform() is where you read values that are already resolved. If the device can finish the action, finish it there.
- 5Answer Siri
Return the outcome with
IntentResultor a dialog. A failure still needs a sentence a person can hear. Do not leave the error only in a server log.
Three kinds of parameters
Parameter types are covered in Adding parameters to an app intent. Pick the wrong type and the JSON downstream will not stay stable.
| Type | Use it for | In JSON |
|---|---|---|
| String, number, date | Simple input such as a quantity or a note | Copy it into parameters as-is |
AppEnum | A set fixed at compile time, such as pickup versus delivery | Store the enum value. Do not use the display string as the key |
AppEntity | User data that changes, such as one product | Store only the resolved id |
A fixed set is an AppEnum. A list the person can add to or delete is an AppEntity plus a query. If you model a changing list as an enum, phrases stop matching as soon as an option expires.
An entity keeps only its id
The system needs an entity it can display and query. Your database remains the source of the data. The entity needs at least a stable id and a name a person can read.
{
"entity": "OrderItem",
"id": "sku_42",
"display": "Oat milk"
}
Implement entities(for identifiers:) and load the object by id. If it is missing, do not invent an id and continue.
The parameter JSON you own
The document below is the contract you persist inside perform() before you decide whether to call the API. It is not Apple's request format, and the system will not read the file for you.
{
"intent": "StartOrder",
"source": "siri",
"parameters": {
"item_id": "sku_42",
"quantity": 1
},
"resolved": true
}
intentuses the Intent type name so it lines up with the action in Shortcuts.item_idis the entity id, not the spoken phrase. The phrase can change. The id should not.- If
resolvedis false, resolution is unfinished or the person cancelled the follow-up. Do not call the API. - Do not put the raw utterance, a location trace, or a token in this JSON.
When to call the API
- 1Finish on device
An action that only changes local state finishes inside perform(). It does not need the network.
- 2Validate first
When you need a server, validate the JSON with a schema first. A missing item_id or a quantity below 1 stops on the device.
- 3Then go to the network
Send parameters to your API only after validation passes and resolved is true. The server looks up its own record by id. It does not trust the display name.
- 4Say the failure in plain language
If the API rejects the call or times out, tell the person through the Intent dialog that it did not finish. Do not let Siri say it succeeded.
How a third-party app declares the Intent and returns a failure is the next article. This one stops at the data path.
How this differs from older articles
| Is Siri an agent? | This article | |
|---|---|---|
| Question | Whether the system plans and calls tools on its own | Which JSON a single request passes through on the way to an API |
| Do not look here for | Another product announcement | Treating the raw utterance as a request body you can store |
The product story of the hardware and system features is in why iPhone 18 is more than hardware. That piece does not split parameter fields.
Check this JSON in JSONNote
- 1Format
Open the parameter record in JSON format and confirm there is no trailing comma.
- 2Catch missing fields with a schema
Paste the schema below into JSON Schema. A missing intent or item_id, or a quantity that is not a positive integer, should not be sent to the API.
- 3Then check one sample
Paste a real sample into JSON validate. Look especially at whether
item_idis an empty string.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"required": ["intent", "source", "parameters", "resolved"],
"properties": {
"intent": { "type": "string", "minLength": 1 },
"source": { "enum": ["siri", "shortcut", "app"] },
"resolved": { "type": "boolean" },
"parameters": {
"type": "object",
"required": ["item_id", "quantity"],
"properties": {
"item_id": { "type": "string", "minLength": 1 },
"quantity": { "type": "integer", "minimum": 1 }
}
}
}
}
FAQ
Does the system send the whole utterance to my server?
Not on this path. The server should receive the parameter JSON you assemble and validate inside perform(). Speech stays in on-device recognition.
Why not put the product name in the parameters?
Names change and collide. An AppEntity uses a stable id, and the query loads the object by that id. The API should accept the id only.
If the schema passes, can I call the API?
Also check resolved. A valid shape with an unresolved entity means the person has not picked an object yet. Calling the API then turns a follow-up question into a wrong order.
How do you split on-device work from a network call?
Changes that stay on device finish inside perform(). Work that needs your backend writes the parameter JSON, validates it, then requests. Both paths return the outcome through IntentResult.
Is a Shortcut with hand-filled parameters the same path?
Yes, it is the same AppIntent. The difference is who fills the parameters: Siri uses the phrase, Shortcuts uses the person or the previous action. Entity resolution, JSON, and the API gate stay the same.
Conclusion
The data path of one request is: a phrase selects an Intent, parameters are filled by type, the entity collapses to an id, you write JSON, the API runs only after validation, and a dialog returns the outcome to Siri.
Direct conclusion: do not upload the raw utterance. Do not call the API before the id is resolved. Say a failure back to the person instead of leaving it only in a server log.
Next: lock this parameter JSON with a schema before you wire it into perform().