How-to: sla
Common crm sla recipes. See the CLI reference for every flag.
Full SLA lifecycle
The three verbs run in order:
sla create— creates the SLA record and ensures the target entity is SLA-enabled.sla add-kpi— attaches one or more KPI / SLA-item records with their applicability conditions.sla activate— activates the backing workflows and then the SLA itself.
The sla entity has no FetchXML condition attribute of its own — per-KPI
conditions (--applicable-when, --success-criteria) live on each SLA item and
are set via sla add-kpi. sla create only takes --applicable-from (the
SLA's date-anchor field, e.g. createdon). SLA failure/warning action steps are
workflow-designer constructs and are outside CLI scope.
Create an SLA
crm --json sla create \
--name "Gold SLA" \
--entity incident \
--applicable-from createdon \
--solution MySolution
--entity is the target entity's logical name. If that entity's IsSLAEnabled
metadata flag is not already set, the command enables and publishes it automatically.
The sla_enabled field in the response tells you what happened:
already— the entity was already SLA-enabled; nothing changed.set— the command flipped the flag and published the metadata change.
{"ok": true, "data": {
"created": true, "name": "Gold SLA", "entity": "incident",
"slaid": "<new-guid>", "sla_enabled": "already", "solution": "MySolution"}}
--applicable-from sets the date-anchor field the SLA calculates warning/failure
times from. --business-hours <GUID> associates a business-hours calendar.
Preview before creating
crm --json --dry-run sla create \
--name "Gold SLA" --entity incident --applicable-from createdon
The IsSLAEnabled GET runs live even in dry-run (so the preview is honest about
whether the flag needs flipping); the metadata write is suppressed. The response
carries sla_enabled: "already" or sla_enabled: "would_set".
{"ok": true, "data": {"_dry_run": true,
"would_create": {"entity_set": "slas", "body": {...}},
"entity": "incident", "sla_enabled": "already"},
"meta": {"dry_run": true}}
Add KPI / SLA-item conditions
After creating the SLA, attach one KPI per metric you want to track. Each KPI
needs an --applicable-when condition (when this KPI fires) and a
--success-criteria condition (what counts as success).
Pass conditions inline or from files — exactly one source per condition:
# Inline FetchXML/condition strings
crm --json sla add-kpi \
--sla <sla-guid> \
--kpi firstresponsebykpiid \
--applicable-when '<fetch>...</fetch>' \
--success-criteria '<fetch>...</fetch>'
# From files (useful when conditions are long)
crm --json sla add-kpi \
--sla <sla-guid> \
--kpi firstresponsebykpiid \
--applicable-when-file ./conditions/applicable.xml \
--success-criteria-file ./conditions/success.xml \
--solution MySolution
--name defaults to the --kpi value when omitted. Repeat sla add-kpi for
each KPI you need on the same SLA.
{"ok": true, "data": {
"created": true, "slaitemid": "<item-guid>",
"sla_id": "<sla-guid>", "name": "firstresponsebykpiid",
"solution": "MySolution"}}
Preview before adding
crm --json --dry-run sla add-kpi \
--sla <sla-guid> --kpi firstresponsebykpiid \
--applicable-when-file ./applicable.xml \
--success-criteria-file ./success.xml
{"ok": true, "data": {"_dry_run": true,
"would_create": {"entity_set": "slaitems", "body": {...}},
"sla_id": "<sla-guid>"},
"meta": {"dry_run": true}}
Activate an SLA and its backing workflows
crm --json sla activate <sla-guid>
SLAs are enforced by backing workflows — one per SLA item (slaitem.workflowid) — and the SLA cannot be activated until every one of them is active. The command:
- Fetches the SLA and its SLA items, resolving each item's backing workflow.
- Activates each backing workflow (already-active ones are skipped, so re-running is safe).
- Activates the SLA itself (
statecode=1, statuscode=2) — only if every backing workflow is active.
The result reports per-workflow status:
{"ok": true, "data": {"sla_id": "...", "name": "Gold SLA", "sla_activated": true,
"workflows": [
{"workflow_id": "...", "name": "First response", "status": "activated"},
{"workflow_id": "...", "name": "Resolve by", "status": "already_active"}
]}}
When backing workflows have compile errors
After a solution import, backing workflows can carry compile errors (InvalidEntity, InvalidRelationship). The platform buries the detail in a raw message string — ErrorMap Details: {ConditionBranchStep2: InvalidEntity, InvalidRelationship; ...} — which the command parses into structured per-step entries:
{"ok": false, "data": {"sla_activated": false, "ui_activation_required": true,
"workflows": [
{"workflow_id": "...", "name": "First response", "status": "failed",
"error": "This workflow has errors. ErrorMap Details: {...}",
"errors": [{"step": "ConditionBranchStep2",
"errors": ["InvalidEntity", "InvalidRelationship"]}]}
]},
"error": "SLA ... was NOT activated: ..."}
If the message doesn't match the expected shape, the raw platform string is still reported in error — the detail is never dropped.
In this case the SLA is not touched and the exit code is non-zero. The Web API cannot activate a workflow that fails compilation, so activation must be done from the D365 UI (Settings → Service Level Agreements → open the SLA → Activate). Workflows that did activate during the run stay active — that matches platform behavior, and re-running after a fix picks up where it left off.
Preview with --dry-run
crm --json --dry-run sla activate <sla-guid>
The resolution GETs run live; nothing is PATCHed. The preview lists what a live run would do:
{"ok": true, "data": {"_dry_run": true, "would_activate": [...],
"already_active": [...], "would_activate_sla": true}, "meta": {"dry_run": true}}