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}/linear2. Configure Linear Webhook
- Go to Linear Settings → API → Webhooks
- Click New webhook
- Enter your Hookbase ingest URL
- Select the resource types you want to subscribe to
- Copy the Signing secret and update your Hookbase source
- 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:
| Header | Description |
|---|---|
Linear-Signature | HMAC-SHA256 signature (hex) |
Linear-Event | Resource type (e.g., Issue) |
Linear-Delivery | Unique delivery ID |
User-Agent | Linear-Webhook |
Content-Type | application/json |
Troubleshooting
Signature Verification Failed
- Verify you're using the webhook signing secret, not your API key
- Ensure the secret matches the one shown in Linear's webhook settings
- Check that
encodingis set tohexin your verification config
Missing Events
- Check which resource types are selected in Linear's webhook settings
- Verify filters aren't blocking expected events
- Check Linear's webhook delivery log for failed attempts
Duplicate Events
- Linear retries failed deliveries up to 10 times
- Use
data.id+actionas an idempotency key - Check for multiple webhooks configured for the same workspace