When an Agentic Flow agent sends a message through a channel, a delivery template controls what that message looks like. Templates are configured on the Output node in the flow editor, once Channel Delivery is turned on.
You have three options — leave the template empty, write a fixed message, or write a template with placeholders. The right choice depends on how much control you need over the output.
Quick Decision Guide
Do you know what the message should look like?
- Yes, same every time → write a fixed template with no placeholders. The agent is not involved.
- Yes, but the details change → write a template with placeholders. You define the layout; the agent fills in the values.
- No, let the agent decide → leave the template empty. The agent writes the full message. For more control over when to deliver, set Invocation to
agentic.
Is this a HITL approval card or regular delivery?
- HITL approval → template must include Approve and Reject buttons. Only the 7 tokens in the HITL placeholders table are substituted.
- Regular delivery → no button requirement. Any placeholder token works; the agent fills it in.
Which channels support structured templates?
- Adaptive Cards — Microsoft Teams only (
adaptive_cardevent type). - Email — Outlook (
email,email_replyevent types). The template is a JSON object withsubjectandbody. - Plain messages — Telegram, Facebook, Universal Webhook, and Google Chat (
messageevent type) deliver the agent’s response as text. The template is not applied tomessageevents.
The Delivery Targets Table
Open a flow in the Agentic Flow editor, select the Output node, and turn on Channel Delivery. The Delivery Targets table appears, with one row per destination.
| Column | Description |
|---|---|
| Channel | Where the message goes (Teams, Outlook, Telegram, etc.). |
| Channel Type | Auto-filled from the channel you select. |
| Route Type | Auto-filled (conversation, notification, etc.). |
| Event Type | The kind of message: adaptive_card, message, email, etc. For HITL rows this is locked to hitl_approval. |
| Recipient | Who receives it. Pick a named contact, or use auto to let the system resolve the recipient. |
| Template | The message layout in JSON. Paste an Adaptive Card or email template here. |
| Invocation | automatic — fires on every invocation. agentic — the agent decides whether and to whom to deliver. Default: automatic. |
With automatic invocation, the Template column appears after you have selected a channel and event type for that row. With agentic invocation, it appears as soon as the row exists.
The Template Editor
Click the </> icon (Open template editor) next to the Template column header. The editor matches the row’s event type:
| Editor | Opens for | Preview |
|---|---|---|
| HITL Adaptive Card Template | hitl_approval rows | Adaptive Card |
| Delivery Adaptive Card Template | Other card rows, such as adaptive_card | Adaptive Card |
| Email Delivery Template | email and email_reply rows |
In each editor you can:
- Write or paste the template JSON. It is validated as you type, and Save template is blocked until the template is valid or empty.
- Load a built-in example with Use example, or Copy it from the Example panel.
- Remove the template with Clear.
- Check the live preview, which shows the template with sample values for placeholders. Click refresh to re-render it. The preview is hidden while the template is invalid, and shows Preview unavailable if the card cannot be rendered.
The HITL and email editors also list the placeholders they substitute.
Note
The live preview is a structural check, not a pixel-perfect render. Channels apply their own theme and button chrome at send time. Use the preview to verify structure and content, not exact styling.
Three Ways to Write a Template
Option A — Leave it empty
For message events, the agent’s response is sent as a plain message. For adaptive_card and email events, the agent writes the full card or email itself. Best when you want the agent to fully control the output.
Option B — Fixed message (no placeholders)
Your JSON is sent exactly as written on every invocation. The agent is not involved. Use this for messages that always look the same — daily status cards, fixed notifications.
Option C — Template with placeholders
Define the layout using {{token}} placeholders. The agent (or the system, for HITL cards) fills in each token at run time. The structure and wording stay exactly as you wrote them; only the placeholder values change.
Allowed Placeholders
HITL Templates
Only the following 7 tokens are substituted in approval cards. Any other {{token}} appears as literal text in the delivered card.
| Token | What it shows | Example |
|---|---|---|
{{title}} | Headline from the Approval Title field. | Action Required |
{{description}} | Short explanation from the Approval Description field. | Please review before sending. |
{{bot_response}} | The agent’s proposed response — the approver can edit this before approving. | Hi! Your refund of $42 has been processed. |
{{execution_id}} | Internal ID used to resume the flow after a decision. | f87a3d0f-0c66-4c1b-8f30-e082297be365 |
{{original_message}} | The user message that triggered the flow. | Can you refund my last order? |
{{sender_name}} | Display name of the user who sent the original message. | Alex Tan |
{{source_channel}} | The channel the original message came from. | microsoft_teams |
Output Templates
For regular delivery, placeholders are filled by the agent. You can use any token name and the agent will populate it with a contextually appropriate value. The email editor lists these common tokens:
| Token | What it shows |
|---|---|
{{title}} | A short headline derived from the agent’s response. |
{{bot_response}} | The full agent response. |
{{sender_name}} | Display name of the user who started the conversation. |
{{source_channel}} | The channel the original message came from. |
| Any custom token | {{priority}}, {{amount}}, {{order_id}}, etc. — the agent fills these in based on the conversation context. |
Tip
To prevent a token from being substituted, write it as plain text without
{{ }}.
Template Examples
Example 1 — HITL Approval Card
An approval card for a Human-in-the-Loop flow. Includes the original message, a proposed response the approver can edit, and Approve/Reject buttons.
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "Container", "style": "accent", "bleed": true,
"items": [
{ "type": "TextBlock", "text": "⚠ {{title}}",
"size": "Large", "weight": "Bolder", "color": "Warning", "wrap": true },
{ "type": "TextBlock",
"text": "From {{sender_name}} via {{source_channel}}",
"size": "Small", "isSubtle": true, "spacing": "None" }
]
},
{ "type": "TextBlock", "text": "{{description}}", "wrap": true, "spacing": "Medium" },
{ "type": "TextBlock", "text": "💬 {{original_message}}", "wrap": true, "spacing": "Medium" },
{ "type": "Input.Text", "id": "edited_response",
"placeholder": "Edit the response before approving…",
"isMultiline": true, "value": "{{bot_response}}" },
{ "type": "TextBlock", "text": "Ref: {{execution_id}}",
"size": "Small", "isSubtle": true, "spacing": "Small" }
],
"actions": [
{ "type": "Action.Submit", "title": "✅ Approve & Send",
"style": "positive", "data": { "hitl_action": "approve" } },
{ "type": "Action.Submit", "title": "Reject",
"style": "destructive", "data": { "hitl_action": "reject" } }
]
}
Example 2 — Output Delivery Card
A delivery card for the Output node. No approve/reject buttons — just a formatted message.
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "Container", "style": "emphasis", "bleed": true,
"items": [
{ "type": "TextBlock", "text": "{{title}}",
"size": "Large", "weight": "Bolder", "wrap": true }
]
},
{ "type": "TextBlock", "text": "{{bot_response}}", "wrap": true, "spacing": "Medium" },
{ "type": "TextBlock", "text": "Sent via {{source_channel}}",
"size": "Small", "isSubtle": true, "spacing": "Small" }
]
}
Example 3 — Empty template
Leave the template field blank. On a message event, the agent’s response is sent as plain text. Best for short, conversational replies.
Example 4 — Fixed card (no placeholders)
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{ "type": "TextBlock", "text": "Daily summary ready.",
"weight": "Bolder", "size": "Medium", "wrap": true }
]
}
Sent exactly as written on every invocation. No placeholder substitution, no agent involvement.
Validation
The system validates your template when you save a delivery target row.
HITL templates — save is blocked unless all four checks pass:
| Check | What it means |
|---|---|
| Valid JSON | The template must be parseable JSON. |
"type": "AdaptiveCard" | The root object must be an Adaptive Card. |
| Approve action present | The template must include an Approve button. |
| Reject action present | The template must include a Reject button. |
Delivery card templates — only valid JSON and "type": "AdaptiveCard" are required.
Email templates — must be a JSON object that includes subject and body.
An empty template is always valid.
If you use a token not in the HITL allowed list, you can still save. The token appears as literal text in the delivered card.
HITL Configuration
HITL (Human-in-the-Loop) pauses a flow and sends an approval request to a reviewer before any message is delivered. Use it for high-impact actions — emails to customers, payments, anything that touches another system.
In an Agentic Flow, the approval card is configured in the Approval Delivery Targets table of the Human In The Loop node. For AI Coworkers, set the approval delivery target on the Governance tab. See Human in the Loop for how approvals work.
Template rules:
- The template must include at least one Approve button and one Reject button.
- Tracking IDs (execution ID, approver identity) are added to each button automatically — you do not need to include them.
- Only the 7 tokens in the HITL placeholders table are substituted. Anything else appears as literal text.
- If the template is empty or invalid, the system uses a default card with Approve and Reject buttons only.
After approval: The flow resumes. If the approver edited the edited_response field, that text is used as the delivered message. If not, the original {{bot_response}} value is used.
After rejection: The flow resumes with a rejection signal and the proposed response is not sent.
Note
The HITL template controls the approval card sent to the reviewer. The Output node’s template controls the final delivered message to the end user. These are separate templates on separate nodes.