PagerDuty Collector
Query the PagerDuty API to collect on-call schedule, escalation policy, and current responder data. Normalizes results into the .oncall category for tool-agnostic policy evaluation.
pagerduty to your lunar-config.yml:uses: github://earthly/lunar-lib/collectors/pagerduty@v1.0.5
What This Integration Collects
This integration includes 2 collectors that gather metadata from your systems.
oncall
Queries the PagerDuty REST API for the component's service on a code hook
— it runs when commits are pushed (PRs and the default branch). Resolves
the service ID in order: the component's pagerduty/service-id meta
annotation (set by a cataloger via
lunar catalog component --meta pagerduty/service-id <id>), then the
explicit service_id input, then — when backstage_discovery is enabled
— the component's own catalog-info.yaml (read from the fresh checkout
the code hook provides, so no clone-code is needed), reading the service
ID directly from a pagerduty.com/service-id / pagerduty/service-id
annotation. Fetches service details, on-call schedule participants, and
escalation policy. Writes normalized data to .oncall.service,
.oncall.schedule, .oncall.escalation, and .oncall.summary. Stores the raw
API response under .oncall.native.pagerduty.
oncall-cron
Same PagerDuty query as oncall, but on a daily cron instead of on push —
it re-collects on a schedule so .oncall stays fresh as on-call schedules
and escalation policies rotate between commits (they change on their own
clock, independent of code). Resolves the service ID identically and writes
the same normalized .oncall.service, .oncall.schedule, .oncall.escalation,
and .oncall.summary (raw responses under .oncall.native.pagerduty).
clone-code gives it the checkout so backstage_discovery can still read
catalog-info.yaml. Include oncall for on-push evaluation, oncall-cron
for always-fresh scheduled refresh, or both.
How Collectors Fit into Lunar
Lunar watches your code and CI/CD systems to collect SDLC data from config files, test results, IaC, deployment configurations, security scans, and more.
Collectors are the automatic data-gathering layer. They extract structured metadata from your repositories and pipelines, feeding it into Lunar's centralized database where guardrails evaluate it to enforce your engineering standards.
Learn How Lunar Works →Example Collected Data
This collector writes structured metadata to the Component JSON. Here's an example of the data it produces:
{
"oncall": {
"source": {
"tool": "pagerduty",
"integration": "api"
},
"service": {
"id": "PXXXXXX",
"name": "Payment API",
"status": "active"
},
"schedule": {
"exists": true,
"participants": 4,
"rotation": "weekly"
},
"escalation": {
"exists": true,
"levels": 3,
"policy_name": "Payment API Escalation"
},
"summary": {
"has_oncall": true,
"has_escalation": true,
"min_participants": 4
},
"native": {
"pagerduty": { "...full PagerDuty API response..." }
}
}
}
Configuration
Configure this collector in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
service_id
|
Required | — | PagerDuty service ID to query (e.g. PXXXXXX). Optional if the component has a `pagerduty/service-id` meta annotation set by a cataloger. |
pagerduty_base_url
|
Optional |
https://api.pagerduty.com
|
PagerDuty API base URL |
backstage_discovery
|
Optional |
false
|
When "true", and no service ID is found via component meta or the service_id input, discover it from the component's own catalog-info.yaml: the collector reads the file from the runner's checkout (oncall runs on a code hook, which clones; oncall-cron sets clone-code) and takes the PagerDuty service ID from the annotation keys listed in backstage_annotations. Opt-in, and needs no extra secret — the runner's checkout is used, not a token. Lets the oncall guardrails work off the standard PagerDuty Backstage annotation without a cataloger or component meta. |
backstage_annotations
|
Optional |
pagerduty.com/service-id,pagerduty/service-id
|
Comma-separated annotation keys to read the service ID from, tried in order (first non-empty value across the file's Component entities wins). Defaults to both conventional spellings — PagerDuty's Backstage integration guide uses `pagerduty.com/service-id`; Lunar's meta uses `pagerduty/service-id`. Only used when backstage_discovery is "true". |
backstage_catalog_paths
|
Optional |
catalog-info.yaml,catalog-info.yml
|
Comma-separated catalog-info file paths to try in the checked-out repo (first match wins). Only used when backstage_discovery is "true". |
Secrets
This collector requires the following secrets to be configured in Lunar:
| Secret | Description |
|---|---|
PAGERDUTY_API_KEY
|
PagerDuty REST API key (read-only token with service and oncall scopes) |
Documentation
View on GitHubPagerDuty Collector
Collect on-call schedule and escalation data from the PagerDuty API.
Overview
This collector queries the PagerDuty REST API to gather on-call schedule,
escalation policy, and service data, writing normalized results to the
.oncall category in a tool-agnostic format so the same oncall policy works
for PagerDuty, OpsGenie, or any other provider. It ships two trigger variants
that run the same query and write the same data — oncall (code hook, on PRs
and the default branch) and oncall-cron (daily cron); pick whichever fits
(see Collectors below). The service ID is discovered from the component's
pagerduty/service-id meta annotation, an explicit service_id input, or —
with backstage_discovery enabled — the repo's catalog-info.yaml annotation.
Collected Data
This collector writes to the following Component JSON paths:
| Path | Type | Description |
|---|---|---|
.oncall.source |
object | Tool and integration metadata |
.oncall.service |
object | PagerDuty service ID, name, and status |
.oncall.schedule |
object | On-call schedule: exists flag, participant count, rotation type |
.oncall.escalation |
object | Escalation policy: exists flag, level count, policy name |
.oncall.summary |
object | Summary flags for quick policy evaluation |
.oncall.native.pagerduty |
object | Raw PagerDuty API responses |
Collectors
This integration provides the following collectors — use include to select
one (or include both to collect on both triggers). Both run the same query and
write the same .oncall data; they differ only in when they run.
| Collector | Description |
|---|---|
oncall |
Code hook — queries PagerDuty on pushes to PRs and the default branch, so the on-call guardrail is evaluated as part of a commit/PR check |
oncall-cron |
Cron hook — queries PagerDuty daily (04:00 UTC, staggered off the 02:00/03:00 scheduled jobs) and refreshes .oncall so the data stays current as schedules rotate, independent of code changes |
Most setups want one or the other. Including both is supported and the
normalized .oncall data stays correct either way — but be aware the raw arrays
under .oncall.native.pagerduty will carry duplicate entries, because Lunar
concatenates arrays written to the same path by different collectors. Guardrail
results are unaffected: the oncall policy reads only the normalized scalars.
Installation
Add to your lunar-config.yml (use include to pick a trigger variant):
collectors:
- uses: github://earthly/lunar-lib/collectors/pagerduty@v1.0.0
include: [oncall] # code hook (PRs + default branch); use [oncall-cron] for the daily-cron variant
on: ["domain:your-domain"]
# with:
# service_id: "PXXXXXX" # Optional — falls back to catalog meta annotation
Secrets:
PAGERDUTY_API_KEY— PagerDuty REST API key (read-only, with service and oncall scopes). Required.
(No GitHub token is needed for backstage_discovery — oncall (code) runs on a fresh checkout and oncall-cron sets clone-code: true, so either way the collector reads catalog-info.yaml from the runner's checkout, not the API.)
Service ID discovery
The collector resolves the PagerDuty service ID in this order:
-
Catalog meta annotation — reads
pagerduty/service-idfrom the component's lunar catalog meta. Set vialunar catalog component --meta pagerduty/service-id <id>, typically invoked by a company-specific cataloger that knows which components map to which PagerDuty services. This is the recommended approach for orgs where each component has its own service. -
Explicit
service_idinput — set inlunar-config.ymlfor static org-wide configurations, or when importing the collector multiple times with differenton:scopes (e.g. one import per domain, each with its own service ID). -
Backstage discovery (opt-in) — when
backstage_discovery: "true", the collector reads the component's owncatalog-info.yamlfrom the runner's checkout (theoncallcode hook clones automatically;oncall-cronsetsclone-code: true) and takes the service ID directly from its annotations (backstage_annotations, defaultpagerduty.com/service-id,pagerduty/service-id). This lets theoncallguardrails work off the standard PagerDuty Backstage annotation with no cataloger and no component meta — reach for it when your components already carry the PagerDuty annotation and you'd rather read it directly than run a cataloger to copy it into component meta. No GitHub token needed: it reads the runner's checkout, not the API.collectors: - uses: github://earthly/lunar-lib/collectors/pagerduty@v1.0.0 on: ["domain:your-domain"] with: backstage_discovery: "true" -
None found — the collector exits cleanly with no data written.
Inputs
| Input | Default | Description |
|---|---|---|
service_id |
(empty — falls back to catalog meta) | PagerDuty service ID (e.g. PXXXXXX). Optional if pagerduty/service-id meta annotation is set. |
pagerduty_base_url |
https://api.pagerduty.com |
PagerDuty API base URL |
backstage_discovery |
"false" |
When "true", discover the service ID from the component's checked-out catalog-info.yaml annotations if meta/service_id don't provide one. No token needed (uses the runner's clone-code checkout). |
backstage_annotations |
pagerduty.com/service-id,pagerduty/service-id |
Comma-separated annotation keys to read the service ID from (first non-empty wins), tried in order. Only used when backstage_discovery is "true". |
backstage_catalog_paths |
catalog-info.yaml,catalog-info.yml |
Comma-separated catalog-info file paths to try in the checked-out repo (first match wins). Only used when backstage_discovery is "true". |
Open Source
This collector is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore guardrails that use data from PagerDuty Collector.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.