Tools Used in SRE · PagerDuty

PagerDuty

PagerDuty is the tool most of this course's escalation-policy language was written against before it ever had a vendor name attached to it. The primary-then-secondary rotation, the acknowledgement window, the automatic hand-off to a second responder described in incident management & on-call — that's the abstract shape of the mechanic. PagerDuty is the concrete machine that implements it: a service receives an event, points at one escalation policy, and that policy works down an ordered list of on-call schedules and people, waiting a fixed number of minutes between each try before it moves to the next. Founded in 2009 by three engineers who'd lived through enough 3am pages at Amazon to build something better, and public on the NYSE (ticker PD) since 2019, PagerDuty became the long-standing market leader at exactly this job. This page covers that routing model in full, then the layer most teams under-use once a human is already on the line: Event Orchestration, incident workflows, status pages, and postmortems.

☺ Explain it like I'm 10

Think of an apartment building's emergency intercom panel, not its doorbell. Press the buzzer for unit 4B and the panel doesn't just ring 4B once and give up — it rings 4B first, and if nobody answers within five minutes it automatically rings 4B's downstairs neighbor instead. If that goes unanswered for another fifteen minutes, it rings the building superintendent's cell phone directly, no matter what time it is. Who gets tried, in what order, and how long the panel waits before moving to the next name — that whole chain is programmed in ahead of time, once, by the building manager on a calm afternoon. Nobody improvises it at 2am while the alarm is going off. That pre-programmed chain is a PagerDuty escalation policy; the apartments are on-call schedules; and the buzzer button is a service.

🐦Your host for this topic: Pip the Hummingbird — nobody in this course covers ground faster once an SLO starts burning, and PagerDuty is the actual machine deciding who Pip wakes up first, second, and third.

What PagerDuty is and the problem it solves

☺ Like you're 10: It's the phone tree that never forgets to call the next person if the first one doesn't pick up — and these days it also runs a chunk of the response after somebody finally does.

PagerDuty was founded in 2009 by Alex Solomon, Andrew Miklas, and Baskar Puvanathasan, three engineers who'd carried a pager at Amazon and built the product they wished they'd had, going through Y Combinator before growing into the category's default choice. It went public on the NYSE under ticker PD in 2019. Over the years the core paging mechanic has been folded into a broader suite the company now markets as the PagerDuty Operations Cloud — Incident Management, On-Call Management, Automation (Runbook Automation, built on Rundeck, which PagerDuty acquired in 2022), AIOps/Event Intelligence, Status Pages, and Analytics, all sharing one incident record and one permission model. Feature names and packaging shift with product releases, so treat the shape described on this page as durable and verify current naming against PagerDuty's own docs before you build against it.

PagerDuty doesn't generate alerts — it receives them. A monitoring tool (Prometheus Alertmanager, Datadog, CloudWatch, a homegrown script) sends an event in through one of several hundred built-in integrations or a generic webhook, and PagerDuty's job starts the instant that event lands: decide which service it belongs to, decide whether it's new or a repeat of something already in flight, and if it's new, work through that service's escalation policy until a human acknowledges it. Everything else on this page — Event Orchestration, incident workflows, status pages — is built on top of that one core loop.

The escalation-policy model: services, schedules, levels, and teams

☺ Like you're 10: An alert lands on one service, that service points at one escalation policy, and the policy is just an ordered list of "try this person, then that person, then this whole team," with a timer between each try.

Four objects do essentially all the work, and precision about which one owns which job is what makes the rest of this page make sense.

Alert source Alertmanager · Datadog · CloudWatch · webhook Service checkout-api Integration = routing key grouping: content / time / ML points at Escalation Policy checkout-primary-ep Level 1 — primary on-call schedule · urgency: high +15 min, no ack Level 2 — secondary a second on-call schedule +15 min, still no ack Level 3 — team lead or: page the whole team num_loops: repeat the whole chain (e.g. ×2), then stop Team owns the service + schedules + policy; scopes who can view or edit any of it On-call schedule layer 1: weekly rotation layer 2: override (PTO swap) time zone lives on the schedule resolves to today's user Notification rules per user, in order: 1. push (0 min) 2. SMS (+2 min) 3. phone call (+5 min)

Event Orchestration, alert grouping, and the urgency/priority split

☺ Like you're 10: Before anyone gets paged, PagerDuty first has to decide whether this event is a brand-new problem or just one more symptom of a fire it's already paging someone about.

Raw events don't walk straight into an escalation policy — they pass through Event Orchestration first, a rules engine (the successor to PagerDuty's older Event Rules and Rulesets) evaluated top-to-bottom against the incoming payload, at both a global level and per service. A rule can route an event to a specific service, set its priority, suppress it entirely, override its severity, or extract structured fields out of unstructured payload text with a regex — all before an escalation policy ever sees it.

The single most important field in that payload is the dedup key. Every event sent to PagerDuty's Events API carries an event_actiontrigger, acknowledge, or resolve — and a dedup_key, and PagerDuty treats every event sharing the same key as the same underlying problem rather than a new one. A monitoring rule that fires trigger fifteen times in ten minutes for one flapping check should send the same dedup_key every time; PagerDuty updates the one open alert instead of opening fifteen incidents and paging someone fifteen times over. Beyond dedup, each service also has an alert grouping setting that decides how multiple distinct alerts become one page-worthy incident: content-based (group alerts sharing identical field values — the same error signature), time-based (group anything arriving within a configurable window), or Intelligent Alert Grouping, a machine-learning feature under PagerDuty's AIOps/Event Intelligence add-on that clusters related alerts without a human writing the grouping rule by hand.

◆ Key idea — urgency and priority are not the same field

Urgency (high or low) is what actually drives escalation-policy behavior: a high-urgency incident rings phones per its notification rules; a low-urgency one might only email, and never triggers a phone call regardless of what an escalation level says. A service's urgency can even be dynamic — configured to run high during defined support hours and drop to low outside them, so the same alert pages loudly at 2pm and quietly at 2am without a second escalation policy to maintain. Priority (P1P5) is a separate business-severity classification, frequently synced in from a linked Jira issue's Priority field, used for triage and reporting — setting it does not, by itself, change who gets called or how urgently. Confusing the two is one of the most common PagerDuty misconfigurations in the wild: a team that sets priority and assumes it controls paging behavior discovers the gap during exactly the incident where it mattered.

The config you actually write

☺ Like you're 10: Four blocks of Terraform build the whole chain: a person, a rotation for that person, a policy that says who to call and when, and a service that points at the policy.

Nearly every mature PagerDuty account manages schedules, escalation policies, services, and integrations through the official Terraform provider rather than the web UI, for the same reason any other production config lives in git: reviewable diffs, no click-ops drift, and a rollback path. Field names below match the provider's shape at the time of writing — the provider has renamed a few attributes across major versions, so check the current schema on the Terraform Registry before copying this into a real module.

resource "pagerduty_user" "asha" {
  name  = "Asha Patel"
  email = "asha@acme.io"
  role  = "user"
}

resource "pagerduty_schedule" "checkout_primary" {
  name      = "checkout-primary-oncall"
  time_zone = "America/New_York"      # DST handled once, here — not per engineer

  layer {
    name                          = "Weekly rotation"
    start                         = "2026-01-05T09:00:00-05:00"
    rotation_virtual_start        = "2026-01-05T09:00:00-05:00"
    rotation_turn_length_seconds  = 604800            # 7 days
    users = [
      pagerduty_user.asha.id,
      pagerduty_user.marco.id,
    ]
  }
}

resource "pagerduty_escalation_policy" "checkout" {
  name      = "checkout-primary-ep"
  num_loops = 2                       # repeat the whole chain twice before giving up

  rule {
    escalation_delay_in_minutes = 15  # matches the default this course assumes elsewhere
    target {
      type = "schedule_reference"
      id   = pagerduty_schedule.checkout_primary.id
    }
  }
  rule {
    escalation_delay_in_minutes = 15
    target {
      type = "user_reference"
      id   = pagerduty_user.team_lead.id
    }
  }
}

resource "pagerduty_service" "checkout" {
  name                    = "checkout-api"
  escalation_policy       = pagerduty_escalation_policy.checkout.id
  alert_creation          = "create_alerts_and_incidents"
  acknowledgement_timeout = 1800      # re-escalates if acked but not resolved in 30m
  auto_resolve_timeout    = 14400     # auto-resolves a stale, untouched incident in 4h

  incident_urgency_rule {
    type    = "constant"
    urgency = "high"
  }
}

data "pagerduty_vendor" "alertmanager" {
  name = "Prometheus"
}

resource "pagerduty_service_integration" "checkout_prometheus" {
  name    = "Prometheus Alertmanager"
  service = pagerduty_service.checkout.id
  vendor  = data.pagerduty_vendor.alertmanager.id
}

The integration resource is what actually mints the integration/routing key Alertmanager's pagerduty_configs receiver — or any other source — needs to send events at this specific service.

Day-to-day operations: the REST API, overrides, and the CLI gap

☺ Like you're 10: There's no single command-line tool for PagerDuty the way there is for Kubernetes — instead there are two HTTP APIs, one for sending events in and one for asking questions or making changes, plus the web UI for everything else.

Unlike Prometheus's promtool or Helm's own binary, PagerDuty ships no first-party CLI. Day-to-day interaction happens through the web UI, the Terraform provider for anything declarative, and two REST-ish HTTP APIs for anything scripted: the Events API v2 for sending alerts in, and the general-purpose REST API for reading and mutating almost everything else — incidents, schedules, overrides, users. (Community-maintained CLIs exist; none is officially supported, so treat them as convenience wrappers over the same APIs shown here, not a source of truth.)

# Events API v2 — trigger a new incident (or update one sharing the same dedup_key)
$ curl -X POST https://events.pagerduty.com/v2/enqueue \
    -H 'Content-Type: application/json' \
    -d '{
      "routing_key": "R0ABC1234567890DEADBEEF00112233",
      "event_action": "trigger",
      "dedup_key": "checkout-api-5xx-us-east-1",
      "payload": {
        "summary": "checkout-api error rate above SLO burn threshold",
        "source": "alertmanager/prod-us-east-1",
        "severity": "critical",
        "timestamp": "2026-08-16T03:14:00Z",
        "custom_details": { "burn_rate_1h": 14.2, "slo": "checkout-availability-99.9" }
      }
    }'

# same dedup_key, event_action resolve — closes it out once the burn rate recovers
$ curl -X POST https://events.pagerduty.com/v2/enqueue \
    -H 'Content-Type: application/json' \
    -d '{"routing_key":"R0ABC...","event_action":"resolve","dedup_key":"checkout-api-5xx-us-east-1"}'

# REST API — who's actually on call right now for a given schedule
$ curl -s "https://api.pagerduty.com/oncalls?schedule_ids[]=PSCHEDULEID" \
    -H 'Authorization: Token token=YOUR_API_KEY' \
    -H 'Accept: application/vnd.pagerduty+json;version=2'

# REST API — acknowledge an incident (mutating calls require a valid From user email)
$ curl -X PUT https://api.pagerduty.com/incidents/PINCIDENTID \
    -H 'Authorization: Token token=YOUR_API_KEY' \
    -H 'Content-Type: application/json' \
    -H 'From: asha@acme.io' \
    -d '{"incident": {"type": "incident_reference", "status": "acknowledged"}}'

# REST API — a one-off schedule override, covering someone's shift for a day
$ curl -X POST https://api.pagerduty.com/schedules/PSCHEDULEID/overrides \
    -H 'Authorization: Token token=YOUR_API_KEY' \
    -H 'Content-Type: application/json' \
    -d '{"overrides":[{"start":"2026-08-20T00:00:00Z","end":"2026-08-21T00:00:00Z",
        "user":{"id":"PUSERID","type":"user_reference"}}]}'

$ terraform plan   # review before shipping any escalation-policy or schedule change
$ terraform apply

Incident-response workflow beyond raw paging

☺ Like you're 10: Getting someone's phone to ring is the easy 10% — the rest of PagerDuty's product is everything that happens between "phone rings" and "postmortem gets filed."

This is the half of PagerDuty most teams that adopted it purely for paging never turn on, and it's the half the content this page sits alongside — incident management & on-call — describes in the abstract. Incident Workflows are automations triggered on lifecycle events (an incident is triggered, acknowledged, escalated, resolved) that can spin up a dedicated Slack channel, invite the right subject-matter responders, post a structured update, or kick off a Runbook Automation job, without a human doing any of it by hand mid-incident. Status updates are a structured field on the incident itself, distinct from ad hoc chat messages, meant to be the single source of truth an Ops/Comms lead posts outward on a cadence — the exact role described in incident command for large incidents. Post-Incident Reviews (PagerDuty's postmortem tooling) auto-populate a timeline from the incident's own log entries — who acknowledged, who escalated, when status updates went out — so the blameless postmortem starts from a real timestamped record instead of everyone's imperfect memory the next morning. Runbook Automation, built on the Rundeck acquisition, lets a responder trigger a pre-approved remediation job — restart a service, roll back a deploy, scale a pool — directly from the incident, the same automate-the-repeat-fix instinct toil and automation teaches applied at the moment of the page itself. And Status Pages is PagerDuty's own native public-status-page product bundled into the same platform — worth distinguishing from Atlassian's separately owned Statuspage.io, a similarly named but unrelated product some organizations also run — letting the incident's status updates publish outward to customers without the Comms lead re-typing them into a second tool. Analytics rolls all of this up into org-level numbers: mean time to acknowledge (MTTA), mean time to resolve (MTTR), and per-responder page load, the same health signals a sustainable on-call rotation is measured against.

Gotchas and failure modes

☺ Like you're 10: Almost every PagerDuty incident-about-PagerDuty traces back to one of a handful of settings nobody double-checked before the real incident arrived.

Urgency, not priority, controls whether the phone rings

Covered above and worth repeating as a gotcha in its own right: teams that set priority and assume it drives notification behavior discover during a live SEV1 that the field they configured never touched the escalation policy at all. If a call needs to happen, urgency is the field to check.

An exhausted escalation policy doesn't page anyone else on its own

When num_loops runs out and nobody has acknowledged, PagerDuty doesn't invent a new target — the incident simply sits open and unacknowledged, visible in the dashboard but silent to any human who isn't already looking. The fix is a deliberate final level (page the whole team, or a manager-escalation target) rather than trusting the loop count alone, and it's exactly the gap the on-call readiness checklist asks a team to verify before go-live, not discover during an incident.

A missing dedup key turns one flapping check into a dozen pages

Every monitoring integration that constructs its own Events API calls has to supply a stable dedup_key per underlying condition. Omit it, or derive it from something that changes on every fire (a timestamp, a random ID), and a single flapping alert opens a new incident — and a fresh page — on every trigger, which is precisely the noisy-pager failure mode alert design & alert fatigue covers in depth.

⚠ Watch out

A per-user notification rule with a long delay before the loud channel — push immediately, but SMS only after ten minutes, a phone call only after twenty — is a reasonable default for a low-urgency service and a dangerous one for a SEV1-critical service, because the escalation policy's own delay clock is running in parallel the whole time. Check both clocks together: if a user's slowest notification method fires later than the escalation policy's delay to the next level, that user's phone call may arrive after the page has already moved on to someone else.

Auto-resolve can quietly close a stuck incident

The auto_resolve_timeout shown in the Terraform example above exists to clean up incidents nobody will ever act on, but the same setting will silently resolve a real, still-broken incident if it's set too aggressively relative to how long a genuine fix can take — a resolved incident stops paging and stops showing up as "open" in dashboards, so a too-short timeout can make an unresolved outage look finished.

Schedule layers and time-zone math are the most common on-call-config bug

An override layer stacks on top of a base rotation layer rather than replacing it outright, and a schedule built by several people over time without anyone reviewing it end to end can quietly develop an uncovered gap — a window where the resolved on-call user is nobody, because a rotation and an override disagree about who owns it. PagerDuty's own schedule preview UI is the fastest way to check this before it becomes a live incident with no primary; treating a schedule change like any other production change, reviewed before it ships, catches most of these.

PagerDuty vs. the alternatives

☺ Like you're 10: Other tools ask the same "call the right person, in the right order" question — the real differences are depth of incident-response features, ecosystem fit, and price.

OptionModelBest whenCosts you
PagerDutyDeep escalation-policy model plus a full incident-response suite (workflows, status pages, postmortems, runbook automation)You want the market-leading feature depth and the largest built-in integration catalog, and are willing to pay for itThe most expensive option per seat at scale; the incident-workflow and AIOps depth is easy to under-use if a team only ever turns on raw paging
OpsgenieComparable escalation-policy and schedule model, owned by AtlassianAn Atlassian-centric shop already living in Jira and Confluence, where native integration outweighs PagerDuty's extra incident-workflow depthA generally smaller incident-response feature set beyond raw routing than PagerDuty's newer suite
Grafana OnCallOpen-core paging and scheduling, tightly integrated with Grafana's own alertingA team already standardized on Grafana for dashboards and alerting and wants schedules and escalation living beside itA thinner incident-response layer than PagerDuty's; the open-source edition trades some polish for cost and self-hosting control
VictorOps (Splunk On-Call)Escalation and on-call scheduling under the Splunk umbrellaA Splunk-centric observability stack where native integration matters more than best-in-class incident workflow toolingSmaller market share and integration catalog than PagerDuty or Opsgenie
Roll your own (cron + Twilio/SNS)A hand-built script that pages a hard-coded number on a timerEssentially never, past a toy project — see the gotchas above and imagine debugging them without a UI, an audit log, or a vendor to escalate toNo schedule UI, no acknowledgement tracking, no audit trail, and every one of this page's gotchas rediscovered the hard way, in production

The practical rule most teams land on: PagerDuty earns its price when the incident-workflow, status-page, and runbook-automation features actually get switched on and used — otherwise a team is paying suite pricing for what a leaner competitor's raw escalation policy would have covered just as well. See the SRE toolchain for how the on-call-and-paging category sits next to monitoring and chaos tooling, and verify current plans, seat pricing, and feature-tier boundaries on PagerDuty's own site before committing a budget, since packaging shifts more often than the underlying escalation-policy model does.

🐦 Pip's workshop · 15 min

On a free PagerDuty trial account, build the chain end to end: one user, a weekly schedule with that user in it, a two-level escalation policy (yourself, then a second test user), and a service pointing at it. Send a trigger event at the Events API v2 endpoint above with your own routing key and a fixed dedup_key, and watch the notification arrive. Then send a second trigger with the exact same dedup_key but a different summary — confirm it updates the existing alert instead of paging you twice. Finally, create a one-off schedule override for tomorrow covering a different user, and check that the escalation policy's Level 1 now resolves to them, not you. That's the whole model, felt once instead of just read.

🎬 At the Reliability Watch
🐦

Pip: Checkout's error rate just crossed the burn-rate threshold — Alertmanager sent the trigger, PagerDuty resolved the schedule, and I've got a phone ringing in three seconds.

🦊

Foxy: And if that person doesn't pick up?

🐦

Pip: Fifteen minutes, then Level 2 — a second schedule, different person entirely. I'm not waiting around to find out; the policy handles it whether I'm watching or not.

🐢

Timmy the Turtle: And if Level 2 also doesn't answer, and the loop runs out?

🐦

Pip: Then it just... sits there. Open, unacknowledged, nobody paged further — unless somebody built a real last level into the policy months ago, on a calm afternoon, instead of hoping the first two levels are always enough.

🦉

Professor Owl: Which is why the policy itself deserves the same review a production deploy gets. It's not configuration you set once and forget — it's the thing standing between an alert and a human, every single time.

Going further

☺ Like you're 10: This page is enough to configure a real escalation policy and read a real incident — PagerDuty's own docs are where the newest feature names and current pricing actually live.

The canonical sources are PagerDuty's product documentation at support.pagerduty.com, the API reference at developer.pagerduty.com (Events API v2 and the REST API both documented there in full), and the official Terraform provider on the Terraform Registry. Pair this page with incident management & on-call for the human process this tool exists to support, alert design & alert fatigue for how to keep what reaches PagerDuty actionable in the first place, and SRE Tools & Automation for where this category sits in the exam blueprint. If you want hands-on reps writing an actual runbook against a schedule and an escalation policy rather than just reading about one, Capstone Part 3 — write the on-call runbook is exactly that exercise.

✓ Checkpoint

1. Name the four core PagerDuty objects from this page and, in one sentence each, what job each one owns. 2. What's the difference between a service's integration key and its escalation policy? 3. Explain the difference between urgency and priority, and which one actually determines whether a phone rings. 4. What's a dedup key for, and what happens if a monitoring integration omits it? 5. If an escalation policy's num_loops runs out with nobody acknowledging, what does PagerDuty do about it, and what's the usual fix?

Check your answers
  1. Service — the monitored thing that receives events and points at one escalation policy. On-call schedule — who's up right now, built from a rotation layer plus optional overrides. Escalation policy — the ordered list of levels/targets and delays that decides who gets tried, and when the next person gets tried. Team — the ownership and permission boundary grouping services, schedules, policies, and users together.
  2. An integration key (routing key) identifies which upstream monitoring source is sending an event and which service it lands on; a service has one escalation policy at a time but can have many integrations, each with its own key, feeding that one service.
  3. Urgency (high/low) is what actually drives notification behavior in an escalation policy — a low-urgency incident may never trigger a phone call. Priority (P1–P5) is a separate business-severity classification, often synced from Jira, used for triage and reporting, and does not by itself change who gets paged or how.
  4. A dedup key tells PagerDuty that multiple events referring to the same underlying condition should update one alert instead of creating a new one. Omitting it, or generating a key that changes on every fire, means a single flapping check opens a fresh incident — and a fresh page — every time it triggers.
  5. The incident is simply left open and unacknowledged; PagerDuty does not invent a new target on its own. The usual fix is to build a deliberate final level into the policy — paging the whole team or a manager — rather than relying on the loop count alone to guarantee someone eventually answers.