> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devinenterprise.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Generar automáticamente post mortems de incidentes

export const UseCaseHero = ({title, description, prompt, category, features, devinUrl, agent, intent, playbookId, type}) => {
  const encodedPrompt = encodeURIComponent(prompt || '');
  const tag = 'docs-use-case-gallery';
  const utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=hero-cta';
  const agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  const devinHref = type === 'schedule' ? 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + (prompt ? '&prompt=' + encodedPrompt : '') : type === 'review' ? 'https://app.devin.ai/review?' + utm : agent === 'ada' ? 'https://app.devin.ai/search?' + utm + '&noSubmit=true' + (prompt ? '&prompt=' + encodedPrompt : '') : devinUrl ? devinUrl.includes('?') ? devinUrl + '&' + utm + agentParams : devinUrl + '?' + utm + agentParams : prompt ? 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encodedPrompt : 'https://app.devin.ai/?' + utm + agentParams;
  const buttonLabel = type === 'schedule' ? 'Schedule in Devin ↗' : type === 'review' ? 'Set Up Devin Review ↗' : agent === 'advanced' ? 'Try in Devin ↗' : agent === 'dana' ? 'Try in Dana ↗' : agent === 'ada' ? 'Try in Ask Devin ↗' : 'Try in Devin ↗';
  const featureList = features ? features.split(',').map(f => f.trim()) : [];
  return <div className="uc-hero">
      <div className="uc-hero-inner">
        <div className="uc-hero-left">
          <h1 className="uc-hero-title">{title}</h1>
          <p className="uc-hero-desc">{description}</p>
          <div>
            <a href={devinHref} target="_blank" rel="noopener noreferrer" className="try-in-devin-btn">
              {buttonLabel}
            </a>
          </div>
        </div>
        <div className="uc-hero-meta">
          <div className="uc-meta-item">
            <span className="uc-meta-label">Author</span>
            <span className="uc-meta-value">Cognition</span>
          </div>
          <div className="uc-meta-item">
            <span className="uc-meta-label">Category</span>
            <span className="uc-meta-value">{category}</span>
          </div>
          {featureList.length > 0 && <div className="uc-meta-item">
              <span className="uc-meta-label">Features</span>
              <span className="uc-meta-value">{featureList.join(', ')}</span>
            </div>}
        </div>
      </div>
    </div>;
};

export const PromptBlock = ({children, type, agent, intent, playbookId}) => {
  var utm = 'utm_source=docs&utm_medium=use-case-gallery&utm_campaign=prompt-block';
  var tag = 'docs-use-case-gallery';
  var agentParams = (agent ? '&agent=' + agent : '') + (intent ? '&intent=' + intent : '') + (playbookId ? '&playbookId=' + playbookId : '');
  var label = type === 'schedule' ? 'Schedule in Devin' : type === 'playbook' ? 'Create Playbook' : type === 'knowledge' ? 'Add to Knowledge' : agent === 'advanced' ? 'Try in Devin' : agent === 'dana' ? 'Try in Dana' : agent === 'ada' ? 'Try in Ask Devin' : 'Try in Devin';
  var buildUrl = function (text) {
    var encoded = encodeURIComponent(text);
    if (type === 'schedule') return 'https://app.devin.ai/settings/schedules/create?' + utm + agentParams + '&prompt=' + encoded;
    if (type === 'playbook') return 'https://app.devin.ai/settings/playbooks/create?' + utm + '&body=' + encoded;
    if (type === 'knowledge') return 'https://app.devin.ai/knowledge?' + utm + '&body=' + encoded;
    if (agent === 'ada') return 'https://app.devin.ai/search?' + utm + '&noSubmit=true&prompt=' + encoded;
    return 'https://app.devin.ai/?tags=' + tag + '&' + utm + agentParams + '&prompt=' + encoded;
  };
  const ref = React.useRef(null);
  const [href, setHref] = React.useState('#');
  React.useEffect(() => {
    if (!ref.current) return;
    var codeEl = ref.current.querySelector('pre code');
    if (codeEl) {
      var text = codeEl.textContent.trim();
      if (text) setHref(buildUrl(text));
    }
    var header = ref.current.querySelector('[data-component-part="code-block-header"]');
    if (header && !header.querySelector('.prompt-block-devin-link')) {
      var link = document.createElement('a');
      link.href = href;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.className = 'prompt-block-devin-link';
      link.style.cssText = 'display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:#fff;font-size:11px;font-weight:500;padding:4px 10px;border-radius:6px;white-space:nowrap;background:#317CFF;transition:background 0.2s;margin-left:8px;';
      link.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg> ' + label;
      link.onmouseenter = function () {
        link.style.background = '#2968D9';
      };
      link.onmouseleave = function () {
        link.style.background = '#317CFF';
      };
      header.appendChild(link);
    }
    var existingLink = ref.current.querySelector('.prompt-block-devin-link');
    if (existingLink && href !== '#') existingLink.href = href;
  });
  return <div className="prompt-block" ref={ref}>{children}</div>;
};

<UseCaseHero title="Generar automáticamente informes post mortem de incidentes" description="Cuando se resuelve un incidente de PagerDuty, Devin redacta un informe post mortem estructurado con cronología, análisis de causa raíz y acciones de seguimiento." prompt="Ayúdame a configurar un pipeline de post mortem de PagerDuty a Devin. Sigue la guía en https://docs.devin.ai/use-cases/gallery/api-pagerduty-postmortem y guíame paso a paso: desplegar el puente de webhook, configurar PagerDuty y conectar los MCP de observabilidad." category="Respuesta a incidentes" features="API, MCP" />

<div className="uc-detail-wrapper">
  <Tip>Para obtener una guía más detallada sobre la integración con PagerDuty, [haz clic aquí](/es/enterprise/integrations/pagerduty).</Tip>

  <Steps>
    <Step title="Implementar un puente de webhooks">
      Crea un pequeño servicio que escuche los eventos `incident.resolved` de PagerDuty e inicie una sesión de Devin para redactar el postmortem. Despliega esto como una función serverless (AWS Lambda, Cloudflare Worker) o un contenedor ligero:

      ```javascript theme={null}
      const express = require('express');
      const crypto = require('crypto');
      const app = express();
      app.use(express.json());

      function verifySignature(req) {
        const secret = Buffer.from(req.headers['x-webhook-secret'] || '');
        const expected = Buffer.from(process.env.WEBHOOK_SECRET || '');
        if (!expected.length) throw new Error('WEBHOOK_SECRET environment variable is not set');
        if (secret.length !== expected.length) return false;
        return crypto.timingSafeEqual(secret, expected);
      }

      app.post('/pagerduty-resolved', async (req, res) => {
        if (!verifySignature(req)) return res.status(401).send('Bad signature');

        const event = req.body?.event;
        if (!event || event.event_type !== 'incident.resolved') {
          return res.sendStatus(200);
        }

        const incident = event.data;
        const title = incident.title || 'Unknown incident';
        const service = incident.service?.summary || 'unknown-service';
        const urgency = incident.urgency || 'high';
        const incidentUrl = incident.html_url || '';
        const createdAt = incident.created_at || '';
        const resolvedAt = incident.resolved_at || new Date().toISOString();

        const orgId = process.env.DEVIN_ORG_ID;
        const response = await fetch(
          `https://api.devin.ai/v3/organizations/${orgId}/sessions`, {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${process.env.DEVIN_API_KEY}`,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            prompt: [
              `A PagerDuty incident has been resolved. Draft a postmortem.`,
              ``,
              `Incident: "${title}"`,
              `Service: ${service}`,
              `Urgency: ${urgency}`,
              `Created: ${createdAt}`,
              `Resolved: ${resolvedAt}`,
              `Incident URL: ${incidentUrl}`,
              ``,
              `Write a structured postmortem:`,
              `1. Use the Datadog MCP to pull logs and metrics for ${service} during the incident window`,
              `2. Identify the root cause — check for deploys, config changes, or upstream failures`,
              `3. Build a detailed timeline from first alert to resolution`,
              `4. List action items to prevent recurrence`,
              `5. Post the postmortem as a PR to our docs/postmortems/ directory`,
            ].join('\n'),
            tags: ['pagerduty-postmortem', `service:${service}`],
          }),
        });

        const { session_id } = await response.json();
        console.log(`Started postmortem session ${session_id} for: ${title}`);
        res.sendStatus(200);
      });

      app.listen(3000);
      ```

      Crea un [usuario de servicio](/es/api-reference/v3/overview) en **Settings > Service Users** de [app.devin.ai](https://app.devin.ai/?utm_source=docs\&utm_medium=use-case-gallery) con el permiso `ManageOrgSessions`. Copia el token de API que se muestra tras la creación y guárdalo como `DEVIN_API_KEY` en tu servicio puente. Configura `DEVIN_ORG_ID` con el ID de tu organización; para obtenerlo, llama a `GET https://api.devin.ai/v3/enterprise/organizations` con tu token. Configura `WEBHOOK_SECRET` con un secreto compartido que también configurarás en PagerDuty.
    </Step>

    <Step title="Configurar PagerDuty">
      1. En PagerDuty, ve a **Services > \[your service] > Integrations**
      2. Haz clic en **Add Integration** y selecciona **Generic Webhooks (v3)**
      3. Establece la **Webhook URL** como el endpoint de tu bridge (p. ej., `https://your-bridge.example.com/pagerduty-resolved`)
      4. En **Custom Headers**, agrega `X-Webhook-Secret` con el mismo valor que almacenaste como `WEBHOOK_SECRET`
      5. En **Event Subscription**, filtra por el tipo de evento `incident.resolved` para que el postmortem se active solo después de que se cierre el incidente

      <Note>
        También puedes suscribirte a `incident.acknowledged` si quieres que Devin empiece a recopilar datos mientras el incidente aún está en curso y luego finalice el postmortem cuando se resuelva.
      </Note>
    </Step>

    <Step title="Conectar MCPs de observabilidad (opcional)">
      Devin redacta mejores postmortems cuando puede acceder a tus datos de telemetría. Habilita uno o más MCP para que Devin pueda extraer datos reales del período del incidente:

      **Datadog MCP** — Ve a **Settings > Connections > MCP servers**, busca **Datadog**, haz clic en **Enable** e ingresa tus claves de API y de aplicación. Devin consultará registros, métricas, eventos de despliegue y el historial de monitores.

      **Sentry MCP** — Busca **Sentry** en el MCP Marketplace, haz clic en **Enable** y completa el flujo de OAuth. Devin extraerá detalles de errores, trazas de pila y etiquetas de versión.

      Una vez conectados, Devin correlaciona automáticamente la telemetría con la cronología del incidente para compilar un postmortem respaldado por evidencias. Obtén más información sobre [cómo conectar servidores MCP](/es/work-with-devin/mcp).
    </Step>

    <Step title="Qué genera Devin">
      Cuando se resuelve un incidente de PagerDuty, Devin analiza el periodo del incidente y redacta un postmortem estructurado:

      <PromptBlock>
        ```txt Generar postmortem del incidente theme={null}
        Se ha resuelto un incidente de PagerDuty. Redacta un postmortem.

        Incidente: "Agotamiento del pool de conexiones a la base de datos en orders-service"
        Servicio: orders-service
        Creado: 2026-02-10T14:32:00Z
        Resuelto: 2026-02-10T15:18:00Z

        Con los MCP de Datadog y Sentry:
        1. Obtén los registros y las métricas de orders-service entre las 14:00 y las 15:30 UTC
        2. Comprueba si hubo despliegues, cambios de configuración o fallos en servicios upstream durante ese periodo
        3. Elabora una cronología detallada desde la primera alerta hasta la resolución
        4. Identifica los factores que contribuyeron y la causa raíz
        5. Redacta acciones para evitar que vuelva a ocurrir
        6. Haz commit del postmortem como archivo Markdown en docs/postmortems/
        ```
      </PromptBlock>

      Ejemplo de postmortem que produce Devin:

      ```markdown theme={null}
      # Postmortem: Agotamiento del Pool de Conexiones de Base de Datos — orders-service
      **Fecha:** 2026-02-10 | **Duración:** 46 minutos | **Severidad:** P1

      ## Resumen
      orders-service experimentó agotamiento del pool de conexiones entre
      las 14:32 y las 15:18 UTC, causando errores 502 en aproximadamente el 12% de las
      solicitudes de creación de pedidos.

      ## Cronología
      - 14:15 UTC — Deploy #387 publicado (commit e4f29a1)
      - 14:28 UTC — El uso del pool de conexiones aumentó del 60% al 92%
      - 14:32 UTC — Pool agotado; incidente de PagerDuty activado
      - 14:38 UTC — Ingeniero de guardia notificado
      - 14:45 UTC — Se identificó que el Deploy #387 agregó una nueva verificación
                    de inventario que abre una conexión de BD por línea de pedido
                    sin liberarla en el bloque finally
      - 15:02 UTC — Reversión al Deploy #386 iniciada
      - 15:18 UTC — Pool de conexiones recuperado; incidente resuelto

      ## Causa Raíz
      El Deploy #387 introdujo `checkInventoryAvailability()` en
      `src/services/orders.ts:142`. La función abre una nueva conexión de BD
      por cada línea de pedido, pero solo la libera en la ruta de éxito.
      Cuando las verificaciones de inventario fallan (por tiempo de espera
      o falta de stock), las conexiones quedan en fuga.

      Los pedidos con 5 o más líneas agotaban el pool de forma consistente en
      15 minutos tras el deploy.

      ## Elementos de Acción
      - [ ] Corregir la fuga de conexiones: agregar bloque `finally` para liberar
            la conexión (PR #388 abierto)
      - [ ] Agregar monitor de uso del pool de conexiones con alerta al 80%
      - [ ] Agregar prueba de integración para pedidos con múltiples líneas con
            fallos de inventario simulados
      - [ ] Revisar otros patrones de acceso a BD en busca de fugas similares
      ```
    </Step>

    <Step title="Personaliza el postmortem">
      Adapta el pipeline al proceso de postmortem de tu equipo:

      **Usa un [Playbook](/es/product-guides/creating-playbooks)** para definir tu plantilla de postmortem: secciones, clasificación por gravedad, campos obligatorios y dónde almacenar el resultado. Pasa un `playbook_id` en la solicitud a la API para estandarizar cada postmortem.

      **Enruta por gravedad.** Agrega lógica en tu bridge para generar postmortems solo para incidentes P1/P2. Es posible que los incidentes de menor gravedad no requieran un informe completo.

      **Agrega [Knowledge](/es/product-guides/knowledge)** sobre tu arquitectura, los responsables de los servicios y los incidentes anteriores para que Devin pueda conectar los puntos; por ejemplo, "orders-service depende de inventory-service, que es conocido por problemas de tiempo de espera bajo carga."

      **Publica en tu wiki.** En lugar de hacer commit en un repo, haz que Devin publique el postmortem en Confluence, Notion o tu wiki interna mediante el prompt de la sesión.
    </Step>
  </Steps>
</div>
