ChatGPTSalesCustomer supportAI score · PendingAI-assisted edit · no obvious prompt-injection riskn8n.io

PagerDuty-Port AI Incident Lifecycle Automation in n8n

PagerDuty webhook events → Port software catalog context → OpenAI severity assessment → Slack tiered alerts & Jira tickets → post-resolution MTTR calculation & post-mortem automation

ExperiencedStepsWorkflowPrompt
Who
SREs or platform engineers with PagerDuty, Port, Jira, and Slack accounts, using a self-hosted n8n instance
You get
On incident trigger: auto-fetch service context, assess severity, create tickets, and notify teams. On resolution: auto-calculate MTTR, generate post-mortem template, schedule review meetings, and write reliability metrics back to Port
You need
n8n · slack · jira · port

Constraints

Prerequisites: self-hosted n8n instance (template explicitly states Self-Hosted only); Port account with software catalog configured (services, on-call schedules, deployment history); PagerDuty with webhook capabilities; Jira Cloud project permissions; Slack workspace bot permissions; OpenAI API key. Required credentials: portIoApi, openAiApi, slackApi, jiraSoftwareCloudApi. Costs: billed per respective platform pricing; OpenAI charged by token usage.

What they did

Port.io published an incident lifecycle management workflow template (ID 11610) on the n8n official template marketplace. The workflow receives events via PagerDuty webhook, uses an n8n Switch node to branch by event type: triggered events flow through Port context retrieval → OpenAI severity assessment → conditional routing to Slack notifications and Jira ticket creation; resolved events flow through MTTR calculation → OpenAI post-mortem template generation → Port AI Agent meeting scheduling → metric writeback. The template contains 21 nodes (including 4 sticky notes), using 7 Port custom nodes, 2 OpenAI nodes, 4 Slack nodes, 1 Jira node, and 3 core control nodes.

How it went

The author (Port.io) states the template can: on trigger, automatically fetch service context, assess severity, create Jira tickets with investigation checklists, and send tiered Slack notifications; on resolution, automatically calculate MTTR, generate structured post-mortem templates, schedule review meetings via Port AI Agent, create documentation, and write MTTR metrics back to Port's service catalog. These effects are author-reported (author_report) and have not been verified by this site.

Worth knowing

1. The template is explicitly marked for Self-Hosted n8n instances only; Cloud users may be restricted. 2. The Port node parameter model='gpt-5' is an internal Port platform model identifier, not an OpenAI publicly released GPT-5 product; the OpenAI nodes actually call gpt-4o-mini. 3. The Port custom node must be installed on your n8n instance; it is not a built-in n8n node. 4. All Slack message templates read channel names from Port context, falling back to #incidents if missing; leadership escalation is hardcoded to #leadership-alerts. 5. The Jira project key defaults to INC and can be customized via the jira_project_key field in Parse Context output. 6. Post-mortem meeting scheduling depends on Port AI Agent calendar integration capabilities, which require pre-configuration of Confluence/Notion spaces and calendar integrations in Port. 7. The source does not provide specific pricing for any platform (Port, OpenAI, PagerDuty, Jira, Slack); actual execution will incur costs per respective service pricing.

n8n workflow template

Structure checked · Not run-tested

Use “Import from File” in n8n, or copy the JSON and paste it into the editor. Connect your own accounts, then try test data. The template is inactive by default.

Setup and test checklist

Credentials to connect

  • Extract Context (New Incident) node: connect portIoApi credentials.
  • Parse Context (New Incident) node: connect portIoApi credentials.
  • Assess Severity node: connect OpenAI API credentials.
  • Notify Team Channel node: connect Slack API credentials.
  • Escalate to Leadership node: connect Slack API credentials.
  • Create Jira Incident Ticket node: connect jiraSoftwareCloudApi credentials.
  • Notify Jira Created node: connect Slack API credentials.
  • Extract Context (Resolved) node: connect portIoApi credentials.
  • Parse Context (Resolved) node: connect portIoApi credentials.
  • Generate Post-Mortem Template node: connect OpenAI API credentials.
  • Schedule Post-Mortem via Port node: connect portIoApi credentials.
  • Parse Schedule Response node: connect portIoApi credentials.
  • Notify Incident Resolved node: connect Slack API credentials.
  • Log MTTR to Port node: connect portIoApi credentials.

Configuration to replace

  • Source template is n8n public workflow #11610 (~21 nodes). Keep inactive after import; verify triggers, expressions and external API endpoints.
  • Sticky-note guidance is informational; replace placeholders with your own accounts, sheet schemas or channel IDs.

Test input and expected output

  • Manually run the main path once in a test workspace and confirm credentialed nodes authenticate without errors.
  • Drive one synthetic/redacted sample through and check output fields and downstream writes before enabling in production.

Template changes

  • Author credential bindings, webhookId and execution data are removed; the workflow is inactive. Nodes, connections and original prompts are preserved. Not run-tested in n8n.
  • No business-logic edits; verify keys, quotas and privacy compliance before use.

Template retrieved: 2026-10-24

Steps

  1. Configure PagerDuty Webhook and Event Routing

    Create a Webhook node in n8n with path pagerduty/incident and method POST. Configure PagerDuty to send webhooks to this URL. Add a Switch node to route by body.event.event_type: incident.triggered to the trigger flow, incident.resolved to the resolution flow.

  2. Query Port Software Catalog for Incident Context

    Add the Port custom node (agentIdentifier: context_retriever_agent), passing incident ID, title, service name, urgency, and created_at. The node queries Port for: service tier, SLA, owners, on-call engineers, deployments in last 48h, dependencies, runbook URLs, monitoring dashboards, and past incidents. Outputs a specified JSON with empty strings/arrays for missing fields.

    Execution prompt · Source text。Port custom node 'Extract Context (New Incident)' prompt field

    =A PagerDuty incident has been triggered.
    
    Incident Details:
    - ID: {{ $('On PagerDuty Incident').item.json.body.event.data.id }}
    - Title: {{ $('On PagerDuty Incident').item.json.body.event.data.title }}
    - Service: {{ $('On PagerDuty Incident').item.json.body.event.data.service.name }}
    - Urgency: {{ $('On PagerDuty Incident').item.json.body.event.data.urgency }}
    - Created At: {{ $('On PagerDuty Incident').item.json.body.event.data.created_at }}
    
    Query the Port catalog for comprehensive context about this incident.
    
    Retrieve:
    1. Affected service details (tier, criticality, SLA)
    2. Service owners and current on-call engineers
    3. Recent deployments (last 48 hours)
    4. Related pull requests or configuration changes
    5. Dependencies and upstream/downstream services
    6. Known vulnerabilities or ongoing issues
    7. Runbook URLs and monitoring dashboards
    8. Past similar incidents and resolution patterns
    9. Team's Slack channel
    
    Output as JSON:
    {
      "service_name": "",
      "service_tier": "tier1|tier2|tier3",
      "sla_minutes": 0,
      "owners": [],
      "on_call_engineers": [],
      "slack_channel": "",
      "recent_deployments": [],
      "recent_changes": [],
      "dependencies": [],
      "runbook_url": "",
      "dashboard_url": "",
      "past_incidents_summary": "",
      "known_issues": [],
      "jira_project_key": ""
    }
    
    Rules:
    - Only include data that exists in Port
    - Use empty strings/arrays if not found
  3. OpenAI Severity Assessment and Escalation Recommendation

    Add an OpenAI node (model: gpt-4o-mini), feeding Port context along with incident title, service name, and urgency. Returns JSON: severity level (critical/high/medium/low), escalation flag, reason, likely cause, recommended actions, and investigation checklist.

    Execution prompt · Source text。OpenAI node 'Assess Severity' chat messages[0].content field

    =You are an incident management expert. Assess this incident and determine if immediate escalation is needed.
    
    Incident:
    - Title: {{ $('On PagerDuty Incident').item.json.body.event.data.title }}
    - Service: {{ $('On PagerDuty Incident').item.json.body.event.data.service.name }}
    - Urgency: {{ $('On PagerDuty Incident').item.json.body.event.data.urgency }}
    
    Context from Port:
    {{ $json.result.message }}
    
    Consider:
    1. Is this a production service?
    2. Were there recent deployments that could be related?
    3. Are there known issues affecting this service?
    4. What is the SLA requirement?
    
    Provide your response as JSON:
    {
      "severity_assessment": "critical|high|medium|low",
      "needs_escalation": true or false,
      "escalation_reason": "reason if needs_escalation is true",
      "likely_cause": "brief assessment of likely cause",
      "recommended_actions": ["action 1", "action 2", "action 3"],
      "investigation_checklist": ["check 1", "check 2", "check 3"]
    }
    
    Return ONLY the JSON object.
  4. Slack Tiered Notifications to Team and Leadership

    Add an If node checking needs_escalation. In all cases, send incident details, severity, on-call, likely cause, recommended actions, recent changes, and resource links to the team's Slack channel. If escalation is needed, also send an escalation notice to #leadership-alerts. Channel name read from Port context, defaulting to #incidents if missing.

    Execution prompt · Source text。Slack node 'Notify Team Channel' text field

    =:rotating_light: *INCIDENT ALERT*
    
    *{{ $('On PagerDuty Incident').item.json.body.event.data.title }}*
    
    *Service:* {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().service_name }} ({{ $('Parse Context (New Incident)').item.json.result.message.parseJson().service_tier }})
    *Urgency:* {{ $('On PagerDuty Incident').item.json.body.event.data.urgency }}
    *Severity Assessment:* {{ $('Assess Severity').item.json.message.content.parseJson().severity_assessment }}
    
    *On-Call:* {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().on_call_engineers.join(', ') || 'Check PagerDuty' }}
    
    *Likely Cause:*
    {{ $('Assess Severity').item.json.message.content.parseJson().likely_cause }}
    
    *Recommended Actions:*
    {{ $('Assess Severity').item.json.message.content.parseJson().recommended_actions.map((a, i) => (i+1) + '. ' + a).join('\n') }}
    
    *Recent Changes:*
    {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().recent_deployments.slice(0,3).map(d => '- ' + d).join('\n') || 'None in last 48h' }}
    
    *Resources:*
    {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().runbook_url ? '<' + $('Parse Context (New Incident)').item.json.result.message.parseJson().runbook_url + '|Runbook>' : '' }} {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().dashboard_url ? '| <' + $('Parse Context (New Incident)').item.json.result.message.parseJson().dashboard_url + '|Dashboard>' : '' }}
    
    :pagerduty: <{{ $('On PagerDuty Incident').item.json.body.event.data.html_url }}|View in PagerDuty>

    Execution prompt · Source text。Slack node 'Escalate to Leadership' text field

    =:rotating_light::rotating_light: *INCIDENT ESCALATION*
    
    *{{ $('On PagerDuty Incident').item.json.body.event.data.title }}*
    
    *Service:* {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().service_name }} ({{ $('Parse Context (New Incident)').item.json.result.message.parseJson().service_tier }})
    *Escalation Reason:* {{ $('Assess Severity').item.json.message.content.parseJson().escalation_reason }}
    
    *Team Channel:* {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().slack_channel || '#incidents' }}
    *On-Call:* {{ $('Parse Context (New Incident)').item.json.result.message.parseJson().on_call_engineers.join(', ') || 'Check PagerDuty' }}
    
    :pagerduty: <{{ $('On PagerDuty Incident').item.json.body.event.data.html_url }}|View in PagerDuty>
    
    _Response team has been notified._
  5. Create Jira Incident Ticket and Notify

    Add a Jira node. Project key read from Port context (default INC). Issue type Bug. Priority mapped from severity (critical→Highest, high→High, others→Medium). Description includes full incident details, service context, AI assessment, investigation checklist, recommended actions, recent changes, resource links, and past incident summary. After creation, send confirmation to the team channel.

    Execution prompt · Source text。Slack node 'Notify Jira Created' text field

    =:jira: *Incident Ticket Created*
    
    {{ $json.key }}
    
    Track investigation and resolution in Jira.
  6. Post-Resolution Context Extraction and Post-Mortem Template Generation

    On incident resolution, the Port node (agentIdentifier: context_retriever_agent) queries service details, owners, Slack channel, changes during incident window, Confluence/Notion space, and calendar integration, calculating incident_duration_minutes. Then an OpenAI node (gpt-4o-mini) generates a structured post-mortem JSON template with timeline, impact, root cause analysis placeholder, action items, and lessons learned.

    Execution prompt · Source text。Port node 'Extract Context (Resolved)' prompt field

    =A PagerDuty incident has been resolved.
    
    Incident Details:
    - ID: {{ $('On PagerDuty Incident').item.json.body.event.data.id }}
    - Title: {{ $('On PagerDuty Incident').item.json.body.event.data.title }}
    - Service: {{ $('On PagerDuty Incident').item.json.body.event.data.service.name }}
    - Created At: {{ $('On PagerDuty Incident').item.json.body.event.data.created_at }}
    - Resolved At: {{ $('On PagerDuty Incident').item.json.body.event.data.resolved_at || new Date().toISOString() }}
    
    Query the Port catalog for post-incident context.
    
    Retrieve:
    1. Service details and owners
    2. Team's Slack channel
    3. Changes made during the incident window
    4. Confluence/Notion space for post-mortems
    5. Calendar integration details for scheduling
    
    Calculate incident_duration_minutes from created_at to resolved_at.
    
    Output as JSON:
    {
      "service_name": "",
      "owners": [],
      "slack_channel": "",
      "confluence_space": "",
      "calendar_id": "",
      "incident_duration_minutes": 0,
      "changes_during_incident": [],
      "stakeholders_to_invite": []
    }
    
    Only include data that exists in Port.

    Execution prompt · Source text。OpenAI node 'Generate Post-Mortem Template' chat messages[0].content field

    =Create a post-mortem document template for this resolved incident.
    
    Incident:
    - ID: {{ $('On PagerDuty Incident').item.json.body.event.data.id }}
    - Title: {{ $('On PagerDuty Incident').item.json.body.event.data.title }}
    - Service: {{ $json.result.message.parseJson().service_name }}
    - Duration: {{ $json.result.message.parseJson().incident_duration_minutes }} minutes
    - Created: {{ $('On PagerDuty Incident').item.json.body.event.data.created_at }}
    - Resolved: {{ $('On PagerDuty Incident').item.json.body.event.data.resolved_at }}
    
    Context:
    {{ $json.result.message }}
    
    Create a structured post-mortem template as JSON:
    {
      "title": "Post-Mortem: [incident title]",
      "summary": "Brief 2-3 sentence summary",
      "timeline": [
        {"time": "HH:MM", "event": "Incident detected"},
        {"time": "HH:MM", "event": "Response initiated"},
        {"time": "HH:MM", "event": "Root cause identified"},
        {"time": "HH:MM", "event": "Resolution applied"},
        {"time": "HH:MM", "event": "Incident resolved"}
      ],
      "impact": "Description of customer/business impact",
      "root_cause_analysis": "[To be filled during post-mortem meeting]",
      "action_items": [
        {"action": "Suggested action 1", "owner": "TBD", "due_date": "TBD"},
        {"action": "Suggested action 2", "owner": "TBD", "due_date": "TBD"}
      ],
      "lessons_learned": "[To be filled during post-mortem meeting]",
      "meeting_attendees": []
    }
    
    Return ONLY the JSON object.
  7. Port AI Agent Schedules Post-Mortem and Notifies Team

    Add a Port node (agentIdentifier: post_mortem_scheduler_agent), passing incident details, duration, resolved time, stakeholder list, and post-mortem template content. Agent tasks: create post-mortem document, schedule meeting 2-3 business days out, invite relevant stakeholders, include document link in invite. Returns JSON with document status, meeting time, and attendees. After parsing, send resolution notice to team channel with MTTR, document link, and meeting details.

    Execution prompt · Source text。Port node 'Schedule Post-Mortem via Port' prompt field

    =An incident has been resolved and needs a post-mortem meeting scheduled.
    
    Incident Details:
    - ID: {{ $('On PagerDuty Incident').item.json.body.event.data.id }}
    - Title: {{ $('On PagerDuty Incident').item.json.body.event.data.title }}
    - Service: {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().service_name }}
    - Duration: {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().incident_duration_minutes }} minutes
    - Resolved At: {{ $('On PagerDuty Incident').item.json.body.event.data.resolved_at }}
    
    Stakeholders to invite:
    {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().stakeholders_to_invite.join(', ') || $('Parse Context (Resolved)').item.json.result.message.parseJson().owners.join(', ') }}
    
    Post-Mortem Template:
    {{ $('Generate Post-Mortem Template').item.json.message.content }}
    
    Your tasks:
    1. Create a post-mortem document (in Confluence/Notion if available) with the template content
    2. Schedule a post-mortem meeting for 2-3 business days from now
    3. Invite relevant stakeholders (service owners, on-call engineers who responded)
    4. Include the incident details and post-mortem document link in the meeting invite
    
    Respond with JSON:
    {
      "document_created": true or false,
      "document_url": "URL if created",
      "meeting_scheduled": true or false,
      "meeting_time": "ISO timestamp",
      "attendees_invited": [],
      "status": "success|partial|failed",
      "message": "Summary of actions taken"
    }

    Execution prompt · Source text。Slack node 'Notify Incident Resolved' text field

    =:white_check_mark: *INCIDENT RESOLVED*
    
    *{{ $('On PagerDuty Incident').item.json.body.event.data.title }}*
    
    *Service:* {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().service_name }}
    *Duration:* {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().incident_duration_minutes }} minutes
    *MTTR:* {{ Math.floor($('Parse Context (Resolved)').item.json.result.message.parseJson().incident_duration_minutes / 60) }}h {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().incident_duration_minutes % 60 }}m
    
    *Post-Mortem:*
    {{ $json.result.message.parseJson().document_url ? '<' + $json.result.message.parseJson().document_url + '|View Document>' : 'Document creation pending' }}
    
    *Post-Mortem Meeting:*
    {{ $json.result.message.parseJson().meeting_scheduled ? 'Scheduled for ' + $json.result.message.parseJson().meeting_time : 'Scheduling in progress' }}
    {{ $json.result.message.parseJson().attendees_invited.length > 0 ? 'Attendees: ' + $json.result.message.parseJson().attendees_invited.join(', ') : '' }}
    
    {{ $json.result.message.parseJson().message }}
    
    :pagerduty: <{{ $('On PagerDuty Incident').item.json.body.event.data.html_url }}|View in PagerDuty>
  8. Write MTTR Metrics Back to Port

    Add a Port node (agentIdentifier: metrics_logger_agent), passing incident ID, service name, MTTR in minutes, and resolved time. Tasks: update the service entity in Port with latest MTTR, increment incident count, update last incident timestamp. Returns JSON confirming whether metrics were logged.

    Execution prompt · Source text。Port node 'Log MTTR to Port' prompt field

    =Log the incident resolution metrics to Port.
    
    Incident:
    - ID: {{ $('On PagerDuty Incident').item.json.body.event.data.id }}
    - Service: {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().service_name }}
    - MTTR: {{ $('Parse Context (Resolved)').item.json.result.message.parseJson().incident_duration_minutes }} minutes
    - Resolved At: {{ $('On PagerDuty Incident').item.json.body.event.data.resolved_at }}
    
    Update the service entity in Port with:
    1. Latest incident MTTR
    2. Increment incident count
    3. Update last incident timestamp
    
    Respond with JSON:
    {
      "metrics_logged": true or false,
      "service_updated": "",
      "message": ""
    }

Prompt you can copy

Setup guidance · Editorial suggestion。Hand to setup assistant; confirm inputs and permissions first

This block is the prompt. Ads are never placed here.

You are setting up an n8n workflow for automated incident lifecycle management. Please confirm the following prerequisites first:
1. You are using a self-hosted n8n instance (the template explicitly states Self-Hosted only).
2. You have registered on Port.io and configured your software catalog, on-call schedules, and deployment history.
3. You have installed the Port custom node in n8n and configured credentials for portIoApi, openAiApi, slackApi, and jiraSoftwareCloudApi.
4. Your PagerDuty webhook can reach your n8n instance's public URL.
5. Slack channels #incidents and #leadership-alerts exist; Jira project key is INC (or customize as needed).

After confirmation, import the workflow.json or build manually per node descriptions. Key checks:
- Webhook path matches PagerDuty configuration;
- Switch node rules match incident.triggered / incident.resolved;
- Port node agentIdentifier matches your AI Agent names in Port;
- OpenAI node model selection matches your account (template uses gpt-4o-mini).

Before first production run, test with a PagerDuty test event to verify the trigger flow (Slack message received, Jira ticket created), then test the resolution flow.

Self-hosted environment required; Port custom node must be installed separately; all credentials must be pre-configured and connectivity-tested in n8n.

Source

Automate Incident Management with PagerDuty, Port AI, Jira & Slack · portio · n8n.io · 2025-12-08

Comments & feedback

Tried this method? Share results, problems or improvements. Comments appear after moderation. Please avoid sensitive information.

Loading…

    Related