Skip to content

Linear Integration

Receive and route Linear webhooks for issues, projects, cycles, and team events.

Setup

1. Create a Source in Hookbase

bash
curl -X POST https://api.hookbase.app/api/sources \
  -H "Authorization: Bearer whr_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Linear Production",
    "slug": "linear",
    "verificationConfig": {
      "type": "hmac",
      "secret": "your-linear-webhook-secret",
      "algorithm": "sha256",
      "header": "Linear-Signature",
      "encoding": "hex"
    }
  }'

Save your webhook URL:

https://api.hookbase.app/ingest/{orgSlug}/linear

2. Configure Linear Webhook

  1. Go to Linear Settings → API → Webhooks
  2. Click New webhook
  3. Enter your Hookbase ingest URL
  4. Select the resource types you want to subscribe to
  5. Copy the Signing secret and update your Hookbase source
  6. Click Create webhook

3. Create Routes

bash
# Create destination for your issue handler
curl -X POST https://api.hookbase.app/api/destinations \
  -H "Authorization: Bearer whr_your_api_key" \
  -d '{"name": "Issue Tracker", "url": "https://api.myapp.com/webhooks/linear"}'

# Create route
curl -X POST https://api.hookbase.app/api/routes \
  -H "Authorization: Bearer whr_your_api_key" \
  -d '{"name": "Linear to Issue Tracker", "sourceId": "src_...", "destinationIds": ["dst_..."]}'

Signature Verification

Linear signs webhooks using HMAC-SHA256. The signature is sent in the Linear-Signature header as a hex-encoded digest of the raw request body.

Hookbase automatically verifies this when configured:

json
{
  "verificationConfig": {
    "type": "hmac",
    "secret": "your-linear-webhook-secret",
    "algorithm": "sha256",
    "header": "Linear-Signature",
    "encoding": "hex"
  }
}

Common Events

Issue Created

Triggered when a new issue is created.

json
{
  "action": "create",
  "type": "Issue",
  "createdAt": "2026-03-07T12:00:00.000Z",
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "title": "Fix login redirect on mobile",
    "description": "Users on iOS Safari are not redirected after login.",
    "priority": 2,
    "priorityLabel": "High",
    "state": {
      "id": "state-id",
      "name": "Todo",
      "type": "unstarted"
    },
    "team": {
      "id": "team-id",
      "key": "ENG",
      "name": "Engineering"
    },
    "assignee": {
      "id": "user-id",
      "name": "Jane Smith",
      "email": "[email protected]"
    },
    "labels": [
      { "id": "label-id", "name": "bug" }
    ],
    "number": 423,
    "identifier": "ENG-423",
    "url": "https://linear.app/myteam/issue/ENG-423"
  },
  "url": "https://linear.app/myteam/issue/ENG-423",
  "organizationId": "org-id"
}

Issue Updated

Triggered when an issue is modified (status change, assignment, priority, etc).

json
{
  "action": "update",
  "type": "Issue",
  "createdAt": "2026-03-07T12:05:00.000Z",
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "title": "Fix login redirect on mobile",
    "priority": 1,
    "priorityLabel": "Urgent",
    "state": {
      "id": "state-id",
      "name": "In Progress",
      "type": "started"
    },
    "identifier": "ENG-423"
  },
  "updatedFrom": {
    "priority": 2,
    "priorityLabel": "High",
    "updatedAt": "2026-03-07T12:00:00.000Z"
  },
  "organizationId": "org-id"
}

Comment Created

Triggered when a comment is added to an issue.

json
{
  "action": "create",
  "type": "Comment",
  "createdAt": "2026-03-07T12:10:00.000Z",
  "data": {
    "id": "comment-id",
    "body": "Reproduced on iOS 17.3 Safari. Looks like the OAuth callback URL is missing the state parameter.",
    "issue": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "identifier": "ENG-423",
      "title": "Fix login redirect on mobile"
    },
    "user": {
      "id": "user-id",
      "name": "Jane Smith"
    }
  },
  "organizationId": "org-id"
}

Transform Examples

Slack Alert for Urgent Issues

javascript
function transform(payload) {
  const issue = payload.data;
  const isUrgent = issue.priority <= 1;

  return {
    blocks: [
      {
        type: "header",
        text: {
          type: "plain_text",
          text: isUrgent ? "Urgent Issue Created" : "New Issue Created"
        }
      },
      {
        type: "section",
        fields: [
          {
            type: "mrkdwn",
            text: `*Issue:*\n<${issue.url}|${issue.identifier}: ${issue.title}>`
          },
          {
            type: "mrkdwn",
            text: `*Priority:*\n${issue.priorityLabel}`
          },
          {
            type: "mrkdwn",
            text: `*Team:*\n${issue.team.name}`
          },
          {
            type: "mrkdwn",
            text: `*Assignee:*\n${issue.assignee ? issue.assignee.name : 'Unassigned'}`
          }
        ]
      }
    ]
  };
}

Database Format

javascript
function transform(payload) {
  const data = payload.data;

  return {
    linear_id: data.id,
    action: payload.action,
    resource_type: payload.type,
    identifier: data.identifier,
    title: data.title,
    priority: data.priority,
    state: data.state ? data.state.name : null,
    team_key: data.team ? data.team.key : null,
    assignee_email: data.assignee ? data.assignee.email : null,
    labels: data.labels ? data.labels.map(l => l.name) : [],
    url: data.url || payload.url,
    created_at: payload.createdAt
  };
}

Filter Examples

Issue Events Only

json
{
  "name": "Issues Only",
  "logic": "and",
  "conditions": [
    {
      "field": "type",
      "operator": "equals",
      "value": "Issue"
    }
  ]
}

Urgent and High Priority

json
{
  "name": "Urgent & High Priority",
  "logic": "and",
  "conditions": [
    {
      "field": "type",
      "operator": "equals",
      "value": "Issue"
    },
    {
      "field": "data.priority",
      "operator": "less_than",
      "value": "3"
    }
  ]
}

Status Changes to Done

json
{
  "name": "Completed Issues",
  "logic": "and",
  "conditions": [
    {
      "field": "action",
      "operator": "equals",
      "value": "update"
    },
    {
      "field": "data.state.type",
      "operator": "equals",
      "value": "completed"
    }
  ]
}

Headers

Linear webhooks include these headers:

HeaderDescription
Linear-SignatureHMAC-SHA256 signature (hex)
Linear-EventResource type (e.g., Issue)
Linear-DeliveryUnique delivery ID
User-AgentLinear-Webhook
Content-Typeapplication/json

Troubleshooting

Signature Verification Failed

  1. Verify you're using the webhook signing secret, not your API key
  2. Ensure the secret matches the one shown in Linear's webhook settings
  3. Check that encoding is set to hex in your verification config

Missing Events

  1. Check which resource types are selected in Linear's webhook settings
  2. Verify filters aren't blocking expected events
  3. Check Linear's webhook delivery log for failed attempts

Duplicate Events

  1. Linear retries failed deliveries up to 10 times
  2. Use data.id + action as an idempotency key
  3. Check for multiple webhooks configured for the same workspace

Released under the MIT License.