PagerDuty
Port's PagerDuty integration allows you to model PagerDuty resources in your software catalog and ingest data into them.
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:
-
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":{}
} -
Add
serviceAnalyticsproperty to the integrationselectorkey. When set totrue, the integration will fetch data from the PagerDuty aggregated service analytics API and ingest it to Port. By default, this property is set totrue.Also, by default, the integration aggregates the analytics over a period of 3 months. Use the
analyticsMonthsPeriodfilter 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 -
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
__analyticskey 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 -
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:
-
Update the incident blueprint to include an
analyticsproperty.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
}
}
} -
Add
incidentAnalyticsproperty to the integrationselectorkey. When set totrue, the integration will fetch data from the PagerDuty Analytics API and ingest it to Port. By default, this property is set tofalse.resources:
- kind: incidents
selector:
query: "true"
incidentAnalytics: "true"
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"pagerdutyIncident"'
properties:
status: .status
url: .self -
Establish a mapping between the
analyticsblueprint 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 -
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:
-
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_fieldskey. 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 namedteamandenvironmentin 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":{}
} -
Add
includeCustomFieldsto theselectorkey and map specific custom field values using jq. When set totrue, the integration fetches custom field values for each service. By default, this property is set tofalse. Use jq expressions to extract specific fields by theirname, 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:
-
Update the incident blueprint to include properties for the custom fields you want to ingest. The
__custom_fieldsarray has the same structure as described in the service custom fields section above. For example, if you have custom fields namedseverityandaffected_regionin 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
}
}
} -
Add
includeCustomFieldsto theselectorkey and map specific custom field values using jq. When set totrue, the integration fetches custom field values from the PagerDuty Custom Fields API for each incident. By default, this property is set tofalse. 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.