Workflows
A workflow is a reusable automation that fires on a call event, calls an HTTP API (your CRM, an ITSM, a Power Automate flow, any HTTPS endpoint), and can store fields from the response as variables that the rest of the call can reuse. Use workflows to look up a customer at the moment of pickup, store their CRM/ITSM record id, and push the call result back to that record when the call ends.
Each workflow is built from one Action — a single HTTP call with a method, URL, headers, body and an optional response mapping.
The big picture: get → map → store → reuse
The pattern that makes workflows powerful is looking data up early and reusing it later:
- Get — on Agent Connected, a workflow calls your CRM/ITSM API with the caller’s number.
- Map & store — the Mapping pulls the record id out of the response and stores it as
$CRM_CONTACT_ID$. - Reuse — on Call Ended, a second workflow pushes the call outcome (duration, summary, recording link) back to that same record using
$CRM_CONTACT_ID$.
Stored variables live on the call (in its workflowContext) and persist across triggers, so a value captured at Agent Connected is still available at Call Ended.
Agent Connected ──► GET https://crm/contacts?phone=$CALLER_ID_E164$
mapping: { CRM_CONTACT_ID: "id" } ─┐ stores $CRM_CONTACT_ID$
│
Call Ended ───────► POST https://crm/contacts/$CRM_CONTACT_ID$/calls ◄─┘ reuses it
body: { duration: "$CALL_HANDLE_TIME$", summary: "$CALL_SUMMARY$" }
Creating a workflow
- Open Workflows from the sidebar.
- Click +Add.
- Fill in the fields and click Save.
Fields
| Field | Description |
|---|---|
| Display name | Workflow name. Required. |
| Scope | The Entity the workflow belongs to. Required. |
| Trigger event | The call event that fires the workflow — one of the five below. Required. |
| Action → Method | HTTP method: GET, POST or PUT. |
| Action → URL | The API endpoint to call. Supports $VARIABLE$ tokens (e.g. ?phone=$CALLER_ID_E164$). |
| Action → Headers | Key/value list of HTTP headers (e.g. Authorization). Values support $VARIABLE$. |
| Action → Body (JSON) | JSON object sent with POST/PUT. Values support $VARIABLE$. Toggle on/off. |
| Action → Mapping | Key/value list that stores response fields as variables — { variableName : responseField }. Toggle on/off. |
Trigger events
Pick one event per workflow from the fixed list shown in the portal.
| Event | When it fires | Typical use |
|---|---|---|
| Agent Connected | An agent picks up the call. | Screen-pop / look up the customer and store their CRM/ITSM id for later. |
| Customer Abandoned | The caller hangs up while waiting in queue. | Log a missed call / create a call-back task. |
| Call Connected | The call is connected end to end. | Notify an external system that a conversation started. |
| Call Ended | The call ends, regardless of outcome. | Push the call result (duration, summary, recording) back to the CRM/ITSM. |
| Agent Declined | An alerted agent rejects or lets it ring out (RONA). | Alerting / supervision hooks. |
Look-ups belong on Agent Connected (early, so the value is available for the rest of the call). Write-backs belong on Call Ended (late, when the duration, summary and recording link exist).
Action: calling an API
The Action is one HTTP request.
- Method —
GETto read,POST/PUTto send a body. ForGET, put any query parameters directly in the URL. - URL — the full HTTPS endpoint. Every
$VARIABLE$is replaced before the call is sent. - Headers — add one row per header. Common headers:
| Header | Example value |
|---|---|
Authorization | Bearer $env.CRM_TOKEN$ |
Ocp-Apim-Subscription-Key | $env.APIM_KEY$ |
Content-Type | application/json |
- Body (JSON) — sent with
POST/PUT. Must be a valid JSON object (no duplicate keys, not an array).
Calling a Power Automate flow
Paste the flow’s HTTP request trigger URL into URL, set Method to POST, and send your fields in the Body:
// Action
"method": "POST",
"url": "https://prod-xx.westeurope.logic.azure.com/workflows/.../triggers/manual/paths/invoke?...sig=...",
"headers": { "Content-Type": "application/json" },
"body": {
"callId": "$callId$",
"caller": "$CALLER_ID_E164$",
"agent": "$AGENT_NAME$",
"summary": "$CALL_SUMMARY$"
}
If the Power Automate flow responds with data, add a Mapping to capture it (see below).
Variables — using call data in the Action
Anywhere in the URL, Headers or Body, wrap a variable name in $...$ and Heedify replaces it with the live value before sending the request. Names are case-sensitive; an unknown token is left unchanged.
Most-used variables
| Variable | Value |
|---|---|
$callId$ | Unique call id |
$tenantId$ | Tenant id |
$CALLER_ID$ | Caller number (digits, no +) or Teams user id |
$CALLER_ID_E164$ | Caller number in E.164 (+33…) — use this for CRM lookups |
$AGENT_ID$ / $AGENT_NAME$ | Connected agent id / display name |
$FLOW_NAME$ | Call flow name |
$QUEUE_NAME$ | First queue the call went through |
$CALL_HANDLE_TIME$ | Talk time in seconds (available at Call Ended) |
$CALL_TERMINATION_REASON$ | How the call ended (available at Call Ended) |
$CALL_SUMMARY$ | AI call summary (available at Call Ended when transcription is on) |
$CALL_SENTIMENT$ | Call sentiment: positive / neutral / negative / mixed |
$RECORDING_FILE_URL$ | Link to the recording (available at Call Ended when recording is on) |
$TRANSCRIPT_FILE_URL$ | Link to the transcript |
$env.NAME$ | An environment secret (for tokens/keys — never hard-code secrets) |
Not every variable exists at every moment. Caller, agent, flow and queue values are available from Agent Connected. Duration, termination reason, summary, sentiment and recording/transcript links only become available at Call Ended (summary and transcript require transcription/recording to be enabled on the flow).
Mapping — storing the response for later
A Mapping turns fields from the API response into named variables you can reuse for the rest of the call. Each line is:
variableName ⟶ responseField
- Left (key) — the variable name you invent. Use it later as
$variableName$. Pick names that won’t clash with the built-ins above. - Right (value) — the field to read from the response JSON.
Example — look up a customer at pickup and store their CRM contact id and tier:
// Workflow A — Trigger: Agent Connected
"action": {
"method": "GET",
"url": "https://crm.example.com/contacts?phone=$CALLER_ID_E164$",
"headers": { "Authorization": "Bearer $env.CRM_TOKEN$" },
"mapping": {
"CRM_CONTACT_ID": "id",
"CRM_TIER": "tier"
}
}
After Workflow A runs, $CRM_CONTACT_ID$ and $CRM_TIER$ are available to every later workflow on the same call.
Then push the result back when the call ends:
// Workflow B — Trigger: Call Ended
"action": {
"method": "POST",
"url": "https://crm.example.com/contacts/$CRM_CONTACT_ID$/activities",
"headers": { "Authorization": "Bearer $env.CRM_TOKEN$" },
"body": {
"type": "phone_call",
"agent": "$AGENT_NAME$",
"durationSec": "$CALL_HANDLE_TIME$",
"outcome": "$CALL_TERMINATION_REASON$",
"summary": "$CALL_SUMMARY$",
"recording": "$RECORDING_FILE_URL$"
}
}
The same pattern works for an ITSM: store the ticket id at Agent Connected, append the call notes/recording to that ticket at Call Ended.
Worked example — CRM/ITSM screen-pop and write-back
| Step | Trigger | Action | Stores / uses |
|---|---|---|---|
| 1. Look up | Agent Connected | GET …/contacts?phone=$CALLER_ID_E164$ | stores $CRM_CONTACT_ID$ |
| 2. Open ticket (optional) | Agent Connected | POST …/tickets with { "contactId": "$CRM_CONTACT_ID$" } | stores $TICKET_ID$ |
| 3. Write back | Call Ended | POST …/tickets/$TICKET_ID$/notes with summary, duration, recording | uses $CRM_CONTACT_ID$, $TICKET_ID$, $CALL_SUMMARY$ |
Order matters: a workflow that stores a variable must run before the workflow that uses it. The look-up (step 1) is on an early trigger; the write-back (step 3) is on Call Ended.
Validation
- Action URL must use HTTP or HTTPS.
- Body must be valid JSON — an object, no duplicate keys, not an array.
- Mapping and Header values must be strings.
Attaching a workflow
Workflows run for the Entity (Scope) you selected, on the trigger you picked. You can also reference them from:
FAQ
Q: How do I store data from an API call and reuse it later? A: Add a Mapping to the Action. Each line stores a response field under a variable name (e.g. CRM_CONTACT_ID = id). It becomes $CRM_CONTACT_ID$ and stays available for the rest of the call, including later workflows on later triggers.
Q: Can a workflow send custom HTTP headers? A: Yes — the Headers key/value list. Use it for Authorization, Ocp-Apim-Subscription-Key, serviceApiKey, Content-Type, etc. Values support $VARIABLE$, so inject secrets with $env.NAME$.
Q: Can I call a Power Automate flow? A: Yes. Paste the flow’s HTTP trigger URL into the Action URL, set the method to POST, and send fields in the Body with $VARIABLE$ tokens. Map the response if the flow returns data you need later.
Q: What events trigger a workflow? A: Five fixed events: Agent Connected, Customer Abandoned, Call Connected, Call Ended, Agent Declined. Each workflow listens to exactly one.
Q: What validation does Heedify apply? A: The Action URL must be HTTP/HTTPS. The Body must be valid JSON (object, no duplicate keys). Mapping and Header values must be strings.
Works with: Microsoft Teams, Teams Phone, HTTPS APIs, Power Automate, webhook-based CRMs and ITSMs, Variables, Call Flows, Queues. </content> </invoke>