Vibe code your own PagerDuty
Vibe code your own PagerDuty as a weekly rotation, a timeout, and one email alert. Phone calls, SMS, and event intelligence stay on the skip row.
You can vibe code your own PagerDuty as a weekly rotation, a timeout, and one email alert. PagerDuty is that loop. The catalog line is “Who is on call, and who gets the next ping.”
You pay $21–$25 a person a month. The card says that price scales with the team. That is $252–$300 a person a year. The first estimate is 12 hours.
Last time I wrote about building a Better Proposals alternative. That was a regular backlog post. This one is a teardown.
Vibe code your own PagerDuty as a rotation
The PagerDuty page splits the work into three rows.
The first row is 12 hours. Schedules, escalation, email and webhook alerts. One weekly rotation, a delay, and a message to the person on it.
The second row is 4 days. Acknowledge, handoff, overrides, and an incident timeline. Acknowledge is what stops the timer, because someone took the incident.
The third row is 3 months and up. Event intelligence, AI remediation, and a global on-call mesh. Skip that row.
If you tell an agent to “clone PagerDuty”, it aims at the third row. Copy the prompt, then pin it to the first one.
Store four fields. The server picks the assignee. A name on the webhook is ignored.
const event = {
routingKey: 'slot-api',
dedupKey: 'slot-api-5xx',
action: 'trigger',
summary: 'Slot API 5xx rate above 2%',
}
The same dedupKey stays on the open incident. A new key opens a new incident. That is the idempotency in the guardrail on the card.
The audience is a small engineering team sharing nights and weekends. One rotation covers that. If the company already lives in phone bridges and event intelligence, keep paying.
The card lists Opsgenie and Incident.io beside it. Sentry is $26–$89 a month when the code throws and nobody should wake up yet. I wrote that teardown. A URL check is UptimeRobot at $24–$69, walked in the uptime guide. A missed job is Cronitor at $10–$49. A board customers read is Statuspage, $29–$399.
How does PagerDuty work
PagerDuty publishes the model in API concepts. I am summarizing that glossary, the schedules article, and the Events API. Where those pages stop, I call it a guess.
A service is the thing you monitor. Slot API is a service. It points at one escalation policy.
An escalation policy is an ordered list of rules. Each rule names users or schedules, plus a delay. The first rule hears about a new incident.
Their schedules article walks a primary schedule at level one and a secondary schedule at level two. In that example each level has 30 minutes. If the person does not acknowledge, resolve, or reassign in that window, the incident moves to the next level. The example then repeats three times. When a level has more than one person or schedule, they ask for at least five minutes between levels.
A schedule names one user at a time. The concepts page says it specifies which single user is on call at any moment.
Layers stack, and the lowest layer takes precedence. Their example is Layer 3 covering Layers 1 and 2. Ada and Marco at the same minute means two schedules on the same escalation level. A second layer covers whoever the lower layer already named.
On-call is a computed result. The API only lets you read it. Compute the assignee on the server, which is the guardrail on the card. A posted name can page someone who left the rotation on Tuesday.
An incident is triggered, acknowledged, or resolved. A triggered incident notifies the current on-call users. Each change becomes a read-only log entry.
An event opens an alert, and that alert opens an incident. The concepts page says many alerts can sit on one incident. The grouping rules are an educated guess. A 12-hour clone keeps one open incident per dedup key.
Those events are trigger, acknowledge, or resolve at https://events.pagerduty.com/v2/enqueue. routing_key is a 32-character integration key. dedup_key stops at 255 characters, and payload.summary at 1024. Severity is critical, error, warning, or info.
The same routing key and dedup key land on the open alert. A trigger with no key opens a new alert, because they mint a UUID. After resolve, the old key opens a new incident. Acknowledge and resolve are dropped when nothing is open, or when the routing key differs. An acknowledged incident stays quiet when more triggers arrive on that key.
Notifications are email, SMS, phone, and push. The API only lets you read them, because they fall out of assignment and escalation. A 12-hour v1 sends one email. The other channels are the mesh on the skip row.
The card’s stack is Astro, Workers, and D1. The webhook worker and the sweeper are the two background jobs.
The schedule stores a time zone. Their API example uses America/New_York. Yours needs a zone too. “Monday 09:00” has to become an instant in that zone. Stored as a bare UTC string, that hour lands on the wrong person after the clocks change.
With one team, hang the policy on the team. Add a service row when the API and the database need different rotations.
Screens of a PagerDuty alternative
v1 needs the week, the incident, and the policy.
On-call week
Home is the week. Each day names one person. Today is marked. The zone sits in the header so Sunday 02:10 means the same thing to everyone.
Open incident
The incident names the service, the summary, and the assignee. The dedup key is on the page, so you can see why a second webhook did not open a second row. Acknowledge waits on the 4-day row. Until then, resolve is the way to stop the sweeper.
Escalation steps
The policy is two levels. Level one is the primary schedule. Level two is Marco, the backup. The delay is the number you stored. Their documented example uses 30 minutes. The server reads that number. The browser does not get to invent a shorter one on the way out.
How a PagerDuty alternative pages someone
The loop is ingest, assign, wait, escalate.
Slot’s monitor posts a signed webhook at 02:10. The worker rejects a bad signature. The dedup key slot-api-5xx has no open incident, so the worker inserts one and reads the schedule. Sunday 02:10 in America/New_York is Lea’s shift. One email goes to Lea. The row stores 02:40 as the next step.
A repeat of the same key while the incident is open updates the alert event and does not email Lea again.
At 02:40 the sweeper emails Marco if the row is still open. A resolved row sends nothing. The repeat count is how many times the policy loops. Their example uses three.
Acknowledge, on the 4-day row, means someone has the incident. Their Events API says an acknowledged incident sends no further notifications, even when new triggers arrive on that key. The next trigger after resolve opens a new incident. An override replaces the scheduled person for a window and leaves the rotation alone. The concepts page describes that for flexible schedules. The week view has to show the replacement.
The hard half of a PagerDuty alternative
The skip row starts when one email becomes “reach this human, on the right device, inside five minutes.”
Their June 2020 engineering post describes the notification scheduler. In 2018 they rewrote it in Elixir. Each user is an Erlang process. Each contact method is another process. A phone number used as a call is a different channel from the same number used as SMS. High urgency and low urgency stay apart.
They describe pacing and bundling. Pacing holds a second incident when they just called you about the first. Bundling waits for the next rule, then tells you about both in one call, if both are still yours and still open. A notification rule is per person. “Phone me now” and “phone me again in 5 minutes if it is still mine” are two rules. They reported the new service at one tenth the infrastructure, half the lag, and 10 times the throughput, carrying all notification traffic since January 2019. Treat the 2026 process map as an educated guess. The public writeup is the 2020 one.
The June 2026 reliability post says the platform processes over 23 billion events a year. A notification slower than five minutes counts against the SLA, including during maintenance. The target they publish is 99.99% over any rolling 30 days, on the path from event to notification. US and EU are separate deploy surfaces. They also describe a production check that hits the Events API, opens an incident, and confirms a notification arrived inside that window. A v1 on one Worker and one email provider owes one team an email that matches the schedule.
Event intelligence is the other product on that row. Event Orchestrations are rule sets that route and rewrite events before a service sees them. A global orchestration has its own routing key. A service orchestration starts at one rule set and can change the event. Related incidents are described as an online model plus service dependencies, limited to the 20 most recent. The weights are an educated guess. That work sits on the catalog’s third row, beside AI remediation.
Schedules get harder than a weekly list. V2 is layers at /schedules. V3 flexible schedules, in early access at /v3/schedules, allow up to 10 rotations, custom shifts, and overrides. Overrides and handoffs on one weekly layer are the 4-day row.
The non-goal on the card also names status pages and phone-bridge conference calls. A public board is the status page guide.
Host it on Node.js and Astro, with a Worker for the webhook and the sweeper, because that is the stack on the card. Use TanStack Start if React is your weekday language. The hosting post already covers D1 and cron Workers. Persist the team, the schedule, the policy, incidents, and alert events in D1.
Start with the first row
Go to Build your own PagerDuty. Copy the Astro prompt, or TanStack Start if that is what you write.
Tell the agent the first estimate only. Schedules, escalation, email and webhook alerts. Twelve hours.
If the rent is a URL check, use the uptime guide. If it is a missed cron, use the cron guide. If the requirement is a phone call inside five minutes, keep paying.