Learning & reference
A free mock API for testing AI agents and tool calls
An agent is only as reliable as what it does when a tool call goes wrong. This is a deterministic REST
API you can point an agent at, plus endpoints that fail on purpose, reproducibly, so a failure in your
evaluation means the agent failed and not the network. Free, no sign-up, nothing stored. Base URL:
https://gen.hexaqa.com
The data your agent reads
Three collections that return the same records on every call, so a test that passes today passes tomorrow.
| Endpoint | Returns | Use it to test |
|---|---|---|
/api/users | 250 users | Lookups and joins. Emails use example.test and phones use 555-01xx, so nothing reaches a real person. |
/api/products | 500 products | Numeric reasoning, filtering and sorting on price, stock and rating. |
/api/posts | 1000 posts | Search and summarisation over a larger collection. |
/api/users/42 | One record | A single-entity tool call. An id out of range returns a JSON 404 naming the valid range. |
Pagination, the tool call agents get wrong most
An agent that reads page one and answers as if it had read everything is the most common silent failure in tool use.
/api/products?page=2&limit=50 returns the page in the body and also sends a
Link header with next, prev, first and
last, plus X-Total-Count: 500. So you can check two things: does the agent
follow next until it runs out, and does it stop, rather than looping on the last page.
A good question to ask it
"How many products are in stock?" The answer needs every page. An agent that reads one page and extrapolates will give a confident wrong number.
Sort and filter
?sort=-price sorts descending on any field.
?q=cache is a case-insensitive substring filter. Check the agent uses them instead of
fetching everything and filtering in its own context.
A filter that matches nothing
Ask for something absent. A good agent says so. A weak one invents a plausible record, which is the failure worth catching.
Failures on demand
The part a real API will not give you when you need it. Each route below reproduces one failure, every time you call it.
| Endpoint | What happens | What a good agent does |
|---|---|---|
/flaky?rate=30 | Fails about 30% of calls with 503 and Retry-After | Retries with backoff, honours Retry-After, gives up after a bound. |
/flaky?rate=50&seed=7 | The same outcome on every call | Lets you assert on it. See the note below. |
/status/429 | Too many requests | Slows down. Does not hammer the endpoint. |
/status/500 | A server error | Reports failure instead of claiming success. |
/delay?ms=5000 | Nothing until 5 seconds pass | Hits a connect or read timeout rather than waiting indefinitely. |
/slow?size=10mb&bps=50000 | First byte at once, then a trickle | Enforces a total deadline. A per-read timeout never fires here. |
/truncate?size=10mb | Declares a length, then closes at half | Notices the body is short instead of parsing half a response. |
/jitter?min=100&max=3000 | A random delay in the range | Behaves the same whatever the latency. |
/api/users?delay=2000 | Real data, held for 2 seconds | Exposes whether the agent waits or gives up and guesses. |
About the seed: it makes the outcome reproducible, which is what an assertion needs.
It does not play back a scripted sequence of failures and then a success. To test a retry that
eventually works, point the first call at a seed that fails and the next at one that succeeds, or use
/status/503 then a normal endpoint.
What to score
The pass and fail conditions are mechanical, so no model has to judge them.
Did it finish honestly?
After a failure it cannot recover from, the agent should say the task failed. Reporting success is the most expensive bug here, because nobody checks.
Did it stay bounded?
Count the calls. A retry loop with no ceiling against
/flaky?rate=100 is a runaway bill in production.
Did it read everything it claimed to?
Compare what it reports against
X-Total-Count. That header is the answer key.
Honest limits
This API is read-mostly and stateless. POST /api/users returns 201 and echoes your body,
and PUT, PATCH and DELETE return success codes, but nothing is stored, so a write followed by a read
will not show your change. That is fine for testing how an agent handles responses, and wrong for
testing whether it verifies its own writes. There is no authentication beyond /bearer and
/basic-auth, which only check that a credential was sent.
Questions
Is there a free mock API for testing AI agents?
Yes. gen.hexaqa.com serves deterministic collections at /api/users, /api/products and /api/posts, plus endpoints that fail on purpose. Nothing is stored, there is no sign-up, and the same request always returns the same data.
How do I make a flaky failure reproducible?
Add a seed: /flaky?rate=50&seed=7 returns the same outcome on every call. A seed pins one outcome, it does not replay a sequence, so for a retry that eventually succeeds use two different seeds.
Why not test against the real API?
A real API rarely fails on cue, charges for calls, and returns changing data, so a run against it is neither repeatable nor able to exercise the failure paths.
What should an agent do on a 503?
Honour Retry-After, back off, retry a bounded number of times, then report failure. Never retry forever, never in a tight loop, never report success.
What is the difference between /delay and /slow?
/delay holds the first byte, which a read timeout catches. /slow sends the first byte then trickles, which only a total deadline catches.
Keep going
Open the generator Synthetic data for AI evals → Status codes →
More from Learning
Guides and references for test data, file handling and AI evals. All free, no sign-up. See the full hub.