Scitor + Linear
File a Linear issue straight from a customer bug report
When Scitor's AI triage labels an inbound ticket category:bug-report, a GitHub Actions workflow can call Linear's GraphQL API directly — creating an issue in your engineering backlog and posting its URL back to the support ticket. No manual copy-pasting between the support inbox and the engineering tracker.
What this workflow does
It fires on the category:bug-report label — but only when that label lands on a ticket Scitor's own bot opened, so a contributor can't trigger a Linear issue (and spend your API quota) by applying the label themselves — and calls Linear's GraphQL API (https://api.linear.app/graphql, issueCreate mutation) directly — no third-party marketplace action, just a fetch call with your API key. It comments the resulting Linear issue URL back onto the GitHub Issue.
What it does not do
Status doesn't sync back — closing the Linear issue does not close the GitHub ticket, or the reverse. The two are linked by a one-time comment, not a live sync. The Linear description also truncates the ticket body to 500 characters; the full ticket is one click away via the linked GitHub Issue. It also doesn't de-duplicate: removing and re-applying the label on the same ticket creates a second Linear issue, so treat the label as a one-shot trigger.
The workflow file
Save this as .github/workflows/bug-report-to-linear.yml in your Scitor-connected repository.
# Bug report → Linear
#
# Creates a Linear issue whenever Scitor's AI triage categorizes an inbound
# ticket as a bug report, and posts the Linear issue URL back to the ticket
# so both sides stay linked.
#
# What this does:
# - Fires when the `category:bug-report` label is applied.
# - Calls Linear's GraphQL API directly (issueCreate mutation) — no
# third-party marketplace action, just a fetch() call with your API key.
# - Comments the resulting Linear issue URL back onto the GitHub Issue.
#
# What this does NOT do:
# - It does not sync status back — closing the Linear issue does not close
# the GitHub ticket, and vice versa. They're linked by a one-time comment,
# not a live sync.
# - It truncates the ticket body to 500 characters in the Linear description;
# the full ticket is always one click away via the linked GitHub Issue URL.
# - It does not de-duplicate: removing and re-applying `category:bug-report`
# on the same ticket fires this again and creates a second Linear issue.
# Treat the label as a one-shot trigger, or add your own "does a Linear
# link already exist in this issue's comments" check before creating one.
#
# Required secrets:
# LINEAR_API_KEY — a Linear personal API key (Linear -> Settings -> API ->
# Create key). Sent as a raw `Authorization` header value, with no
# "Bearer " prefix — that's how Linear's own API expects a personal key.
# LINEAR_TEAM_ID — the Linear team ID issues should be created in (visible
# in the URL of your Linear team's settings page, or via the API/GraphQL
# explorer).
#
# Source: Scitor's own documented example at
# https://support.scitor.io/guides/github-actions#file-a-linear-issue-from-a-bug-report
# Endpoint (https://api.linear.app/graphql) and the no-Bearer-prefix
# Authorization header both cross-checked against Linear's own developer
# documentation, fetched 2026-09-17.
name: Bug report → Linear
on:
issues:
types: [labeled]
jobs:
linear:
if: >
github.event.label.name == 'category:bug-report' &&
github.event.issue.user.login == 'scitor-customerops[bot]'
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Create Linear issue
uses: actions/github-script@v7
with:
script: |
const description = [
`Customer bug report: ${context.payload.issue.html_url}`,
'',
context.payload.issue.body?.substring(0, 500) ?? '',
].join('\n');
const res = await fetch('https://api.linear.app/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// Linear's personal API keys are sent as-is, without a "Bearer " prefix.
'Authorization': process.env.LINEAR_API_KEY,
},
body: JSON.stringify({
query: `
mutation($title: String!, $desc: String!, $teamId: String!) {
issueCreate(input: { title: $title, description: $desc, teamId: $teamId }) {
issue { id url }
}
}
`,
variables: {
title: `[Customer] ${context.payload.issue.title}`,
desc: description,
teamId: process.env.LINEAR_TEAM_ID,
},
}),
});
const { data, errors } = await res.json();
if (errors) core.setFailed(`Linear API error: ${JSON.stringify(errors)}`);
const linearUrl = data?.issueCreate?.issue?.url;
if (linearUrl) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `🔗 Linear: ${linearUrl}`,
});
}
env:
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
LINEAR_TEAM_ID: ${{ secrets.LINEAR_TEAM_ID }} Required secrets
| Secret | Where to get it |
|---|---|
| LINEAR_API_KEY | Linear → Settings → API → Create key. Sent as a raw Authorization header value — Linear's own API expects personal keys without a "Bearer " prefix. |
| LINEAR_TEAM_ID | The Linear team issues should be created in — visible in your Linear team's settings URL, or via Linear's GraphQL API explorer. |
Questions about this integration
- Does this replace GitHub Issues with Linear for support?
- No. The support ticket stays a GitHub Issue — this workflow creates a linked Linear issue only when a ticket is categorized as a bug report, for teams that track engineering work in Linear rather than GitHub Issues/Projects. The two are linked by a one-time comment, not a live sync.
- Does the Linear issue update if the customer replies again?
- No, the example workflow only fires once, on the category:bug-report label. Anyone using the linked ticket for ongoing context follows the GitHub Issue link back to see new replies.
Connect the support ticket to the engineering task
Takes under 5 minutes. Free tier available. No credit card required.