Skip to main content

SLA Policies

Define response and resolution targets with business hours, read a ticket's live SLA clock, and list what is breaching.

Overview

An SLA policy promises two things about a ticket: how fast someone will respond, and how fast it will be resolved. A policy may be scoped to one priority, or left un-scoped as the catch-all.

Deadlines are computed against the ticket's server-managed lifecycle stamps, so a policy cannot be gamed by editing a timestamp.

Breach is computed on read, never stored. That means the numbers are always current, and it has one consequence for pagination — see the note on /breaches.

Authentication

Authorization: Bearer cm_your_api_key
OperationScope
List policies, ticket status, breachessla:read
Create, update, delete a policysla:write

Business hours

A policy with business_hours only burns its clock during those hours. Omit it and the clock runs continuously.

FieldTypeDefaultConstraints
tzstring | nullYour tenant's timezoneAt most 64 characters
daysinteger[][1,2,3,4,5]1–7 entries, values 1–7 where Monday is 1 and Sunday is 7. Stored sorted and de-duplicated
startstring"09:00"HH:MM, 24-hour
endstring"18:00"HH:MM, must be later than start
{ "tz": "Asia/Kolkata", "days": [1,2,3,4,5,6], "start": "10:00", "end": "19:00" }

The policy object

{
  "id": "d1c2…",
  "tenant_id": "a0b1…",
  "name": "Urgent — 15 min first response",
  "priority": "urgent",
  "first_response_minutes": 15,
  "resolution_minutes": 240,
  "business_hours": null,
  "is_active": true,
  "created_at": "2026-08-10T08:00:00Z",
  "updated_at": "2026-08-10T08:00:00Z"
}

GET /api/v1/support/sla/policies

Returns an array of policy objects, newest first.

ParameterTypeConstraints
prioritystringAt most 16 characters, matched lowercase
is_activeboolean
limitinteger1 <= limit <= 200, default 50
offsetinteger0 <= offset <= 100000, default 0
curl "https://api.callmissed.com/api/v1/support/sla/policies?is_active=true" \
  -H "Authorization: Bearer cm_your_api_key"

POST /api/v1/support/sla/policies

FieldTypeRequiredConstraints
namestringYes1–255 characters, not blank, unique per tenant
prioritystringNoAt most 16 characters, must start with a letter. Omit for a catch-all policy
first_response_minutesintegerNo1 <= n <= 100000
resolution_minutesintegerNo1 <= n <= 100000
business_hoursobjectNoSee above
is_activebooleanNoDefault true

At least one of first_response_minutes / resolution_minutes must be set — a policy that promises nothing is rejected with 422 set at least one of first_response_minutes / resolution_minutes.

curl -X POST https://api.callmissed.com/api/v1/support/sla/policies \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Urgent — 15 min first response",
    "priority": "urgent",
    "first_response_minutes": 15,
    "resolution_minutes": 240
  }'

A duplicate name returns 409 An SLA policy named '…' already exists.

PATCH /api/v1/support/sla/policies/{policy_id}

All fields optional; only the fields you send are changed. Sending business_hours: null removes business hours (the clock then runs continuously); sending priority: null turns the policy into a catch-all. The "must promise something" rule is re-checked against the merged result, so you cannot clear both minute fields in two steps. Returns the updated policy.

curl -X PATCH https://api.callmissed.com/api/v1/support/sla/policies/{policy_id} \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "first_response_minutes": 30,
    "business_hours": { "tz": "Asia/Kolkata", "days": [1,2,3,4,5], "start": "09:00", "end": "18:00" }
  }'

404 SLA policy not found; 409 on a name another policy already uses.

DELETE /api/v1/support/sla/policies/{policy_id}

Returns 204. 404 SLA policy not found.

curl -X DELETE https://api.callmissed.com/api/v1/support/sla/policies/{policy_id} \
  -H "Authorization: Bearer cm_your_api_key"

GET /api/v1/support/sla/status/{ticket_id}

The live clock for one ticket.

curl https://api.callmissed.com/api/v1/support/sla/status/{ticket_id} \
  -H "Authorization: Bearer cm_your_api_key"
{
  "ticket_id": "e5d4…",
  "policy_id": "d1c2…",
  "policy_name": "Urgent — 15 min first response",
  "first_response_due_at": "2026-08-17T06:25:00Z",
  "first_response_breached": true,
  "resolution_due_at": "2026-08-17T10:10:00Z",
  "resolution_breached": false,
  "minutes_remaining": 84
}
FieldTypeNotes
policy_idUUID | nullnull when no policy matched this ticket
minutes_remaininginteger | nullWall-clock minutes to the nearest still-running deadline. Negative when overdue. null when both clocks have stopped or no policy matched
first_response_breached / resolution_breachedbooleanA stopped clock is judged against its stamp: a ticket first answered after the deadline stays breached for good, and one answered in time never becomes breached later

Policy selection: only active policies (is_active: true) are considered. A policy whose priority matches the ticket's priority (case-insensitive) wins; otherwise the oldest catch-all policy applies; otherwise nothing does and every due date is null.

404 Ticket not found.

GET /api/v1/support/sla/status

The same answer as /status/{ticket_id}, for up to 200 tickets in one call — what a ticket list uses to show every row's clock.

ParameterTypeRequiredConstraints
ticket_idUUID (repeatable)Yes1–200 ids; duplicates are ignored
curl "https://api.callmissed.com/api/v1/support/sla/status?ticket_id={id_1}&ticket_id={id_2}" \
  -H "Authorization: Bearer cm_your_api_key"

Returns an array of status objects. Ids that are not tickets in your tenant are left out of the answer rather than reported as errors.

GET /api/v1/support/sla/breaches

Tickets currently past a deadline, oldest first.

ParameterTypeConstraints
prioritystringAt most 16 characters, matched lowercase
include_resolvedbooleanDefault false, which skips tickets that have a resolved_at stamp
limitinteger1 <= limit <= 200, default 50
offsetinteger0 <= offset <= 100000, default 0
curl "https://api.callmissed.com/api/v1/support/sla/breaches?priority=urgent&limit=200" \
  -H "Authorization: Bearer cm_your_api_key"
[
  {
    "ticket_id": "e5d4…",
    "subject": "Refund not received",
    "status": "open",
    "priority": "urgent",
    "created_at": "2026-08-17T06:10:00Z",
    "sla": {
      "ticket_id": "e5d4…",
      "policy_id": "d1c2…",
      "policy_name": "Urgent — 15 min first response",
      "first_response_due_at": "2026-08-17T06:25:00Z",
      "first_response_breached": true,
      "resolution_due_at": "2026-08-17T10:10:00Z",
      "resolution_breached": false,
      "minutes_remaining": -32
    }
  }
]

sla has the same shape as the /status/{ticket_id} response.

Pagination behaves differently here. Because breach is computed rather than stored, limit and offset page over the tickets scanned (oldest first), not the breaches returned. A page can come back shorter than limit, or empty, and still have more behind it — the response does not tell you how many tickets were scanned. To sweep everything, advance offset by limit each call until offset passes your ticket count, rather than stopping at the first short or empty page.

Errors

StatusWhen
403Key is missing sla:read / sla:write
404Policy or ticket not in your tenant
409Duplicate policy name
422Policy promises nothing, blank name, minutes outside 1..100000, a priority that is not a short identifier, or end not later than start

Nothing on this page consumes credits.