Founding keys are opena year free at 6,000 req/hour, for the first 1,000 developersClaim yours
All comparisons

Prove it, in one terminal

The argument on the other comparison pages is that a specification gives you shapes and shapes are not data. This page is that argument as a script. Seven requests, run against a public spec-derived mock of GitHub and against a pinned SandboxAPIs host, with both sets of real output pasted below.

01 / What spec-derived mock are good at

Read this part first.

This page is not an argument that WireMock is bad. WireMock is an excellent tool, it is Apache-2.0, it has been maintained since 2011, and for defining the responses you want it is the right answer. Its GitHub template is also generated from GitHub's own OpenAPI description and covers far more paths than we serve.

It is an argument that an endpoint count and a data set are different products, and WireMock itself says so on the page: its shared sandbox returns simulated example data only, and the responses are fixed success cases. That sentence is easy to miss next to a figure like 1,222 endpoints, which is why this page exists.

Both columns below were captured by us on 16 September 2026, against the free public sandbox WireMock publishes and against our own pinned host. Every request is in the script. Run it and you should get what we got, because one side is frozen and the other is a fixed stub.

WireMock Cloud's GitHub template

A mock advertised at 1,222 endpoints and 1,275 stubs, with a free public sandbox anybody can call. Its own page states that it is not an official GitHub sandbox and that it returns simulated example data only; the sibling GitLab page adds that shared-sandbox responses are fixed success cases. Everything below is consistent with both sentences.

GitHub's own OpenAPI description

Version 1.1.4, which is what the template is generated from, and the reason its shapes are right. A specification defines what a field is called and what type it holds. It does not say who opened the pull request, so no tool generated from one can either.

The SandboxAPIs pin

gh-2026-03-g12.snap.sandboxapis.dev, a frozen snapshot host on the current data set. No key, no account, and byte-identical on every request, so the output printed below is the output you get when you run it.

02 / Side by side

8 dimensions, both columns honest.

Every cell below describes what each approach does by definition, not what any one product happens to ship this quarter. Our column says where we lose: we are read-only, we replicate a fixed set of services rather than every API, and a pinned host never changes while the live hosts re-roll every day. Check any vendor's own docs against the sources at the foot of this page.

DimensionSpec-derived mockSandboxAPIs
Endpoints coveredTheir winMore than us, and this is their row outright. The template advertises 1,222 endpoints and 1,275 stubs, generated from GitHub's published OpenAPI description version 1.1.4. If your measure is how many paths answer at all, it wins and we do not.Fewer paths, each carrying data. Our GitHub coverage is published endpoint by endpoint on the coverage manifest, and anything we do not serve returns GitHub's own 404 with a coverage header rather than a plausible empty object.
Does the repository you asked for come backNo. GET /repos/olympus-labs/parthenon answers with name "example-name" and full_name "octocat/Hello-World". The path parameters are not resolved, so every repository you ask for is the same repository.Our winYes. The same request answers with name "parthenon", full_name "olympus-labs/parthenon", owner "olympus-labs".
Are there any pull requests in itNo. GET /repos/{owner}/{repo}/pulls returns an empty array, on every call we made. A client that lists and then walks finds nothing to walk.Our winFive on the first page, the first being number 85, "Support graceful upstream draining in the API gateway", opened by jason.
Does a listed issue have a title and an authorThe issues list answers, and its first entry has the literal title "example issue" with user null. A triage rule reading that list has nothing to triage on.Our winIssue 85 carries the same title as the pull request that addresses it, and user "jason", who is a person you can fetch.
Is an organization lookup an organizationPartly. The type field does say "Organization", but the login is "octocat", which is a user, and the url on the object points at /orgs/github. The node_id is the same base64 string on repositories, organizations and commits alike, and it decodes to a user id.Our winlogin "olympus-labs", type "Organization", and a node_id that decodes to this entity rather than to a user.
Is a commit SHA a commit SHANo, and this is the clearest single result on the page. The first commit's sha is 42 characters long; a git SHA is 40. The object's own url names a different SHA entirely, commit.author is an empty object, and parents is an empty array.Our win40 hexadecimal characters, the object's url names that same SHA, commit.author carries a name, an email and a date, and parents names the commit before it.
Does an author resolve to the right userNo. GET /users/jason returns login "octocat", company "GitHub". It answers, which is the point of a stub, but it answers with somebody else, so following a reference goes nowhere you asked to go.Our winGET /users/jason returns jason, company "@olympus-labs", which is the same person the pull request and the issue name. Every reference resolves the same way.
Are the headers the vendor's headersNo. A listing returns matched-stub-name, plus vary and content-type. There is no link header, no x-github-api-version and no x-ratelimit family, so a client that paginates or backs off has nothing to read.Our winA link header carrying rel="next", rel="first" and rel="last", plus x-github-api-version, x-github-media-type, x-github-request-id and the full x-ratelimit set.

03 / Run it yourself

The difference, as a command.

Seven requests against each host, no key and no account on either side, and nothing that writes. Paste the whole thing. The output underneath is exactly what this script printed for us on 16 September 2026, unedited.

prove-it.sh
WM=https://1k3k3.wiremockapi.cloud              # WireMock Cloud's public GitHub template
SB=https://gh-2026-03-g12.snap.sandboxapis.dev  # a frozen SandboxAPIs pin

for HOST in "$WM" "$SB"; do
  echo "== $HOST"
  # 1. the repository you actually asked for
  curl -s "$HOST/repos/olympus-labs/parthenon" | jq -c '{name, full_name, owner: .owner.login}'
  # 2. is there anything in it
  curl -s "$HOST/repos/olympus-labs/parthenon/pulls" | jq -c 'length'
  # 3. does a listed issue have a title and an author
  curl -s "$HOST/repos/olympus-labs/parthenon/issues" | jq -c '.[0] | {number, title, user: .user.login}'
  # 4. is an organization lookup an organization
  curl -s "$HOST/orgs/olympus-labs" | jq -c '{login, type}'
  # 5. is a commit SHA a commit SHA
  curl -s "$HOST/repos/olympus-labs/parthenon/commits" \
    | jq -c '.[0] | {sha_len: (.sha|length), sha, url_sha: (.url|split("/")|last), author: .commit.author}'
  # 6. does an author resolve to the person you asked for
  curl -s "$HOST/users/jason" | jq -c '{login, company}'
  # 7. are the headers the vendor's headers
  curl -s -D - -o /dev/null "$HOST/repos/olympus-labs/parthenon/issues?per_page=2" \
    | grep -iE '^(link|x-ratelimit-limit|x-github-api-version|matched-stub-name)' | tr -d '\r'
  echo
done
what it prints
== https://1k3k3.wiremockapi.cloud
{"name":"example-name","full_name":"octocat/Hello-World","owner":"octocat"}
0
{"number":1406266365,"title":"example issue","user":null}
{"login":"octocat","type":"Organization"}
{"sha_len":42,"sha":"abc123def456abc123def456abc123def456abc123","url_sha":"6dcb09b5b57875f334f61aebed695e2e4193db5e","author":{}}
{"login":"octocat","company":"GitHub"}
matched-stub-name: List repository issues

== https://gh-2026-03-g12.snap.sandboxapis.dev
{"name":"parthenon","full_name":"olympus-labs/parthenon","owner":"olympus-labs"}
5
{"number":85,"title":"Support graceful upstream draining in the API gateway","user":"jason"}
{"login":"olympus-labs","type":"Organization"}
{"sha_len":40,"sha":"6da56bead49874592a691b7a22eee0b59d3b72c3","url_sha":"6da56bead49874592a691b7a22eee0b59d3b72c3","author":{"name":"Athena","email":"athena@users.noreply.sandboxapis.dev","date":"2026-07-25T16:06:09Z"}}
{"login":"jason","company":"@olympus-labs"}
link: <https://gh-2026-03-g12.snap.sandboxapis.dev/repos/olympus-labs/parthenon/issues?per_page=2&page=2>; rel="next", <https://gh-2026-03-g12.snap.sandboxapis.dev/repos/olympus-labs/parthenon/issues?per_page=2&page=1>; rel="first", <https://gh-2026-03-g12.snap.sandboxapis.dev/repos/olympus-labs/parthenon/issues?per_page=2&page=20>; rel="last"
x-github-api-version: 2026-03-10
x-ratelimit-limit: 60

Read the two blocks as one sentence: the left-hand host answers every request and knows nothing, and the right-hand host answers every request and knows who jason is. Both are legitimate products, and WireMock's own page says which one it is. Only the right-hand column supports a test that asserts on a value, follows a reference, or paginates.

That host is a pinned snapshot, so those bytes are the bytes you get next year too. The live hosts re-roll daily with new activity, which is the right choice for a demo and the wrong one for an assertion. See versioning and pinning.

04 / Picking one

Which should you actually use?

When to choose the other thing

Choose the spec-derived mock

  • You need a path we do not serve, and an empty but correctly shaped answer is enough to unblock you.
  • You are checking that your client can parse a response, not that it can reason about one.
  • You want to define the response yourself, which is what the paid product is actually for and what it does well.
  • You need a write to return a success, and whether it persists does not matter to the test.
  • The API is not GitHub, and not one of the services we replicate.

When to choose SandboxAPIs

Choose SandboxAPIs

  • Your test asserts on a value, not only on a shape.
  • Your code walks a list, follows a reference, or paginates.
  • You read rate-limit headers, or back off on them.
  • You want a write refused loudly rather than accepted quietly.
  • You are giving an agent a world to reason about, and an empty array is not one.

Two minutes, no signup

Run the commands, then decide.

Read the quickstart See the coverage manifest

05 / Sources

Every claim about somebody else, with the page it came from.

7 sources, each read on the date beside it. If one of these pages has changed since and a cell above is now wrong, that is a bug in this page: tell us and we will fix it.

The other comparisons.