> ## 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.

# Corrección automática de tickets vía webhooks

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="Corrección automática de tickets mediante webhooks" description="Conecta sistemas de tickets locales o no compatibles con Devin a través de un puente de webhook a sesión." prompt="Ayúdame a configurar un flujo de webhook a Devin para mi sistema de tickets. Sigue la guía en https://docs.devin.ai/use-cases/gallery/api-webhook-custom-ticketing y guíame paso a paso: crear un usuario de servicio, crear el controlador del webhook y configurar mi sistema de tickets para enviarle eventos." category="Automatizaciones" features="API, Playbooks" />

<div className="uc-detail-wrapper">
  <Tip>¿Prefieres no configurarlo manualmente? Pega un enlace a esta página en una sesión de Devin y pídele que lo configure todo por ti.</Tip>

  <Steps>
    <Step title="Crear un usuario de servicio">
      Devin usa [service user tokens](/es/api-reference/v3/overview) para autenticar las llamadas a la API. Este es el enfoque recomendado para la automatización en producción.

      1. Ve a [app.devin.ai](https://app.devin.ai/?utm_source=docs\&utm_medium=use-case-gallery) > **Settings** > **Service Users** y crea un nuevo usuario de servicio con el permiso `ManageOrgSessions`
      2. Copia el token de API que se muestra después de la creación y guárdalo de forma segura: solo se muestra una vez y lo usarás como `DEVIN_API_KEY` en tu handler de webhook

      Para encontrar el ID de tu organización, realiza una llamada `GET https://api.devin.ai/v3/enterprise/organizations` con tu token: la URL solo muestra el slug de la organización, no el ID.

      Pruébalo con un comando curl rápido:

      ```bash theme={null}
      curl -X POST https://api.devin.ai/v3/organizations/YOUR_ORG_ID/sessions \
        -H "Authorization: Bearer YOUR_API_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"prompt": "Say hello — this is a test session."}'
      ```

      Deberías obtener un `session_id` y una `url` como respuesta. Elimina la sesión de prueba en la aplicación web de Devin y pasa al siguiente paso.
    </Step>

    <Step title="Crea el controlador de webhooks">
      Este patrón es ideal para **sistemas de tickets on-premise** (como Jira autohospedado, Redmine o Bugzilla) o **herramientas de gestión de tickets que no tienen una integración nativa con Devin** (a diferencia de [Linear](/es/integrations/linear) y [Jira Cloud](/es/integrations/jira), que tienen soporte integrado). Si tu sistema de tickets admite webhooks, puedes conectarlo a Devin con un servicio ligero.

      Incluye un enlace a la documentación de la API de tu sistema de tickets en el prompt para que Devin pueda determinar cómo publicar comentarios de nuevo en los tickets. Pasa el token de la API de tickets como un [session secret](/es/api-reference/common-flows) para que Devin pueda autenticarse directamente.

      Pídele a Devin que genere el esqueleto:

      <PromptBlock>
        ```txt Webhook handler for custom ticketing theme={null}
        Crea un servicio Express.js que:
        1. Acepte POST /webhooks/tickets con un cuerpo JSON que contenga id, title,
           description y labels
        2. Verifique la firma del webhook usando HMAC-SHA256
        3. Omita los tickets que no tengan una etiqueta "devin-autofix" o "devin-feature"
        4. Llame a POST https://api.devin.ai/v3/organizations/{org_id}/sessions
           con un prompt creado a partir de los campos del ticket, un playbook_id
           basado en la etiqueta y el token de la API de tickets como session secret

        Lee DEVIN_API_KEY, DEVIN_ORG_ID, TICKET_API_TOKEN y WEBHOOK_SECRET
        de las variables de entorno.
        ```
      </PromptBlock>

      Así se ve el handler principal:

      ```javascript theme={null}
      const PLAYBOOKS = {
        'devin-autofix': 'playbook-a1b2c3d4e5f6',
        'devin-feature': 'playbook-f6e5d4c3b2a1',
      };

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

        const { id, title, description, labels } = req.body;
        const label = labels.find(l => PLAYBOOKS[l]);
        if (!label) return res.status(200).send('No Devin label — skipped');

        const orgId = process.env.DEVIN_ORG_ID;
        const { session_id } = 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: [
              `Ticket ${id}: ${title}`,
              description,
              `Reference ticket ${id} in your commit message.`,
              `When done, post a comment on ticket ${id} with a summary of your`,
              `changes and a link to the PR. Use the ticketing API at`,
              `https://your-ticketing-system.com/api/docs to post the comment.`,
              `Authenticate with the $TICKET_API_TOKEN environment variable.`,
            ].join('\n\n'),
            playbook_id: PLAYBOOKS[label],
            session_secrets: [
              { key: 'TICKET_API_TOKEN', value: process.env.TICKET_API_TOKEN },
            ],
          }),
        }).then(r => r.json());

        res.json({ session_id });
      });
      ```

      El mapa `PLAYBOOKS` enruta las etiquetas de los tickets a los [playbooks](/es/product-guides/creating-playbooks) que creas en **Settings > Playbooks**. Un playbook de corrección de errores podría decir: *«Añade siempre una prueba de regresión»*; un playbook de funcionalidades podría decir: *«Crea un PR de borrador y solicita revisión»*.

      El prompt incluye un enlace a la documentación de la API de tu sistema de tickets para que Devin sepa cómo publicar comentarios de vuelta. El `TICKET_API_TOKEN` se pasa como un [session secret](/es/api-reference/common-flows): se inyecta como una variable de entorno solo para esa sesión y nunca se almacena. Sustituye la URL de la documentación de la API por la documentación real de tu sistema de tickets.

      Despliega el handler en cualquier lugar que pueda recibir solicitudes HTTPS POST: una función en la nube (AWS Lambda, Google Cloud Functions), un contenedor o un VPS. Registra su URL como un webhook en la configuración de notificaciones o integraciones de tu sistema de tickets y configúralo para los eventos de **ticket created**.

      Crea un ticket de prueba con la etiqueta `devin-autofix` para verificar el ciclo completo: creación del ticket → se dispara el webhook → se inicia la sesión de Devin → se abre un PR → Devin publica un comentario en el ticket.
    </Step>
  </Steps>
</div>
