Documentation 29
GitHub quickstart · 3 min read
Keep Octokit. Change one line.
Everything you need for your first call is on this screen. No account creation, no seed data, no mock server to maintain.
Coverage, hosts and pinned snapshots for GitHub — 327 of 650 read surfaces served and verified.
01 / Base URL
One host, provider paths.
Point your GitHub client at https://gh.sandboxapis.dev. Paths, JSON, headers, and status codes mirror api.github.com.
curl https://gh.sandboxapis.dev/repos/olympus-labs/parthenon02 / Drop in your client
Octokit works unmodified.
The only change is the base URL — Octokit and everything built on it work as-is.
import { Octokit } from "@octokit/rest";
const octokit = new Octokit({ baseUrl: "https://gh.sandboxapis.dev" });
const { data } = await octokit.repos.get({ owner: "olympus-labs", repo: "parthenon" });
console.log(data.full_name); // "olympus-labs/parthenon"
const pulls = await octokit.pulls.list({ owner: "olympus-labs", repo: "parthenon", state: "all" });Two clients on this host are proved end to end rather than described: @octokit/rest and the gh CLI, whose exact snippets a script executes against https://gh.sandboxapis.dev and checks the output of. Verified quickstarts →
03 / Conditional requests
A 304, and what it actually costs.
Reads carry an ETag. Send it back as If-None-Match and an unchanged resource answers 304 Not Modified with an empty body — smaller and faster, exactly as on real GitHub. It is also free of charge whenever our CDN answers it from its shared cache, which covers the anonymous reads of this host below. A request carrying your key returns private, never reaches that shared cache, and spends a unit even when the answer is a 304 — why, in full.
# 1 — read the validator off a normal response
curl -sD- -o /dev/null https://gh.sandboxapis.dev/repos/olympus-labs/parthenon | grep -i '^etag:'
# etag: W/"153b66fcd19c7efe…"
# 2 — send it back: 304, empty body (anonymous here, so the CDN answers it free)
curl -i -H 'If-None-Match: W/"153b66fcd19c7efe…"' \
https://gh.sandboxapis.dev/repos/olympus-labs/parthenonOctokit rejects on a 304 rather than resolving, so catch it — the error carries status: 304:
const first = await octokit.repos.get({ owner: "olympus-labs", repo: "parthenon" });
const etag = first.headers.etag;
try {
const next = await octokit.repos.get({
owner: "olympus-labs",
repo: "parthenon",
headers: { "if-none-match": etag },
});
// changed — use next.data
} catch (err) {
if (err.status === 304) {
// unchanged — nothing to re-download
} else throw err;
}ETag is served wherever the real provider serves one: GitHub, GitLab and Azure DevOps use weak validators (W/"…"), Bitbucket uses strong ones. Providers whose real APIs send no validator — Jira, Linear, and the AI-tool hosts — send none here either.
04 / A real response
Live from the universe.
Every reference below — owner, branches, commits — resolves to a fetchable object.
{
"id": 273073411,
"node_id": "UmVwb3NpdG9yeToyNzMwNzM0MTE",
"name": "parthenon",
"full_name": "olympus-labs/parthenon",
"owner": {
"login": "olympus-labs",
"id": 674901807,
"node_id": "T3JnYW5pemF0aW9uOjY3NDkwMTgwNw",
"avatar_url": "https://gh.sandboxapis.dev/avatars/u/674901807?v=4",
"gravatar_id": "",
"url": "https://gh.sandboxapis.dev/users/olympus-labs",
"html_url": "https://gh.sandboxapis.dev/olympus-labs",
"followers_url": "https://gh.sandboxapis.dev/users/olympus-labs/followers",
"following_url": "https://gh.sandboxapis.dev/users/olympus-labs/following{/other_user}",
"gists_url": "https://gh.sandboxapis.dev/users/olympus-labs/gists{/gist_id}",
"starred_url": "https://gh.sandboxapis.dev/users/olympus-labs/starred{/owner}{/repo}",
"subscriptions_url": "https://gh.sandboxapis.dev/users/olympus-labs/subscriptions",
"organizations_url": "https://gh.sandboxapis.dev/users/olympus-labs/orgs",
"repos_url": "https://gh.sandboxapis.dev/users/olympus-labs/repos",
"events_url": "https://gh.sandboxapis.dev/users/olympus-labs/events{/privacy}",
"received_events_url": "https://gh.sandboxapis.dev/users/olympus-labs/received_events",
"type": "Organization",
"site_admin": false
},
"private": true,
"description": "Monorepo for the Olympus Labs developer platform — the temple everything is built on.",
"fork": false,
"url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon",
"html_url": "https://gh.sandboxapis.dev/olympus-labs/parthenon",
"archive_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/{archive_format}{/ref}",
"assignees_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/assignees{/user}",
"blobs_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/git/blobs{/sha}",
"branches_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/branches{/branch}",
"collaborators_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/collaborators{/collaborator}",
"comments_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/comments{/number}",
"commits_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/commits{/sha}",
"compare_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/compare/{base}...{head}",
"contents_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/contents/{+path}",
"contributors_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/contributors",
"deployments_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/deployments",
"downloads_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/downloads",
"events_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/events",
"forks_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/forks",
"git_commits_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/git/commits{/sha}",
"git_refs_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/git/refs{/sha}",
"git_tags_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/git/tags{/sha}",
"git_url": "git://gh.sandboxapis.dev/olympus-labs/parthenon.git",
"hooks_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/hooks",
"issue_comment_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/issues/comments{/number}",
"issue_events_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/issues/events{/number}",
"issues_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/issues{/number}",
"keys_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/keys{/key_id}",
"labels_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/labels{/name}",
"languages_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/languages",
"merges_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/merges",
"milestones_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/milestones{/number}",
"notifications_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/notifications{?since,all,participating}",
"pulls_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/pulls{/number}",
"releases_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/releases{/id}",
"ssh_url": "git@gh.sandboxapis.dev:olympus-labs/parthenon.git",
"stargazers_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/stargazers",
"statuses_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/statuses/{sha}",
"subscribers_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/subscribers",
"subscription_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/subscription",
"tags_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/tags",
"teams_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/teams",
"trees_url": "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/git/trees{/sha}",
"clone_url": "https://gh.sandboxapis.dev/olympus-labs/parthenon.git",
"svn_url": "https://gh.sandboxapis.dev/olympus-labs/parthenon",
"homepage": null,
"language": "TypeScript",
"forks_count": 0,
"forks": 0,
"stargazers_count": 0,
"watchers_count": 0,
"watchers": 0,
"size": 4096,
"default_branch": "main",
"open_issues_count": 37,
"open_issues": 37,
"is_template": false,
"topics": [
"developer-tools",
"platform",
"typescript",
"monorepo"
],
"has_issues": true,
"has_projects": true,
"has_wiki": false,
"has_pages": false,
"has_downloads": true,
"has_discussions": false,
"archived": false,
"disabled": false,
"visibility": "private",
"mirror_url": null,
"license": {
"key": "mit",
"name": "MIT License",
"spdx_id": "MIT",
"url": "https://gh.sandboxapis.dev/licenses/mit",
"node_id": "MDc6TGljZW5zZTEz"
},
"allow_forking": true,
"web_commit_signoff_required": false,
"pushed_at": "2026-04-26T17:20:00Z",
"created_at": "2026-04-26T17:20:00Z",
"updated_at": "2026-04-26T17:20:00Z",
"network_count": 0,
"subscribers_count": 0
}05 / Repository files
The repo has real files.
Repositories carry actual source — a README, a package.json, TypeScript modules, workflow YAML — served through GitHub's own file endpoints. The tree evolves with history: a file at an older commit is that file as it was.
# the README, base64 like the real API
curl https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/readme
# a directory listing, then a single file
curl https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/contents/src
curl "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/contents/README.md?ref=main"
# the whole tree, and a blob by its sha
curl "https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/git/trees/HEAD?recursive=1"The SHAs are real git object hashes: run git hash-object over the bytes you download and you get back the sha the API advertised. The same file, byte for byte, is served by GitLab's repository/files and Bitbucket's src — one canonical repository, three dialects.
06 / Clone the repo
git clone works.
The repositories are real remotes over git smart-HTTP, served from the same host as the API. There is no separate git hostname, so the clone URL your API base URL implies is the one that works — which is what makes tools that discover files by cloning drop in on a single env-var swap.
git clone https://gh.sandboxapis.dev/olympus-labs/parthenon.git
cd parthenon
git log --oneline -3
git fsck --full # exits clean: a real object graph, not a stub
# the SHAs are the API's SHAs — one repository, two dialects
HEAD_SHA=$(git rev-parse HEAD)
curl -s https://gh.sandboxapis.dev/repos/olympus-labs/parthenon/commits/$HEAD_SHA
# shallow clones work too
git clone --depth 1 https://gh.sandboxapis.dev/olympus-labs/parthenon.git shallowSupported: full and shallow clones (--depth, then fetch --deepen/--unshallow), git ls-remote, incremental git fetch, and the .git suffix with or without. Not supported: git push — this universe is read-only, so it answers 403 like every other write — partial clone (--filter=blob:none; git falls back to a full clone), protocol v2 (we speak v0 and every modern client downgrades silently), git archive, and the dumb HTTP protocol.
07 / Pin a snapshot
Deterministic CI.
Same env-var swap, a *.snap. host — the universe regenerates byte-identically on every request, so pinned tests never drift.
# reproducible in CI
export GITHUB_API_URL=https://gh-2026-03.snap.sandboxapis.devPins also preserve what GitHub has since removed: the original Copilot metrics endpoint (GET /orgs/{org}/copilot/metrics, retired upstream 2026-04-02) still answers on gh pins frozen before the closure, while the live host's 404 points you at its replacement, the Copilot metrics-reports family.
Tour the universe → · Coverage manifest → · Versioning & pinning →