Calling Azure OpenAI from Power Automate
Call your own Azure OpenAI deployment from a cloud flow with the HTTP action, keep the key out of your flow, and parse the response properly.
What you'll learn
- Know when to use Azure OpenAI instead of AI Builder
- Build the chat completions request in an HTTP action
- Store the key safely with an environment variable or Key Vault
- Extract the answer from the response
On this page
AI Builder prompts are the easiest route to GPT in Power Platform. Sometimes, though, you need your own Azure OpenAI deployment — to pick a specific model, keep data in your own Azure region, or share one deployment across apps. Here's how to call it from a flow.
AI Builder or Azure OpenAI?
| Need | AI Builder prompt | Azure OpenAI |
|---|---|---|
| Fastest to build | Yes | No |
| No Azure subscription needed | Yes | No |
| Choose exact model and version | Limited | Yes |
| Billing | AI Builder credits | Azure usage |
| Reuse from non-Power Platform apps | No | Yes |
What you need from Azure
From your Azure OpenAI resource, note three values: the endpoint (for example https://my-resource.openai.azure.com), the deployment name you gave the model, and an API key. You also need the API version your resource supports — check the Azure OpenAI documentation for the current one.
Keep the key out of the flow
Never paste the key into the HTTP action. Two good options:
- Environment variable of type Secret, backed by Azure Key Vault — the cleanest choice for solutions that move between environments.
- At minimum, a Secret environment variable so the key isn't visible in the flow definition.
Build the request
Add an HTTP action:
- Method:
POST - URI:
https://my-resource.openai.azure.com/openai/deployments/{deployment}/chat/completions?api-version={version} - Headers:
Content-Type: application/jsonandapi-key: <your secret variable> - Body:
{
"messages": [
{ "role": "system", "content": "You summarise Dataverse case notes for managers in 3 bullet points." },
{ "role": "user", "content": "@{triggerBody()?['notes']}" }
],
"temperature": 0.2,
"max_tokens": 300
}Read the answer
The model's reply is inside the first choice. Use this expression in a Compose action:
body('HTTP')?['choices']?[0]?['message']?['content']Also log body('HTTP')?['usage']?['total_tokens'] so you can track cost per run.
Handle failures
Wrap the HTTP call in a Try scope. In the Catch scope, check the status code:
- 429 means you hit a rate limit — retry later with a delay.
- 400 often means the content was filtered or the body is malformed.
- 401 means the key is wrong or expired.