> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Manage PagerDuty on-call schedules

Implement with AI

Send this guide to your coding agent.

Prerequisite: Install Port MCP

Open plan mode. Implement this Port guide in my org via MCP:

https://docs.port.io/guides/all/manage-pagerduty-on-call-schedules/

Goal: get the guide's core flow working end-to-end in my org; adapting it to fit my existing setup takes priority over matching the guide 1:1.

Plan:
1. Confirm MCP is connected, in the right org, with sufficient permissions.
2. Diff the guide's data model (blueprints, properties, relations, actions, agents, automations, integrations, secrets) against mine.
3. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates.
4. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out.
5. Stop on any blocker and give me options. Approving this plan authorizes the writes it lists; pause only for writes beyond what's listed.

Build:
- Extend blueprint schema additively when upserting; don't remove or overwrite existing properties, and treat type conflicts as a blocker, not an auto-fix.
- List any mock data in the plan, minimal and labeled mock; once approved, seed it without re-asking, and tell me what you seeded.
- For anything the guide writes downstream (e.g. a webhook target), use a real entity, not a mock.
- For pages/widgets, use the real page identifier from the app URL, not a guessed slug.
- When you hit a UI step confirmed (not assumed) unsupported via MCP, pause, give exact clicks, then resume via MCP.
- Validate and give links after each meaningful step (only a tool-returned URL, no guessed paths); don't proceed if the last run wasn't a success.

Done:
- Confirm the guide's expected output exists and runs in Port.
- Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.

This guide demonstrates how to bring your on-call management experience into Port using PagerDuty and Port workflows.
You will learn how to:

  • Build self-service workflows to manage on-call schedules (view the current on-call user, change on-call users, and delete overrides).
  • Build dashboards in Port to visualize on-call coverage, rotation schedules, and team assignments.
  • Track on-call engineers across different teams and services.
PagerDuty on-call management dashboard overview

Common use cases

  • On-call visibility: Get a centralized view of who's on-call across all teams and services.
  • Schedule management: Easily change on-call assignments and create temporary overrides.
  • Team coordination: Track on-call rotations and ensure proper coverage across services.
  • Escalation planning: Visualize escalation policies and on-call hierarchies.
  • Burnout prevention: Monitor on-call frequency and distribute responsibilities fairly.

Prerequisites

This guide assumes the following:

  • You have a Port account and have completed the onboarding process.
  • Port's PagerDuty integration is installed in your account.
  • You have access to your PagerDuty organization with permissions to manage schedules and on-call assignments.
  • You have a PagerDuty API token so the workflows can call the PagerDuty API.

How it works

You will build three self-service workflows, each triggered on demand and calling the PagerDuty API directly:

  1. View current on-call user - a self-service trigger collects the schedule, then a webhook node queries the PagerDuty on-calls API and returns the current on-call engineer.
  2. Change on-call user - a self-service trigger collects the schedule, new on-call user, and time window. Webhook nodes look up the user and create a PagerDuty override, and an upsert entity node syncs the updated schedule back to Port.
  3. Delete schedule override - a self-service trigger collects the schedule and override ID, then a webhook node deletes the override and an upsert entity node syncs the updated schedule back to Port.

Set up data model

If you haven't installed the PagerDuty integration, you'll need to create blueprints for PagerDuty schedules and users.
However, we highly recommend you install the PagerDuty integration to have these automatically set up for you.

Create the PagerDuty Schedule blueprint

  1. Go to the Builder page in Port.

  2. Click on + Blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add this JSON schema:

    PagerDuty Schedule Blueprint (click to expand)
    {
    "identifier": "pagerdutySchedule",
    "description": "This blueprint represents a PagerDuty schedule in our context lake",
    "title": "PagerDuty Schedule",
    "icon": "pagerduty",
    "schema": {
    "properties": {
    "url": {
    "type": "string",
    "format": "url",
    "title": "Schedule URL"
    },
    "timezone": {
    "type": "string",
    "title": "Timezone"
    },
    "description": {
    "type": "string",
    "title": "Description"
    },
    "users": {
    "title": "Users",
    "type": "array",
    "items": {
    "type": "string",
    "format": "user"
    }
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "relations": {
    "pagerdutyService": {
    "title": "PagerDuty Service",
    "target": "pagerdutyService",
    "required": false,
    "many": true
    }
    }
    }
  5. Click Save.

Create the PagerDuty User blueprint

  1. Go to the Builder page in Port.

  2. Click on + Blueprint.

  3. Click on the {...} button in the top right corner, and choose Edit JSON.

  4. Add this JSON schema:

    PagerDuty User Blueprint (click to expand)
    {
    "identifier": "pagerdutyUser",
    "description": "This blueprint represents a PagerDuty user in our context lake",
    "title": "PagerDuty User",
    "icon": "pagerduty",
    "schema": {
    "properties": {
    "email": {
    "type": "string",
    "format": "email",
    "title": "Email"
    },
    "time_zone": {
    "type": "string",
    "title": "Time Zone"
    },
    "color": {
    "type": "string",
    "title": "Color"
    },
    "role": {
    "type": "string",
    "title": "Role"
    },
    "avatar_url": {
    "type": "string",
    "format": "url",
    "title": "Avatar URL"
    },
    "description": {
    "type": "string",
    "title": "Description"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "relations": {
    "pagerdutyTeam": {
    "title": "PagerDuty Team",
    "target": "pagerdutyTeam",
    "required": false,
    "many": true
    }
    }
    }
  5. Click Save.

Add Port secrets

The workflows call the PagerDuty API, so add your PagerDuty API token as a Port secret.

  1. In your Port application, click your profile picture Profile picture icon.
  2. Click on Credentials.
  3. Click on the Secrets tab.
  4. Click on + Secret and add the following secret:
Existing secrets

If you have already installed Port's PagerDuty integration, these secrets should already exist in Port. To view your existing secrets:

  1. In your Port application, click on your profile picture .
  2. Choose Credentials, then click on the Secrets tab.

Build the workflows

Now let's build the three self-service workflows that manage your PagerDuty on-call schedules directly from Port. Each workflow reuses the _PAGERDUTY_TOKEN secret you added above.

To build each workflow:

  1. Go to the Workflows page in Port.

  2. Click on the + Workflow button in the top-right corner.

  3. In the Name field, enter a descriptive name for the workflow then click Confirm.

  4. On the editor page, click the see workflow JSON button (the code icon) to open the JSON editor.

  5. Copy and paste the workflow JSON below to replace the example workflow:

  6. Click Save to save the workflow.

View current on-call user

This workflow collects a schedule and queries the PagerDuty on-calls API to return the current on-call engineer.

View current on-call user workflow (click to expand)
{
"identifier": "view_current_oncall",
"title": "View current on-call user",
"icon": "pagerduty",
"description": "Get information about who is currently on-call for a PagerDuty schedule",
"nodes": [
{
"identifier": "trigger",
"title": "View Current Oncall",
"icon": "pagerduty",
"description": "Select the PagerDuty schedule to look up",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"schedule": {
"type": "string",
"format": "entity",
"blueprint": "pagerdutySchedule",
"title": "PagerDuty schedule",
"description": "The schedule to look up the current on-call user for"
}
},
"required": ["schedule"],
"order": ["schedule"]
}
},
"variables": {}
},
{
"identifier": "get_oncall",
"title": "Get current on-call",
"icon": "pagerduty",
"description": "Query the PagerDuty on-calls API for the selected schedule",
"config": {
"type": "WEBHOOK",
"url": "https://api.pagerduty.com/oncalls?schedule_ids[]={{ .outputs.trigger.schedule }}",
"method": "GET",
"headers": {
"Content-Type": "application/json",
"Accept": "application/vnd.pagerduty+json;version=2",
"Authorization": "Token token={{ .secrets[\"_PAGERDUTY_TOKEN\"] }}"
}
},
"variables": {
"onCallUser": "{{ .result.response.data.oncalls[0].user.summary // \"No one currently on-call\" }}",
"start": "{{ .result.response.data.oncalls[0].start // \"N/A\" }}",
"end": "{{ .result.response.data.oncalls[0].end // \"N/A\" }}",
"escalationLevel": "{{ .result.response.data.oncalls[0].escalation_level // \"N/A\" }}"
}
}
],
"connections": [
{
"sourceIdentifier": "trigger",
"targetIdentifier": "get_oncall"
}
]
}

Change on-call user

This workflow looks up a PagerDuty user by email, creates an override for the selected time window, and then syncs the updated schedule back to Port.

Change on-call user workflow (click to expand)
{
"identifier": "change_oncall_user",
"title": "Change on-call user",
"icon": "pagerduty",
"description": "Create a PagerDuty override to change the current on-call user, then sync the schedule to Port",
"nodes": [
{
"identifier": "trigger",
"title": "Override Oncall Details",
"icon": "pagerduty",
"description": "Collect the schedule, new on-call user, and override time window",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"schedule": {
"type": "string",
"format": "entity",
"blueprint": "pagerdutySchedule",
"title": "PagerDuty schedule"
},
"new_on_call_user": {
"type": "string",
"format": "user",
"title": "New on-call user email",
"description": "Email address of the user who will take over the on-call duty"
},
"start_time": {
"type": "string",
"format": "date-time",
"title": "Start time",
"description": "Override start time"
},
"end_time": {
"type": "string",
"format": "date-time",
"title": "End time",
"description": "Override end time"
}
},
"required": ["schedule", "new_on_call_user", "start_time", "end_time"],
"order": ["schedule", "new_on_call_user", "start_time", "end_time"]
}
},
"variables": {}
},
{
"identifier": "find_user",
"title": "Find PagerDuty user",
"icon": "pagerduty",
"description": "Look up the PagerDuty user by email",
"config": {
"type": "WEBHOOK",
"url": "https://api.pagerduty.com/users?query={{ .outputs.trigger.new_on_call_user }}",
"method": "GET",
"headers": {
"Content-Type": "application/json",
"Accept": "application/vnd.pagerduty+json;version=2",
"Authorization": "Token token={{ .secrets[\"_PAGERDUTY_TOKEN\"] }}"
}
},
"variables": {
"userId": "{{ .result.response.data.users[0].id }}"
}
},
{
"identifier": "create_override",
"title": "Create override",
"icon": "pagerduty",
"description": "Create the override in PagerDuty for the selected user and time window",
"config": {
"type": "WEBHOOK",
"url": "https://api.pagerduty.com/schedules/{{ .outputs.trigger.schedule }}/overrides",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Accept": "application/vnd.pagerduty+json;version=2",
"Authorization": "Token token={{ .secrets[\"_PAGERDUTY_TOKEN\"] }}"
},
"body": {
"override": {
"start": "{{ .outputs.trigger.start_time }}",
"end": "{{ .outputs.trigger.end_time }}",
"user": {
"id": "{{ .outputs.find_user.userId }}",
"type": "user_reference"
}
}
}
},
"variables": {}
},
{
"identifier": "fetch_schedule",
"title": "Fetch updated schedule",
"icon": "pagerduty",
"description": "Get the updated schedule from PagerDuty",
"config": {
"type": "WEBHOOK",
"url": "https://api.pagerduty.com/schedules/{{ .outputs.trigger.schedule }}",
"method": "GET",
"headers": {
"Content-Type": "application/json",
"Accept": "application/vnd.pagerduty+json;version=2",
"Authorization": "Token token={{ .secrets[\"_PAGERDUTY_TOKEN\"] }}"
}
},
"variables": {}
},
{
"identifier": "sync_schedule",
"title": "Sync schedule to Port",
"icon": "pagerduty",
"description": "Update the PagerDuty schedule entity in Port",
"config": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "pagerdutySchedule",
"mapping": {
"identifier": "{{ .outputs.fetch_schedule.response.data.schedule.id }}",
"title": "{{ .outputs.fetch_schedule.response.data.schedule.name }}",
"properties": {
"url": "{{ .outputs.fetch_schedule.response.data.schedule.html_url }}",
"timezone": "{{ .outputs.fetch_schedule.response.data.schedule.time_zone }}",
"description": "{{ .outputs.fetch_schedule.response.data.schedule.description }}"
}
}
},
"variables": {}
}
],
"connections": [
{
"sourceIdentifier": "trigger",
"targetIdentifier": "find_user"
},
{
"sourceIdentifier": "find_user",
"targetIdentifier": "create_override"
},
{
"sourceIdentifier": "create_override",
"targetIdentifier": "fetch_schedule"
},
{
"sourceIdentifier": "fetch_schedule",
"targetIdentifier": "sync_schedule"
}
]
}
User must exist in PagerDuty

The Find PagerDuty user node looks up the user by the email you provide. Make sure the email matches a valid PagerDuty user, otherwise the override creation will fail because no user ID is found.

Delete schedule override

This workflow deletes an existing override from a schedule and then syncs the updated schedule back to Port.

Finding the override ID

PagerDuty override IDs are not shown in the PagerDuty web UI, so you need to fetch them from the PagerDuty API. Query the schedule for a time range that includes the override:

curl -s 'https://api.pagerduty.com/schedules/<SCHEDULE_ID>/overrides?since=<START_TIME>&until=<END_TIME>' \
-H 'Accept: application/vnd.pagerduty+json;version=2' \
-H 'Authorization: Token token=<_PAGERDUTY_TOKEN>'

Each override in the response includes its id, along with the start, end, and assigned user. Copy the id of the override you want to remove and use it as the Override ID input.

Delete schedule override workflow (click to expand)
{
"identifier": "delete_schedule_override",
"title": "Delete schedule override",
"icon": "pagerduty",
"description": "Delete a PagerDuty schedule override, then sync the schedule to Port",
"nodes": [
{
"identifier": "trigger",
"title": "Delete Pagerduty Override",
"icon": "pagerduty",
"description": "Collect the schedule and the override to delete",
"config": {
"type": "SELF_SERVE_TRIGGER",
"userInputs": {
"properties": {
"schedule": {
"type": "string",
"format": "entity",
"blueprint": "pagerdutySchedule",
"title": "PagerDuty schedule"
},
"override_id": {
"type": "string",
"title": "Override ID",
"description": "The ID of the override to delete"
}
},
"required": ["schedule", "override_id"],
"order": ["schedule", "override_id"]
}
},
"variables": {}
},
{
"identifier": "delete_override",
"title": "Delete override",
"icon": "pagerduty",
"description": "Delete the override from PagerDuty",
"config": {
"type": "WEBHOOK",
"url": "https://api.pagerduty.com/schedules/{{ .outputs.trigger.schedule }}/overrides/{{ .outputs.trigger.override_id }}",
"method": "DELETE",
"headers": {
"Content-Type": "application/json",
"Accept": "application/vnd.pagerduty+json;version=2",
"Authorization": "Token token={{ .secrets[\"_PAGERDUTY_TOKEN\"] }}"
}
},
"variables": {}
},
{
"identifier": "fetch_schedule",
"title": "Fetch updated schedule",
"icon": "pagerduty",
"description": "Get the updated schedule from PagerDuty",
"config": {
"type": "WEBHOOK",
"url": "https://api.pagerduty.com/schedules/{{ .outputs.trigger.schedule }}",
"method": "GET",
"headers": {
"Content-Type": "application/json",
"Accept": "application/vnd.pagerduty+json;version=2",
"Authorization": "Token token={{ .secrets[\"_PAGERDUTY_TOKEN\"] }}"
}
},
"variables": {}
},
{
"identifier": "sync_schedule",
"title": "Sync schedule to Port",
"icon": "pagerduty",
"description": "Update the PagerDuty schedule entity in Port",
"config": {
"type": "UPSERT_ENTITY",
"blueprintIdentifier": "pagerdutySchedule",
"mapping": {
"identifier": "{{ .outputs.fetch_schedule.response.data.schedule.id }}",
"title": "{{ .outputs.fetch_schedule.response.data.schedule.name }}",
"properties": {
"url": "{{ .outputs.fetch_schedule.response.data.schedule.html_url }}",
"timezone": "{{ .outputs.fetch_schedule.response.data.schedule.time_zone }}",
"description": "{{ .outputs.fetch_schedule.response.data.schedule.description }}"
}
}
},
"variables": {}
}
],
"connections": [
{
"sourceIdentifier": "trigger",
"targetIdentifier": "delete_override"
},
{
"sourceIdentifier": "delete_override",
"targetIdentifier": "fetch_schedule"
},
{
"sourceIdentifier": "fetch_schedule",
"targetIdentifier": "sync_schedule"
}
]
}

Let's test it!

Each workflow appears as a self-service action in your portal. To run them:

  1. Head to the self-service page in Port.

  2. Test viewing current on-call user:

    • Run the View current on-call user workflow.
    • Select a PagerDuty schedule.
    • Click Execute.
    • Open the workflow run and review the Get current on-call node output to see who is currently on-call.
  3. Test changing on-call user:

    • Run the Change on-call user workflow.
    • Fill in the required information:
      • PagerDuty schedule: the schedule to override.
      • New on-call user email: PagerDuty user email to assign.
      • Start time: when the override should begin.
      • End time: when the override should end.
    • Click Execute, then confirm the override was created in PagerDuty and the schedule entity was updated in Port.
  4. Test deleting schedule override:

    • Run the Delete schedule override workflow.
    • Select the schedule and enter the Override ID you want to remove.
    • Click Execute, then confirm the override was removed in PagerDuty.

Visualize metrics

With your on-call management workflows in place and data flowing, we can create a dedicated dashboard in Port to visualize on-call coverage, schedules, and team assignments.

Create a dashboard

  1. Navigate to your context lake.

  2. Click on the + button in the left sidebar.

  3. Select New dashboard.

  4. Name the dashboard PagerDuty On-call Management.

  5. Input Monitor and manage your PagerDuty on-call schedules and assignments under Description.

  6. Select the PagerDuty icon.

  7. Click Create.

We now have a blank dashboard where we can start adding widgets to visualize insights from our PagerDuty on-call data.

Add widgets

In the new dashboard, create the following widgets:

Total schedules count (click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Total schedules

  3. Select Count entities Chart type and choose PagerDuty Schedule as the Blueprint.

  4. Select count for the Function.

  5. Select custom as the Unit and input schedules as the Custom unit.

  6. Click Save.

Schedules created today (click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Schedules created today.

  3. Select Count entities Chart type and choose PagerDuty Schedule as the Blueprint.

  4. Select count for the Function.

  5. Add this JSON to the Additional filters editor to filter schedules created today:

    [
    {
    "combinator": "and",
    "rules": [
    {
    "property": "$createdAt",
    "operator": "between",
    "value": {
    "preset": "today"
    }
    }
    ]
    }
    ]
  6. Select custom as the Unit and input schedules as the Custom unit.

  7. Click Save.

Users by role (click to expand)
  1. Click + Widget and select Pie chart.

  2. Title: Users by role.

  3. Choose the PagerDuty User blueprint.

  4. Under Breakdown by property, select the Role property.

  5. Click Save.

Total users count (click to expand)
  1. Click + Widget and select Number Chart.

  2. Title: Total users (add the User icon).

  3. Select Count entities Chart type and choose PagerDuty User as the Blueprint.

  4. Select count for the Function.

  5. Select custom as the Unit and input users as the Custom unit.

  6. Click Save.

All schedules table (click to expand)
  1. Click + Widget and select Table.

  2. Title the widget All Schedules.

  3. Choose the PagerDuty Schedule blueprint.

  4. Click Save to add the widget to the dashboard.

All users table (click to expand)
  1. Click + Widget and select Table.

  2. Title the widget All Users.

  3. Choose the PagerDuty User blueprint.

  4. Click Save to add the widget to the dashboard.

  5. Click on the ... button in the top right corner of the table and select Customize table.

  6. In the top right corner of the table, click on Manage Properties and add the following properties:

    • Email: User's email address.
    • Role: User's role in PagerDuty.
    • Time Zone: User's timezone.
    • Created At: When the user account was created.
  7. Click on the save icon in the top right corner of the widget to save the customized table.

On-call actions (click to expand)
  1. Click + Widget and select Action card.

  2. Select the View current on-call user, Change on-call user, and Delete schedule override workflows as the Actions.

  3. Click Save.