Skip to main content

Microsoft Copilot Studio + AxonFlow Integration

Overview

Microsoft Copilot Studio is Microsoft's enterprise AI agent platform for building, customizing, and deploying agents that connect to Microsoft 365, Power Platform, and 1,400+ systems. It supports multi-agent orchestration, GPT-4 family models, and integrates with Microsoft Entra ID for governance.

AxonFlow adds real-time policy enforcement, cross-system audit trails, and fine-grained access control to ensure Copilot Studio agents operate within enterprise compliance requirements.

Together, they enable enterprises to deploy AI agents across Microsoft 365 with full governance, observability, and cost control.


Why Use AxonFlow with Copilot Studio?

Copilot Studio Strengths

  • Native Microsoft 365 integration (Teams, Outlook, SharePoint)
  • Multi-agent orchestration capabilities
  • 1,400+ Power Platform and MCP connectors
  • GPT-4 family model support
  • Microsoft Entra ID authentication
  • WhatsApp, web, and custom channel deployment

AxonFlow Strengths

  • Real-time inference governance (block/allow/modify at request time)
  • Cross-platform audit trails (unified logging across all AI systems)
  • Granular policy enforcement (per-agent, per-user, per-department)
  • Cost control and allocation (budget limits, chargeback tracking)
  • PII protection (automatic masking before model inference)
  • Model-agnostic governance (works with any LLM provider)

The Perfect Combination

Copilot Studio handles: Agent building, Microsoft 365 integration, Power Platform connectors
AxonFlow handles: Inference governance, compliance audit, cost control, policy enforcement

Integration Architecture

AxonFlow integrates with Copilot Studio using Gateway Mode, which provides policy pre-checks before LLM calls and audit logging after:

[Copilot Studio Agent]
|
v
[Power Automate Flow]
|
v
[AxonFlow Pre-Check] --> Policy Evaluation
|
v (if approved)
[Azure OpenAI / External LLM]
|
v
[AxonFlow Audit] --> Compliance Logging
|
v
[Response to Copilot Studio]

Note: AxonFlow uses its own API for governance, not an OpenAI-compatible endpoint. Integration requires calling AxonFlow's pre-check and audit endpoints around your LLM calls.


Quick Start

Prerequisites

  • Microsoft Copilot Studio license
  • AxonFlow running locally or deployed (see Getting Started)
  • Azure subscription (for Azure OpenAI)
  • Power Platform admin access

AxonFlow API Overview

AxonFlow Gateway Mode uses two main endpoints:

EndpointPurpose
POST /api/policy/pre-checkPolicy evaluation before LLM call
POST /api/audit/llm-callAudit logging after LLM call completes

Required Headers:

  • Content-Type: application/json
  • X-Client-Secret: your-client-secret
  • X-License-Key: your-license-key (optional, for enterprise features)

Integration Pattern: Power Automate Flow

Create a Power Automate cloud flow that wraps Azure OpenAI calls with AxonFlow governance:

Step 1: Create the Governance Flow

Flow Name: AxonFlow-Governed-LLM-Call
Trigger: When a HTTP request is received

Actions:
1. Pre-Check with AxonFlow
2. If approved → Call Azure OpenAI
3. Audit the call with AxonFlow
4. Return response

Step 2: Pre-Check Action (HTTP)

{
"method": "POST",
"uri": "https://your-axonflow.example.com/api/policy/pre-check",
"headers": {
"Content-Type": "application/json",
"X-Client-Secret": "@{parameters('AxonFlowClientSecret')}"
},
"body": {
"user_token": "@{triggerBody()?['user_token']}",
"client_id": "copilot-studio-@{triggerBody()?['agent_id']}",
"query": "@{triggerBody()?['user_message']}",
"data_sources": [],
"context": {
"department": "@{outputs('GetUserProfile')?['department']}",
"agent_type": "copilot-studio"
}
}
}

Step 3: Condition - Check Approval

Condition: body('PreCheckAxonFlow')?['approved'] is equal to true

If Yes:
→ Proceed to Azure OpenAI call
If No:
→ Return blocked message

Step 4: Call Azure OpenAI (HTTP)

{
"method": "POST",
"uri": "https://your-aoai.openai.azure.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-15-preview",
"headers": {
"Content-Type": "application/json",
"api-key": "@{parameters('AzureOpenAIKey')}"
},
"body": {
"messages": [
{
"role": "system",
"content": "@{triggerBody()?['system_prompt']}"
},
{
"role": "user",
"content": "@{triggerBody()?['user_message']}"
}
]
}
}

Step 5: Audit Action (HTTP)

{
"method": "POST",
"uri": "https://your-axonflow.example.com/api/audit/llm-call",
"headers": {
"Content-Type": "application/json",
"X-Client-Secret": "@{parameters('AxonFlowClientSecret')}"
},
"body": {
"context_id": "@{body('PreCheckAxonFlow')?['context_id']}",
"client_id": "copilot-studio-@{triggerBody()?['agent_id']}",
"response_summary": "@{substring(body('CallAzureOpenAI')?['choices'][0]?['message']?['content'], 0, 200)}",
"provider": "azure-openai",
"model": "gpt-4",
"token_usage": {
"prompt_tokens": "@{body('CallAzureOpenAI')?['usage']?['prompt_tokens']}",
"completion_tokens": "@{body('CallAzureOpenAI')?['usage']?['completion_tokens']}",
"total_tokens": "@{body('CallAzureOpenAI')?['usage']?['total_tokens']}"
},
"latency_ms": "@{div(sub(ticks(utcNow()), ticks(outputs('PreCheckAxonFlow')?['headers']?['Date'])), 10000)}"
}
}

Step 6: Return Response

{
"statusCode": 200,
"body": {
"response": "@{body('CallAzureOpenAI')?['choices'][0]?['message']?['content']}",
"governed": true,
"context_id": "@{body('PreCheckAxonFlow')?['context_id']}"
}
}

Configure Copilot Studio Agent

In Copilot Studio, create an action that calls the Power Automate flow:

  1. Open your agent in Copilot Studio
  2. Go to Actions > Add an action
  3. Select Call a Power Automate flow
  4. Choose the AxonFlow-Governed-LLM-Call flow
  5. Map inputs:
    • user_token: User identifier from conversation
    • agent_id: Current agent ID
    • user_message: User's input
    • system_prompt: Agent's system instructions
  6. Map outputs: Response text

Integration Patterns

Pattern 1: Per-Department Policy Routing

Route different Copilot Studio agents through department-specific AxonFlow contexts:

{
"context": {
"department": "@{if(contains(triggerBody()?['agent_name'], 'HR'), 'hr', if(contains(triggerBody()?['agent_name'], 'Finance'), 'finance', if(contains(triggerBody()?['agent_name'], 'Sales'), 'sales', 'default')))}",
"data_tier": "@{if(equals(outputs('GetDepartment'), 'finance'), 'restricted', if(equals(outputs('GetDepartment'), 'hr'), 'sensitive', 'standard'))}"
}
}

Pattern 2: Microsoft 365 Context Enrichment

Enrich AxonFlow requests with Microsoft 365 context using Office 365 connector:

Actions in Power Automate:
1. Office365Users.GetMyProfile
2. Office365Groups.ListGroupsUserBelongsTo
3. Build context for AxonFlow

Pre-check body with enriched context:

{
"user_token": "@{outputs('GetMyProfile')?['id']}",
"client_id": "copilot-studio-@{triggerBody()?['agent_id']}",
"query": "@{triggerBody()?['user_message']}",
"context": {
"user_email": "@{outputs('GetMyProfile')?['mail']}",
"user_department": "@{outputs('GetMyProfile')?['department']}",
"user_title": "@{outputs('GetMyProfile')?['jobTitle']}",
"user_groups": "@{join(outputs('ListGroups')?['value'], ',')}",
"tenant_id": "@{outputs('GetMyProfile')?['tenantId']}"
}
}

Pattern 3: Error Handling with Fallback

Handle AxonFlow unavailability gracefully:

Scope: TryGovernedCall
Actions:
- PreCheckAxonFlow
- CallAzureOpenAI
- AuditAxonFlow

Configure Run After for Scope:
- If TryGovernedCall Failed or TimedOut:
→ DirectAzureOpenAICall (fallback without governance)
→ Log to Application Insights (governance bypassed)

Pattern 4: Multi-Agent Orchestration

When using Copilot Studio's multi-agent features, pass orchestration context:

{
"context": {
"orchestrator_id": "@{triggerBody()?['orchestrator_id']}",
"sub_agent_id": "@{triggerBody()?['sub_agent_id']}",
"conversation_id": "@{triggerBody()?['conversation_id']}",
"agent_chain": "@{triggerBody()?['agent_chain']}"
}
}

AxonFlow Policy Configuration

Create policies that match your Copilot Studio agent types. Register these in AxonFlow:

{
"policies": [
{
"name": "copilot-studio-hr-policy",
"description": "Policy for Copilot Studio HR agents",
"enabled": true,
"rules": [
{
"type": "content_filter",
"config": {
"blocked_patterns": ["salary details", "performance reviews"],
"action": "block"
}
},
{
"type": "pii_protection",
"config": {
"fields": ["ssn", "salary", "address"],
"action": "mask"
}
}
]
},
{
"name": "copilot-studio-sales-policy",
"description": "Policy for Copilot Studio Sales agents",
"enabled": true,
"rules": [
{
"type": "rate_limit",
"config": {
"requests_per_minute": 60,
"action": "throttle"
}
}
]
}
]
}

Best Practices

1. Always Store Context ID

The context_id from pre-check must be passed to audit for proper correlation:

Variable: ContextId = body('PreCheckAxonFlow')?['context_id']
... make LLM call ...
Audit body: { "context_id": "@{variables('ContextId')}", ... }

2. Handle Blocked Requests Gracefully

If: body('PreCheckAxonFlow')?['approved'] equals false
Then:
Response: {
"message": "I'm unable to help with that request due to policy restrictions.",
"reason": "@{body('PreCheckAxonFlow')?['block_reason']}"
}

3. Always Audit, Even on Errors

Scope: TryLLMCall
Action: CallAzureOpenAI

Configure Run After:
AuditSuccess (if TryLLMCall succeeded)
AuditFailure (if TryLLMCall failed) - audit with error message

4. Agent Naming Convention

Use consistent naming for governance and audit clarity:

copilot-studio-{department}-{function}-{environment}

Examples:
- copilot-studio-hr-onboarding-prod
- copilot-studio-sales-research-dev
- copilot-studio-support-tier1-prod

Monitoring with Azure

Azure Monitor Integration

Send AxonFlow events to Azure Monitor via Power Automate:

After each governed call:
Action: Send Data to Azure Log Analytics
Body: {
"context_id": "@{body('PreCheckAxonFlow')?['context_id']}",
"client_id": "copilot-studio-...",
"approved": "@{body('PreCheckAxonFlow')?['approved']}",
"latency_ms": "...",
"timestamp": "@{utcNow()}"
}

Power BI Dashboard Query

-- KQL query for Azure Log Analytics
CustomLogs_CL
| where Category == "AxonFlowGovernance"
| where ClientId_s startswith "copilot-studio"
| summarize
TotalRequests = count(),
BlockedRequests = countif(Approved_b == false),
AvgLatencyMs = avg(LatencyMs_d)
by bin(TimeGenerated, 1h), Department_s
| order by TimeGenerated desc

Troubleshooting

Common Issues

Issue: Pre-check returns 401 Unauthorized

  • Verify X-Client-Secret header is correct
  • Check X-License-Key if using enterprise features
  • Ensure client_id is registered in AxonFlow

Issue: Audit calls failing

  • Verify context_id is from a valid pre-check (not expired)
  • Check that AxonFlow agent is healthy (/health endpoint)

Issue: All requests being blocked

  • Review policy configuration in AxonFlow
  • Check if rate limits are exceeded
  • Verify context fields match policy conditions

Issue: Power Automate flow timing out

  • Increase timeout in HTTP actions (default 100s)
  • Check AxonFlow gateway health endpoint
  • Verify network connectivity from Power Platform

Additional Resources