Skip to content

SLA Tracking

SLA Tracking

Service Level Agreement (SLA) tracking ensures your support team meets response and resolution time commitments. The Pulse API provides comprehensive SLA monitoring with configurable thresholds, automatic status updates, and detailed reporting.

Overview

SLA tracking monitors two critical metrics:

  1. First Response Time - How quickly the first response is provided to the customer
  2. Resolution Time - How long it takes to fully resolve the ticket

Each priority level has its own SLA thresholds, and tickets are automatically tracked against these targets with real-time status updates.

SLA Thresholds

Default Thresholds by Priority

PriorityFirst ResponseResolution
Urgent15 minutes4 hours
High1 hour8 hours
Medium4 hours24 hours
Low8 hours48 hours

These defaults can be customized per account to match your organization’s commitments.

SLA Status

Tickets progress through different SLA statuses based on elapsed time:

Status Values

StatusDescriptionWhen It Occurs
on_timeWithin SLA targetsTime elapsed < 80% of threshold
at_riskApproaching breachTime elapsed ≥ 80% of threshold
breachedSLA violatedTime elapsed > threshold
pausedTimer pausedWaiting on customer or manually paused

Status Progression

┌─────────┐ 80% threshold ┌─────────┐ 100% threshold ┌──────────┐
│ on_time │ ───────────────────> │ at_risk │ ──────────────────> │ breached │
└─────────┘ └─────────┘ └──────────┘
│ │ │
│ │ │
└────────────────────────────────┴───────────────────────────────┘
Manual pause or
waiting on customer
┌────────┐
│ paused │
└────────┘

Configuration

Viewing Current SLA Settings

const response = await fetch("/api/tickets/settings", {
headers: {
Authorization: `Bearer ${token}`,
},
});
const settings = await response.json();
console.log(settings.slaThresholds);

Updating SLA Thresholds

const response = await fetch("/api/tickets/settings/sla", {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
slaThresholds: {
urgent: {
firstResponseMinutes: 15,
resolutionMinutes: 240,
},
high: {
firstResponseMinutes: 60,
resolutionMinutes: 480,
},
medium: {
firstResponseMinutes: 240,
resolutionMinutes: 1440,
},
low: {
firstResponseMinutes: 480,
resolutionMinutes: 2880,
},
},
businessHoursOnly: false,
pauseOnCustomerWaiting: true,
atRiskThresholdPercent: 80,
}),
});

SLA Configuration Options

Time Thresholds

Define response and resolution targets in minutes for each priority:

{
"urgent": {
"firstResponseMinutes": 15,
"resolutionMinutes": 240
}
}

Business Hours

  • businessHoursOnly (boolean) - If true, SLA timers only advance during configured business hours
  • Useful for standard support contracts that don’t include 24/7 coverage
  • After-hours tickets resume counting when business hours begin

Customer Waiting

  • pauseOnCustomerWaiting (boolean) - If true, SLA pauses when status is waiting_customer
  • Prevents penalizing support team for customer delays
  • Timer resumes when customer responds or status changes

At-Risk Threshold

  • atRiskThresholdPercent (number) - Percentage of elapsed time before marking ticket “at risk”
  • Default: 80 (marks at-risk when 80% of time has elapsed)
  • Valid range: 1-99
  • Used for proactive alerts and dashboard warnings

SLA Tracking Fields

Each ticket includes comprehensive SLA tracking data:

First Response SLA

{
"slaFirstResponseDue": "2025-11-01T15:45:00Z", // When first response is due
"slaFirstResponseMet": true, // Whether target was met
"firstResponseTime": 12 // Actual response time in minutes
}

Resolution SLA

{
"slaResolutionDue": "2025-11-01T19:30:00Z", // When resolution is due
"slaResolutionMet": false, // Whether target was met
"resolutionTime": null // Actual resolution time (null if unresolved)
}

Overall SLA Status

{
"slaStatus": "at_risk", // Current overall SLA status
"slaBreachedAt": null, // When SLA was breached (if applicable)
"slaPausedAt": "2025-11-01T16:00:00Z", // When SLA was paused (if applicable)
"slaTotalPausedTime": 45 // Total paused time in minutes
}

SLA Calculation

First Response Time

Starts: When ticket is created Stops: When first comment is added by support agent

// Created at 14:30
{
"createdAt": "2025-11-01T14:30:00Z",
"slaFirstResponseDue": "2025-11-01T14:45:00Z" // 15 min for urgent
}
// First response at 14:42
{
"firstResponseTime": 12, // 12 minutes elapsed
"slaFirstResponseMet": true // Within 15 minute target
}

Resolution Time

Starts: When ticket is created Stops: When ticket is marked as resolved or closed

// Created at 14:30, resolved at 18:15
{
"createdAt": "2025-11-01T14:30:00Z",
"resolvedAt": "2025-11-01T18:15:00Z",
"resolutionTime": 225, // 3 hours 45 minutes
"slaResolutionDue": "2025-11-01T18:30:00Z", // 4 hour target
"slaResolutionMet": true
}

Paused Time Handling

When SLA is paused, the paused duration is subtracted from elapsed time:

// Ticket created at 14:00, urgent priority (4 hour resolution SLA)
{
"createdAt": "2025-11-01T14:00:00Z",
"slaResolutionDue": "2025-11-01T18:00:00Z"
}
// Paused at 15:00 (1 hour elapsed)
{
"slaPausedAt": "2025-11-01T15:00:00Z",
"slaStatus": "paused"
}
// Resumed at 16:30 (90 minutes paused)
{
"slaPausedAt": null,
"slaTotalPausedTime": 90,
"slaResolutionDue": "2025-11-01T19:30:00Z" // Extended by 90 minutes
}

Business Hours Calculation

When businessHoursOnly: true, only time during business hours counts:

// Business hours: Mon-Fri 9:00-17:00
// Ticket created Friday at 16:30 (30 min before end of business day)
// Urgent priority: 4 hour resolution SLA
{
"createdAt": "2025-10-31T16:30:00Z", // Friday 4:30 PM
"slaResolutionDue": "2025-11-03T13:00:00Z" // Monday 1:00 PM
}
// Calculation:
// Friday: 30 minutes (16:30-17:00)
// Monday: 3.5 hours (9:00-13:00)
// Total: 4 hours

SLA Monitoring

Real-Time Status Updates

The system automatically updates slaStatus as time progresses:

// At creation (Urgent: 4 hour resolution)
{
"slaStatus": "on_time",
"timeElapsed": 0,
"percentElapsed": 0
}
// After 3 hours (75% elapsed, still on_time)
{
"slaStatus": "on_time",
"timeElapsed": 180,
"percentElapsed": 75
}
// After 3.5 hours (87.5% elapsed, now at_risk)
{
"slaStatus": "at_risk",
"timeElapsed": 210,
"percentElapsed": 87.5
}
// After 4.5 hours (112.5% elapsed, breached)
{
"slaStatus": "breached",
"slaBreachedAt": "2025-11-01T18:30:00Z",
"timeElapsed": 270,
"percentElapsed": 112.5
}

Dashboard Metrics

Query tickets by SLA status for dashboard displays:

// Get all at-risk tickets
const response = await fetch("/api/tickets?slaStatus=at_risk", {
headers: {
Authorization: `Bearer ${token}`,
},
});
// Get all breached tickets
const response = await fetch("/api/tickets?slaStatus=breached", {
headers: {
Authorization: `Bearer ${token}`,
},
});

SLA Reports

Get comprehensive SLA statistics:

const response = await fetch('/api/tickets/statistics?groupBy=slaStatus', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"on_time": 145,
"at_risk": 23,
"breached": 8,
"paused": 12
}

Integration with Other Features

Escalation Rules

Escalation rules can use SLA status as conditions:

{
"name": "Escalate At-Risk Urgent Tickets",
"priority": "urgent",
"conditions": [
{"field": "slaStatus", "operator": "equals", "value": "at_risk"}
],
"escalateAfterMinutes": 0, // Immediate when at-risk
"escalateTo": "manager"
}

Automation Rules

Automation rules can trigger on SLA breaches:

{
"name": "Auto-Priority Increase on Breach",
"trigger": "ticket_updated",
"conditions": [
{"field": "slaStatus", "operator": "equals", "value": "breached"},
{"field": "priority", "operator": "not_equals", "value": "urgent"}
],
"actions": [
{"type": "change_priority", "priority": "urgent"}
]
}

Notifications

Send alerts when tickets approach or breach SLA:

{
"name": "SLA At-Risk Alert",
"trigger": "ticket_updated",
"conditions": [
{"field": "slaStatus", "operator": "equals", "value": "at_risk"}
],
"actions": [
{"type": "send_notification", "channels": ["slack"]}
]
}

Manual SLA Control

Pausing SLA

const response = await fetch("/api/tickets/1234/sla/pause", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
reason: "Waiting for customer to provide additional information",
}),
});

Resuming SLA

const response = await fetch("/api/tickets/1234/sla/resume", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
});

Resetting SLA

In rare cases, you may need to reset SLA (e.g., ticket was incorrectly classified):

const response = await fetch("/api/tickets/1234/sla/reset", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
reason: "Priority changed from Low to Urgent",
recalculate: true, // Recalculate based on new priority
}),
});

Reporting and Analytics

SLA Compliance Reports

Calculate SLA compliance percentage:

const response = await fetch('/api/tickets/statistics/sla-compliance', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"firstResponse": {
"met": 234,
"breached": 12,
"compliancePercent": 95.1
},
"resolution": {
"met": 189,
"breached": 34,
"compliancePercent": 84.8
},
"byPriority": {
"urgent": {
"firstResponse": { "met": 45, "breached": 2, "compliancePercent": 95.7 },
"resolution": { "met": 38, "breached": 9, "compliancePercent": 80.9 }
}
}
}

Average Response Times

Track team performance:

const response = await fetch('/api/tickets/statistics/response-times', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Returns:
{
"urgent": {
"avgFirstResponseMinutes": 12.3,
"avgResolutionMinutes": 187.5
},
"high": {
"avgFirstResponseMinutes": 45.7,
"avgResolutionMinutes": 398.2
}
}

SLA Breach Analysis

Identify patterns in SLA breaches:

const response = await fetch(
"/api/tickets?slaStatus=breached&include=breachReason",
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);

Common Scenarios

Scenario 1: Standard Support Hours

9-5 support team with SLA only during business hours:

{
"businessHoursOnly": true,
"pauseOnCustomerWaiting": true,
"slaThresholds": {
"urgent": { "firstResponseMinutes": 30, "resolutionMinutes": 480 },
"high": { "firstResponseMinutes": 120, "resolutionMinutes": 960 },
"medium": { "firstResponseMinutes": 480, "resolutionMinutes": 2880 },
"low": { "firstResponseMinutes": 960, "resolutionMinutes": 5760 }
}
}

Scenario 2: 24/7 Critical Support

Always-on support for critical systems:

{
"businessHoursOnly": false,
"pauseOnCustomerWaiting": false, // Never pause for critical issues
"slaThresholds": {
"urgent": { "firstResponseMinutes": 15, "resolutionMinutes": 240 },
"high": { "firstResponseMinutes": 30, "resolutionMinutes": 480 }
}
}

Scenario 3: Customer Self-Service

Pause SLA when waiting on customer:

{
"businessHoursOnly": false,
"pauseOnCustomerWaiting": true, // Pause when ball is in customer's court
"atRiskThresholdPercent": 75 // Earlier warning
}

Best Practices

1. Set Realistic Targets

Choose SLA thresholds your team can consistently meet (aim for 90%+ compliance).

2. Align with Escalation

Configure escalation rules to trigger before SLA breach:

  • Escalate at 70-80% of SLA threshold
  • Provides buffer time to meet commitment

3. Monitor Compliance

Review SLA reports weekly to identify trends and areas for improvement.

4. Adjust for Business Hours

If support isn’t 24/7, enable businessHoursOnly to avoid unfair penalization.

5. Use Pause Appropriately

Pause SLA when waiting on customer, but document pause reasons clearly.

6. Track Breach Reasons

When SLA is breached, document the reason for post-mortem analysis.

7. Different Thresholds for Customer Tiers

Consider different SLA configurations for premium vs. standard customers.

8. Regular Review

Review and adjust SLA thresholds quarterly based on team capacity and performance.

Performance Impact

Database Indexing

SLA calculations use indexed fields for performance:

  • slaStatus - Indexed for fast filtering
  • slaResolutionDue - Indexed for sorting
  • priority - Indexed for threshold lookups

Caching

Current SLA status is cached on the ticket record to avoid repeated calculations.

Background Jobs

SLA status updates occur via background job every 5 minutes to minimize API latency.

Permissions

SLA tracking requires:

  • Permission.readSupport - View SLA data
  • Permission.writeSupport - Manual SLA pause/resume
  • Permission.manageSettings - Modify SLA thresholds

API Endpoints

Settings

  • GET /api/tickets/settings - Get current SLA configuration
  • PUT /api/tickets/settings/sla - Update SLA thresholds

Manual Control

  • POST /api/tickets/:ticketId/sla/pause - Pause SLA timer
  • POST /api/tickets/:ticketId/sla/resume - Resume SLA timer
  • POST /api/tickets/:ticketId/sla/reset - Reset SLA calculation

Reporting

  • GET /api/tickets/statistics/sla-compliance - SLA compliance reports
  • GET /api/tickets/statistics/response-times - Average response time metrics
  • GET /api/tickets?slaStatus=<status> - Filter tickets by SLA status

Database Fields

SLA tracking fields on the tickets table:

Status

  • slaStatus - Current SLA status (on_time, at_risk, breached, paused)
  • slaBreachedAt - Timestamp when SLA was breached
  • slaPausedAt - Timestamp when SLA was paused
  • slaTotalPausedTime - Total paused duration in minutes

First Response

  • slaFirstResponseDue - Target timestamp for first response
  • slaFirstResponseMet - Boolean indicating if target was met
  • firstResponseTime - Actual response time in minutes

Resolution

  • slaResolutionDue - Target timestamp for resolution
  • slaResolutionMet - Boolean indicating if target was met
  • resolutionTime - Actual resolution time in minutes

Troubleshooting

SLA not calculating correctly

  1. Check configuration - Verify SLA thresholds are set properly
  2. Business hours - Ensure business hours are configured if using businessHoursOnly
  3. Timezone issues - Verify account timezone matches expected behavior
  4. Pause state - Check if ticket is unexpectedly paused

At-risk threshold not triggering

  1. Verify percentage - Check atRiskThresholdPercent setting
  2. Calculation delay - Background job runs every 5 minutes
  3. Check time elapsed - Ensure ticket has actually exceeded threshold

Reports showing incorrect data

  1. Date range - Verify report date filters
  2. Timezone - Ensure report timezone matches expected
  3. Archived tickets - Check if archived tickets should be included
  4. Cache - Clear report cache if seeing stale data