Details
| ID | PagerDuty v2 |
|---|---|
| Provider | PagerDuty |
| Category | Messaging and Conferencing |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix Cloud Runtime Security Cloud Posture Security XSIAM EDR Cortex Cloud |
README
Use the PagerDuty integration to manage schedules and on-call users.
This integration was integrated and tested with PagerDuty API v2.
Configure PagerDuty v2 on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for PagerDuty v2.
-
Click Add instance to create and configure a new integration instance.
Parameter Description Required API Key False Service Key (for triggering, acknowledging and resolving events only) False Trust any certificate (not secure) False Use system proxy settings False Fetch incidents False Incident type False Initial Fetch Interval (In minutes, used only for first fetch or after Reset last run) False Default requestor ID for adding people to incidents False Maximum number of incidents per fetch The maximum number of incidents to retrieve per fetch cycle. Hard upper limit is 200. False Incident statuses to fetch The statuses of PagerDuty incidents to ingest. Include “resolved” to capture short-lived incidents. False - Click Test to validate the URLs, token, and connection.
Fetched Incidents Data
By default, the integration will import PagerDuty incidents data as Cortex XSOAR incidents. All incidents created in the minute prior to the configuration of Fetch Incidents and up to current time will be imported.
Commands
You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
- Get all schedules: PagerDuty-get-all-schedules
- Get information for on-call users by time or schedule: PagerDuty-get-users-on-call
- Get information for current on-call users: PagerDuty-get-users-on-call-now
- Get incidents: PagerDuty-incidents
- Create a new event/incident: PagerDuty-submit-event
- Get the contact methods of a user: PagerDuty-get-contact-methods
- Get a user’s notification rules: PagerDuty-get-users-notification
- Resolve an event: PagerDuty-resolve-event
- Acknowledge an event: PagerDuty-acknowledge-event
- Get incident information: PagerDuty-get-incident-data
- Get service keys for each configured service: PagerDuty-get-service-keys
- Add responder to an incident: PagerDuty-add-responders
- Run response play to an incident: PagerDuty-run-response-play
PagerDuty-get-all-schedules
Receive all schedules from PagerDuty.
Base Command
PagerDuty-get-all-schedules
Input
| Argument Name | Description | Required |
|---|---|---|
| query | Show only the schedules whose name matches the query. | Optional |
| limit | The limit for the amount of schedules to receive(Default is 25, max value is 100). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Schedules.id | string | The ID of the schedule. |
| PagerDuty.Schedules.name | string | The name of the schedule. |
Command Example
#### Context Example
```json
{
"PagerDuty": {
"Schedules": [
{
"escalation_policies": [
{
"id": "someid",
"name": "Default"
}
],
"id": "scheduleid",
"name": "New Schedule #1",
"time_zone": "America/Los_Angeles",
"today": "2021-03-10"
},
{
"escalation_policies": [
{
"id": "anotherid",
"name": "test policy"
}
],
"id": "anotherscheduleid",
"name": "New Schedule #2",
"time_zone": "Europe/Athens",
"today": "2021-03-10"
}
]
}
}
Human Readable Output
All Schedules
ID Name Today Time Zone Escalation Policy Escalation Policy ID scheduleid New Schedule #1 2021-03-10 America/Los_Angeles Default someid anotherscheduleid New Schedule #2 2021-03-10 Europe/Athens test policy anotherid
PagerDuty-get-users-on-call
Returns the names and details of on call users at a certain time or by specific schedule.
Base Command
PagerDuty-get-users-on-call
Input
| Argument Name | Description | Required |
|---|---|---|
| scheduleID | (default and mandatory) The unique identifier of the schedule. | Required |
| since | The start of the date range Using ISO 8601 Representation. Maximum range is 6 months and default is 1 month. E.g. !PagerDutyGetUsersOnCall since=2011-05-06T17:00Z. | Optional |
| until | The end of the date range. Maximum range is 6 months and default is 1 month. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDutyUser.id | string | User’s ID. |
| PagerDutyUser.Emails | string | Email of user. |
| PagerDutyUser.Username | string | Username of person. |
| PagerDutyUser.DisplayName | string | Display name of person. |
| PagerDutyUser.Role | string | Display role of person. |
| PagerDutyUser.TimeZone | string | The time zone of the user. |
Command Example
!PagerDuty-get-users-on-call scheduleID=scheduleid
Context Example
{
"PagerDutyUser": [
{
"DisplayName": "Demisto User",
"Email": "demisto@demisto.com",
"ID": "someid",
"Role": "owner",
"TimeZone": "Europe/Athens",
"Username": "Demisto User"
},
{
"DisplayName": "Another User",
"Email": "demisto@gmail.com",
"ID": "anotherid",
"Role": "user",
"TimeZone": "Europe/Athens",
"Username": "Another User"
}
]
}
Human Readable Output
Users On Call
ID Name Role User Url Time Zone someid demisto@demisto.com Demisto User owner https://demisto.pagerduty.com/users/someid Europe/Athens anotherid demisto@mail.com Another User user https://demisto.pagerduty.com/users/anotherid Europe/Athens
PagerDuty-get-users-on-call-now
Returns the names and details of current on call personnel.
Base Command
PagerDuty-get-users-on-call-now
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The limit for the amount of users to receive(Default is 25, max value is 100). | Optional |
| escalation_policy_ids | Filters the results, showing only on-call users for the specified escalation policy IDs. | Optional |
| schedule_ids | Filters the results, showing only on-call users for the specified schedule IDs. If the value is null, permanent on-call user are included due to direct user escalation policy targets. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDutyUser.ID | string | User’s ID. |
| PagerDutyUser.Email | string | Email of user. |
| PagerDutyUser.Username | string | Username of person. |
| PagerDutyUser.DisplayName | string | Display name of person. |
| PagerDutyUser.Role | string | Role of person. |
| PagerDutyUser.TimeZone | string | The time zone of the user. |
Command Example
#### Context Example
```json
{
"PagerDutyUser": [
{
"DisplayName": "Demisto User",
"Email": "demisto@demisto.com",
"ID": "someid",
"Role": "owner",
"TimeZone": "Europe/Athens",
"Username": "Demisto User"
}
]
}
Human Readable Output
Users On Call Now
ID Name Role User Url Time Zone someid demisto@demisto.com Demisto User owner https://demisto.pagerduty.com/users/someid Europe/Athens
PagerDuty-incidents
Shows incidents in PagerDuty. Default status parameters are triggered,acknowledged.
Base Command
PagerDuty-incidents
Input
| Argument Name | Description | Required |
|---|---|---|
| status | Returns only the incidents currently in the passed status(es). Valid status options are triggered,acknowledged, and resolved. (Default values are triggered,acknowledged). Possible values are: triggered, acknowledged, resolved. | Optional |
| since | Beginning date and time. Using ISO 8601 Representation. E.g. PagerDutyIncidents since=2011-05-06T17:00Z (must be used with until argument). | Optional |
| sortBy | Used to specify both the field you wish to sort the results on, as well as the direction (ascending/descending) of the results.See more https://v2.developer.pagerduty.com/v2/page/api-reference#!/Incidents/get_incidents. | Optional |
| until | Last date and time. Using ISO 8601 Representation. E.g. PagerDutyIncidents until=2016-05-06T13:00Z. | Optional |
| incident_key | Incident de-duplication key. E.g., 8e42eeb6391a4a2abeda5d12e09bddec. | Optional |
| limit | The maximum number of incidents to retrieve. If “page_size” is defined, this argument is ignored. Default is 50. | Optional |
| user_id | Comma separated list of User IDs. Returns only the incidents currently assigned to the passed user(s). Note: When using the assigned_to_user filter, you will only receive incidents with statuses of triggered or acknowledged. This is because resolved incidents are not assigned to any user. | Optional |
| urgencies | Array of the urgencies of the incidents to be returned. Defaults to all urgencies. Account must have the urgencies ability to do this. Possible values are: high, low. | Optional |
| date_range | When set to all, the since and until parameters and defaults are ignored. Possible values are: all. | Optional |
| page | The page number of incidents to retrieve (used for pagination) starting from 1. The page size is defined by the “page_size” argument. | Optional |
| page_size | The number of incidents per page to retrieve (used for pagination). The page number is defined by the “page” argument. The maximum value is 100. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Incidents.ID | string | Incident ID. |
| PagerDuty.Incidents.Title | string | The title of the incident. |
| PagerDuty.Incidents.Status | string | Incident Status. |
| PagerDuty.Incidents.created_at | date | Time in which the incident was created. |
| PagerDuty.Incidents.urgency | string | Incident Urgency. |
| PagerDuty.Incidents.assignee | string | The assignee of the incident. |
| PagerDuty.Incidents.service_id | string | The id of the impacted service. |
| PagerDuty.Incidents.service_name | string | The name of the impacted service. |
| PagerDuty.Incidents.escalation_policy | string | The escalation policy. |
| PagerDuty.Incidents.last_status_change_at | date | Time in which the last status change occurred. |
| PagerDuty.Incidents.last_status_change_by | string | Name of the user who done the last status change. |
| PagerDuty.Incidents.number_of_escalations | number | Number of escalations that took place. |
| PagerDuty.Incidents.resolved_by | string | Name of the User who resolved the incident. |
| PagerDuty.Incidents.resolve_reason | string | The reason for resolving the issue. |
| PagerDuty.Incidents.Description | string | The Description of the incident. |
| PagerDuty.Incidents.teams.ID | string | The ID of the team assigned for the incident. |
| PagerDuty.Incidents.teams.ID | string | The name of the team assigned for the incident. |
| PagerDuty.Incidents.assignment.time | date | The time of the assignment to the incident. |
| PagerDuty.Incidents.assignment.assignee | string | The name of the assignee to the incident. |
| PagerDuty.Incidents.assignment.assigneeId | string | The ID of the assignee to the incident. |
| PagerDuty.Incidents.acknowledgement.time | date | The time of the acknowledgement to the incident. |
| PagerDuty.Incidents.acknowledgement.acknowledger | string | The name of the acknowledger to the incident. |
| PagerDuty.Incidents.acknowledgement.acknowledgerId | string | The ID of the acknowledger to the incident. |
| PagerDuty.Incidents.incident_key | String | The incident’s de-duplication key. |
Command Example
#### Context Example
```json
{
"PagerDuty": {
"Incidents": [
{
"Description": {
"description": "No description"
},
"ID": "someid",
"Status": "acknowledged",
"Title": "[#264] Ticket 01439490",
"acknowledgement": {
"acknowledger": "someone",
"acknowledgerId": "ABC123",
"time": "2021-03-04T08:53:04Z"
},
"assignee": "someone",
"assignment": {
"assignee": "someone",
"assigneeId": "ABC123",
"time": "2021-03-04T08:53:04Z"
},
"created_at": "2021-03-04T08:52:56Z",
"escalation_policy": "Default",
"incident_key": null,
"last_status_change_at": "2021-03-04T08:53:04Z",
"last_status_change_by": "someone",
"number_of_escalations": null,
"resolve_reason": "",
"resolved_by": "someone",
"service_id": "P5CX6RZ",
"service_name": "PD SF",
"teams": [],
"urgency": "high"
},
{
"Description": {
"description": "No description"
},
"ID": "anotherid",
"Status": "triggered",
"Title": "[#278] my event",
"acknowledgement": {},
"assignee": "someone-else",
"assignment": {
"assignee": "someone-else",
"assigneeId": "ABC123",
"time": "2021-03-10T08:37:17Z"
},
"created_at": "2021-03-10T07:57:16Z",
"escalation_policy": "Default",
"incident_key": "somekey",
"last_status_change_at": "2021-03-10T08:37:17Z",
"last_status_change_by": "API Service",
"number_of_escalations": null,
"resolve_reason": "",
"resolved_by": "someone-else",
"service_id": "someid",
"service_name": "API Service",
"teams": [],
"urgency": "high"
}
]
}
}
Human Readable Output
PagerDuty Incidents
ID Title Description Status Created On Urgency Html Url Incident key Assigned To User Service ID Service Name Escalation Policy Last Status Change On Last Status Change By Resolved By User someid [#264] Ticket 01439490 description: No description acknowledged 2021-03-04T08:52:56Z high https://demisto.pagerduty.com/incidents/someid someone P5CX6RZ PD SF Default 2021-03-04T08:53:04Z someone - anotherid [#278] my event description: No description triggered 2021-03-10T07:57:16Z high https://demisto.pagerduty.com/incidents/anotherid somekey someone-else someid API Service Default 2021-03-10T08:37:17Z API Service -
PagerDuty-submit-event
Creates a new event/incident in PagerDuty(In order to use this command you have to enter the Service Key in the integration settings).
Base Command
PagerDuty-submit-event
Input
| Argument Name | Description | Required |
|---|---|---|
| source | Specific human-readable unique identifier, such as a hostname, for the system having the problem. | Required |
| summary | A high-level, text summary message of the event. Will be used to construct an alert’s description. | Required |
| severity | The severity of the event. Possible values are: critical, error, warning, info. | Required |
| action | The action to be executed. Possible values are: trigger, acknowledge, resolve. | Required |
| description | A short description of the problem. | Optional |
| group | A cluster or grouping of sources. For example, sources “prod-datapipe-02” and “prod-datapipe-03” might both be part of “prod-datapipe”. Example: “prod-datapipe” “www”. | Optional |
| event_class | The class/type of the event. Example: “High CPU” “Latency”. | Optional |
| component | The part or component of the affected system that is broken. Example: “keepalive” “webping”. | Optional |
| incident_key | Incident key, used to acknowledge/resolve specific event. | Optional |
| serviceKey | Service key for the integration. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Event.Status | string | Status of the action on the event. |
| PagerDuty.Event.incident_key | string | Incident key. |
Command Example
!PagerDuty-submit-event action=trigger severity=info source=demisto summary="my new event"
Human Readable Output
Incident key Message Status somekey Event processed success
PagerDuty-get-contact-methods
Get the contact methods of a given user.
Base Command
PagerDuty-get-contact-methods
Input
| Argument Name | Description | Required |
|---|---|---|
| UserID | ID of the wanted user. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Contact_methods.phone | string | The phone number of the user. |
| PagerDuty.Contact_methods.id | string | ID of the contact method. |
| PagerDuty.Contact_methods.type | string | The type of the current contact method. |
| PagerDuty.Contact_methods.email | string | The email of the user. |
Command Example
!PagerDuty-get-contact-methods UserID=someid
Context Example
{
"PagerDuty": {
"Contact_methods": [
{
"email": "demisto@demisto.com",
"html_url": null,
"id": "someotherid",
"label": "Default",
"self": "https://api.pagerduty.com/users/someid/contact_methods/someotherid",
"send_html_email": false,
"send_short_email": false,
"summary": "Default",
"type": "email_contact_method"
},
{
"blacklisted": false,
"html_url": null,
"id": "someid",
"label": "Mobile",
"phone": "000000",
"self": "https://api.pagerduty.com/users/someid/contact_methods/someid",
"summary": "Mobile",
"type": "phone_contact_method"
},
{
"blacklisted": false,
"enabled": true,
"html_url": null,
"id": "onemoreid",
"label": "Mobile",
"phone": "0000000",
"self": "https://api.pagerduty.com/users/someid/contact_methods/onemoreid",
"summary": "Mobile",
"type": "sms_contact_method"
}
]
}
}
Human Readable Output
Contact Methods
ID Type Details someotherid demisto@demisto.com someid Phone 0000000 onemoreid SMS 000000
PagerDuty-get-users-notification
Get the users notification rules.
Base Command
PagerDuty-get-users-notification
Input
| Argument Name | Description | Required |
|---|---|---|
| UserID | ID of the wanted user. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Notification_rules.start_delay_in_minutes | string | The delay time for notifying the user. |
| PagerDuty.Notification_rules.urgency | string | The urgency of the notification. |
| PagerDuty.Notification_rules.id | string | The id of the notification rule. |
Command Example
!PagerDuty-get-users-notification UserID=someid
Context Example
{
"PagerDuty": {
"Notification_rules": {
"contact_method": {
"address": "demisto@demisto.com",
"html_url": null,
"id": "someotherid",
"label": "Default",
"self": "https://api.pagerduty.com/users/someid/contact_methods/someotherid",
"send_html_email": false,
"send_short_email": false,
"summary": "Default",
"type": "email_contact_method"
},
"html_url": null,
"id": "someid",
"self": "https://api.pagerduty.com/users/someid/notification_rules/someid",
"start_delay_in_minutes": 0,
"summary": "0 minutes: channel someotherid",
"type": "assignment_notification_rule",
"urgency": "high"
}
}
}
Human Readable Output
User notification rules
ID Type Urgency Notification timeout(minutes) someid assignment_notification_rule high 0
PagerDuty-resolve-event
Resolves an existing event in PagerDuty.
Base Command
PagerDuty-resolve-event
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_key | Incident key. | Required |
| serviceKey | Service key for the integration. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Event.Status | string | Status of the action on the event. |
| PagerDuty.Event.incident_key | string | Incident key. |
Command Example
!PagerDuty-resolve-event incident_key=somekey serviceKey=servicekey
Context Example
{
"Event": {
"ID": "somekey"
},
"PagerDuty": {
"Event": {
"Message": "Event processed",
"Status": "success",
"incident_key": "somekey"
}
}
}
Human Readable Output
Resolve Event
Incident key Message Status somekey Event processed success
PagerDuty-acknowledge-event
Acknowledges an existing event in PagerDuty.
Base Command
PagerDuty-acknowledge-event
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_key | Incident key. | Required |
| serviceKey | Service key for the integration. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Event.Status | string | Status of the action on the event. |
| PagerDuty.Event.incident_key | string | Incident key. |
Command Example
!PagerDuty-acknowledge-event incident_key=somekey serviceKey=servicekey
Context Example
{
"Event": {
"ID": "8e42eeb6391a4a2abeda5d12e09bddec"
},
"PagerDuty": {
"Event": {
"Message": "Event processed",
"Status": "success",
"incident_key": "somekey"
}
}
}
Human Readable Output
Acknowledge Event
Incident key Message Status somekey Event processed success
PagerDuty-get-incident-data
Get data about a incident from PagerDuty.
Base Command
PagerDuty-get-incident-data
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | ID of the incident to get information for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Incidents.ID | string | Incident ID. |
| PagerDuty.Incidents.Title | string | The title of the incident. |
| PagerDuty.Incidents.Status | string | Incident Status. |
| PagerDuty.Incidents.created_at | date | Time in which the incident was created. |
| PagerDuty.Incidents.urgency | string | Incident Urgency. |
| PagerDuty.Incidents.assignee | string | The assignee of the incident. |
| PagerDuty.Incidents.service_id | string | The id of the impacted service. |
| PagerDuty.Incidents.service_name | string | The name of the impacted service. |
| PagerDuty.Incidents.escalation_policy | string | The escalation policy. |
| PagerDuty.Incidents.last_status_change_at | date | Time in which the last status change occurred. |
| PagerDuty.Incidents.last_status_change_by | string | Name of the user who done the last status change. |
| PagerDuty.Incidents.number_of_escalations | number | Number of escalations that took place. |
| PagerDuty.Incidents.resolved_by | string | Name of the User who resolved the incident. |
| PagerDuty.Incidents.resolve_reason | string | The reason for resolving the issue. |
| PagerDuty.Incidents.Description | string | The Description of the incident. |
| PagerDuty.Incidents.teams.ID | string | The ID of the team assigned for the incident. |
| PagerDuty.Incidents.teams.ID | string | The name of the team assigned for the incident. |
| PagerDuty.Incidents.assignment.time | date | The time of the assignment to the incident. |
| PagerDuty.Incidents.assignment.assignee | string | The name of the assignee to the incident. |
| PagerDuty.Incidents.assignment.assigneeId | string | The ID of the assignee to the incident. |
| PagerDuty.Incidents.acknowledgement.time | date | The time of the acknowledgement to the incident. |
| PagerDuty.Incidents.acknowledgement.acknowledger | string | The name of the acknowledger to the incident. |
| PagerDuty.Incidents.acknowledgement.acknowledgerId | string | The ID of the acknowledger to the incident. |
| PagerDuty.Incidents.incident_key | String | The incident’s de-duplication key. |
Command Example
!PagerDuty-get-incident-data incident_id=someid
Context Example
{
"PagerDuty": {
"Incidents": {
"Description": "",
"ID": "someid",
"Status": "acknowledged",
"Title": "[#281] my new event",
"acknowledgement": {
"acknowledgerId": "ABC123",
"acknowledger": "someone",
"time": "2021-03-10T09:31:48Z"
},
"assignee": null,
"assignment": {
"assignee": "someone",
"assigneeId": "ABC123",
"time": "2021-03-10T09:31:48Z"
},
"created_at": "2021-03-10T09:31:48Z",
"escalation_policy": "Default",
"incident_key": "somekey",
"last_status_change_at": "2021-03-10T10:00:50Z",
"last_status_change_by": "API Service",
"number_of_escalations": null,
"resolve_reason": "",
"resolved_by": null,
"service_id": "someid",
"service_name": "API Service",
"teams": [],
"urgency": "high"
}
}
}
Human Readable Output
PagerDuty Incident
ID Title Status Created On Urgency Html Url Incident key Service ID Service Name Escalation Policy Last Status Change On Last Status Change By Resolved By User someid [#281] my new event acknowledged 2021-03-10T09:31:48Z high https://demisto.pagerduty.com/incidents/someid 8e42eeb6391a4a2abeda5d12e09bddec someid API Service Default 2021-03-10T10:00:50Z API Service -
PagerDuty-get-service-keys
Get Service keys for each of the services configured in the PagerDuty instance.
Base Command
PagerDuty-get-service-keys
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.Service.ID | string | The ID of the service connected to PagerDuty. |
| PagerDuty.Service.Name | string | The name of the service connected to PagerDuty. |
| PagerDuty.Service.Status | string | The status of the service connected to PagerDuty. |
| PagerDuty.Service.CreatedAt | date | The date in which the service connected to PagerDuty was created. |
| PagerDuty.Service.Integration.Name | string | The name of the integration used with the service. |
| PagerDuty.Service.Integration.Vendor | string | The name of the vendor for the integration used with the service.(A value of ‘Missing Vendor information’ will appear once no information could be found). |
| PagerDuty.Service.Integration.Key | string | The key used to control events with the integration. |
Command Example
#### Context Example
```json
{
"PagerDuty": {
"Service": [
{
"CreatedAt": "2016-03-20T14:00:55+02:00",
"ID": "someid",
"Integration": [
{
"Key": "somekey",
"Name": "API Service",
"Vendor": "Missing Vendor information"
}
],
"Name": "API Service",
"Status": "critical"
}
]
}
}
Human Readable Output
Service List
ID Name Status Created At Integration someid API Service critical 2016-03-20T14:00:55+02:00 Name: API Service, Vendor: Missing Vendor information, Key: somekey
PagerDuty-add-responders
Add responders to an incident.
Base Command
PagerDuty-add-responders
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | PagerDuty Incident ID to add responders to. | Required |
| message | Message to send to responders. | Required |
| user_requests | Comma separated list of User IDs to request response from. | Optional |
| escalation_policy_requests | Comma separated list of Escalation Policy IDs to request response from. | Optional |
| requestor_id | UserID sending the request (if blank, uses the default for the integration). | Optional |
Command Example
!PagerDuty-add-responders incident_id=PXP12GZ UserRequests=P09TT3C,PAIXXX Message="Please join zoom meeting"
Context Output
| Path | Type | Description |
|---|---|---|
| PagerDuty.ResponderRequests.ResponderID | String | The user ID of the responder added. |
| PagerDuty.ResponderRequests.ResponderName | String | The name of the responder added. |
Context Example
{
"PagerDuty":
{
"ResponderRequests": [
{
"ID": "P09TT3C",
"IncidentID": "PXP12GZ",
"IncidentSummary": "[#31028] Test Incident for Demisto Integration - No Action",
"Message": "Please help with issue - join bridge at +1(234)-567-8910",
"RequesterID": "P09TT3C",
"ResponderName": "John Doe",
"ResponderType": "user_reference",
"Type": "user"
},
{
"ID": "PAIXXX",
"IncidentID": "PXP12GZ",
"IncidentSummary": "[#31028] Test Incident for Demisto Integration - No Action",
"Message": "Please help with issue - join bridge at +1(234)-567-8910",
"RequesterID": "P09TT3C",
"ResponderName": "Jane Doe",
"ResponderType": "user_reference",
"Type": "user"
}
]
}
}
PagerDuty-run-response-play
Run a response play on PagerDuty (based on its UUID).
Response Plays are a package of Incident Actions that can be applied during an Incident’s life cycle.
Base Command
PagerDuty-run-response-play
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The PagerDuty incident ID to run the play on. | Required |
| from_email | User’s email to trigger the response play from. | Required |
| response_play_uuid | The UUID of the response play to run. | Required |
Command Example
!PagerDuty-run-response-play incident_id="Q107XAAAAMBBR" from_email="john.doe@example.com" response_play_uuid="111111-88bb-bb37-181d-11111111110dewsq"
Human Readable Output
Response play successfully run to the incident Q107XAAAAMBBR by john.doe@example.com
Configuration parameters
APIKey— API Keycredentials_api_key—ServiceKey— Service Key (for triggering, acknowledging and resolving events only)insecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch IntervalFetchInterval— Initial Fetch Interval (In minutes, used only for first fetch or after Reset last run)DefaultRequestor— Default requestor ID for adding people to incidentsmax_fetch— Maximum number of incidents per fetchincident_statuses— Incident statuses to fetch
Commands (13)
-
PagerDuty-acknowledge-eventAcknowledges an existing event in PagerDuty.
-
PagerDuty-add-respondersAdd responders to an incident.
-
PagerDuty-get-all-schedulesReceive all schedules from PagerDuty.
-
PagerDuty-get-contact-methodsGet the contact methods of a given user.
-
PagerDuty-get-incident-dataGet data about a incident from PagerDuty.
-
PagerDuty-get-service-keysGet Service keys for each of the services configured in the PagerDuty instance.
-
PagerDuty-get-users-notificationGet the users notification rules.
-
PagerDuty-get-users-on-callReturns the names and details of on call users at a certain time or by specific schedule.
-
PagerDuty-get-users-on-call-nowReturns the names and details of current on call personnel.
-
PagerDuty-incidentsShows incidents in PagerDuty. Default status parameters are triggered,acknowledged.
-
PagerDuty-resolve-eventResolves an existing event in PagerDuty.
-
PagerDuty-run-response-playRun a response play on PagerDuty (based on its UUID).
-
PagerDuty-submit-eventCreates a new event/incident in PagerDuty(In order to use this command you have to enter the Service Key in the integration settings).
import pytest from CommonServerPython import * from pytest_mock import MockerFixture from requests_mock import MockerCore def load_mock_response(file_name: str) -> dict: """ Load mock file that simulates an API response. Args: file_name (str): Name of the mock response JSON file to return. Returns: str: Mock file content. """ with open(f"test_data/{file_name}") as f: return json.loads(f.read()) def test_get_incidents(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - An incident with non-ascii character in its documentation When: - Running get incidents command Then: - Ensure command run without failing on UnicodeError - Verify the non-ascii character appears in the human readable output as expected """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "DefaultRequestor", }, ) from PagerDuty import get_incidents_command requests_mock.get( "https://api.pagerduty.com/incidents?include%5B%5D=assignees&statuses%5B%5D=triggered&statuses%5B%5D" "=acknowledged&include%5B%5D=first_trigger_log_entries&include%5B%5D=assignments&time_zone=UTC", json={"incidents": [{"first_trigger_log_entry": {"channel": {"details": {"Documentation": "•"}}}}]}, ) res = get_incidents_command({}) assert "| Documentation: • |" in res["HumanReadable"] def test_add_responders(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - a responder request. When: - Running PagerDuty-add-responders command. Then: - Ensure command returns the correct output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) mocker.patch.object( demisto, "args", return_value={ "incident_id": "PXP12GZ", "message": "Please help with issue - join bridge at +1(234)-567-8910", "user_requests": "P09TT3C,PAIXXX", }, ) requests_mock.post( "https://api.pagerduty.com/incidents/PXP12GZ/responder_requests", json=load_mock_response("responder_requests.json")["specific_users"], ) from PagerDuty import add_responders_to_incident res = add_responders_to_incident(**demisto.args()) expected_users_requested = ",".join([x["ID"] for x in res.outputs]) assert demisto.args()["incident_id"] == res.outputs[0]["IncidentID"] assert demisto.args()["message"] == res.outputs[0]["Message"] assert demisto.params()["DefaultRequestor"] == res.outputs[1]["RequesterID"] assert demisto.args()["user_requests"] == expected_users_requested def test_add_responders_default(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - a responder request without specifying responders. When: - Running add_responders_to_incident function. Then: - Ensure the function returns the correct output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) mocker.patch.object( demisto, "args", return_value={"incident_id": "PXP12GZ", "message": "Please help with issue - join bridge at +1(234)-567-8910"}, ) requests_mock.post( "https://api.pagerduty.com/incidents/PXP12GZ/responder_requests", json=load_mock_response("responder_requests.json")["default_user"], ) from PagerDuty import add_responders_to_incident res = add_responders_to_incident(**demisto.args()) expected_users_requested = ",".join([x["ID"] for x in res.outputs]) assert demisto.args()["incident_id"] == res.outputs[0]["IncidentID"] assert demisto.args()["message"] == res.outputs[0]["Message"] assert demisto.params()["DefaultRequestor"] == res.outputs[0]["RequesterID"] assert demisto.params()["DefaultRequestor"] == expected_users_requested def test_play_response_play(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - a responder request without specifying responders. When: - Running PagerDuty-run-response-play function. Then: - Ensure the function returns a valid status. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) mocker.patch.object( demisto, "args", return_value={ "incident_id": "PXP12GZ", "from_email": "john.doe@example.com", "response_play_uuid": "response_play_id", }, ) requests_mock.post("https://api.pagerduty.com/response_plays/response_play_id/run", json={"status": "ok"}) from PagerDuty import run_response_play res = run_response_play(**demisto.args()) assert res.raw_response == {"status": "ok"} def test_get_users_on_call(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - a request to get user on-call by schedule ID. When: - Running get_on_call_users_command function. Then: - Ensure the function returns a valid output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) mocker.patch.object( demisto, "args", return_value={ "scheduleID": "PI7DH85", }, ) requests_mock.get("https://api.pagerduty.com/schedules/PI7DH85/users", json=load_mock_response("schedules.json")) from PagerDuty import get_on_call_users_command res = get_on_call_users_command(**demisto.args()) assert demisto.args()["scheduleID"] == res.outputs[0]["ScheduleID"] def test_get_users_on_call_now(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - a reqest to get user oncall by schedule ID without specifying responders. When: - Running get_on_call_users_command function. Then: - Ensure the function returns a valid output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) mocker.patch.object( demisto, "args", return_value={ "schedule_ids": "PI7DH85,PA7DH85", }, ) requests_mock.get("https://api.pagerduty.com/oncalls", json=load_mock_response("oncalls.json")) from PagerDuty import get_on_call_now_users_command res = get_on_call_now_users_command(**demisto.args()) assert res.outputs[0]["ScheduleID"] in demisto.args()["schedule_ids"] assert "oncalls" in res.raw_response def test_submit_event(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - a reqest to submit request. When: - Running submit_event function. Then: - Ensure the function returns a valid output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) source = "test" summary = "test" severity = "test" action = "test" requests_mock.post( "https://events.pagerduty.com/v2/enqueue", json={"status": "status", "message": "message", "dedup_key": "dedup_key"} ) from PagerDuty import submit_event_command res = submit_event_command(source, summary, severity, action) assert "### Trigger Event" in res["HumanReadable"] def test_get_all_schedules_command(mocker: MockerFixture, requests_mock: MockerCore) -> None: """ Given: - a reqest to get all schedule When: - Running get_all_schedules function. Then: - Ensure the function returns a valid output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) requests_mock.get( "https://api.pagerduty.com/schedules", json={ "schedules": [ { "id": "id", "name": "name", "time_zone": "time_zone", "escalation_policies": [{"id": "id", "summary": "summary"}], } ] }, ) from PagerDuty import get_all_schedules_command res = get_all_schedules_command() assert "### All Schedules" in res["HumanReadable"] def test_get_users_contact_methods_command(mocker: MockerFixture, requests_mock: MockerCore) -> None: """ Given: - a reqest to get all schedule. When: - Running get_all_schedules function. Then: - Ensure the function returns a valid output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) user_id = "id" requests_mock.get( f"https://api.pagerduty.com/users/{user_id}/contact_methods", json={"contact_methods": [{"id": "id", "address": "address", "country_code": "country_code"}]}, ) from PagerDuty import get_users_contact_methods_command res = get_users_contact_methods_command(user_id) assert "### Contact Methods" in res["HumanReadable"] def test_get_users_notification_command(mocker: MockerFixture, requests_mock: MockerCore) -> None: """ Given: - a request to get users notifications. When: - Running get_users_notification_command function. Then: - Ensure the function returns a valid output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) user_id = "id" requests_mock.get( f"https://api.pagerduty.com/users/{user_id}/notification_rules", json={"notification_rules": [{"id": "id", "urgency": "urgency", "type": "type"}]}, ) from PagerDuty import get_users_notification_command res = get_users_notification_command(user_id) assert "### User notification rules" in res["HumanReadable"] @pytest.mark.parametrize("severity, expected_result", [("high", 3), ("low", 1), ("other_severity", 0)]) def test_translate_severity(mocker: MockerFixture, severity: str, expected_result: int) -> None: """ Given: - a severity. When: - Running translate_severity function. Then: - Ensure the function returns a valid output. """ mocker.patch.object( demisto, "params", return_value={ "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "FETCH_INTERVAL", "DefaultRequestor": "P09TT3C", }, ) from PagerDuty import translate_severity res = translate_severity(severity) assert res == expected_result def test_paginate_with_limit(mocker: MockerFixture): """This test verifies that the function correctly handles pagination when a limit is provided, making a single API request with the expected parameters and returning the correct results. Given: a test scenario where the `pagination_incidents` function is called with a specified limit, When: the function is invoked with a limit of 79, Then: it should make a single API request with the specified limit and offset 0, and the result should match the mocked API response. """ from PagerDuty import pagination_incidents re = mocker.patch( "PagerDuty.http_request", side_effect=[{"incidents": list(range(79))}], ) result = pagination_incidents({"user_ids": "test_id"}, {"limit": 79}, "") assert result == list(range(79)) assert re.call_count == 1 assert re.call_args_list[0].args == ("GET", "", {"user_ids": "test_id", "limit": 79, "offset": 0}) def test_paginate_with_limit_is_more_than_INCIDENT_API_LIMIT(mocker: MockerFixture): """This test ensures that the function correctly handles pagination for large limits, making multiple API calls to retrieve all incidents. Given: a test scenario where the requested limit exceeds the max incidents per page (100), When: the `pagination_incidents` function is called with a limit of 179, Then: it should make two API calls: - First call with limit 100 and offset 0. - Second call with limit 79 (to fetch the remaining incidents) and offset 100. """ from PagerDuty import pagination_incidents re = mocker.patch( "PagerDuty.http_request", side_effect=[ {"incidents": list(range(100))}, # the response for the first call {"incidents": list(range(100, 179))}, # the response for the secund call ], ) result = pagination_incidents({"user_ids": "test_id"}, {"limit": 179}, "") assert result == list(range(179)) assert re.call_count == 2 assert re.call_args_list[0].args == ("GET", "", {"user_ids": "test_id", "limit": 100, "offset": 0}) # first call assert re.call_args_list[1].args == ("GET", "", {"user_ids": "test_id", "limit": 79, "offset": 100}) # secund call def test_paginate_with_page_size(mocker: MockerFixture): """This test verifies that the pagination functionality correctly handles the provided page size and page number, making a single API request with the expected parameters. Given: a test scenario where pagination is performed with a specified page size, When: the `pagination_incidents` function is called with a page size of 100 and page number 2, Then: it should make a single API request to fetch results from offset 100 to 199. """ from PagerDuty import pagination_incidents re = mocker.patch("PagerDuty.http_request", side_effect=[{"incidents": list(range(100, 200))}]) result = pagination_incidents({"user_ids": "test_id"}, {"page_size": 100, "page": 2}, "") assert result == list(range(100, 200)) assert re.call_count == 1 assert re.call_args_list[0].args == ("GET", "", {"user_ids": "test_id", "limit": 100, "offset": 100}) def test_paginate_with_page_size_more_than_INCIDENT_API_LIMIT(): """This test ensures that the function correctly handles the case where the provided page size exceeds the API limit, raising a DemistoException with the appropriate error message. Given: a test scenario where the `pagination_incidents` function is called with a page size greater than the API limit, When: the function is invoked with a page size of 200 and page number 2, Then: it should raise a DemistoException with the message "The max size for page is 100. Please provide a smaller page size." """ from PagerDuty import pagination_incidents with pytest.raises(DemistoException, match="The max size for page is 100. Please provide a lower page size."): pagination_incidents({"user_ids": "test_id"}, {"page_size": 200, "page": 2}, "") @pytest.mark.parametrize("add_content", [True, False]) def test_main_handles_httperror(requests_mock, mocker, add_content): """ Given: params that causes http error. When: sending an HTTP request. Then: print the correct error message. """ mocker.patch.object(demisto, "params", return_value={"APIKey": "test", "ServiceKey": "test", "FetchInterval": "1"}) from PagerDuty import ON_CALLS_USERS_SUFFIX, SERVER_URL, main class Response: def __init__(self, add_content): if add_content: self.content = "Https error test" url = SERVER_URL + ON_CALLS_USERS_SUFFIX requests_mock.get(url, exc=requests.exceptions.HTTPError(response=Response(add_content))) mocker.patch.object(demisto, "command", return_value="test-module") error_method = mocker.patch("PagerDuty.return_error") main() assert error_method.call_count == 1 if add_content: assert error_method.call_args.args[0] == "Error in API request Https error test" else: assert error_method.call_args.args[0] == "Error in API request " def _mk_incident( idx: int, status: str = "triggered", created_at: str = "2026-05-24T10:00:00Z", ) -> dict: """Build a minimal PagerDuty incident dict the parser can consume.""" return { "id": f"P{idx:04d}", "summary": f"incident {idx}", "status": status, "urgency": "high", "created_at": created_at, "html_url": f"https://example.pagerduty.com/incidents/P{idx:04d}", "service": {"id": "SVC1", "summary": "svc"}, "first_trigger_log_entry": {"channel": {"details": "x"}}, "assignments": [], "acknowledgements": [], "teams": [], } def _page( incidents: list, more: bool = False, offset: int = 0, limit: int = 100, total: int | None = None, ) -> dict: """Build a PagerDuty `GET /incidents` style page response.""" return { "incidents": incidents, "more": more, "offset": offset, "limit": limit, "total": total if total is not None else len(incidents), } def _base_params(**overrides) -> dict: """Default integration params for fetch_incidents tests.""" base = { "APIKey": "API_KEY", "ServiceKey": "SERVICE_KEY", "FetchInterval": "10", "DefaultRequestor": "DefaultRequestor", } base.update(overrides) return base def test_fetch_incidents_paginated_over_25(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - max_fetch=120 and an API that returns 100 incidents on the first page and 20 incidents on the second page. When: - fetch_incidents is called. Then: - All 120 incidents are reported via demisto.incidents (i.e., pagination works and we do not silently drop the long tail past the first page). """ mocker.patch.object(demisto, "params", return_value=_base_params()) mocker.patch.object(demisto, "getLastRun", return_value={}) set_last_run = mocker.patch.object(demisto, "setLastRun") set_incidents = mocker.patch.object(demisto, "incidents") page1 = [_mk_incident(i, created_at=f"2026-05-24T10:{i:02d}:00Z") for i in range(100)] page2 = [_mk_incident(100 + i, created_at=f"2026-05-24T11:{i:02d}:00Z") for i in range(20)] def _responder(request, _context): qs = request.qs offset = int(qs.get("offset", ["0"])[0]) return _page(page2 if offset == 100 else page1, more=(offset == 0), offset=offset, limit=100) requests_mock.get("https://api.pagerduty.com/incidents", json=_responder) from PagerDuty import fetch_incidents fetch_incidents(_base_params(max_fetch="120")) assert set_incidents.call_count == 1 assert len(set_incidents.call_args.args[0]) == 120 assert set_last_run.called def test_fetch_incidents_more_false_short_circuit(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - The API returns 10 incidents with more=False on the first page. When: - fetch_incidents is called with default max_fetch. Then: - Only a single HTTP request is made and 10 incidents are emitted. """ mocker.patch.object(demisto, "params", return_value=_base_params()) mocker.patch.object(demisto, "getLastRun", return_value={}) mocker.patch.object(demisto, "setLastRun") set_incidents = mocker.patch.object(demisto, "incidents") incidents = [_mk_incident(i, created_at=f"2026-05-24T10:{i:02d}:00Z") for i in range(10)] matcher = requests_mock.get("https://api.pagerduty.com/incidents", json=_page(incidents, more=False)) from PagerDuty import fetch_incidents fetch_incidents(_base_params()) assert matcher.call_count == 1 assert len(set_incidents.call_args.args[0]) == 10 def test_fetch_incidents_respects_max_fetch_cap(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - max_fetch is set absurdly high (9999) and the API would return 300 incidents. When: - fetch_incidents is called. Then: - The hard MAX_FETCH_CAP (200) is respected — at most 200 incidents are emitted. """ mocker.patch.object(demisto, "params", return_value=_base_params(max_fetch="9999")) mocker.patch.object(demisto, "getLastRun", return_value={}) mocker.patch.object(demisto, "setLastRun") set_incidents = mocker.patch.object(demisto, "incidents") full_pool = [_mk_incident(i, created_at=f"2026-05-24T{10 + i // 60:02d}:{i % 60:02d}:00Z") for i in range(300)] def _responder(request, _context): qs = request.qs offset = int(qs.get("offset", ["0"])[0]) limit = int(qs.get("limit", ["100"])[0]) chunk = full_pool[offset : offset + limit] return _page(chunk, more=(offset + limit < 300), offset=offset, limit=limit) requests_mock.get("https://api.pagerduty.com/incidents", json=_responder) from PagerDuty import MAX_FETCH_CAP, fetch_incidents fetch_incidents(_base_params(max_fetch="9999")) assert len(set_incidents.call_args.args[0]) <= MAX_FETCH_CAP def test_fetch_incidents_passes_statuses_param(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - incident_statuses param is "triggered,acknowledged,resolved". When: - fetch_incidents is called. Then: - The outgoing request URL contains all three statuses encoded as statuses[]. """ mocker.patch.object( demisto, "params", return_value=_base_params(incident_statuses="triggered,acknowledged,resolved"), ) mocker.patch.object(demisto, "getLastRun", return_value={}) mocker.patch.object(demisto, "setLastRun") mocker.patch.object(demisto, "incidents") matcher = requests_mock.get("https://api.pagerduty.com/incidents", json=_page([], more=False)) from PagerDuty import fetch_incidents fetch_incidents(_base_params(incident_statuses="triggered,acknowledged,resolved")) assert matcher.call_count >= 1 url = matcher.last_request.url assert "statuses%5B%5D=triggered" in url assert "statuses%5B%5D=acknowledged" in url assert "statuses%5B%5D=resolved" in url def test_fetch_incidents_watermark_from_created_at(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - Two incidents with created_at T10:00:00 and T10:05:00. - Wall-clock now is T10:10:00. When: - fetch_incidents is called. Then: - setLastRun is called with time == max(created_at) ("2026-05-24T10:05:00Z"), NOT the wall-clock value. """ mocker.patch.object(demisto, "params", return_value=_base_params()) mocker.patch.object(demisto, "getLastRun", return_value={}) set_last_run = mocker.patch.object(demisto, "setLastRun") mocker.patch.object(demisto, "incidents") incidents = [ _mk_incident(1, created_at="2026-05-24T10:00:00Z"), _mk_incident(2, created_at="2026-05-24T10:05:00Z"), ] requests_mock.get("https://api.pagerduty.com/incidents", json=_page(incidents, more=False)) from PagerDuty import fetch_incidents fetch_incidents(_base_params()) saved = set_last_run.call_args.args[0] assert saved["time"] == "2026-05-24T10:05:00Z" assert "P0002" in saved["ids"] def test_fetch_incidents_dedup_against_lastrun_ids(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - lastRun contains ids=["P0001"]. - The API returns P0001 (boundary duplicate) and P0002 (new). When: - fetch_incidents is called. Then: - Only P0002 is emitted, and the new ids buffer retains P0001 up to the retention cap. """ mocker.patch.object(demisto, "params", return_value=_base_params()) mocker.patch.object( demisto, "getLastRun", return_value={"time": "2026-05-24T09:00:00Z", "ids": ["P0001"]}, ) set_last_run = mocker.patch.object(demisto, "setLastRun") set_incidents = mocker.patch.object(demisto, "incidents") incidents = [ _mk_incident(1, created_at="2026-05-24T09:00:00Z"), _mk_incident(2, created_at="2026-05-24T09:05:00Z"), ] requests_mock.get("https://api.pagerduty.com/incidents", json=_page(incidents, more=False)) from PagerDuty import fetch_incidents fetch_incidents(_base_params()) emitted = set_incidents.call_args.args[0] assert len(emitted) == 1 assert emitted[0]["name"].startswith("P0002 - ") saved = set_last_run.call_args.args[0] assert saved["ids"] == ["P0001", "P0002"] # Watermark must advance to the newest incident's created_at (P0002), not stay pinned. assert saved["time"] == "2026-05-24T09:05:00Z" def test_fetch_incidents_no_new_advances_watermark_to_now(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - lastRun = {"time": "T09:00:00Z", "ids": ["P0001"]}. - The API returns only P0001 (which is filtered out by dedup, so 0 new emitted). - Wall-clock now is mocked to a deterministic value. When: - fetch_incidents is called. Then: - demisto.incidents([]) is called and setLastRun advances `time` to the mocked `now` (so the next since→until window stays bounded). `ids` is preserved as the prior seen_ids (no merge — there are no new IDs in this branch). """ last_run = {"time": "2026-05-24T09:00:00Z", "ids": ["P0001"]} mocker.patch.object(demisto, "params", return_value=_base_params()) mocker.patch.object(demisto, "getLastRun", return_value=last_run) set_last_run = mocker.patch.object(demisto, "setLastRun") set_incidents = mocker.patch.object(demisto, "incidents") fixed_now = datetime(2026, 5, 24, 10, 0, 0) class _FixedDatetime(datetime): @classmethod def utcnow(cls): return fixed_now mocker.patch("PagerDuty.datetime", _FixedDatetime) expected_now_iso = datetime.isoformat(fixed_now) incidents = [_mk_incident(1, created_at="2026-05-24T09:00:00Z")] requests_mock.get("https://api.pagerduty.com/incidents", json=_page(incidents, more=False)) from PagerDuty import fetch_incidents fetch_incidents(_base_params()) assert set_incidents.call_args.args[0] == [] saved = set_last_run.call_args.args[0] assert saved["time"] == expected_now_iso assert saved["ids"] == last_run["ids"] def test_fetch_incidents_first_run_uses_fetch_interval(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - No prior lastRun. - FetchInterval=10 minutes and a deterministic utcnow. When: - fetch_incidents is called. Then: - The outgoing request 'since' value is exactly 10 minutes before now. """ mocker.patch.object(demisto, "params", return_value=_base_params(FetchInterval="10")) mocker.patch.object(demisto, "getLastRun", return_value=None) mocker.patch.object(demisto, "setLastRun") mocker.patch.object(demisto, "incidents") fixed_now = datetime(2026, 5, 24, 12, 0, 0) class _FixedDatetime(datetime): @classmethod def utcnow(cls): return fixed_now mocker.patch("PagerDuty.datetime", _FixedDatetime) matcher = requests_mock.get("https://api.pagerduty.com/incidents", json=_page([], more=False)) from PagerDuty import fetch_incidents fetch_incidents(_base_params(FetchInterval="10")) from urllib.parse import unquote expected_since = "2026-05-24T11:50:00" url = unquote(matcher.last_request.url) assert f"since={expected_since}" in url def test_fetch_incidents_empty_dicts_filtered(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - The API returns {"incidents": [{}]} (the paginator's empty-dict fallback shape). - Wall-clock now is mocked to a deterministic value. When: - fetch_incidents is called with a fresh lastRun. Then: - No exception is raised, demisto.incidents([]) is called, and setLastRun advances `time` to the mocked `now` (since 0 new incidents were emitted, per the hybrid rule). `ids` is preserved as the prior (empty) seen_ids. """ prior_last_run: dict = {} mocker.patch.object(demisto, "params", return_value=_base_params()) mocker.patch.object(demisto, "getLastRun", return_value=prior_last_run) set_last_run = mocker.patch.object(demisto, "setLastRun") set_incidents = mocker.patch.object(demisto, "incidents") fixed_now = datetime(2026, 5, 24, 12, 0, 0) class _FixedDatetime(datetime): @classmethod def utcnow(cls): return fixed_now mocker.patch("PagerDuty.datetime", _FixedDatetime) expected_now_iso = datetime.isoformat(fixed_now) requests_mock.get("https://api.pagerduty.com/incidents", json={"incidents": [{}]}) from PagerDuty import fetch_incidents fetch_incidents(_base_params()) assert set_incidents.call_args.args[0] == [] saved = set_last_run.call_args.args[0] assert saved["time"] == expected_now_iso assert saved["ids"] == [] def test_fetch_incidents_accepts_list_statuses(requests_mock: MockerCore, mocker: MockerFixture) -> None: """ Given: - params["incident_statuses"] is delivered as a Python list (XSOAR multiSelect type 16 may serialize the value either as a comma-string or as a list). When: - fetch_incidents is called. Then: - No AttributeError is raised, and the outgoing request URL contains BOTH statuses[]=triggered AND statuses[]=resolved. """ params = _base_params(incident_statuses=["triggered", "resolved"]) mocker.patch.object(demisto, "params", return_value=params) mocker.patch.object(demisto, "getLastRun", return_value={}) mocker.patch.object(demisto, "setLastRun") mocker.patch.object(demisto, "incidents") matcher = requests_mock.get("https://api.pagerduty.com/incidents", json=_page([], more=False)) from PagerDuty import fetch_incidents fetch_incidents(params) from urllib.parse import unquote assert matcher.last_request is not None url = unquote(matcher.last_request.url) assert "statuses[]=triggered" in url assert "statuses[]=resolved" in url