httptest answers HTTP requests the way httpbin.org does. Point a client or a CI job at it when you need an endpoint that reflects your request back, forces a status code, stalls before responding, or hands you junk bytes.
It exists because httpbin.org has a habit of being down, and a test service you can't reach fails your build for reasons that have nothing to do with your code.
The base URL is https://hypothesis.sh/api/httptest, and every endpoint hangs off that prefix. Switching over is a find-and-replace:
- curl https://httpbin.org/get
+ curl https://hypothesis.sh/api/httptest/getCORS is open to any origin, so browser clients work without a proxy. Every response sets Cache-Control: no-store, since a cached answer would defeat the point.
| Endpoint | Behavior |
|---|---|
/get, /post, /put, /patch, /delete | Reflects args, headers, origin, and the body's parsed views |
/anything/* | The same reflection on any path and any method, so it never 405s |
/headers, /ip, /user-agent | One piece of the request each |
/status/:codes | Returns the code you name. A comma-separated list picks one at random |
/delay/:n | Responds after n seconds, up to 10 |
/bytes/:n | n random bytes, up to 100 KB |
/stream/:n | n newline-delimited JSON objects, up to 100 |
/redirect/:n | n hops of 302 before landing on /get, up to 10 |
/basic-auth/:user/:passwd, /bearer | 401 challenges you can satisfy |
/response-headers | Echoes query params back as real response headers |
/cookies, /cookies/set, /cookies/delete | Reads and writes cookies |
/json, /html, /xml, /uuid | Sample documents, plus a fresh UUID per call |
Sizes and durations clamp rather than error, matching httpbin. Status codes don't: /status/999 returns a 400, because answering with a code you never asked for is worse than refusing.
Prove your client's timeout fires:
curl --max-time 1 https://hypothesis.sh/api/httptest/delay/5
# curl: (28) Operation timed out after 1000 millisecondsPoint retry logic at an endpoint that fails about a third of the time:
curl -o /dev/null -w '%{http_code}\n' \
https://hypothesis.sh/api/httptest/status/200,200,500The /httptest page lists every endpoint and fires real requests from your browser, reporting status, timing, response headers, and body. Binary responses are summarized by length instead of rendered as mojibake. The method and path live in the URL, so a specific request is shareable:
/httptest?path=/status/418This is a TypeScript port of httpbin's core surface rather than the Flask app, checked against psf/httpbin 0.10.4. Multipart bodies aren't decoded, and they land in data as raw text. Several endpoints are missing, including /gzip and /image/*.
/response-headers carries a Content-Security-Policy: sandbox header. That endpoint lets a caller put arbitrary bytes in the body and set the Content-Type, which is a live XSS on real httpbin. httpbin.org gets away with it as a sacrificial domain, and this one shares an origin with every other tool here. Scripts can't run, and programmatic clients read headers exactly as they would from httpbin.
The docs list every deviation, including the ones that come from the CDN rather than the code.