One‑click answer
- Add a Start Trigger (Webhook, Cron, or Poll).
- Insert an IF node that evaluates the incoming ticket’s SLA tier (e.g., “Gold”, “Silver”, “Bronze”).
- Use Delay or Set nodes to calculate the deadline (
now + SLA‑time). - Route the execution through Priority Queues (Redis, RabbitMQ, or n8n’s built‑in “Queue” node) so high‑priority items are processed first.
- End with Notification (Email, Slack, or Opsgenie) and Audit Log (Postgres/BigQuery).
Quick Diagnosis – Your workflow isn’t respecting SLA deadlines because it processes tickets FIFO, never calculates a deadline, or never escalates overdue items. Embed SLA logic (tier check → deadline → priority queue → escalation) directly into the n8n flow.
Most teams discover the missing deadline calculation only after a few tickets slip past the SLA.
Who this is for – Platform engineers who need to enforce contractual response times inside n8n without writing a full‑stack service.
1. Mapping Business SLA Requirements to n8n Logic
We cover this in detail in the n8n Architectural Decision Making Guide
Micro‑summary: Translate each SLA tier into concrete trigger, response, and resolution windows that n8n can act on.
| SLA Tier | Max Response Time | Max Resolution Time |
|---|---|---|
| Platinum | 15 min | 2 h |
| Gold | 30 min | 4 h |
| Silver | 1 h | 8 h |
| Bronze | 4 h | 24 h |
| Typical Trigger Source |
|---|
| High‑priority webhook (Platinum) |
| Standard webhook or email parser (Gold) |
| Cron‑based poll of ticket DB (Silver) |
| Batch import (CSV, API) (Bronze) |
EEFA note – Store the SLA tier as a canonical enum (sla_tier = 'gold') in the source system. Inconsistent strings cause the IF node to mis‑route, breaking deadlines.
1.1. Normalising Incoming Data
Purpose: Ensure every downstream node sees the same field names and a lower‑cased tier value.
{
"parameters": {
"values": [
{ "name": "ticketId", "value": "={{$json[\"id\"]}}" },
{
"name": "slaTier",
"value": "={{$json[\"sla_tier\"]?.toLowerCase() || \"bronze\"}}"
}
],
"options": {}
},
"name": "Normalise SLA",
"type": "n8n-nodes-base.set"
}
2. Calculating Dynamic Deadlines
If you encounter any deciding sync vs async in n8n resolve them before continuing with the setup.
Micro‑summary: Use the Date & Time node to add the appropriate number of minutes based on the tier.
Once the tier is known we need a concrete timestamp to compare against later.
| Tier | Minutes to add |
|---|---|
| Platinum | 15 |
| Gold | 30 |
| Silver | 60 |
| Bronze | 240 |
2.1. Deadline Calculation Snippet
Purpose: Convert the tier into a concrete deadline timestamp.
{
"parameters": {
"operation": "add",
"value": "={{ $json[\"slaTier\"] === \"platinum\" ? 15 : $json[\"slaTier\"] === \"gold\" ? 30 : $json[\"slaTier\"] === \"silver\" ? 60 : 240 }}",
"unit": "minutes",
"date": "={{$now.utc()}}"
},
"name": "Compute Deadline",
"type": "n8n-nodes-base.dateTime"
}
EEFA warning – The node follows the server’s timezone, which can bite you if you assume UTC. Using $now.utc() guarantees SLA contracts remain timezone‑agnostic.
3. Prioritising Execution with Queues
If you encounter any choosing trigger types in n8n resolve them before continuing with the setup.
Micro‑summary: Push tickets into a Redis sorted‑set where the score reflects the deadline, then pull the earliest deadline first.
If you’re already running Redis for caching, reusing it for the SLA queue usually saves a lot of operational overhead.
3.1. Enqueue a Ticket in Redis
Purpose: Store the ticket payload with the deadline as the sorting key.
{
"parameters": {
"command": "ZADD",
"key": "sla_queue",
"score": "={{ $json[\"deadlineTimestamp\"] }}",
"member": "={{ JSON.stringify($json) }}"
},
"name": "Enqueue Ticket",
"type": "n8n-nodes-base.redis"
}
3.2. Dequeue the Next Ticket
Purpose: A Cron node (every 30 s) fetches the ticket with the lowest score (earliest deadline).
{
"parameters": {
"command": "ZRANGE",
"key": "sla_queue",
"start": 0,
"stop": 0,
"withscores": true
},
"name": "Dequeue Next Ticket",
"type": "n8n-nodes-base.redis"
}
{
"parameters": {
"command": "ZREM",
"key": "sla_queue",
"member": "={{ $json[\"member\"] }}"
},
"name": "Remove Processed Ticket",
"type": "n8n-nodes-base.redis"
}
EEFA tip – Set Redis maxmemory-policy to allkeys-lru so stale tickets are evicted automatically if the queue grows too large. In production, you’ll hit the maxmemory limit if you forget this setting.
3.3. Pure‑n8n Alternative: Community Queue Node
If you prefer staying inside n8n, install the community Queue node and set its priority field (0 = high, 10 = low). It stores jobs in a local SQLite DB—suitable for low‑to‑moderate volume.
4. Automated Escalation & Notification
If you encounter any auditability vs speed in n8n resolve them before continuing with the setup.
Micro‑summary: Detect overdue tickets and push alerts through Slack, Opsgenie, and email.
4.1. Overdue Check
Purpose: Compare the deadline against the current time.
{
"parameters": {
"operation": "isAfter",
"date1": "={{ $json[\"deadline\"] }}",
"date2": "={{ $now.utc() }}"
},
"name": "Is Overdue?",
"type": "n8n-nodes-base.if"
}
4.2. Notification Branches
When a ticket passes the overdue check we fan out to the notification channels.
Slack alert – immediate team notification.
{
"parameters": {
"text": "⚠️ Ticket {{ $json[\"ticketId\"] }} overdue ({{ $json[\"slaTier\"] }})"
},
"name": "Slack Alert",
"type": "n8n-nodes-base.slack"
}
Opsgenie incident – creates a high‑priority incident for SREs.
{
"parameters": {
"message": "Ticket {{ $json[\"ticketId\"] }} has breached SLA."
},
"name": "Opsgenie Incident",
"type": "n8n-nodes-base.opsgenie"
}
EEFA caution – Opsgenie free tier caps at 60 req/min. At this point, pushing a single Opsgenie incident for a batch of tickets is often simpler than spamming the service.
5. Auditing & Reporting for SLA Compliance
Micro‑summary: Log every state change to a PostgreSQL table for legal and operational audits.
5.1. Audit Table Schema
| Column | Type | Description |
|---|---|---|
| event_id | UUID | Primary key |
| ticket_id | TEXT | Source ticket identifier |
| sla_tier | TEXT | Tier at the time of event |
| event_type | TEXT | `queued`, `started`, `escalated`, `resolved` |
| event_timestamp | TIMESTAMPTZ | UTC timestamp |
| payload | JSONB | Full n8n node output (debugging) |
5.2. Insert an Audit Record
Purpose: Capture the moment a ticket enters the queue.
{
"parameters": {
"operation": "insert",
"table": "sla_audit",
"values": [
{
"event_id": "={{ $uuid() }}",
"ticket_id": "={{ $json[\"ticketId\"] }}",
"sla_tier": "={{ $json[\"slaTier\"] }}",
"event_type": "queued",
"event_timestamp": "={{ $now.utc().toISOString() }}",
"payload": "={{ JSON.stringify($json) }}"
}
]
},
"name": "Log Queue Event",
"type": "n8n-nodes-base.postgres"
}
EEFA note – Enable PostgreSQL wal_level = replica and schedule regular backups; audit logs are often required for compliance (e.g., GDPR breach‑notification windows).
6. Production‑Ready Checklist
| Item | Why It Matters |
|---|---|
| Time‑zone normalisation (store all dates in UTC) | Prevents hidden deadline drift across regions |
Idempotent queue inserts (use ticketId as Redis member) |
Avoids duplicate processing during retries |
| Circuit‑breaker on external APIs (Opsgenie, Slack) | Stops cascading failures if a downstream service is down |
Health‑check endpoint (/healthz) exposing queue length & Redis latency |
*We’ve found the health‑check endpoint is the fastest way to spot a stuck queue during on‑call* |
| Retention policy (keep audit rows ≤ 90 days) | Controls DB growth while satisfying compliance |
| Load‑test the queue (simulate 10 k tickets/h) | Guarantees SLA adherence under peak load |
7. Common Pitfalls & How to Fix Them
| Symptom | Root Cause | Fix |
|---|---|---|
| Tickets never hit the “Escalated” branch | `Is Overdue?` IF uses wrong date order | Swap date1/date2 or use isBefore |
| High‑priority tickets processed after low‑priority ones | Redis score uses deadline only | Use a composite score: deadlineTimestamp * 10 + tierWeight (lower weight = higher priority) |
| Workflow stalls after a failure | No error workflow attached to critical nodes | Add a Run Once error node that pushes the failed payload to a dead‑letter queue |
| SLA calculations off by 1 hour during DST change | `Date & Time` node respects server local time | Force UTC ($now.utc()) or use Moment‑TZ via a Function node |
8. Visual Overview
Diagram 1 – End‑to‑End SLA Flow
Diagram 2 – Redis Priority Queue Detail
sla_queueBottom Line
By normalising SLA tiers, calculating precise deadlines, routing through a priority queue, and automating escalation & audit, you turn a generic n8n workflow into a production‑grade, SLA‑aware orchestration engine. Follow the checklist, respect the EEFA notes, and you’ll consistently meet your contractual response‑time guarantees.



