Documentation 40
Guide · Linear
How do I test a Linear integration without a real workspace?
You do not need one. Point your client at a read-only Linear replica that already holds the olympus-labs data set, and your code runs unchanged.
01 / The one change
Swap the base URL. Nothing else.
Your client talks to api.linear.app. Point it at linear.sandboxapis.dev instead: same paths, same JSON, same headers, same status codes. No workspace to create, no seed script.
For CI, use a pinned host. This page uses linear-2026-08-g12.snap.sandboxapis.dev, the newest pin for Linear, which answers the same bytes on every run, so an assertion written today still holds next month.
The live host, linear.sandboxapis.dev, re-rolls daily and can carry a newer generation of the data set than linear-2026-08-g12.snap.sandboxapis.dev; every answer on this page is for linear-2026-08-g12.snap.sandboxapis.dev.
02 / Run it now
One request, no account.
curl -X POST "https://linear-2026-08-g12.snap.sandboxapis.dev/graphql" -H 'content-type: application/json' -d '{"query":"{ rateLimitStatus { kind } }"}'It answers with Linear's own data envelope with the kind of key you sent: the smallest read in the schema, and proof the client is wired.
With a real client, the verified quickstart for fetch (Node built-in) runs against the live host on every check. It prints every team key and name, then three Argonauts issues with their workflow states. For CI, change its base URL to https://linear-2026-08-g12.snap.sandboxapis.dev.
const api = async (query, variables) => {
const res = await fetch("https://linear.sandboxapis.dev/graphql", {
method: "POST",
headers: { "content-type": "application/json", authorization: "any-token" },
body: JSON.stringify({ query, variables }),
});
const { data, errors } = await res.json();
if (!res.ok || errors) throw new Error(res.status + " " + JSON.stringify(errors));
return data;
};
const { teams } = await api("{ teams(first: 10) { nodes { key name } } }");
const { issues } = await api(
`query($key: String!) {
issues(filter: { team: { key: { eq: $key } } }, first: 3) {
nodes { identifier title state { name } }
}
}`,
{ key: "ARGO" },
);
console.log("teams:", teams.nodes.map((t) => t.key + " " + t.name).join(", "));
for (const i of issues.nodes) console.log(i.identifier, i.title, "[" + i.state.name + "]");
What it prints always contains ARGO Argonauts, ORCL Oracles and ARGO-.
03 / Writes
A write gets Linear's own error shape.
Every host is read-only. Linear's API is GraphQL only, so a write is a mutation, and it answers 200 with data set to null and the refusal in errors, naming what you tried, so your client's existing error handling meets a shape it knows.
curl -s -X POST "https://linear-2026-08-g12.snap.sandboxapis.dev/graphql" -H 'content-type: application/json' -d '{"query":"mutation { issueCreate(input: { title: \"test\", teamId: \"ARGO\" }) { success } }"}'
{"data":null,"errors":[{"message":"This universe is read-only. See what's covered at https://sandboxapis.dev/coverage. (You tried to run the mutation(s): issueCreate.) Tell us what you needed to write: https://sandboxapis.dev/feedback","extensions":{"code":"FORBIDDEN","readOnlySandbox":true,"roadmapUrl":"https://sandboxapis.dev/coverage","feedbackUrl":"https://sandboxapis.dev/feedback"}}]}04 / Where it stops
Coverage is counted, not claimed.
16 of 17 Linear read surfaces are served and verified against Linear's own published spec. A query for a field that is not covered returns an explicit coverage error in errors, never a silent null. The row-by-row list is on the Linear reference and the coverage page.
Next: read the Linear quickstart, or run the four-hop walk to watch one incident cross four services.
What this is not
Read this before you rely on it.
SandboxAPIs is read-only: a write returns the provider's own error unless your key has opted in to scratch writes, and those never reach anybody else. Coverage is bounded, and the manifest that says exactly where it stops is public. The data is a simulated company, not yours and not a copy of anybody's. And it reproduces what each vendor documents and publishes, not the vendor's undocumented behaviour, so keep one test against the real service for that.