There's No REST API Here.
Linear's API has a single GraphQL endpoint rather than REST paths. The video covers UUIDs versus readable identifiers, the bare authorization header, why HTTP 200 can hide errors, and why rate limits return 400 instead of 429.
A common assumption is that Linear has a REST API with paths like /issues and /projects. The video explains that it does not: there is one GraphQL endpoint for everything. The rest of the video walks through what that means for anyone calling the Linear API with Claude, including the quirks that trip up people who are used to REST.
One endpoint, reads and writes alike
Linear's API has exactly one endpoint, a POST to api.linear.app/graphql. Reads are queries and writes are mutations, and everything goes through that same URL, never a REST-style path. The Authorization header is also different from what many people expect. The key goes in by itself, with no Bearer prefix.
Two ID systems side by side
Two kinds of ID live together in Linear. A UUID is what the API expects for every operation. A human-readable identifier such as ENG-123 works only when you are reading. If you pass an identifier where a mutation expects a UUID, you get an INVALID_INPUT error back. That makes it important to look up the UUIDs you need before you try to change anything.
HTTP 200 does not mean it worked
The video is emphatic that a 200 status does not prove success. GraphQL returns 200 for most errors, and the real failure sits in the response body under the errors field. A mutation's response also carries its own success field, separate from both the HTTP status and the errors field. That success field can be false even when the other two look fine, so it needs checking too.
Workflow patterns that keep it manageable
The video recommends a few habits:
- Start with the viewer query, a quick sanity check that confirms who you are authenticated as.
- Before creating or updating anything, look up the UUIDs you will need, such as a team's UUID for a new issue or a workflow state's UUID to move an issue along.
- Write description and comment text as plain Markdown.
- Remember that most connections do not return a total count. To know how many issues are on a team, paginate and count, or read an aggregate field instead.
The rate limit that returns 400, not 429
The point that catches people coming from REST is the rate limit. Linear does not return the usual 429. It returns HTTP 400 with an error code of RATELIMITED in the body, the same status you would get from a broken query. A retry loop written to watch for 429 never fires. When you read the reset time, it is in epoch milliseconds, not seconds, so you need to divide by a thousand or the wait comes out wrong.
Key takeaways
- Linear has a single GraphQL endpoint at api.linear.app/graphql, with queries for reads and mutations for writes.
- The Authorization header carries the key alone, with no Bearer prefix.
- UUIDs are required for every operation; identifiers like ENG-123 work only for reading.
- An HTTP 200 can still be a failure, so check the errors field in the body.
- Check the mutation's own success field as well.
- Begin with the viewer query and look up UUIDs before you mutate.
- Rate limiting arrives as HTTP 400 with the code RATELIMITED, and the reset time is in epoch milliseconds.
- Neither a 200 nor a 400 tells you the truth by itself.
Try it yourself
Paste a prompt into Claude asking it to show the GraphQL query that lists your open Linear issues and the mutation that moves one to In Progress, using real field names and IDs. For each one, ask what exactly you should check in the response to know it worked, beyond a 200 status, and what changes about that check if you have been rate limited. Try it on your own Linear workspace, or simply to see the shape of the calls.
Chapters
Full transcript(auto-generated, with timestamps)
The naive framing: "how do I call the Linear REST API?"
[0:00]Someone assumed Linear has a rest API endpoints like /issues, /projects. It doesn't. There's one GraphQL endpoint for everything. So, how do you actually call the Linear API with Claude?
One endpoint, two ID systems
[0:12]Linear's API has exactly one endpoint, post to API.linear.app/graphql. Reads are queries, writes are mutations, everything goes through that same URL, never a rest style path. Two ID systems live side by side, a UUID which the API expects for every operation, and a human-readable identifier like ENG-123, which only works when you're reading. Pass an identifier where mutation expects a UUID and you get back invalid input. The authorization header is different, too. The key goes in by itself with no bearer prefix, and an HTTP 200 doesn't mean it worked. GraphQL returns 200 for most errors with the real failure sitting in the body under dot errors. A few patterns keep this
Viewer first, then UUID
[0:52]Manageable. Start with the viewer query, a quick sanity check that confirms who you're authenticated as. Before creating or updating anything, look up the UUIDs you'll need. A team's UUID for a new issue, a workflow state's UUID to move one along. Description and comment text is just markdown, nothing fancier. And a mutation's response carries its own success field, separate from the HTTP status and separate from dot errors. Check that, too, because it can be false even when both of the others look fine. One more quirk, most connections don't return a total count. To know how many issues are on a team, you paginate and count, or read an aggregate field instead. Here's the one that catches
400, not 429
[1:28]People coming from rest. Linear's rate limit doesn't come back as the usual 429. It comes back as HTTP 400 with an error code of rate limited buried in the body, the exact same status you'd get from a broken query. A retry loop written to watch for 429 never fires, and when you do read the reset time, it's an epoch milliseconds, not seconds. Divide by a thousand, or the weight comes out wrong. There's one endpoint,
Carry-out
[1:53]Not many, and neither a 200 nor a 400 tells you the truth by itself. A 200 can still mean it failed and a 400 can just mean you're rate limited. Your turn.
Your turn
[2:04]Paste this into Claude. Show me the GraphQL query I'd send to list my open issues in Linear and the mutation to move one to in progress using real field names and ID. For each one, tell me exactly what I'd check in the response to know it actually worked, not just that the HTTP status came back 200. Then tell me what changes about that check if I've been rate limited. There's no REST
Outro
[2:24]API here. Lay 'em in for bare.





