Skip to main content

Auto-Fix Tickets via Webhooks

Connect on-prem or unsupported ticketing systems to Devin with a webhook-to-session bridge.
AuthorCognition
CategoryAutomations
FeaturesAPI, Playbooks
1

Create a service user

Devin uses service user tokens to authenticate API calls. This is the recommended approach for production automation.
  1. Go to app.devin.ai > Settings > Service Users and create a new service user with the ManageOrgSessions permission
  2. Copy the API token shown after creation and store it securely — it’s only displayed once and you’ll use it as DEVIN_API_KEY in your webhook handler
To find your organization ID, call GET https://api.devin.ai/v3/enterprise/organizations with your token — the URL only shows the org slug, not the ID.Test it with a quick curl:
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."}'
You should get back a session_id and url. Delete the test session in the Devin web app and move on.
2

Build the webhook handler

This pattern is ideal for on-prem ticketing systems (like self-hosted Jira, Redmine, or Bugzilla) or ticketing tools that don’t have a native Devin integration (unlike Linear and Jira Cloud, which have built-in support). If your ticketing system supports webhooks, you can bridge it to Devin with a small service.Include a link to your ticketing system’s API documentation in the prompt so Devin can figure out how to post comments back to tickets. Pass the ticketing API token as a session secret so Devin can authenticate directly.Ask Devin to scaffold it:Here’s what the core handler looks like:
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 });
});
The PLAYBOOKS map routes ticket labels to playbooks you create in Settings > Playbooks. A bug-fix playbook might say “Always add a regression test”; a feature playbook might say “Create a draft PR and request review.”The prompt includes a link to your ticketing system’s API docs so Devin knows how to post comments back. The TICKET_API_TOKEN is passed as a session secret — it’s injected as an environment variable for that session only and never stored. Replace the API docs URL with your actual ticketing system’s documentation.Deploy the handler anywhere that can receive HTTPS POST requests — a cloud function (AWS Lambda, Google Cloud Functions), a container, or a VPS. Register its URL as a webhook in your ticketing system’s notification or integration settings, and filter for ticket created events.Create a test ticket with the devin-autofix label to verify the full loop: ticket created → webhook fires → Devin session starts → PR opened → Devin posts a comment on the ticket.