PagerDuty
Register a PagerDuty OAuth app in the UI, or optionally via deployment env, for self-hosted ctxpipe.
Overview
Self-hosted PagerDuty uses the same connector flow as hosted ctxpipe. Someone still creates a Scoped OAuth application in the PagerDuty developer portal. The usual path is to paste that app's client id and secret in the connector wizard. ctxpipe then creates one v3 webhook subscription per connection. Operators do not paste a shared webhook signing secret.
Deployment env (PAGERDUTY_CLIENT_ID / PAGERDUTY_CLIENT_SECRET) remains an
optional hosted-style shortcut. You do not need to restart Compose, Railway,
or CDK to finish first-time setup.
What you need
- A public HTTPS
AUTH_BASE_URL. In production, keepCTXPIPE_PUBLIC_APP_URLon the same origin. - Permission to create a PagerDuty OAuth application.
- A ctx| GitHub App connection with write access to a destination repository.
- The backend and worker able to reach
identity.pagerduty.comandapi.pagerduty.comorapi.eu.pagerduty.comover HTTPS.
PagerDuty cannot deliver webhooks to a private localhost address. End-to-end connector testing requires a public HTTPS deployment or tunnel.
1. Register the OAuth app in the wizard
- Open Connectors → Add connection → PagerDuty. ctx| creates a draft connection so the app can be saved before account authorization.
- Open PagerDuty App Registration,
select New App, and name the app
ctxpipeor after your deployment. - Under Functionality, select OAuth 2.0. Leave Events Integration unselected. ctxpipe creates a v3 webhook subscription through PagerDuty's API after account authorization; this is not an Events API integration.
- Choose Scoped OAuth and register this redirect URL exactly (the wizard copies it for you):
{AUTH_BASE_URL}/api/v1/integrations/pagerduty/callback- Grant only these permission scopes:
incidents.readservices.readusers.readwebhook_subscriptions.readwebhook_subscriptions.write
- Select Register App. Copy the generated client id and client secret before closing the confirmation; PagerDuty only shows the secret once.
- Save both values in Register PagerDuty OAuth app. ctx| encrypts the secret on the connection and never returns it from connector metadata. Continue to Connect PagerDuty.
Do not add write-back scopes for incidents. ctxpipe does not acknowledge or resolve PagerDuty incidents.
No PAGERDUTY_WEBHOOK_SECRET
Webhook signing secrets are created per subscription and stored encrypted on the connection. Do not invent a deployment-wide PagerDuty webhook secret.
2. Optional: deployment env shortcut
If you prefer one shared app for the whole deployment, set
PAGERDUTY_CLIENT_ID and PAGERDUTY_CLIENT_SECRET on the backend and
the worker. Set PAGERDUTY_REDIRECT_URI only when the public callback
differs from the URL derived from AUTH_BASE_URL. The wizard then starts at
Connect PagerDuty.
Credential resolution is the saved connection app first, then env. The worker needs whichever client secret the refresh path will read.
Docker Compose
Add the values to the root .env, then restart backend and worker:
PAGERDUTY_CLIENT_ID=...
PAGERDUTY_CLIENT_SECRET=...
pnpm startRailway
Set the OAuth variables on the production backend and worker. The repository's
Terraform module passes provided PAGERDUTY_* values to both services. For
the root Terraform stack, the corresponding inputs are
TF_VAR_pagerduty_client_id, TF_VAR_pagerduty_client_secret, and
TF_VAR_pagerduty_redirect_uri.
AWS CDK
Pass the values through connectorSecrets:
new CtxPipe(stack, "CtxPipe", {
// other required settings
connectorSecrets: {
pagerdutyClientId: cdk.SecretValue.secretsManager("pagerduty/client-id"),
pagerdutyClientSecret: cdk.SecretValue.secretsManager(
"pagerduty/client-secret",
),
// Optional when AUTH_BASE_URL already produces the registered callback:
pagerdutyRedirectUri: cdk.SecretValue.unsafePlainText(
"https://app.example.com/api/v1/integrations/pagerduty/callback",
),
},
});The construct stores these values in the connector secret and injects them into backend and worker task definitions.
3. Public webhook URL
After a user completes OAuth, ctxpipe creates one account-level v3 webhook subscription for incident events and points it at:
{AUTH_BASE_URL}/api/v1/webhook/pagerdutyDo not paste this URL into Events Integration during App Registration. PagerDuty receives it when ctxpipe creates the webhook subscription through the Webhook Subscriptions API.
ctxpipe verifies X-PagerDuty-Signature HMAC-SHA256 against the raw request
body, binds the event to the one connection whose stored secret verifies, and
routes with X-PagerDuty-Subscription. Re-authorization replaces a lost
secret instead of stacking another subscription on the same event URL.
Account-level delivery can include every service. Events with no service, or
a service missing from live YAML, are acknowledged with 200 and never
fetched.
4. Verify the connector
- Confirm
GET /.statussucceeds on the public backend origin. - Open Connectors → Add connection → PagerDuty.
- If the wizard shows Register PagerDuty OAuth app, save the client id and secret. Skip this when the deployment already has a shared env app.
- Complete OAuth and confirm the expected account appears.
- Choose a GitHub repository and at least one service. Search and page if the account has more than one page of services.
- Merge the generated
pagerduty/config.yamlpull request. - Confirm the GitHub App delivers the merge push to
{AUTH_BASE_URL}/api/v1/webhook/github/<connectionId>. - Confirm the connector reaches Connected and generated files appear under
pagerduty/incidents/. - Trigger or update an in-scope incident and confirm
POST /api/v1/webhook/pagerdutysucceeds and the corresponding Git file changes. - Confirm repository ingestion completes.
US and EU accounts
ctxpipe discovers the account region from the authorized user's html_url
after OAuth. Do not add a region field to the wizard. The API host is
api.pagerduty.com or api.eu.pagerduty.com.
Troubleshooting
“PagerDuty OAuth is not configured”
Neither the connection nor the deployment has OAuth client credentials. Finish
Register PagerDuty OAuth app in the wizard, or set both
PAGERDUTY_CLIENT_ID and PAGERDUTY_CLIENT_SECRET on backend and worker and
restart. The catalog still opens the setup wizard; Connect fails when the
authorization URL cannot be created.
Callback is rejected
The registered redirect URI must match
{AUTH_BASE_URL}/api/v1/integrations/pagerduty/callback or
PAGERDUTY_REDIRECT_URI exactly, including scheme, host, path, and whether a
trailing slash is present.
Incremental events never arrive
Confirm the public webhook URL is reachable, the connection is live, and the
incident's service is listed in the merged YAML. Tampered or stale signatures
are rejected. Failed enqueue returns 5xx so PagerDuty can retry.
See PagerDuty connector for scope, files, and product troubleshooting.