Source connectors

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, keep CTXPIPE_PUBLIC_APP_URL on 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.com and api.pagerduty.com or api.eu.pagerduty.com over 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

  1. Open Connectors → Add connection → PagerDuty. ctx| creates a draft connection so the app can be saved before account authorization.
  2. Open PagerDuty App Registration, select New App, and name the app ctxpipe or after your deployment.
  3. 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.
  4. Choose Scoped OAuth and register this redirect URL exactly (the wizard copies it for you):
{AUTH_BASE_URL}/api/v1/integrations/pagerduty/callback
  1. Grant only these permission scopes:
  • incidents.read
  • services.read
  • users.read
  • webhook_subscriptions.read
  • webhook_subscriptions.write
  1. Select Register App. Copy the generated client id and client secret before closing the confirmation; PagerDuty only shows the secret once.
  2. 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 start

Railway

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/pagerduty

Do 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

  1. Confirm GET /.status succeeds on the public backend origin.
  2. Open Connectors → Add connection → PagerDuty.
  3. 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.
  4. Complete OAuth and confirm the expected account appears.
  5. Choose a GitHub repository and at least one service. Search and page if the account has more than one page of services.
  6. Merge the generated pagerduty/config.yaml pull request.
  7. Confirm the GitHub App delivers the merge push to {AUTH_BASE_URL}/api/v1/webhook/github/<connectionId>.
  8. Confirm the connector reaches Connected and generated files appear under pagerduty/incidents/.
  9. Trigger or update an in-scope incident and confirm POST /api/v1/webhook/pagerduty succeeds and the corresponding Git file changes.
  10. 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.