Skip to main content

Check out Port for yourself ➜ 

PagerDuty

Loading version...

Port's PagerDuty integration allows you to model PagerDuty resources in your software catalog and ingest data into them.

Ingesting additional resources

The resources listed above are just a subset of what the PagerDuty integration supports. You can ingest additional PagerDuty resources if they have a GET List <resource name> endpoint in the PagerDuty API documentation. This means, resources such as teams, audit records, business services, extensions, incident workflows, status dashboards, vendor etc can be ingested into Port.

Setup

Choose one of the following installation methods: Not sure which method is right for your use case? Check the available installation methods.

Configuration

Port integrations use a YAML mapping block to ingest data from the third-party api into Port.

The mapping makes use of the JQ JSON processor to select, modify, concatenate, transform and perform other operations on existing fields and values from the integration API.

Default mapping configuration

This is the default mapping configuration for this integration:

Default mapping configuration (Click to expand)
deleteDependentEntities: true
createMissingRelatedEntities: true
enableMergeEntity: true
resources:
- kind: services
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"pagerdutyService"'
properties:
status: .status
url: .html_url
oncall: .__oncall_user | sort_by(.escalation_level) | .[0].user.email
secondaryOncall: .__oncall_user | sort_by(.escalation_level) | .[1].user.email
escalationLevels: .__oncall_user | map(.escalation_level) | unique | length
meanSecondsToResolve: .__analytics.mean_seconds_to_resolve
meanSecondsToFirstAck: .__analytics.mean_seconds_to_first_ack
meanSecondsToEngage: .__analytics.mean_seconds_to_engage
- kind: incidents
selector:
query: 'true'
apiQueryParams:
include:
- assignees
- first_trigger_log_entries
statuses:
- resolved
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"pagerdutyIncident"'
properties:
status: .status
url: .html_url
urgency: .urgency
escalation_policy: .escalation_policy.summary
created_at: .created_at
updated_at: .updated_at
priority: if .priority != null then .priority.summary else null end
description: .description
triggered_by: .first_trigger_log_entry.agent.summary
relations:
pagerdutyService: .service.id
service:
combinator: '"and"'
rules:
- property: '"pagerdutyServiceId"'
operator: '"="'
value: .service.id
- kind: incidents
selector:
query: 'true'
apiQueryParams:
include:
- assignees
- first_trigger_log_entries
statuses:
- triggered
- acknowledged
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"pagerdutyIncident"'
properties:
status: .status
url: .html_url
urgency: .urgency
escalation_policy: .escalation_policy.summary
created_at: .created_at
updated_at: .updated_at
priority: if .priority != null then .priority.summary else null end
description: .description
resolvedAt: .resolved_at
recoveryTime: |-
(.created_at as $createdAt | .resolved_at as $resolvedAt | if $resolvedAt == null then null else ( ($resolvedAt | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime) -
($createdAt | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime) ) / 60 | floor end)
triggered_by: .first_trigger_log_entry.agent.summary
relations:
pagerdutyService: .service.id
incident_port_assignee:
combinator: '"and"'
rules:
- property: '"pagerduty_user_id"'
operator: '"in"'
value: .assignments | map(.assignee.id)
incident_pagerduty_assignee: .assignments | map(.assignee.id)
- kind: schedules
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"pagerdutySchedule"'
properties:
url: .html_url
timezone: .time_zone
description: .description
users: '[.users[] | select(has("__email")) | .__email]'
- kind: oncalls
selector:
query: 'true'
apiQueryParams:
include:
- users
port:
entity:
mappings:
identifier: .user.id + "-" + .schedule.id + "-" + .start
title: .user.name
blueprint: '"pagerdutyOncall"'
properties:
startDate: .start
endDate: .end
url: .schedule.html_url
relations:
pagerdutySchedule: .schedule.id
pagerdutyEscalationPolicy: .escalation_policy.id
pagerduty_user: .user.id
port_user:
combinator: '"and"'
rules:
- property: '"$identifier"'
operator: '"="'
value: .user.email
- kind: escalation_policies
selector:
query: 'true'
attachOncallUsers: true
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"pagerdutyEscalationPolicy"'
properties:
url: .html_url
summary: .summary
primaryOncall: .__oncall_users | sort_by(.escalation_level) | .[0].user.email
escalationRules: .escalation_rules
- kind: users
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id
title: .name
blueprint: '"pagerdutyUser"'
properties:
url: .html_url
time_zone: .time_zone
email: .email
description: .description
role: .role
job_title: .job_title
teams: .teams
contact_methods: .contact_methods
- kind: incidents
selector:
query: 'true'
apiQueryParams:
include:
- assignees
- first_trigger_log_entries
statuses:
- resolved
port:
entity:
mappings:
identifier: .id | tostring
blueprint: '"pagerdutyIncident"'
relations:
original_alert: .first_trigger_log_entry.channel.details.id
extrakey: if .kind == "Incident" then .children.edges[].node.identifier else null end
additionalField: .some.new.field.value
- kind: incidents
selector:
query: 'true'
apiQueryParams:
include:
- assignees
- first_trigger_log_entries
statuses:
- triggered
- acknowledged
inducer:
- assignees
- first_trigger_log_entries
port:
entity:
mappings:
identifier: .id | tostring
blueprint: '"pagerdutyIncident"'
relations:
original_alert: .first_trigger_log_entry.channel.details.id
extrakey: if .kind == "Incident" then .children.edges[].node.identifier else null end

Mapping & examples per resource

Use the explorer below to view sample payloads and the resulting Port entities for each resource type.

Monitoring and sync status

To learn more about how to monitor and check the sync status of your integration, see the relevant documentation.

Capabilities

Ingesting service analytics

To enrich your PagerDuty service entities with analytics data, follow the steps below:

  1. Update the service blueprint to include analytics properties. You can add any property that is returned from the PagerDuty aggregated service analytics API

    Updated service blueprint (click to expand)
    {
    "identifier":"pagerdutyService",
    "description":"This blueprint represents a PagerDuty service in our software catalog",
    "title":"PagerDuty Service",
    "icon":"pagerduty",
    "schema":{
    "properties":{
    "status":{
    "title":"Status",
    "type":"string"
    },
    "url":{
    "title":"URL",
    "type":"string",
    "format":"url"
    },
    "oncall":{
    "title":"On Call",
    "type":"array",
    "items":{
    "type":"string",
    "format":"user"
    }
    },
    "meanSecondsToResolve":{
    "title":"Mean Seconds to Resolve",
    "type":"number"
    },
    "meanSecondsToFirstAck":{
    "title":"Mean Seconds to First Acknowledge",
    "type":"number"
    },
    "meanSecondsToEngage":{
    "title":"Mean Seconds to Engage",
    "type":"number"
    },
    "totalIncidentCount":{
    "title":"Total Incident Count",
    "type":"number"
    },
    "totalIncidentsAcknowledged":{
    "title":"Total Incidents Acknowledged",
    "type":"number"
    },
    "totalIncidentsAutoResolved":{
    "title":"Total Incidents Auto Resolved",
    "type":"number"
    },
    "totalIncidentsManualEscalated":{
    "title":"Total Incident Manual Escalated",
    "type":"number"
    }
    },
    "required":[]
    },
    "mirrorProperties":{},
    "calculationProperties":{},
    "relations":{}
    }
  2. Add serviceAnalytics property to the integration selector key. When set to true, the integration will fetch data from the PagerDuty aggregated service analytics API and ingest it to Port. By default, this property is set to true.

    Also, by default, the integration aggregates the analytics over a period of 3 months. Use the analyticsMonthsPeriod filter to override this date range. The accepted values are positive number between 1 to 12. In the provided example below, we aggregate the analytics over the past 6 months.

    resources:
    - kind: services
    selector:
    query: "true"
    serviceAnalytics: "true"
    analyticsMonthsPeriod: 6
    port:
    entity:
    mappings:
    identifier: .id
    title: .name
    blueprint: '"pagerdutyService"'
    properties:
    status: .status
    url: .html_url
    oncall: .__oncall_user | sort_by(.escalation_level) | .[0].user.email
    secondaryOncall: .__oncall_user | sort_by(.escalation_level) | .[1].user.email
  3. Establish a mapping between the analytics properties and the service analytics data response. Following a convention, the aggregated result of the PagerDuty service analytics API is saved to the __analytics key and merged with the response of the service API. Consequently, users can access specific metrics such as the mean seconds to resolve by referencing __analytics.mean_seconds_to_resolve.

    resources:
    - kind: services
    selector:
    query: "true"
    serviceAnalytics: "true"
    analyticsMonthsPeriod: 6
    port:
    entity:
    mappings:
    identifier: .id
    title: .name
    blueprint: '"pagerdutyService"'
    properties:
    status: .status
    url: .html_url
    oncall: .__oncall_user | sort_by(.escalation_level) | .[0].user.email
    secondaryOncall: .__oncall_user | sort_by(.escalation_level) | .[1].user.email
    meanSecondsToResolve: .__analytics.mean_seconds_to_resolve
  4. Below is the complete integration configuration for enriching the service blueprint with analytics data.

    Service analytics integration configuration (click to expand)
    resources:
    - kind: services
    selector:
    query: "true"
    serviceAnalytics: "true"
    analyticsMonthsPeriod: 6
    port:
    entity:
    mappings:
    identifier: .id
    title: .name
    blueprint: '"pagerdutyService"'
    properties:
    status: .status
    url: .html_url
    oncall: .__oncall_user | sort_by(.escalation_level) | .[0].user.email
    secondaryOncall: .__oncall_user | sort_by(.escalation_level) | .[1].user.email
    meanSecondsToResolve: .__analytics.mean_seconds_to_resolve
    meanSecondsToFirstAck: .__analytics.mean_seconds_to_first_ack
    meanSecondsToEngage: .__analytics.mean_seconds_to_engage
    totalIncidentCount: .__analytics.total_incident_count
    totalIncidentsAcknowledged: .__analytics.total_incidents_acknowledged
    totalIncidentsAutoResolved: .__analytics.total_incidents_auto_resolved
    totalIncidentsManualEscalated: .__analytics.total_incidents_manual_escalated

Ingesting incident analytics

To enrich your PagerDuty incident entities with analytics data, follow the steps below:

  1. Update the incident blueprint to include an analytics property.

    Updated incident blueprint (click to expand)
    {
    "identifier": "pagerdutyIncident",
    "description": "This blueprint represents a PagerDuty incident in our software catalog",
    "title": "PagerDuty Incident",
    "icon": "pagerduty",
    "schema": {
    "properties": {
    "status": {
    "type": "string",
    "title": "Incident Status",
    "enum": [
    "triggered",
    "annotated",
    "acknowledged",
    "reassigned",
    "escalated",
    "reopened",
    "resolved"
    ],
    "enumColors": {
    "triggered": "red",
    "annotated": "blue",
    "acknowledged": "yellow",
    "reassigned": "blue",
    "escalated": "yellow",
    "reopened": "red",
    "resolved": "green"
    }
    },
    "url": {
    "type": "string",
    "format": "url",
    "title": "Incident URL"
    },
    "urgency": {
    "title": "Incident Urgency",
    "type": "string",
    "enum": [
    "high",
    "low"
    ],
    "enumColors": {
    "high": "red",
    "low": "green"
    }
    },
    "priority": {
    "type": "string",
    "title": "Priority",
    "enum": [
    "P1",
    "P2",
    "P3",
    "P4",
    "P5"
    ],
    "enumColors": {
    "P1": "red",
    "P2": "yellow",
    "P3": "blue",
    "P4": "lightGray",
    "P5": "darkGray"
    }
    },
    "description": {
    "type": "string",
    "title": "Description"
    },
    "assignees": {
    "title": "Assignees",
    "type": "array",
    "items": {
    "type": "string",
    "format": "user"
    }
    },
    "escalation_policy": {
    "type": "string",
    "title": "Escalation Policy"
    },
    "created_at": {
    "title": "Create At",
    "type": "string",
    "format": "date-time"
    },
    "updated_at": {
    "title": "Updated At",
    "type": "string",
    "format": "date-time"
    },
    "analytics": {
    "title": "Analytics",
    "type": "object"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "relations": {
    "pagerdutyService": {
    "title": "PagerDuty Service",
    "target": "pagerdutyService",
    "required": false,
    "many": true
    }
    }
    }
  2. Add incidentAnalytics property to the integration selector key. When set to true, the integration will fetch data from the PagerDuty Analytics API and ingest it to Port. By default, this property is set to false.

    resources:
    - kind: incidents
    selector:
    query: "true"
    incidentAnalytics: "true"
    port:
    entity:
    mappings:
    identifier: .id | tostring
    title: .title
    blueprint: '"pagerdutyIncident"'
    properties:
    status: .status
    url: .self
  3. Establish a mapping between the analytics blueprint property and the analytics data response.

    resources:
    - kind: incidents
    selector:
    query: 'true'
    include: ['assignees']
    port:
    entity:
    mappings:
    identifier: .id | tostring
    title: .title
    blueprint: '"pagerdutyIncident"'
    properties:
    status: .status
    url: .self
    urgency: .urgency
    assignees: .assignments | map(.assignee.email)
    escalation_policy: .escalation_policy.summary
    created_at: .created_at
    updated_at: .updated_at
    priority: if .priority != null then .priority.summary else null end
    description: .description
    analytics: .__analytics
    relations:
    pagerdutyService: .service.id
  4. Below is the complete integration configuration for enriching the incident blueprint with analytics data.

    Incident analytics integration configuration (click to expand)
    resources:
    - kind: incidents
    selector:
    query: 'true'
    include: ['assignees']
    port:
    entity:
    mappings:
    identifier: .id | tostring
    title: .title
    blueprint: '"pagerdutyIncident"'
    properties:
    status: .status
    url: .self
    urgency: .urgency
    assignees: .assignments | map(.assignee.email)
    escalation_policy: .escalation_policy.summary
    created_at: .created_at
    updated_at: .updated_at
    priority: if .priority != null then .priority.summary else null end
    description: .description
    analytics: .__analytics
    relations:
    pagerdutyService: .service.id

Ingesting service custom fields

To enrich your PagerDuty service entities with custom fields data, follow the steps below:

  1. Update the service blueprint to include properties for the custom fields you want to ingest. When enabled, the integration fetches the custom field values for each service and stores them under the __custom_fields key. Each custom field in the array has the following structure:

    {
    "id": "FIELD_ID",
    "name": "my_custom_field",
    "display_name": "My Custom Field",
    "data_type": "string",
    "field_type": "single_value",
    "type": "field_value",
    "value": {
    "value": "field value here"
    }
    }

    You can extract specific custom field values into individual blueprint properties using jq.
    For example, if you have custom fields named team and environment in PagerDuty:

    Updated service blueprint (click to expand)
    {
    "identifier":"pagerdutyService",
    "description":"This blueprint represents a PagerDuty service in our software catalog",
    "title":"PagerDuty Service",
    "icon":"pagerduty",
    "schema":{
    "properties":{
    "status":{
    "title":"Status",
    "type":"string"
    },
    "url":{
    "title":"URL",
    "type":"string",
    "format":"url"
    },
    "oncall":{
    "title":"On Call",
    "type":"array",
    "items":{
    "type":"string",
    "format":"user"
    }
    },
    "team":{
    "title":"Team",
    "type":"string"
    },
    "environment":{
    "title":"Environment",
    "type":"string"
    }
    },
    "required":[]
    },
    "mirrorProperties":{},
    "calculationProperties":{},
    "relations":{}
    }
  2. Add includeCustomFields to the selector key and map specific custom field values using jq. When set to true, the integration fetches custom field values for each service. By default, this property is set to false. Use jq expressions to extract specific fields by their name, for example: (.__custom_fields[] | select(.name == "team")).value.

    resources:
    - kind: services
    selector:
    query: "true"
    includeCustomFields: "true"
    port:
    entity:
    mappings:
    identifier: .id
    title: .name
    blueprint: '"pagerdutyService"'
    properties:
    status: .status
    url: .html_url
    oncall: .__oncall_user | sort_by(.escalation_level) | .[0].user.email
    secondaryOncall: .__oncall_user | sort_by(.escalation_level) | .[1].user.email
    team: (.__custom_fields[] | select(.name == "team")).value
    environment: (.__custom_fields[] | select(.name == "environment")).value

Ingesting incident custom fields

To enrich your PagerDuty incident entities with custom fields data, follow the steps below:

  1. Update the incident blueprint to include properties for the custom fields you want to ingest. The __custom_fields array has the same structure as described in the service custom fields section above. For example, if you have custom fields named severity and affected_region in PagerDuty:

    Updated incident blueprint (click to expand)
    {
    "identifier": "pagerdutyIncident",
    "description": "This blueprint represents a PagerDuty incident in our software catalog",
    "title": "PagerDuty Incident",
    "icon": "pagerduty",
    "schema": {
    "properties": {
    "status": {
    "type": "string",
    "title": "Incident Status",
    "enum": [
    "triggered",
    "annotated",
    "acknowledged",
    "reassigned",
    "escalated",
    "reopened",
    "resolved"
    ],
    "enumColors": {
    "triggered": "red",
    "annotated": "blue",
    "acknowledged": "yellow",
    "reassigned": "blue",
    "escalated": "yellow",
    "reopened": "red",
    "resolved": "green"
    }
    },
    "url": {
    "type": "string",
    "format": "url",
    "title": "Incident URL"
    },
    "urgency": {
    "title": "Incident Urgency",
    "type": "string",
    "enum": [
    "high",
    "low"
    ],
    "enumColors": {
    "high": "red",
    "low": "green"
    }
    },
    "priority": {
    "type": "string",
    "title": "Priority",
    "enum": [
    "P1",
    "P2",
    "P3",
    "P4",
    "P5"
    ],
    "enumColors": {
    "P1": "red",
    "P2": "yellow",
    "P3": "blue",
    "P4": "lightGray",
    "P5": "darkGray"
    }
    },
    "description": {
    "type": "string",
    "title": "Description"
    },
    "assignees": {
    "title": "Assignees",
    "type": "array",
    "items": {
    "type": "string",
    "format": "user"
    }
    },
    "escalation_policy": {
    "type": "string",
    "title": "Escalation Policy"
    },
    "created_at": {
    "title": "Create At",
    "type": "string",
    "format": "date-time"
    },
    "updated_at": {
    "title": "Updated At",
    "type": "string",
    "format": "date-time"
    },
    "severity":{
    "title": "Severity",
    "type": "string"
    },
    "affectedRegion":{
    "title": "Affected Region",
    "type": "string"
    }
    },
    "required": []
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "relations": {
    "pagerdutyService": {
    "title": "PagerDuty Service",
    "target": "pagerdutyService",
    "required": false,
    "many": true
    }
    }
    }
  2. Add includeCustomFields to the selector key and map specific custom field values using jq. When set to true, the integration fetches custom field values from the PagerDuty Custom Fields API for each incident. By default, this property is set to false. Extract specific fields the same way as in the service example above.

    resources:
    - kind: incidents
    selector:
    query: 'true'
    include: ['assignees']
    includeCustomFields: 'true'
    port:
    entity:
    mappings:
    identifier: .id | tostring
    title: .title
    blueprint: '"pagerdutyIncident"'
    properties:
    status: .status
    url: .self
    urgency: .urgency
    assignees: .assignments | map(.assignee.email)
    escalation_policy: .escalation_policy.summary
    created_at: .created_at
    updated_at: .updated_at
    priority: if .priority != null then .priority.summary else null end
    description: .description
    severity: (.__custom_fields[] | select(.name == "severity")).value
    affectedRegion: (.__custom_fields[] | select(.name == "affected_region")).value
    relations:
    pagerdutyService: .service.id

Examples

To view and test the integration's mapping against examples of the third-party API responses, use the jq playground in your data sources page. Find the integration in the list of data sources and click on it to open the playground.

Additional examples of blueprints and the relevant integration configurations can be found on the pagerduty examples page

Relevant guides

For relevant guides and examples, see the guides section.

Limitations

  • The PagerDuty API uses offset-based pagination, which has a limitation of retrieving a maximum of 10,000 resources. This may affect the integration's ability to sync data if you have more than 10,000 of a specific resource type (e.g., users, services, etc.). Refer to PagerDuty's official documentation on pagination for further details.

Support

For any questions or issues, contact us at support.port.io or via our Community Slack channel.