IntegrationsIntegrations

How to Test Linear Webhooks Locally

What Webhooks Does Linear Send?

Linear sends webhooks for events across its project management platform. Key events include Issue (created, updated, removed), Comment (created, updated), Project (created, updated), Cycle (created, updated), Label (created, updated, removed), and IssueLabel changes. These are useful for building integrations that sync Linear data with other tools or trigger automations.

Linear webhook payloads include an action field (create, update, remove), a type field indicating the entity type, and a data object containing the entity details. For issue events, the data includes the title, description, state, priority, assignee, labels, project, and cycle information.

Linear signs webhooks with an HMAC-SHA256 signature in the Linear-Signature header using your webhook's signing secret. The signature is computed over the raw request body.

Setting Up Linear Webhooks

In Linear, go to Settings > API > Webhooks and click "New webhook." Enter your ReqPour URL as the webhook URL and optionally add a label for identification. Select which resource types you want to receive events for.

Linear also supports creating webhooks via the GraphQL API:

graphql
mutation {
  webhookCreate(input: {
    url: "https://abc123.reqpour.com/linear"
    resourceTypes: ["Issue", "Comment", "Project"]
    label: "Dev webhook"
  }) {
    success
    webhook {
      id
      enabled
    }
  }
}

Once created, make a change in Linear — create an issue, update a status, or add a comment — and the webhook arrives at your ReqPour endpoint within seconds.

Handling Linear Webhooks

Here is a handler that processes Linear webhook events:

javascript
const crypto = require('crypto');

app.post('/api/linear', express.json(), (req, res) => { // Verify signature const signature = req.headers['linear-signature']; const body = JSON.stringify(req.body); const expected = crypto .createHmac('sha256', process.env.LINEAR_WEBHOOK_SECRET) .update(body) .digest('hex');

if (signature !== expected) { return res.status(401).send('Invalid signature'); }

const { action, type, data } = req.body;

if (type === 'Issue') { if (action === 'create') { console.log(New issue: ${data.title} [${data.identifier}]); syncIssueToTracker(data); } else if (action === 'update') { if (data.state?.name === 'Done') { console.log(Issue completed: ${data.identifier}); notifyTeam(data); } } } else if (type === 'Comment' && action === 'create') { console.log(New comment on ${data.issue?.identifier}); }

res.status(200).send('OK'); }); ```

Linear webhooks fire for every change, including changes made by integrations. If your webhook handler updates Linear via the API, add logic to detect and skip changes you initiated to avoid infinite loops.

Building Linear Integrations with ReqPour

Common Linear integrations include syncing issues to external project trackers, triggering CI/CD pipelines when issues move to a "Ready for Deploy" state, posting updates to Slack or Discord, and creating reports based on cycle completion.

ReqPour is ideal for developing these integrations because you can see every event in real time, replay events to test edge cases, and iterate quickly without constantly creating test issues in Linear.

For example, to build a Slack notification when issues are completed, capture a few Issue update events in ReqPour where the state changes to "Done." Examine the payload structure, build your handler, then replay those events to verify the Slack messages are formatted correctly.

Linear Webhook Tips

Linear webhook payloads can be sparse — they include the changed fields and some context, but not always the complete entity. If you need fields that are not in the webhook payload, use the Linear API to fetch the full object using the ID from the webhook.

Linear retries failed webhook deliveries (non-2xx responses) with exponential backoff. After several consecutive failures, Linear disables the webhook. Monitor your handler's response codes in the ReqPour dashboard to catch failures early.

When filtering for specific state transitions (like "In Progress" to "Done"), compare the updated fields against the previous state. Linear includes updated fields in the webhook but does not always include a diff. The ReqPour dashboard helps you understand which fields are present in different event scenarios by letting you compare multiple webhook payloads side by side.

Get started with ReqPour

Catch, inspect, and relay webhooks to localhost. Free to start, $3/mo for Pro.