{
"openapi": "3.2.0",
"info": {
"title": "httpcan.org",
"description": "A modern, high‑performance superset of [httpbin.org](https://httpbin.org) for testing HTTP clients, proxies, and AI agents — with mock OpenAI/Anthropic LLM APIs and a full OAuth 2.0 server. Built with Rust and Actix Web. Every httpbin.org endpoint is covered and drop‑in compatible, plus dedicated endpoints httpbin.org doesn't have and others it has but httpcan fixes or extends — the homepage at <code>/</code> lists every endpoint with Enhanced/New badges. <br/> <br/> <b>Run locally:</b> <code>$ docker run -p 8080:8080 ghcr.io/seedvector/httpcan:latest</code> <br/> <br/> <b>✨ Features</b> <ul> <li><b>Drop‑in httpbin.org superset</b>: use as a drop‑in replacement for testing and migration</li><li><b>AI API mock</b>: OpenAI‑ and Anthropic‑compatible <code>/llm</code> endpoints — point any SDK <code>base_url</code> at it (streaming included) and test AI clients without a paid provider</li><li><b>OAuth 2.0 mock</b>: a full authorization server at <code>/oauth2</code> — four RFC 6749 grants (authorization code + PKCE, implicit, password, rotating refresh, client credentials), Bearer‑protected userinfo, and RFC 8414 discovery</li><li><b>AI‑friendly streaming</b>: native <code>/sse</code> and <code>/ndjson</code> endpoints with OpenAI/Ollama‑compatible chunk formats</li><li><b>Measured performance</b>: in our benchmarks against comparable HTTP testing servers, HTTPCan led on both throughput and tail latency</li><li><b>Anti‑phishing redirects</b>: browser clients hitting <code>/redirect-to</code> see a confirmation page instead of a silent 302</li><li><b>Correct header handling</b>: duplicate and non‑ASCII request headers are preserved instead of being dropped or crashing the server</li><li><b>Safer by default</b>: built‑in filtering strips reverse‑proxy/CDN headers from echoed responses, with <code>--exclude-headers</code> for more</li><li><b>Cloud‑native observability</b>: <code>/healthz</code> liveness probe, <code>/tags</code> instance identification, and <code>Server-Timing</code>/<code>X-Httpcan-Version</code> headers on every response</li><li><b>Self‑documenting homepage</b>: <code>/</code> lists every endpoint by category with compatibility badges and copy‑curl buttons — static HTML, crawlable by search engines and AI agents</li><li><b>Tiny & fast</b>: tiny Docker image, minimal memory footprint, high throughput via Actix Web + Tokio</li>",
"version": "0.8.1",
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
}
},
"externalDocs": {
"description": "GitHub",
"url": "https://github.com/seedvector/httpcan"
},
"servers": [
{
"url": "https://httpcan.org",
"description": "Demo server"
}
],
"tags": [
{
"name": "HTTP Methods",
"description": "Testing different HTTP verbs."
},
{
"name": "Anything",
"description": "Returns anything that is passed to the request."
},
{
"name": "Auth",
"description": "Auth methods."
},
{
"name": "Status codes",
"description": "Generates responses with a given status code."
},
{
"name": "Request inspection",
"description": "Inspect the request data."
},
{
"name": "Response inspection",
"description": "Inspect the response data, like caching and headers."
},
{
"name": "Response formats",
"description": "Returns responses in different data formats."
},
{
"name": "Dynamic data",
"description": "Generates random and dynamic data."
},
{
"name": "Cookies",
"description": "Creates, reads, and deletes cookies."
},
{
"name": "Images",
"description": "Returns different image formats."
},
{
"name": "Redirects",
"description": "Returns different redirect responses."
},
{
"name": "Streaming",
"description": "Server-Sent Events and NDJSON streaming endpoints."
},
{
"name": "AI API Mock",
"description": "Mock OpenAI- and Anthropic-compatible LLM APIs."
},
{
"name": "OAuth 2.0 Mock",
"description": "Mock OAuth 2.0 authorization server: RFC 6749 four grants with PKCE, RFC 8414 discovery."
},
{
"name": "Observability",
"description": "Health checks and instance identification."
}
],
"paths": {
"/absolute-redirect/{n}": {
"get": {
"tags": [
"Redirects"
],
"summary": "Redirects n times, using absolute Location URLs.",
"operationId": "getAbsoluteRedirectN",
"description": "Same as /redirect/{n}, using absolute Location URLs.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of redirects to perform"
}
],
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "n must be greater than 0.",
"content": {}
}
}
}
},
"/anything": {
"get": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "getAnything",
"description": "Accepts any method and echoes the full request; multipart handling matches /post.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"put": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "putAnything",
"description": "Accepts any method and echoes the full request; multipart handling matches /post.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"post": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "postAnything",
"description": "Accepts any method and echoes the full request; multipart handling matches /post.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"delete": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "deleteAnything",
"description": "Accepts any method and echoes the full request; multipart handling matches /post.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"patch": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "patchAnything",
"description": "Accepts any method and echoes the full request; multipart handling matches /post.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"query": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "queryAnything",
"description": "Uses the QUERY HTTP method (RFC 9430): a safe, idempotent method that carries a request body.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"trace": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "traceAnything",
"description": "TRACE variant (RFC 9110 §9.8): echoes the request like GET; TRACE carries no body.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"options": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "optionsAnything",
"description": "Plain OPTIONS (non-preflight) echoes the request like GET; CORS preflights carrying Access-Control-Request-Method are handled by the CORS middleware.",
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
}
},
"/anything/{anything}": {
"get": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "getAnythingAnything",
"description": "Same as /anything, with extra path segment(s) that are ignored.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"put": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "putAnythingAnything",
"description": "Same as /anything, with extra path segment(s) that are ignored.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"post": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "postAnythingAnything",
"description": "Same as /anything, with extra path segment(s) that are ignored.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"delete": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "deleteAnythingAnything",
"description": "Same as /anything, with extra path segment(s) that are ignored.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"patch": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "patchAnythingAnything",
"description": "Same as /anything, with extra path segment(s) that are ignored.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"query": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "queryAnythingAnything",
"description": "Uses the QUERY HTTP method (RFC 9430): a safe, idempotent method that carries a request body.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"trace": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "traceAnythingAnything",
"description": "TRACE variant (RFC 9110 §9.8): echoes the request like GET; TRACE carries no body.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
},
"options": {
"tags": [
"Anything"
],
"summary": "Returns anything passed in request data.",
"operationId": "optionsAnythingAnything",
"description": "Plain OPTIONS (non-preflight) echoes the request like GET; CORS preflights carrying Access-Control-Request-Method are handled by the CORS middleware.",
"parameters": [
{
"name": "anything",
"in": "path",
"required": true,
"description": "Arbitrary path content after /anything (single or multi-segment), echoed back in the response",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The echoed request data (args, headers, origin, url, and body).",
"content": {}
}
}
}
},
"/base64": {
"post": {
"tags": [
"Dynamic data"
],
"summary": "Decodes the base64-encoded request body and returns it as text/plain.",
"operationId": "postBase64",
"description": "Decodes the base64-encoded request body and returns the decoded content as text/plain; invalid base64 returns 400.",
"requestBody": {
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"responses": {
"200": {
"description": "Decoded content as text/plain.",
"content": {}
},
"400": {
"description": "Invalid base64 data.",
"content": {}
}
}
}
},
"/base64/{value}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Decodes a standard base64 string.",
"operationId": "getBase64Value",
"description": "Decodes a standard base64 string; returns raw bytes (application/octet-stream) for non-UTF-8 content instead of erroring.",
"parameters": [
{
"name": "value",
"in": "path",
"required": true,
"schema": {
"type": "string",
"default": "SFRUUEJJTiBpcyBhd2Vzb21l"
},
"description": "Standard base64-encoded string to decode"
}
],
"responses": {
"200": {
"description": "Decoded base64 content.",
"content": {}
},
"400": {
"description": "Invalid base64 data.",
"content": {}
}
}
}
},
"/basic-auth/{user}/{passwd}": {
"get": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Basic Auth with the given credentials.",
"operationId": "getBasicAuthUserPasswd",
"description": "Returns {\"user\": ...} on success; challenges with 401 on incorrect credentials.",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
},
"post": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Basic Auth with the given credentials.",
"operationId": "postBasicAuthUserPasswd",
"description": "Returns {\"user\": ...} on success; challenges with 401 on incorrect credentials.",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
}
},
"/basic-auth/{user}": {
"get": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Basic Auth with username-only check.",
"operationId": "getBasicAuthUser",
"description": "Challenges HTTP Basic Auth with an empty password (username-only check).",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
},
"post": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Basic Auth with username-only check.",
"operationId": "postBasicAuthUser",
"description": "POST variant of the username-only Basic Auth check (empty password).",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
}
},
"/bearer": {
"get": {
"tags": [
"Auth"
],
"summary": "Prompts for Bearer authentication.",
"operationId": "getBearer",
"description": "Checks for a Bearer token in the Authorization header.",
"security": [
{
"bearerAuth": []
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
}
},
"/jwt-bearer": {
"get": {
"tags": [
"Auth"
],
"summary": "Validates a JWT Bearer token and returns its details.",
"operationId": "getJwtBearer",
"description": "Decodes and inspects a JWT Bearer token without verifying its signature: checks expiration claims and returns token analysis including header, payload, claims, and validation status. Useful for testing JWT authentication implementations.",
"security": [
{
"bearerAuth": []
}
],
"responses": {
"200": {
"description": "Valid JWT token with detailed analysis.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"authenticated": {
"type": "boolean",
"example": true
},
"token": {
"type": "object",
"properties": {
"raw": {
"type": "string",
"description": "Original JWT token string",
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
},
"header": {
"type": "object",
"description": "Decoded JWT header",
"example": {
"alg": "HS256",
"typ": "JWT"
}
},
"payload": {
"type": "object",
"description": "Decoded JWT payload",
"example": {
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
},
"payloadFormatted": {
"type": "object",
"description": "JWT payload with timestamps replaced by human-readable formatted versions",
"example": {
"sub": "1234567890",
"name": "John Doe",
"iat": "2018-01-18T01:30:22Z",
"exp": "2025-01-18T01:30:22Z"
}
},
"validationStatus": {
"type": "object",
"properties": {
"structure": {
"type": "string",
"enum": [
"valid",
"invalid"
],
"example": "valid"
},
"expiration": {
"type": "string",
"enum": [
"valid",
"expired",
"not_present",
"invalid_format"
],
"example": "not_present"
}
}
}
}
}
}
}
}
}
},
"401": {
"description": "Invalid, expired, or missing JWT token.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"authenticated": {
"type": "boolean",
"example": false
},
"error": {
"type": "string",
"description": "Error description",
"example": "Token expired"
},
"token": {
"type": "object",
"description": "Available token information (if any could be extracted)"
}
}
}
}
}
},
"400": {
"description": "Bad request (e.g., invalid Authorization header encoding).",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"authenticated": {
"type": "boolean",
"example": false
},
"error": {
"type": "string",
"example": "Invalid Authorization header encoding"
}
}
}
}
}
}
},
"parameters": [
{
"name": "Authorization",
"in": "header",
"required": true,
"description": "JWT Bearer token to validate",
"schema": {
"type": "string"
},
"examples": {
"Valid Token": {
"summary": "Example with valid JWT token",
"description": "Request with a valid JWT token that includes standard claims",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
},
"Expired Token": {
"summary": "Example with expired JWT token",
"description": "Request with an expired JWT token",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjJ9.expired_signature"
}
}
}
]
}
},
"/brotli": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns Brotli-encoded data.",
"operationId": "getBrotli",
"description": "Returns a fixed sample JSON document, Brotli-encoded.",
"responses": {
"200": {
"description": "Brotli-encoded data.",
"content": {}
}
}
},
"post": {
"tags": [
"Response formats"
],
"summary": "Echoes the request body, Brotli-encoded.",
"operationId": "postBrotli",
"description": "Compresses the request body with the matching Content-Encoding and returns it.",
"requestBody": {
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "The request body, Brotli-encoded.",
"content": {}
}
}
}
},
"/zstd": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns Zstandard-encoded data.",
"operationId": "getZstd",
"description": "Returns a fixed sample JSON document, Zstandard-encoded.",
"responses": {
"200": {
"description": "Zstandard-encoded data.",
"content": {}
}
}
},
"post": {
"tags": [
"Response formats"
],
"summary": "Echoes the request body, Zstandard-encoded.",
"operationId": "postZstd",
"description": "Compresses the request body with the matching Content-Encoding and returns it.",
"requestBody": {
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "The request body, Zstandard-encoded.",
"content": {}
}
}
}
},
"/bytes/{n}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Returns n random bytes.",
"operationId": "getBytesN",
"description": "Returns n random bytes; an optional ?seed= makes them deterministic. Over the configured --max-bytes limit returns 404 instead of silently truncating.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of random bytes to return"
},
{
"name": "seed",
"in": "query",
"description": "Optional seed for deterministic random bytes",
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "n random bytes (application/octet-stream).",
"content": {}
},
"404": {
"description": "n exceeds the server max-bytes limit (configurable via --max-bytes).",
"content": {}
}
}
}
},
"/cache": {
"get": {
"tags": [
"Response inspection"
],
"summary": "Returns 304 for conditional requests, 200 otherwise.",
"operationId": "getCache",
"description": "Returns 304 if If-Modified-Since or If-None-Match is present, 200 otherwise.",
"parameters": [
{
"name": "If-Modified-Since",
"in": "header",
"schema": {},
"description": "Conditional request header; a match returns 304"
},
{
"name": "If-None-Match",
"in": "header",
"schema": {},
"description": "Conditional request header; a match returns 304"
}
],
"responses": {
"200": {
"description": "Cached response.",
"content": {}
},
"304": {
"description": "Modified.",
"content": {}
}
}
}
},
"/cache/{value}": {
"get": {
"tags": [
"Response inspection"
],
"summary": "Sets a Cache-Control header for n seconds.",
"operationId": "getCacheValue",
"description": "Sets Cache-Control: public, max-age=<value> seconds on the response.",
"parameters": [
{
"name": "value",
"in": "path",
"required": true,
"schema": {
"type": "integer"
},
"description": "Cache duration in seconds"
}
],
"responses": {
"200": {
"description": "Cache control set.",
"content": {}
}
}
}
},
"/cookies": {
"get": {
"tags": [
"Cookies"
],
"summary": "Returns cookie data.",
"operationId": "getCookies",
"description": "Returns the request cookies as {\"cookies\": {...}}.",
"responses": {
"200": {
"description": "Set cookies.",
"content": {}
}
}
}
},
"/cookies/delete": {
"get": {
"tags": [
"Cookies"
],
"summary": "Deletes the given cookies.",
"operationId": "getCookiesDelete",
"description": "Deletes the given cookies and redirects to /cookies.",
"parameters": [
{
"name": "freeform",
"in": "query",
"allowEmptyValue": true,
"schema": {},
"description": "Cookie names to delete (one per query parameter)"
}
],
"responses": {
"200": {
"description": "Redirects to /cookies.",
"content": {}
}
}
}
},
"/cookies/set": {
"get": {
"tags": [
"Cookies"
],
"summary": "Sets cookies from query string name=value pairs.",
"operationId": "getCookiesSet",
"description": "Sets cookies from query parameters and redirects to /cookies; supports httponly/secure/samesite/domain/path/max_age attributes.",
"parameters": [
{
"name": "freeform",
"in": "query",
"allowEmptyValue": true,
"schema": {},
"description": "Each name=value query pair becomes a cookie (plus httponly/secure/samesite/domain/path/max_age attributes)"
},
{
"name": "httponly",
"in": "query",
"description": "If 'true', set the HttpOnly attribute on all cookies",
"schema": {
"type": "string"
}
},
{
"name": "secure",
"in": "query",
"description": "If 'true', set the Secure attribute (defaults to the request scheme)",
"schema": {
"type": "string"
}
},
{
"name": "samesite",
"in": "query",
"description": "SameSite attribute",
"schema": {
"type": "string",
"enum": [
"strict",
"lax",
"none"
]
}
},
{
"name": "domain",
"in": "query",
"description": "Cookie Domain attribute",
"schema": {
"type": "string"
}
},
{
"name": "max_age",
"in": "query",
"description": "Max-Age in seconds",
"schema": {
"type": "integer"
}
},
{
"name": "path",
"in": "query",
"description": "Cookie Path attribute (defaults to '/')",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Redirects to /cookies.",
"content": {}
}
}
}
},
"/cookies/set/{name}/{value}": {
"get": {
"tags": [
"Cookies"
],
"summary": "Sets a single cookie and redirects to /cookies.",
"operationId": "getCookiesSetNameValue",
"description": "Equivalent to /cookies/set?<name>=<value>: sets one cookie, then redirects to /cookies.",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Cookie name"
},
{
"name": "value",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Cookie value"
}
],
"responses": {
"200": {
"description": "Set cookies and redirects to /cookies.",
"content": {}
}
}
}
},
"/deflate": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns Deflate-encoded data.",
"operationId": "getDeflate",
"description": "Returns a fixed sample JSON document, Deflate-encoded.",
"responses": {
"200": {
"description": "Deflate-encoded data.",
"content": {}
}
}
},
"post": {
"tags": [
"Response formats"
],
"summary": "Echoes the request body, Deflate-encoded.",
"operationId": "postDeflate",
"description": "Compresses the request body with the matching Content-Encoding and returns it.",
"requestBody": {
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "The request body, Deflate-encoded.",
"content": {}
}
}
}
},
"/delay/{delay}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Returns a delayed response (max of 10 seconds).",
"operationId": "getDelayDelay",
"description": "Delays the response by up to 10 seconds.",
"parameters": [
{
"name": "delay",
"in": "path",
"required": true,
"schema": {
"type": "number"
},
"description": "Delay duration in seconds (max 10)"
}
],
"responses": {
"200": {
"description": "A delayed response.",
"content": {}
}
}
},
"put": {
"tags": [
"Dynamic data"
],
"summary": "Returns a delayed response (max of 10 seconds).",
"operationId": "putDelayDelay",
"description": "Delays the response by up to 10 seconds.",
"parameters": [
{
"name": "delay",
"in": "path",
"required": true,
"schema": {
"type": "number"
},
"description": "Delay duration in seconds (max 10)"
}
],
"responses": {
"200": {
"description": "A delayed response.",
"content": {}
}
}
},
"post": {
"tags": [
"Dynamic data"
],
"summary": "Returns a delayed response (max of 10 seconds).",
"operationId": "postDelayDelay",
"description": "Delays the response by up to 10 seconds.",
"parameters": [
{
"name": "delay",
"in": "path",
"required": true,
"schema": {
"type": "number"
},
"description": "Delay duration in seconds (max 10)"
}
],
"responses": {
"200": {
"description": "A delayed response.",
"content": {}
}
}
},
"delete": {
"tags": [
"Dynamic data"
],
"summary": "Returns a delayed response (max of 10 seconds).",
"operationId": "deleteDelayDelay",
"description": "Delays the response by up to 10 seconds.",
"parameters": [
{
"name": "delay",
"in": "path",
"required": true,
"schema": {
"type": "number"
},
"description": "Delay duration in seconds (max 10)"
}
],
"responses": {
"200": {
"description": "A delayed response.",
"content": {}
}
}
},
"patch": {
"tags": [
"Dynamic data"
],
"summary": "Returns a delayed response (max of 10 seconds).",
"operationId": "patchDelayDelay",
"description": "Delays the response by up to 10 seconds.",
"parameters": [
{
"name": "delay",
"in": "path",
"required": true,
"schema": {
"type": "number"
},
"description": "Delay duration in seconds (max 10)"
}
],
"responses": {
"200": {
"description": "A delayed response.",
"content": {}
}
}
},
"trace": {
"tags": [
"Dynamic data"
],
"summary": "Returns a delayed response (max of 10 seconds).",
"operationId": "traceDelayDelay",
"description": "TRACE variant: delays up to 10 seconds, then responds like GET (TRACE carries no body).",
"parameters": [
{
"name": "delay",
"in": "path",
"required": true,
"schema": {
"type": "number"
},
"description": "Delay duration in seconds (max 10)"
}
],
"responses": {
"200": {
"description": "A delayed response.",
"content": {}
}
}
}
},
"/delete": {
"delete": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request's DELETE parameters.",
"operationId": "deleteDelete",
"description": "Same as /post, for DELETE requests.",
"responses": {
"200": {
"description": "The request's DELETE parameters.",
"content": {}
}
}
}
},
"/deny": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns page denied by robots.txt rules.",
"operationId": "getDeny",
"description": "Returns the page that robots.txt disallows.",
"responses": {
"200": {
"description": "Denied message.",
"content": {}
}
}
}
},
"/digest-auth/{qop}/{user}/{passwd}": {
"get": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Digest Auth.",
"operationId": "getDigestAuthQopUserPasswd",
"description": "Supports both 'auth' and 'auth-int' QoP (Quality of Protection). For 'auth-int', the HA2 hash includes the request body per RFC-7616: HA2 = H(method:uri:H(entity-body)). Supported hash algorithms include SHA-512-256; qop=none enables RFC 2069 legacy mode.",
"security": [
{
"digestAuth": []
}
],
"parameters": [
{
"name": "qop",
"in": "path",
"description": "auth, auth-int, or none. 'auth-int' includes the request body in the hash calculation; 'none' omits qop entirely (RFC 2069 legacy mode).",
"required": true,
"schema": {
"type": "string",
"enum": [
"auth",
"auth-int",
"none"
]
}
},
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
},
"post": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Digest Auth.",
"operationId": "postDigestAuthQopUserPasswd",
"description": "POST method for testing 'auth-int' QoP with request bodies. For 'auth-int', the HA2 hash includes the request body per RFC-7616: HA2 = H(method:uri:H(entity-body)). This is essential for proper auth-int testing. Supported hash algorithms include SHA-512-256; qop=none enables RFC 2069 legacy mode.",
"security": [
{
"digestAuth": []
}
],
"parameters": [
{
"name": "qop",
"in": "path",
"description": "auth, auth-int, or none. 'auth-int' includes the request body in the hash calculation; 'none' omits qop entirely (RFC 2069 legacy mode).",
"required": true,
"schema": {
"type": "string",
"enum": [
"auth",
"auth-int",
"none"
]
}
},
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
}
],
"requestBody": {
"description": "Request body for auth-int QoP testing. The body hash is included in HA2 calculation.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
}
},
"/digest-auth/{qop}/{user}/{passwd}/{algorithm}": {
"get": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Digest Auth with a configurable hash algorithm.",
"operationId": "getDigestAuthQopUserPasswdAlgorithm",
"description": "Supports both 'auth' and 'auth-int' QoP with configurable hash algorithm. For 'auth-int', the HA2 hash includes the request body per RFC-7616.",
"security": [
{
"digestAuth": []
}
],
"parameters": [
{
"name": "qop",
"in": "path",
"description": "auth, auth-int, or none. 'auth-int' includes the request body in the hash calculation; 'none' omits qop entirely (RFC 2069 legacy mode).",
"required": true,
"schema": {
"type": "string",
"enum": [
"auth",
"auth-int",
"none"
]
}
},
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
},
{
"name": "algorithm",
"in": "path",
"description": "Hash algorithm for digest calculation",
"required": true,
"schema": {
"type": "string",
"enum": [
"MD5",
"SHA-256",
"SHA-512",
"SHA-512-256"
],
"default": "MD5"
}
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
},
"400": {
"description": "Unsupported hash algorithm.",
"content": {}
}
}
},
"post": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Digest Auth with a configurable hash algorithm.",
"operationId": "postDigestAuthQopUserPasswdAlgorithm",
"description": "POST method for testing 'auth-int' QoP with request bodies and configurable hash algorithm. For 'auth-int', the HA2 hash includes the request body per RFC-7616.",
"security": [
{
"digestAuth": []
}
],
"parameters": [
{
"name": "qop",
"in": "path",
"description": "auth, auth-int, or none. 'auth-int' includes the request body in the hash calculation; 'none' omits qop entirely (RFC 2069 legacy mode).",
"required": true,
"schema": {
"type": "string",
"enum": [
"auth",
"auth-int",
"none"
]
}
},
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
},
{
"name": "algorithm",
"in": "path",
"description": "Hash algorithm for digest calculation",
"required": true,
"schema": {
"type": "string",
"enum": [
"MD5",
"SHA-256",
"SHA-512",
"SHA-512-256"
],
"default": "MD5"
}
}
],
"requestBody": {
"description": "Request body for auth-int QoP testing. The body hash is included in HA2 calculation.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
},
"400": {
"description": "Unsupported hash algorithm.",
"content": {}
}
}
}
},
"/digest-auth/{qop}/{user}/{passwd}/{algorithm}/{stale_after}": {
"get": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Digest Auth with algorithm and stale_after control.",
"operationId": "getDigestAuthQopUserPasswdAlgorithmStaleAfter",
"description": "Full Digest Auth endpoint with stale_after control. Supports both 'auth' and 'auth-int' QoP. For 'auth-int', the HA2 hash includes the request body per RFC-7616.",
"security": [
{
"digestAuth": []
}
],
"parameters": [
{
"name": "qop",
"in": "path",
"description": "auth, auth-int, or none. 'auth-int' includes the request body in the hash calculation; 'none' omits qop entirely (RFC 2069 legacy mode).",
"required": true,
"schema": {
"type": "string",
"enum": [
"auth",
"auth-int",
"none"
]
}
},
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
},
{
"name": "algorithm",
"in": "path",
"description": "Hash algorithm for digest calculation",
"required": true,
"schema": {
"type": "string",
"enum": [
"MD5",
"SHA-256",
"SHA-512",
"SHA-512-256"
],
"default": "MD5"
}
},
{
"name": "stale_after",
"in": "path",
"description": "Number of requests before nonce becomes stale, or 'never'",
"required": true,
"schema": {
"type": "string",
"default": "never"
}
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
},
"400": {
"description": "Unsupported hash algorithm.",
"content": {}
}
}
},
"post": {
"tags": [
"Auth"
],
"summary": "Prompts for HTTP Digest Auth with algorithm and stale_after control.",
"operationId": "postDigestAuthQopUserPasswdAlgorithmStaleAfter",
"description": "Full Digest Auth endpoint with stale_after control. POST method for testing 'auth-int' QoP with request bodies. For 'auth-int', the HA2 hash includes the request body per RFC-7616.",
"security": [
{
"digestAuth": []
}
],
"parameters": [
{
"name": "qop",
"in": "path",
"description": "auth, auth-int, or none. 'auth-int' includes the request body in the hash calculation; 'none' omits qop entirely (RFC 2069 legacy mode).",
"required": true,
"schema": {
"type": "string",
"enum": [
"auth",
"auth-int",
"none"
]
}
},
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
},
{
"name": "algorithm",
"in": "path",
"description": "Hash algorithm for digest calculation",
"required": true,
"schema": {
"type": "string",
"enum": [
"MD5",
"SHA-256",
"SHA-512",
"SHA-512-256"
],
"default": "MD5"
}
},
{
"name": "stale_after",
"in": "path",
"description": "Number of requests before nonce becomes stale, or 'never'",
"required": true,
"schema": {
"type": "string",
"default": "never"
}
}
],
"requestBody": {
"description": "Request body for auth-int QoP testing. The body hash is included in HA2 calculation.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"401": {
"description": "Unsuccessful authentication.",
"content": {}
},
"400": {
"description": "Unsupported hash algorithm.",
"content": {}
}
}
}
},
"/drip": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Drips data over a duration after an optional initial delay.",
"operationId": "getDrip",
"description": "Drips data over a duration; ?chunked=true streams with real chunked transfer-encoding.",
"parameters": [
{
"name": "duration",
"in": "query",
"description": "The amount of time (in seconds) over which to drip each byte",
"schema": {
"type": "number",
"default": 2
}
},
{
"name": "numbytes",
"in": "query",
"description": "The number of bytes to respond with",
"schema": {
"type": "integer",
"default": 10
}
},
{
"name": "code",
"in": "query",
"description": "The response code that will be returned",
"schema": {
"type": "integer",
"default": 200
}
},
{
"name": "delay",
"in": "query",
"description": "The amount of time (in seconds) to delay before responding",
"schema": {
"type": "number",
"default": 2
}
},
{
"name": "chunked",
"in": "query",
"description": "If true, stream with chunked transfer-encoding (omit Content-Length)",
"schema": {
"type": "boolean",
"default": false
}
}
],
"responses": {
"200": {
"description": "A dripped response.",
"content": {}
},
"400": {
"description": "numbytes must be positive.",
"content": {}
},
"404": {
"description": "numbytes exceeds the server max-bytes limit (configurable via --max-bytes).",
"content": {}
}
}
}
},
"/encoding/utf8": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns a UTF-8 encoded body.",
"operationId": "getEncodingUtf8",
"description": "Returns an HTML page of multi-byte UTF-8 demo text.",
"responses": {
"200": {
"description": "Encoded UTF-8 content.",
"content": {}
}
}
}
},
"/encoding/iso-8859-1": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns an ISO-8859-1 (Latin-1) encoded body.",
"operationId": "getEncodingIso88591",
"description": "Returns an ISO-8859-1 encoded page.",
"responses": {
"200": {
"description": "Encoded Latin-1 content.",
"content": {
"text/html": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/etag/{etag}": {
"get": {
"tags": [
"Response inspection"
],
"summary": "Validates conditional requests against the given ETag.",
"operationId": "getEtagEtag",
"description": "Validates If-Match/If-None-Match against the given ETag; supports weak W/\"...\" validators.",
"parameters": [
{
"name": "etag",
"in": "path",
"required": true,
"description": "The etag value. Use the weak form W/\"value\" for weak validation",
"schema": {
"type": "string"
}
},
{
"name": "If-None-Match",
"in": "header",
"schema": {},
"description": "Conditional request header; a match returns 304"
},
{
"name": "If-Match",
"in": "header",
"schema": {},
"description": "Conditional request header; a mismatch returns 412"
}
],
"responses": {
"200": {
"description": "Normal response.",
"content": {}
},
"412": {
"description": "Precondition failed: the conditional header did not match the given ETag.",
"content": {}
}
}
}
},
"/get": {
"get": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request's query parameters, headers, origin, and URL.",
"operationId": "getGet",
"description": "Echoes the request's query parameters, headers, origin, and URL (GET and HEAD); response shape per the GetRequestInfo schema.",
"responses": {
"200": {
"description": "The request's query parameters.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetRequestInfo"
}
}
}
}
}
}
},
"/head": {
"head": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request headers as X-Echo-* response headers.",
"operationId": "headHead",
"description": "HEAD-only: echoes the request headers back as X-Echo-* response headers.",
"responses": {
"200": {
"description": "Empty body; request headers mirrored as X-Echo-* response headers.",
"content": {}
}
}
}
},
"/method": {
"get": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "getMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"post": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "postMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"put": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "putMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"patch": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "patchMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"delete": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "deleteMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"head": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "headMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here. HEAD responses carry the headers with an empty body.",
"responses": {
"200": {
"description": "Headers only; no response body (HEAD).",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"options": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "optionsMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"trace": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "traceMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"query": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "queryMethod",
"description": "Echoes back the HTTP method name used. Any method name is accepted, including extension methods not listed here.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
},
"additionalOperations": {
"ANY_CUSTOM_METHOD": {
"tags": [
"Request inspection"
],
"summary": "Echoes the request's HTTP method name.",
"operationId": "anyCustomMethod",
"description": "Placeholder key demonstrating that ANY method token is accepted: sending ANY_CUSTOM_METHOD — or any other non-standard token such as LINK (RFC 4918) or PURGE — echoes the method name back unchanged.",
"responses": {
"200": {
"description": "JSON object with the method name.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"method": {
"type": "string"
}
}
}
}
}
}
}
}
}
},
"/options": {
"options": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request and returns an Allow header.",
"operationId": "optionsOptions",
"description": "OPTIONS-only: echoes the request and returns an Allow header (RFC 9110 §9.3.7).",
"responses": {
"200": {
"description": "JSON echo of args/headers/origin/url, plus Allow: OPTIONS.",
"content": {}
}
}
}
},
"/query": {
"query": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request like /post (RFC 9430).",
"operationId": "queryQuery",
"description": "Echoes the request's URL args and parsed body (form/JSON/multipart), like /post. Uses the QUERY HTTP method (RFC 9430): a safe, idempotent method that carries a request body.",
"responses": {
"200": {
"description": "Echoed request data.",
"content": {}
}
}
}
},
"/trace": {
"trace": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request back to the client.",
"operationId": "traceTrace",
"description": "TRACE-only: echoes the request like /anything (RFC 9110 §9.8).",
"responses": {
"200": {
"description": "JSON echo of the request.",
"content": {}
}
}
}
},
"/gzip": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns GZip-encoded data.",
"operationId": "getGzip",
"description": "Returns a fixed sample JSON document, GZip-encoded.",
"responses": {
"200": {
"description": "GZip-encoded data.",
"content": {}
}
}
},
"post": {
"tags": [
"Response formats"
],
"summary": "Echoes the request body, GZip-encoded.",
"operationId": "postGzip",
"description": "Compresses the request body with the matching Content-Encoding and returns it.",
"requestBody": {
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "The request body, GZip-encoded.",
"content": {}
}
}
}
},
"/headers": {
"get": {
"tags": [
"Request inspection"
],
"summary": "Returns the request's HTTP headers.",
"operationId": "getHeaders",
"description": "Returns the request's HTTP headers as a JSON object; proxy/CDN headers are filtered per --exclude-headers.",
"responses": {
"200": {
"description": "The request's headers.",
"content": {}
}
}
}
},
"/hidden-basic-auth/{user}/{passwd}": {
"get": {
"tags": [
"Auth"
],
"summary": "Hidden HTTP Basic Auth: 404 instead of 401 on failure.",
"operationId": "getHiddenBasicAuthUserPasswd",
"description": "Like /basic-auth, but returns 404 instead of 401 on failure.",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"404": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
},
"post": {
"tags": [
"Auth"
],
"summary": "Hidden HTTP Basic Auth: 404 instead of 401 on failure.",
"operationId": "postHiddenBasicAuthUserPasswd",
"description": "POST variant: like /basic-auth, but returns 404 instead of 401 on failure.",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
},
{
"name": "passwd",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Password to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"404": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
}
},
"/hidden-basic-auth/{user}": {
"get": {
"tags": [
"Auth"
],
"summary": "Hidden HTTP Basic Auth, username-only: 404 instead of 401 on failure.",
"operationId": "getHiddenBasicAuthUser",
"description": "Like /basic-auth/{user}, but returns 404 instead of 401 on failure.",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"404": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
},
"post": {
"tags": [
"Auth"
],
"summary": "Hidden HTTP Basic Auth, username-only: 404 instead of 401 on failure.",
"operationId": "postHiddenBasicAuthUser",
"description": "POST variant: like /basic-auth/{user}, but returns 404 instead of 401 on failure.",
"security": [
{
"basicAuth": []
}
],
"parameters": [
{
"name": "user",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Username to authenticate with"
}
],
"responses": {
"200": {
"description": "Successful authentication.",
"content": {}
},
"404": {
"description": "Unsuccessful authentication.",
"content": {}
}
}
}
},
"/html": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns a sample HTML document.",
"operationId": "getHtml",
"description": "Returns a sample HTML document (text/html).",
"responses": {
"200": {
"description": "An HTML page.",
"content": {}
}
}
}
},
"/image": {
"get": {
"tags": [
"Images"
],
"summary": "Returns a random image, negotiated via the Accept header.",
"operationId": "getImage",
"description": "Returns a random colored image. If the Accept header specifies an image format (image/png, image/jpeg, image/webp, image/svg+xml), returns an image in that format. Otherwise returns a random format.",
"parameters": [
{
"name": "Accept",
"in": "header",
"description": "Preferred image format. Supports image/png, image/jpeg, image/webp, image/svg+xml, or image/* for random format",
"required": false,
"schema": {
"type": "string",
"enum": [
"image/png",
"image/jpeg",
"image/webp",
"image/svg+xml",
"image/*"
]
},
"example": "image/png"
}
],
"responses": {
"200": {
"description": "A random colored image with X-Image-Color header indicating the color and X-Image-Format-Source indicating how the format was chosen.",
"headers": {
"X-Image-Color": {
"description": "The color name of the returned image",
"schema": {
"type": "string"
}
},
"X-Image-Format-Source": {
"description": "How the image format was determined: 'accept-header', 'random', or 'fallback'",
"schema": {
"type": "string",
"enum": [
"accept-header",
"random",
"fallback"
]
}
}
},
"content": {
"image/png": {
"schema": {
"type": "string",
"format": "binary"
}
},
"image/jpeg": {
"schema": {
"type": "string",
"format": "binary"
}
},
"image/webp": {
"schema": {
"type": "string",
"format": "binary"
}
},
"image/svg+xml": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
"/image/jpeg": {
"get": {
"tags": [
"Images"
],
"summary": "Returns a random colored JPEG image.",
"operationId": "getImageJpeg",
"description": "Returns a random colored JPEG image, served as image/jpeg.",
"responses": {
"200": {
"description": "A random colored JPEG image with X-Image-Color header indicating the color.",
"headers": {
"X-Image-Color": {
"description": "The color name of the returned image",
"schema": {
"type": "string"
}
}
},
"content": {
"image/jpeg": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
"/image/png": {
"get": {
"tags": [
"Images"
],
"summary": "Returns a random colored PNG image.",
"operationId": "getImagePng",
"description": "Returns a random colored PNG image, served as image/png.",
"responses": {
"200": {
"description": "A random colored PNG image with X-Image-Color header indicating the color.",
"headers": {
"X-Image-Color": {
"description": "The color name of the returned image",
"schema": {
"type": "string"
}
}
},
"content": {
"image/png": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
"/image/svg": {
"get": {
"tags": [
"Images"
],
"summary": "Returns a random colored SVG image.",
"operationId": "getImageSvg",
"description": "Returns a random colored SVG image, served as image/svg+xml.",
"responses": {
"200": {
"description": "A random colored SVG image with X-Image-Color header indicating the color.",
"headers": {
"X-Image-Color": {
"description": "The color name of the returned image",
"schema": {
"type": "string"
}
}
},
"content": {
"image/svg+xml": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
"/image/webp": {
"get": {
"tags": [
"Images"
],
"summary": "Returns a random colored WEBP image.",
"operationId": "getImageWebp",
"description": "Returns a random colored WEBP image, served as image/webp.",
"responses": {
"200": {
"description": "A random colored WEBP image with X-Image-Color header indicating the color.",
"headers": {
"X-Image-Color": {
"description": "The color name of the returned image",
"schema": {
"type": "string"
}
}
},
"content": {
"image/webp": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
"/ip": {
"get": {
"tags": [
"Request inspection"
],
"summary": "Returns the requester's IP address.",
"operationId": "getIp",
"description": "Returns the client IP as {\"origin\": \"...\"}.",
"responses": {
"200": {
"description": "The requester's IP address.",
"content": {}
}
}
}
},
"/json": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns a sample JSON document.",
"operationId": "getJson",
"description": "Returns a sample JSON document (application/json).",
"responses": {
"200": {
"description": "An JSON document.",
"content": {}
}
}
}
},
"/links/{n}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Returns the first page of n links.",
"operationId": "getLinks",
"description": "Same as /links/{n}/{offset}, with offset defaulted to 0; redirects to the page.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of links per page"
}
],
"responses": {
"200": {
"description": "HTML links.",
"content": {}
}
}
}
},
"/links/{n}/{offset}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Returns a page of n links.",
"operationId": "getLinksNOffset",
"description": "Returns a page of n links, starting at offset.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of links per page"
},
{
"name": "offset",
"in": "path",
"required": true,
"schema": {},
"description": "Page offset (0-based)"
}
],
"responses": {
"200": {
"description": "HTML links.",
"content": {}
}
}
}
},
"/patch": {
"patch": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request's PATCH parameters.",
"operationId": "patchPatch",
"description": "Same as /post, for PATCH requests.",
"responses": {
"200": {
"description": "The request's PATCH parameters.",
"content": {}
}
}
}
},
"/post": {
"post": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request's POST parameters and uploaded files.",
"operationId": "postPost",
"description": "Echoes the request's parsed body and uploaded files; multiple files with the same parameter name are returned as an array.",
"requestBody": {
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": true,
"description": "Supports file uploads. Multiple files with the same field name are returned as an array."
}
},
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"responses": {
"200": {
"description": "The request's POST parameters and uploaded files.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RequestInfo"
}
}
}
}
}
}
},
"/put": {
"put": {
"tags": [
"HTTP Methods"
],
"summary": "Echoes the request's PUT parameters.",
"operationId": "putPut",
"description": "Same as /post, for PUT requests.",
"responses": {
"200": {
"description": "The request's PUT parameters.",
"content": {}
}
}
}
},
"/range/{numbytes}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Streams bytes with HTTP Range support.",
"operationId": "getRangeNumbytes",
"description": "Streams numbytes bytes; supports Range requests.",
"parameters": [
{
"name": "numbytes",
"in": "path",
"required": true,
"schema": {},
"description": "Total number of bytes in the payload"
},
{
"name": "chunk_size",
"in": "query",
"description": "Bytes per chunk (default: 10240)",
"schema": {
"type": "integer"
}
},
{
"name": "duration",
"in": "query",
"description": "Total streaming duration in seconds (default: 0)",
"schema": {
"type": "number"
}
}
],
"responses": {
"200": {
"description": "The requested byte range of the numbytes payload.",
"content": {}
},
"404": {
"description": "numbytes is 0 or exceeds the server max-bytes limit (configurable via --max-bytes).",
"content": {}
},
"416": {
"description": "Requested Range is not satisfiable for the given numbytes.",
"content": {}
}
}
}
},
"/redirect-to": {
"get": {
"tags": [
"Redirects"
],
"summary": "Redirects to the given URL (302 by default, or a custom status).",
"operationId": "getRedirectTo",
"description": "Redirects to ?url=; POST/PUT/PATCH/DELETE also accept urlencoded, multipart, or JSON bodies (body fields win over query); browser clients see an anti-phishing interstitial instead of a silent redirect.",
"parameters": [
{
"name": "url",
"in": "query",
"required": true,
"description": "Target URL to redirect to",
"schema": {
"type": "string",
"format": "uri"
}
},
{
"name": "status_code",
"in": "query",
"required": false,
"description": "HTTP status code for the redirect (default 302)",
"schema": {
"type": "integer"
}
}
],
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "Missing required url query parameter.",
"content": {}
}
}
},
"put": {
"tags": [
"Redirects"
],
"summary": "Redirects to the given URL (302 by default, or a custom status).",
"operationId": "putRedirectTo",
"description": "Redirects to ?url=; POST/PUT/PATCH/DELETE also accept urlencoded, multipart, or JSON bodies (body fields win over query); browser clients see an anti-phishing interstitial instead of a silent redirect.",
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/x-www-form-urlencoded": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/json": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
}
},
"required": false
},
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "Missing required url query parameter.",
"content": {}
}
},
"parameters": [
{
"name": "url",
"in": "query",
"required": true,
"description": "Target URL to redirect to",
"schema": {
"type": "string",
"format": "uri"
}
},
{
"name": "status_code",
"in": "query",
"required": false,
"description": "HTTP status code for the redirect (default 302)",
"schema": {
"type": "integer"
}
}
]
},
"post": {
"tags": [
"Redirects"
],
"summary": "Redirects to the given URL (302 by default, or a custom status).",
"operationId": "postRedirectTo",
"description": "Redirects to ?url=; POST/PUT/PATCH/DELETE also accept urlencoded, multipart, or JSON bodies (body fields win over query); browser clients see an anti-phishing interstitial instead of a silent redirect.",
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/x-www-form-urlencoded": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/json": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
}
},
"required": false
},
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "Missing required url query parameter.",
"content": {}
}
},
"parameters": [
{
"name": "url",
"in": "query",
"required": true,
"description": "Target URL to redirect to",
"schema": {
"type": "string",
"format": "uri"
}
},
{
"name": "status_code",
"in": "query",
"required": false,
"description": "HTTP status code for the redirect (default 302)",
"schema": {
"type": "integer"
}
}
]
},
"delete": {
"tags": [
"Redirects"
],
"summary": "Redirects to the given URL (302 by default, or a custom status).",
"operationId": "deleteRedirectTo",
"description": "Redirects to ?url=; POST/PUT/PATCH/DELETE also accept urlencoded, multipart, or JSON bodies (body fields win over query); browser clients see an anti-phishing interstitial instead of a silent redirect.",
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "Missing required url query parameter.",
"content": {}
}
},
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/x-www-form-urlencoded": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/json": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
}
},
"required": false
},
"parameters": [
{
"name": "url",
"in": "query",
"required": true,
"description": "Target URL to redirect to",
"schema": {
"type": "string",
"format": "uri"
}
},
{
"name": "status_code",
"in": "query",
"required": false,
"description": "HTTP status code for the redirect (default 302)",
"schema": {
"type": "integer"
}
}
]
},
"patch": {
"tags": [
"Redirects"
],
"summary": "Redirects to the given URL (302 by default, or a custom status).",
"operationId": "patchRedirectTo",
"description": "Redirects to ?url=; POST/PUT/PATCH/DELETE also accept urlencoded, multipart, or JSON bodies (body fields win over query); browser clients see an anti-phishing interstitial instead of a silent redirect.",
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "Missing required url query parameter.",
"content": {}
}
},
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/x-www-form-urlencoded": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
},
"application/json": {
"schema": {
"required": [
"url"
],
"type": "object",
"properties": {
"url": {
"type": "string"
},
"status_code": {}
}
}
}
},
"required": false
},
"parameters": [
{
"name": "url",
"in": "query",
"required": true,
"description": "Target URL to redirect to",
"schema": {
"type": "string",
"format": "uri"
}
},
{
"name": "status_code",
"in": "query",
"required": false,
"description": "HTTP status code for the redirect (default 302)",
"schema": {
"type": "integer"
}
}
]
},
"trace": {
"tags": [
"Redirects"
],
"summary": "Redirects to the given URL (302 by default, or a custom status).",
"operationId": "traceRedirectTo",
"description": "Redirects to ?url=; POST/PUT/PATCH/DELETE also accept urlencoded, multipart, or JSON bodies (body fields win over query); browser clients see an anti-phishing interstitial instead of a silent redirect.",
"parameters": [
{
"name": "url",
"in": "query",
"required": true,
"description": "Target URL to redirect to",
"schema": {
"type": "string",
"format": "uri"
}
},
{
"name": "status_code",
"in": "query",
"required": false,
"description": "HTTP status code for the redirect (default 302)",
"schema": {
"type": "integer"
}
}
],
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "Missing required url query parameter.",
"content": {}
}
}
}
},
"/redirect/{n}": {
"get": {
"tags": [
"Redirects"
],
"summary": "Redirects n times before returning 200.",
"operationId": "getRedirectN",
"description": "Each hop is a 302; after n redirects the chain ends at /get with a 200. ?absolute=true builds absolute (scheme+host) Location URLs and chains via /absolute-redirect instead of /relative-redirect.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of redirects to perform"
},
{
"name": "absolute",
"in": "query",
"description": "If 'true' (case-insensitive), redirect using absolute URLs and chain via /absolute-redirect; default relative via /relative-redirect.",
"schema": {
"type": "string",
"enum": [
"true",
"false"
],
"default": "false"
}
}
],
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "n must be greater than 0.",
"content": {}
}
}
}
},
"/relative-redirect/{n}": {
"get": {
"tags": [
"Redirects"
],
"summary": "Redirects n times, using relative Location URLs.",
"operationId": "getRelativeRedirectN",
"description": "Same as /redirect/{n}, using relative Location URLs.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of redirects to perform"
}
],
"responses": {
"302": {
"description": "A redirection.",
"content": {}
},
"400": {
"description": "n must be greater than 0.",
"content": {}
}
}
}
},
"/response-headers": {
"get": {
"tags": [
"Response inspection"
],
"summary": "Returns a set of response headers from the query string.",
"operationId": "getResponseHeaders",
"description": "Echoes query parameters as response headers; ?body= and ?status= override the response body and status code.",
"parameters": [
{
"name": "freeform",
"in": "query",
"allowEmptyValue": true,
"schema": {},
"description": "Each name=value query pair becomes a response header"
}
],
"responses": {
"200": {
"description": "Response headers.",
"content": {}
}
}
},
"post": {
"tags": [
"Response inspection"
],
"summary": "Returns a set of response headers from the query string.",
"operationId": "postResponseHeaders",
"description": "Echoes query parameters as response headers; ?body= and ?status= override the response body and status code.",
"parameters": [
{
"name": "freeform",
"in": "query",
"allowEmptyValue": true,
"schema": {},
"description": "Each name=value query pair becomes a response header"
}
],
"responses": {
"200": {
"description": "Response headers.",
"content": {}
}
}
}
},
"/status/{codes}": {
"get": {
"tags": [
"Status codes"
],
"summary": "Returns the given status code, or a random pick from a list.",
"operationId": "getStatusCodes",
"description": "Returns the given status, or a random one from a comma-separated list; supports ?header= injection, a custom body, and trailing path segments, and weighted random picks via 'code:weight'.",
"parameters": [
{
"name": "codes",
"in": "path",
"required": true,
"description": "HTTP status code(s). Multiple codes can be comma-separated (e.g., '200,201,202') for random selection; an optional relative weight per code via 'code:weight' (e.g. '200:3,404:1') biases the random pick.",
"schema": {
"type": "string",
"pattern": "^(\\d+(:\\d+(\\.\\d+)?)?)(,\\d+(:\\d+(\\.\\d+)?)?)*$",
"example": "200"
}
},
{
"name": "body",
"in": "query",
"description": "Custom body content to return in the response",
"schema": {
"type": "string"
}
},
{
"name": "header",
"in": "query",
"description": "Response header to inject, formatted 'Name:Value'. Repeatable to add multiple (e.g. ?header=Retry-After:120)",
"schema": {
"type": "string"
}
}
],
"responses": {
"100": {
"description": "Informational responses - empty body.",
"content": {}
},
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"description": "The HTTP status code"
},
"body": {
"type": "string",
"description": "Custom body content if provided"
}
},
"example": {
"status": 200
}
}
},
"text/plain": {
"schema": {
"type": "string",
"description": "Custom body content when Accept header is not application/json"
}
}
}
},
"204": {
"description": "No Content - empty body.",
"content": {}
},
"300": {
"description": "Redirection.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"304": {
"description": "Not Modified - empty body.",
"content": {}
},
"400": {
"description": "Client Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"500": {
"description": "Server Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
},
"put": {
"tags": [
"Status codes"
],
"summary": "Returns the given status code, or a random pick from a list.",
"operationId": "putStatusCodes",
"description": "Returns the given status, or a random one from a comma-separated list; supports ?header= injection, a custom body, and trailing path segments, and weighted random picks via 'code:weight'.",
"parameters": [
{
"name": "codes",
"in": "path",
"required": true,
"description": "HTTP status code(s). Multiple codes can be comma-separated (e.g., '200,201,202') for random selection; an optional relative weight per code via 'code:weight' (e.g. '200:3,404:1') biases the random pick.",
"schema": {
"type": "string",
"pattern": "^(\\d+(:\\d+(\\.\\d+)?)?)(,\\d+(:\\d+(\\.\\d+)?)?)*$",
"example": "200"
}
},
{
"name": "body",
"in": "query",
"description": "Custom body content to return in the response (overridden by request body if present)",
"schema": {
"type": "string"
}
},
{
"name": "header",
"in": "query",
"description": "Response header to inject, formatted 'Name:Value'. Repeatable to add multiple (e.g. ?header=Retry-After:120)",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"description": "Custom body content for the response (takes priority over query parameter)",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
},
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"responses": {
"100": {
"description": "Informational responses - empty body.",
"content": {}
},
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"204": {
"description": "No Content - empty body.",
"content": {}
},
"300": {
"description": "Redirection.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"304": {
"description": "Not Modified - empty body.",
"content": {}
},
"400": {
"description": "Client Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"500": {
"description": "Server Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
},
"post": {
"tags": [
"Status codes"
],
"summary": "Returns the given status code, or a random pick from a list.",
"operationId": "postStatusCodes",
"description": "Returns the given status, or a random one from a comma-separated list; supports ?header= injection, a custom body, and trailing path segments, and weighted random picks via 'code:weight'.",
"parameters": [
{
"name": "codes",
"in": "path",
"required": true,
"description": "HTTP status code(s). Multiple codes can be comma-separated (e.g., '200,201,202') for random selection; an optional relative weight per code via 'code:weight' (e.g. '200:3,404:1') biases the random pick.",
"schema": {
"type": "string",
"pattern": "^(\\d+(:\\d+(\\.\\d+)?)?)(,\\d+(:\\d+(\\.\\d+)?)?)*$",
"example": "200"
}
},
{
"name": "body",
"in": "query",
"description": "Custom body content to return in the response (overridden by request body if present)",
"schema": {
"type": "string"
}
},
{
"name": "header",
"in": "query",
"description": "Response header to inject, formatted 'Name:Value'. Repeatable to add multiple (e.g. ?header=Retry-After:120)",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"description": "Custom body content for the response (takes priority over query parameter)",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
},
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"responses": {
"100": {
"description": "Informational responses - empty body.",
"content": {}
},
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"204": {
"description": "No Content - empty body.",
"content": {}
},
"300": {
"description": "Redirection.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"304": {
"description": "Not Modified - empty body.",
"content": {}
},
"400": {
"description": "Client Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"500": {
"description": "Server Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
},
"delete": {
"tags": [
"Status codes"
],
"summary": "Returns the given status code, or a random pick from a list.",
"operationId": "deleteStatusCodes",
"description": "Returns the given status, or a random one from a comma-separated list; supports ?header= injection, a custom body, and trailing path segments, and weighted random picks via 'code:weight'.",
"parameters": [
{
"name": "codes",
"in": "path",
"required": true,
"description": "HTTP status code(s). Multiple codes can be comma-separated (e.g., '200,201,202') for random selection; an optional relative weight per code via 'code:weight' (e.g. '200:3,404:1') biases the random pick.",
"schema": {
"type": "string",
"pattern": "^(\\d+(:\\d+(\\.\\d+)?)?)(,\\d+(:\\d+(\\.\\d+)?)?)*$",
"example": "200"
}
},
{
"name": "body",
"in": "query",
"description": "Custom body content to return in the response (overridden by request body if present)",
"schema": {
"type": "string"
}
},
{
"name": "header",
"in": "query",
"description": "Response header to inject, formatted 'Name:Value'. Repeatable to add multiple (e.g. ?header=Retry-After:120)",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"description": "Custom body content for the response (takes priority over query parameter)",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
},
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"responses": {
"100": {
"description": "Informational responses - empty body.",
"content": {}
},
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"204": {
"description": "No Content - empty body.",
"content": {}
},
"300": {
"description": "Redirection.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"304": {
"description": "Not Modified - empty body.",
"content": {}
},
"400": {
"description": "Client Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"500": {
"description": "Server Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
},
"patch": {
"tags": [
"Status codes"
],
"summary": "Returns the given status code, or a random pick from a list.",
"operationId": "patchStatusCodes",
"description": "Returns the given status, or a random one from a comma-separated list; supports ?header= injection, a custom body, and trailing path segments, and weighted random picks via 'code:weight'.",
"parameters": [
{
"name": "codes",
"in": "path",
"required": true,
"description": "HTTP status code(s). Multiple codes can be comma-separated (e.g., '200,201,202') for random selection; an optional relative weight per code via 'code:weight' (e.g. '200:3,404:1') biases the random pick.",
"schema": {
"type": "string",
"pattern": "^(\\d+(:\\d+(\\.\\d+)?)?)(,\\d+(:\\d+(\\.\\d+)?)?)*$",
"example": "200"
}
},
{
"name": "body",
"in": "query",
"description": "Custom body content to return in the response (overridden by request body if present)",
"schema": {
"type": "string"
}
},
{
"name": "header",
"in": "query",
"description": "Response header to inject, formatted 'Name:Value'. Repeatable to add multiple (e.g. ?header=Retry-After:120)",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"description": "Custom body content for the response (takes priority over query parameter)",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
},
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"responses": {
"100": {
"description": "Informational responses - empty body.",
"content": {}
},
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"204": {
"description": "No Content - empty body.",
"content": {}
},
"300": {
"description": "Redirection.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"304": {
"description": "Not Modified - empty body.",
"content": {}
},
"400": {
"description": "Client Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"500": {
"description": "Server Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
},
"trace": {
"tags": [
"Status codes"
],
"summary": "Returns the given status code, or a random pick from a list.",
"operationId": "traceStatusCodes",
"description": "TRACE variant: same status selection as GET (TRACE carries no body).",
"parameters": [
{
"name": "codes",
"in": "path",
"required": true,
"description": "HTTP status code(s). Multiple codes can be comma-separated (e.g., '200,201,202') for random selection; an optional relative weight per code via 'code:weight' (e.g. '200:3,404:1') biases the random pick.",
"schema": {
"type": "string",
"pattern": "^(\\d+(:\\d+(\\.\\d+)?)?)(,\\d+(:\\d+(\\.\\d+)?)?)*$",
"example": "200"
}
},
{
"name": "body",
"in": "query",
"description": "Custom body content to return in the response",
"schema": {
"type": "string"
}
},
{
"name": "header",
"in": "query",
"description": "Response header to inject, formatted 'Name:Value'. Repeatable to add multiple (e.g. ?header=Retry-After:120)",
"schema": {
"type": "string"
}
}
],
"responses": {
"100": {
"description": "Informational responses - empty body.",
"content": {}
},
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer",
"description": "The HTTP status code"
},
"body": {
"type": "string",
"description": "Custom body content if provided"
}
},
"example": {
"status": 200
}
}
},
"text/plain": {
"schema": {
"type": "string",
"description": "Custom body content when Accept header is not application/json"
}
}
}
},
"204": {
"description": "No Content - empty body.",
"content": {}
},
"300": {
"description": "Redirection.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"304": {
"description": "Not Modified - empty body.",
"content": {}
},
"400": {
"description": "Client Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"500": {
"description": "Server Errors.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "integer"
},
"body": {
"type": "string"
}
}
}
},
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
},
"options": {
"tags": [
"Status codes"
],
"summary": "CORS preflight for /status/{codes}.",
"operationId": "optionsStatusCodes",
"description": "Returns 200 with Access-Control-Allow-* headers; ?header= overrides apply. The {codes} path segment is accepted but ignored.",
"parameters": [
{
"name": "codes",
"in": "path",
"required": true,
"description": "Ignored by OPTIONS; present to satisfy the path template.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Preflight response with Access-Control-Allow-* headers.",
"content": {}
}
}
}
},
"/stream-bytes/{n}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Streams n random bytes chunk by chunk.",
"operationId": "getStreamBytesN",
"description": "Streams n random bytes chunk by chunk; same limit behavior as /bytes.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of random bytes to stream"
},
{
"name": "seed",
"in": "query",
"description": "Optional seed for deterministic random bytes",
"schema": {
"type": "integer",
"format": "int64"
}
},
{
"name": "chunk_size",
"in": "query",
"description": "Bytes per chunk (default: 10240)",
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "n random bytes, streamed in chunks (application/octet-stream).",
"content": {}
},
"404": {
"description": "n exceeds the server max-bytes limit (configurable via --max-bytes).",
"content": {}
}
}
}
},
"/stream/{n}": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Streams n JSON lines describing the request.",
"operationId": "getStreamN",
"description": "Each line is a JSON description of the request (url, args, headers, origin), like /get; n is capped at 100.",
"parameters": [
{
"name": "n",
"in": "path",
"required": true,
"schema": {},
"description": "Number of JSON lines to stream (max 100)"
}
],
"responses": {
"200": {
"description": "Streamed JSON responses.",
"content": {}
}
}
}
},
"/healthz": {
"get": {
"tags": [
"Observability"
],
"summary": "Liveness probe for orchestrators.",
"operationId": "getHealthz",
"description": "Liveness probe: returns 200 whenever the server is up.",
"responses": {
"200": {
"description": "Service is healthy.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"example": "ok"
}
}
}
}
}
}
}
}
},
"/tags": {
"get": {
"tags": [
"Observability"
],
"summary": "Returns instance tags derived from HTTPCAN_* environment variables.",
"operationId": "getTags",
"description": "Exposes every HTTPCAN_* environment variable as a JSON object (suffix mapped to value). Useful for identifying which instance handled a request behind a load balancer. Additionally, XHTTPCAN_* env vars are injected as response headers on every response.",
"responses": {
"200": {
"description": "Map of tag name to value.",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
}
}
},
"/tags/{name}": {
"get": {
"tags": [
"Observability"
],
"summary": "Returns a single instance tag value by name.",
"operationId": "getTagsName",
"description": "Returns a single HTTPCAN_* environment variable by name.",
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"description": "Tag name (the HTTPCAN_ prefix is added automatically)",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The tag value.",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "Tag not set.",
"content": {}
}
}
}
},
"/user-agent": {
"get": {
"tags": [
"Request inspection"
],
"summary": "Returns the request's User-Agent header.",
"operationId": "getUserAgent",
"description": "Returns the User-Agent header as {\"user-agent\": \"...\"}.",
"responses": {
"200": {
"description": "The request's User-Agent header.",
"content": {}
}
}
}
},
"/uuid": {
"get": {
"tags": [
"Dynamic data"
],
"summary": "Returns a UUIDv4.",
"operationId": "getUuid",
"description": "Returns a fresh UUIDv4 as {\"uuid\": \"...\"}.",
"responses": {
"200": {
"description": "A UUIDv4.",
"content": {}
}
}
}
},
"/xml": {
"get": {
"tags": [
"Response formats"
],
"summary": "Returns a sample XML document.",
"operationId": "getXml",
"description": "Returns a sample XML document (application/xml).",
"responses": {
"200": {
"description": "An XML document.",
"content": {}
}
}
}
},
"/sse": {
"get": {
"tags": [
"Streaming"
],
"summary": "Streams server-sent events (configurable count/delay/format).",
"operationId": "getSse",
"description": "Streams server-sent events; supports OpenAI-compatible chunk formats.",
"parameters": [
{
"name": "count",
"in": "query",
"description": "Number of events to send (default: 5, max: 100)",
"schema": {
"type": "integer",
"default": 5,
"minimum": 1,
"maximum": 100
}
},
{
"name": "delay",
"in": "query",
"description": "Delay between events in milliseconds (default: 1000, max: 10000)",
"schema": {
"type": "integer",
"default": 1000,
"minimum": 100,
"maximum": 10000
}
},
{
"name": "format",
"in": "query",
"description": "Message format",
"schema": {
"type": "string",
"enum": [
"simple",
"openai",
"custom"
],
"default": "simple"
}
},
{
"name": "message",
"in": "query",
"description": "Custom message content (used with format=custom)",
"schema": {
"type": "string"
}
},
{
"name": "event_type",
"in": "query",
"description": "SSE event type",
"schema": {
"type": "string",
"default": "message"
}
}
],
"responses": {
"200": {
"description": "SSE event stream.",
"content": {
"text/event-stream": {
"itemSchema": {
"$ref": "#/components/schemas/SseEventItem"
}
}
}
}
}
}
},
"/sse/{count}": {
"get": {
"tags": [
"Streaming"
],
"summary": "Streams server-sent events with a fixed count.",
"operationId": "getSseCount",
"description": "Same as /sse, with a fixed event count.",
"parameters": [
{
"name": "count",
"in": "path",
"required": true,
"description": "Number of events to send (max: 100)",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
{
"name": "delay",
"in": "query",
"description": "Delay between events in milliseconds (default: 1000, max: 10000)",
"schema": {
"type": "integer",
"default": 1000,
"minimum": 100,
"maximum": 10000
}
},
{
"name": "format",
"in": "query",
"description": "Message format",
"schema": {
"type": "string",
"enum": [
"simple",
"openai",
"custom"
],
"default": "simple"
}
},
{
"name": "message",
"in": "query",
"description": "Custom message content (used with format=custom)",
"schema": {
"type": "string"
}
},
{
"name": "event_type",
"in": "query",
"description": "SSE event type",
"schema": {
"type": "string",
"default": "message"
}
}
],
"responses": {
"200": {
"description": "SSE event stream.",
"content": {
"text/event-stream": {
"itemSchema": {
"$ref": "#/components/schemas/SseEventItem"
}
}
}
}
}
}
},
"/sse/{count}/{delay}": {
"get": {
"tags": [
"Streaming"
],
"summary": "Streams server-sent events with fixed count and delay.",
"operationId": "getSseCountDelay",
"description": "Same as /sse, with a fixed count and delay between events.",
"parameters": [
{
"name": "count",
"in": "path",
"required": true,
"description": "Number of events to send (max: 100)",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
{
"name": "delay",
"in": "path",
"required": true,
"description": "Delay between events in milliseconds (max: 10000)",
"schema": {
"type": "integer",
"minimum": 100,
"maximum": 10000
}
},
{
"name": "format",
"in": "query",
"description": "Message format",
"schema": {
"type": "string",
"enum": [
"simple",
"openai",
"custom"
],
"default": "simple"
}
},
{
"name": "message",
"in": "query",
"description": "Custom message content (used with format=custom)",
"schema": {
"type": "string"
}
},
{
"name": "event_type",
"in": "query",
"description": "SSE event type",
"schema": {
"type": "string",
"default": "message"
}
}
],
"responses": {
"200": {
"description": "SSE event stream.",
"content": {
"text/event-stream": {
"itemSchema": {
"$ref": "#/components/schemas/SseEventItem"
}
}
}
}
}
}
},
"/ndjson": {
"get": {
"tags": [
"Streaming"
],
"summary": "Streams newline-delimited JSON with configurable parameters.",
"operationId": "getNdjson",
"description": "Streams newline-delimited JSON; supports OpenAI/Ollama-compatible chunk formats.",
"parameters": [
{
"name": "count",
"in": "query",
"description": "Number of events to send (default: 5, max: 100)",
"schema": {
"type": "integer",
"default": 5,
"minimum": 1,
"maximum": 100
}
},
{
"name": "delay",
"in": "query",
"description": "Delay between events in milliseconds (default: 1000, max: 10000)",
"schema": {
"type": "integer",
"default": 1000,
"minimum": 100,
"maximum": 10000
}
},
{
"name": "format",
"in": "query",
"description": "Message format",
"schema": {
"type": "string",
"enum": [
"simple",
"openai",
"ollama",
"custom"
],
"default": "simple"
}
},
{
"name": "message",
"in": "query",
"description": "Custom message content (used with format=custom)",
"schema": {
"type": "string"
}
},
{
"name": "model",
"in": "query",
"description": "Model name for ollama format",
"schema": {
"type": "string",
"default": "llama2"
}
}
],
"responses": {
"200": {
"description": "NDJSON stream.",
"content": {
"application/x-ndjson": {
"itemSchema": {
"$ref": "#/components/schemas/NdjsonLineItem"
}
}
}
}
}
}
},
"/ndjson/{count}": {
"get": {
"tags": [
"Streaming"
],
"summary": "Streams newline-delimited JSON with a fixed line count.",
"operationId": "getNdjsonCount",
"description": "Same as /ndjson, with a fixed line count.",
"parameters": [
{
"name": "count",
"in": "path",
"required": true,
"description": "Number of events to send (max: 100)",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
{
"name": "delay",
"in": "query",
"description": "Delay between events in milliseconds (default: 1000, max: 10000)",
"schema": {
"type": "integer",
"default": 1000,
"minimum": 100,
"maximum": 10000
}
},
{
"name": "format",
"in": "query",
"description": "Message format",
"schema": {
"type": "string",
"enum": [
"simple",
"openai",
"ollama",
"custom"
],
"default": "simple"
}
},
{
"name": "message",
"in": "query",
"description": "Custom message content (used with format=custom)",
"schema": {
"type": "string"
}
},
{
"name": "model",
"in": "query",
"description": "Model name for ollama format",
"schema": {
"type": "string",
"default": "llama2"
}
}
],
"responses": {
"200": {
"description": "NDJSON stream.",
"content": {
"application/x-ndjson": {
"itemSchema": {
"$ref": "#/components/schemas/NdjsonLineItem"
}
}
}
}
}
}
},
"/ndjson/{count}/{delay}": {
"get": {
"tags": [
"Streaming"
],
"summary": "Streams newline-delimited JSON with fixed count and delay.",
"operationId": "getNdjsonCountDelay",
"description": "Same as /ndjson, with a fixed count and delay between lines.",
"parameters": [
{
"name": "count",
"in": "path",
"required": true,
"description": "Number of events to send (max: 100)",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
{
"name": "delay",
"in": "path",
"required": true,
"description": "Delay between events in milliseconds (max: 10000)",
"schema": {
"type": "integer",
"minimum": 100,
"maximum": 10000
}
},
{
"name": "format",
"in": "query",
"description": "Message format",
"schema": {
"type": "string",
"enum": [
"simple",
"openai",
"ollama",
"custom"
],
"default": "simple"
}
},
{
"name": "message",
"in": "query",
"description": "Custom message content (used with format=custom)",
"schema": {
"type": "string"
}
},
{
"name": "model",
"in": "query",
"description": "Model name for ollama format",
"schema": {
"type": "string",
"default": "llama2"
}
}
],
"responses": {
"200": {
"description": "NDJSON stream.",
"content": {
"application/x-ndjson": {
"itemSchema": {
"$ref": "#/components/schemas/NdjsonLineItem"
}
}
}
}
}
}
},
"/body": {
"get": {
"tags": [
"Request inspection"
],
"summary": "Returns an empty response for GET requests (no body to return).",
"operationId": "GetBody",
"description": "Mirrors request headers in the response. GET requests return empty body since there's no request body to echo.",
"responses": {
"200": {
"description": "Empty response with mirrored headers.",
"content": {
"text/plain": {
"schema": {
"type": "string",
"example": ""
}
}
}
}
}
},
"post": {
"tags": [
"Request inspection"
],
"summary": "Returns the exact request body with mirrored headers.",
"operationId": "PostBody",
"description": "Echoes the request body exactly as received and mirrors request headers in the response. Content-Type and custom headers are preserved.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object"
},
"example": {
"hello": "world"
}
},
"text/plain": {
"schema": {
"type": "string"
},
"example": "Hello, world!"
},
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": true
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "Echoed request body with mirrored headers.",
"content": {
"application/json": {
"schema": {
"type": "object"
},
"example": {
"hello": "world"
}
},
"text/plain": {
"schema": {
"type": "string"
},
"example": "Hello, world!"
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
},
"put": {
"tags": [
"Request inspection"
],
"summary": "Returns the exact request body with mirrored headers.",
"operationId": "PutBody",
"description": "Echoes the request body exactly as received and mirrors request headers in the response. Content-Type and custom headers are preserved.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": true
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "Echoed request body with mirrored headers.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
},
"patch": {
"tags": [
"Request inspection"
],
"summary": "Returns the exact request body with mirrored headers.",
"operationId": "PatchBody",
"description": "Echoes the request body exactly as received and mirrors request headers in the response. Content-Type and custom headers are preserved.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": true
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "Echoed request body with mirrored headers.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
},
"delete": {
"tags": [
"Request inspection"
],
"summary": "Returns the exact request body with mirrored headers.",
"operationId": "DeleteBody",
"description": "Echoes the request body exactly as received and mirrors request headers in the response. Content-Type and custom headers are preserved.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": true
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "Echoed request body with mirrored headers.",
"content": {
"application/json": {
"schema": {
"type": "object"
}
},
"text/plain": {
"schema": {
"type": "string"
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
},
"query": {
"tags": [
"Request inspection"
],
"summary": "Returns the exact request body with mirrored headers.",
"operationId": "QueryBody",
"description": "Echoes the request body exactly as received, via the QUERY HTTP method (RFC 9430): a safe, idempotent method that carries a request body.",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object"
},
"example": {
"hello": "world"
}
},
"text/plain": {
"schema": {
"type": "string"
},
"example": "Hello, world!"
},
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": true
}
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"responses": {
"200": {
"description": "Echoed request body with mirrored headers.",
"content": {
"application/json": {
"schema": {
"type": "object"
},
"example": {
"hello": "world"
}
},
"text/plain": {
"schema": {
"type": "string"
},
"example": "Hello, world!"
},
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
}
}
}
},
"/llm": {
"get": {
"tags": [
"AI API Mock"
],
"summary": "Self-describing index of the LLM mock endpoints",
"operationId": "getLlmIndex",
"description": "Endpoints, base_url guidance for OpenAI/Anthropic SDKs, and the httpcan response-override contract.",
"responses": {
"200": {
"description": "LLM mock index",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
}
}
},
"/llm/v1/chat/completions": {
"post": {
"tags": [
"AI API Mock"
],
"summary": "Mock OpenAI Chat Completions API",
"operationId": "createChatCompletionMock",
"description": "Returns a canonical chat.completion response. Supports stream:true (chat.completion.chunk SSE with [DONE], include_usage via stream_options) and an httpcan.content body override. /llm/chat/completions is an undocumented silent alias.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"messages"
],
"properties": {
"model": {
"type": "string"
},
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"role": {
"type": "string"
},
"content": {
"oneOf": [
{
"type": "string"
},
{
"type": "array"
}
]
}
}
}
},
"n": {
"type": "integer",
"default": 1
},
"stream": {
"type": "boolean",
"default": false
},
"stream_options": {
"type": "object",
"properties": {
"include_usage": {
"type": "boolean"
}
}
},
"httpcan": {
"type": "object",
"properties": {
"content": {
"type": "string"
}
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "chat.completion object or SSE stream"
},
"400": {
"description": "OpenAI-shaped error"
},
"405": {
"description": "Method not allowed (POST only)"
}
}
}
},
"/llm/v1/messages": {
"post": {
"tags": [
"AI API Mock"
],
"summary": "Mock Anthropic Messages API",
"operationId": "createMessageMock",
"description": "Returns an Anthropic message with text content blocks and stop_reason. Supports stream:true (full event protocol: message_start through message_stop) and an httpcan.content body override.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"messages"
],
"properties": {
"model": {
"type": "string"
},
"messages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"role": {
"type": "string"
},
"content": {
"oneOf": [
{
"type": "string"
},
{
"type": "array"
}
]
}
}
}
},
"max_tokens": {
"type": "integer"
},
"system": {
"oneOf": [
{
"type": "string"
},
{
"type": "array"
}
]
},
"stream": {
"type": "boolean",
"default": false
},
"httpcan": {
"type": "object",
"properties": {
"content": {
"type": "string"
}
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "Anthropic message object or SSE event stream"
},
"400": {
"description": "Anthropic-shaped error"
},
"405": {
"description": "Method not allowed (POST only)"
}
}
}
},
"/llm/v1/models": {
"get": {
"tags": [
"AI API Mock"
],
"summary": "List mock models",
"operationId": "listMockModels",
"description": "OpenAI list shape by default; Anthropic shape when an anthropic-version request header is present (both SDK families construct this same path).",
"responses": {
"200": {
"description": "Model list"
}
}
}
},
"/llm/v1/models/{model}": {
"get": {
"tags": [
"AI API Mock"
],
"summary": "Retrieve a mock model",
"operationId": "retrieveMockModel",
"description": "Always returns 200 and echoes the requested model id — any model name is valid, consistent with the lenient chat endpoints.",
"parameters": [
{
"name": "model",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Model object"
}
}
}
},
"/llm/v1/responses": {
"post": {
"tags": [
"AI API Mock"
],
"summary": "Mock OpenAI Responses API",
"operationId": "createResponseMock",
"description": "Returns a canonical Response object (spec-required fields incl. temperature/top_p/metadata/tool_choice, output_text convenience, ResponseUsage with detail sub-objects). Streaming emits named SSE events (response.created through response.completed) with incrementing sequence_number and no [DONE] sentinel. /llm/responses is an undocumented silent alias. instructions is echoed back.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"model": {
"type": "string"
},
"input": {
"oneOf": [
{
"type": "string"
},
{
"type": "array"
}
]
},
"instructions": {
"type": "string"
},
"stream": {
"type": "boolean",
"default": false
},
"httpcan": {
"type": "object",
"properties": {
"content": {
"type": "string"
}
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "Response object or named SSE event stream"
},
"400": {
"description": "OpenAI-shaped error"
},
"405": {
"description": "Method not allowed (POST only)"
}
}
}
},
"/llm/v1/completions": {
"post": {
"tags": [
"AI API Mock"
],
"summary": "Mock OpenAI legacy Completions API",
"operationId": "createCompletionMock",
"description": "Text-in/text-out legacy completions: canonical text_completion shape with spec-required choices fields (logprobs as null). Supports prompt as string or arrays, echo:true (prepends the prompt), n choices, SSE streaming (no role first-chunk, stop chunk, [DONE], include_usage via stream_options) and the httpcan.content override. /llm/completions is an undocumented silent alias.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"prompt"
],
"properties": {
"model": {
"type": "string"
},
"prompt": {
"oneOf": [
{
"type": "string"
},
{
"type": "array"
}
]
},
"n": {
"type": "integer",
"default": 1
},
"echo": {
"type": "boolean",
"default": false
},
"stream": {
"type": "boolean",
"default": false
},
"stream_options": {
"type": "object",
"properties": {
"include_usage": {
"type": "boolean"
}
}
},
"httpcan": {
"type": "object",
"properties": {
"content": {
"type": "string"
}
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "text_completion object or SSE stream"
},
"400": {
"description": "OpenAI-shaped error"
},
"405": {
"description": "Method not allowed (POST only)"
}
}
}
},
"/oauth2": {
"get": {
"tags": [
"OAuth 2.0 Mock"
],
"summary": "Self-describing index of the OAuth 2.0 mock",
"operationId": "getOauth2Index",
"description": "Endpoints, supported grants, PKCE methods, and the mock's state semantics (any credentials accepted unless --oauth2-clients is configured; restarting invalidates issued codes and tokens).",
"responses": {
"200": {
"description": "OAuth 2.0 mock index",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
}
}
},
"/oauth2/authorize": {
"get": {
"tags": [
"OAuth 2.0 Mock"
],
"summary": "Authorization endpoint (renders the consent page)",
"operationId": "getOauth2Authorize",
"description": "Validates the authorization request (RFC 6749 §4.1.1: response_type, client_id, redirect_uri, scope, state, code_challenge) and renders a mock consent page. response_type=code issues a one-time authorization code on approval; response_type=token (implicit, legacy) returns the access token in the redirect fragment. Invalid redirect_uri or client_id is never redirected (§3.1.2.4); other errors are returned to the client via error redirects (§4.1.2.1).",
"parameters": [
{
"name": "response_type",
"in": "query",
"required": true,
"schema": {
"type": "string",
"enum": [
"code",
"token"
]
}
},
{
"name": "client_id",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "redirect_uri",
"in": "query",
"required": true,
"schema": {
"type": "string",
"format": "uri"
}
},
{
"name": "scope",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "state",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "code_challenge",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "code_challenge_method",
"in": "query",
"schema": {
"type": "string",
"enum": [
"S256",
"plain"
]
}
}
],
"responses": {
"200": {
"description": "Consent page (text/html)"
},
"400": {
"description": "Invalid redirect_uri or missing client_id (not redirected)"
},
"302": {
"description": "Error redirect for other invalid requests (unsupported_response_type, invalid_request)"
}
}
},
"post": {
"tags": [
"OAuth 2.0 Mock"
],
"summary": "Process the consent decision",
"operationId": "submitOauth2Consent",
"description": "Consumes the consent form (hidden authorize parameters plus email and decision). Approve: 302 with code+state in the query (code flow) or access_token in the fragment (implicit flow, never a refresh token). Decline: 302 with error=access_denied.",
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"required": [
"response_type",
"client_id",
"redirect_uri",
"email",
"decision"
],
"properties": {
"response_type": {
"type": "string"
},
"client_id": {
"type": "string"
},
"redirect_uri": {
"type": "string"
},
"state": {
"type": "string"
},
"scope": {
"type": "string"
},
"code_challenge": {
"type": "string"
},
"code_challenge_method": {
"type": "string"
},
"email": {
"type": "string"
},
"decision": {
"type": "string",
"enum": [
"approve",
"decline"
]
}
}
}
}
}
},
"responses": {
"302": {
"description": "Redirect to redirect_uri with code/token or error parameters"
},
"400": {
"description": "Invalid redirect_uri or missing email (not redirected)"
}
}
}
},
"/oauth2/token": {
"post": {
"tags": [
"OAuth 2.0 Mock"
],
"summary": "Token endpoint (four grants)",
"operationId": "createOauth2Token",
"description": "RFC 6749 token endpoint supporting authorization_code (+PKCE), password (legacy), refresh_token (rotating), and client_credentials. Client authentication via Authorization: Basic or form-body client_secret; both at once is rejected. Responses carry Cache-Control: no-store and Pragma: no-cache (§5.1). Without --oauth2-clients any non-empty secret passes.",
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"required": [
"grant_type"
],
"properties": {
"grant_type": {
"type": "string",
"enum": [
"authorization_code",
"password",
"refresh_token",
"client_credentials"
]
},
"code": {
"type": "string"
},
"redirect_uri": {
"type": "string"
},
"code_verifier": {
"type": "string"
},
"username": {
"type": "string"
},
"password": {
"type": "string"
},
"refresh_token": {
"type": "string"
},
"scope": {
"type": "string"
},
"client_id": {
"type": "string"
},
"client_secret": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Token response: access_token, token_type, expires_in, optional refresh_token and scope",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"400": {
"description": "invalid_request / invalid_grant / unsupported_grant_type (RFC 6749 §5.2 JSON)"
},
"401": {
"description": "invalid_client (when --oauth2-clients is configured)"
}
}
}
},
"/oauth2/userinfo": {
"get": {
"tags": [
"OAuth 2.0 Mock"
],
"summary": "Bearer-protected resource returning the mock identity",
"operationId": "getOauth2Userinfo",
"description": "Verifies the Bearer access token and returns sub/email/client_id/scope. 401 challenges carry error=\"invalid_token\" attributes per RFC 6750 §3.",
"responses": {
"200": {
"description": "Identity claims",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"401": {
"description": "Missing or invalid Bearer token (WWW-Authenticate challenge)"
}
},
"security": [
{
"bearerAuth": []
}
]
},
"post": {
"tags": [
"OAuth 2.0 Mock"
],
"summary": "Bearer-protected resource returning the mock identity",
"operationId": "postOauth2Userinfo",
"description": "Same contract as GET.",
"responses": {
"200": {
"description": "Identity claims"
},
"401": {
"description": "Missing or invalid Bearer token"
}
},
"security": [
{
"bearerAuth": []
}
]
}
}
},
"components": {
"schemas": {
"RequestInfo": {
"type": "object",
"properties": {
"args": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Query string parameters."
},
"data": {
"type": "string",
"description": "Request body content."
},
"files": {
"type": "object",
"additionalProperties": {
"oneOf": [
{
"type": "string",
"description": "Single file content (text or base64 encoded)"
},
{
"type": "array",
"items": {
"type": "string",
"description": "File content (text or base64 encoded)"
},
"description": "Multiple files with the same parameter name"
}
]
},
"description": "Uploaded files. Single files return as string, multiple files with same parameter name return as array.",
"example": {
"single_file": "file content here",
"multiple_files": [
"first file content",
"second file content"
]
}
},
"form": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Form data fields."
},
"headers": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Request headers (excluding proxy headers)."
},
"json": {
"description": "Parsed JSON content if Content-Type is application/json."
},
"method": {
"type": "string",
"description": "HTTP method."
},
"origin": {
"type": "string",
"description": "Client IP address."
},
"url": {
"type": "string",
"description": "Full request URL."
},
"user_agent": {
"type": "string",
"description": "User-Agent header value."
}
}
},
"GetRequestInfo": {
"type": "object",
"properties": {
"args": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Query string parameters."
},
"headers": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Request headers (excluding proxy headers)."
},
"origin": {
"type": "string",
"description": "Client IP address."
},
"url": {
"type": "string",
"description": "Full request URL."
}
}
},
"SseEventItem": {
"description": "Payload of one `data:` event in the SSE stream. Shape depends on the `format` parameter: `simple` (default), `openai` (chat.completion.chunk), or `custom` (plain string).",
"oneOf": [
{
"$ref": "#/components/schemas/SimpleStreamEvent"
},
{
"$ref": "#/components/schemas/OpenAIChatChunk"
},
{
"type": "string",
"description": "format=custom: the custom message verbatim"
}
]
},
"NdjsonLineItem": {
"description": "One JSON line in the NDJSON stream. Shape depends on the `format` parameter: `simple` (default), `openai`, `ollama`, or `custom` (plain string).",
"oneOf": [
{
"$ref": "#/components/schemas/SimpleStreamEvent"
},
{
"$ref": "#/components/schemas/OpenAIChatChunk"
},
{
"$ref": "#/components/schemas/OllamaChunk"
},
{
"type": "string",
"description": "format=custom: the custom message verbatim"
}
]
},
"SimpleStreamEvent": {
"type": "object",
"properties": {
"event": {
"type": "integer",
"description": "1-based event index."
},
"message": {
"type": "string",
"description": "Human-readable event text."
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "RFC 3339 timestamp of the event."
}
}
},
"OpenAIChatChunk": {
"type": "object",
"description": "OpenAI-compatible chat.completion.chunk",
"properties": {
"id": {
"type": "string",
"description": "Unique chunk id (chatcmpl-*)."
},
"object": {
"type": "string",
"const": "chat.completion.chunk",
"description": "Always \"chat.completion.chunk\"."
},
"created": {
"type": "integer",
"description": "Unix timestamp (seconds)."
},
"model": {
"type": "string",
"description": "Always \"httpcan-sse\"."
},
"choices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"delta": {
"type": "object",
"properties": {
"content": {
"type": [
"string",
"null"
]
},
"role": {
"type": [
"string",
"null"
]
}
}
},
"index": {
"type": "integer"
},
"finish_reason": {
"type": [
"string",
"null"
]
}
}
},
"description": "Single-element array with the delta."
}
}
},
"OllamaChunk": {
"type": "object",
"description": "Ollama-compatible streaming response",
"properties": {
"model": {
"type": "string",
"description": "Model name (from ?model=, default llama2)."
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "RFC 3339 timestamp."
},
"response": {
"type": "string",
"description": "The text token for this chunk."
},
"done": {
"type": "boolean",
"description": "True on the final chunk."
},
"context": {
"type": "array",
"items": {
"type": "integer"
},
"description": "Token context, only on the final chunk."
},
"total_duration": {
"type": "integer",
"description": "Total time in ns, final chunk only."
},
"load_duration": {
"type": "integer",
"description": "Model load time in ns, final chunk only."
},
"prompt_eval_count": {
"type": "integer",
"description": "Prompt token count, final chunk only."
},
"prompt_eval_duration": {
"type": "integer",
"description": "Prompt eval time in ns, final chunk only."
},
"eval_count": {
"type": "integer",
"description": "Generated token count, final chunk only."
},
"eval_duration": {
"type": "integer",
"description": "Generation time in ns, final chunk only."
}
}
}
},
"securitySchemes": {
"basicAuth": {
"type": "http",
"scheme": "basic"
},
"bearerAuth": {
"type": "http",
"scheme": "bearer"
},
"digestAuth": {
"type": "http",
"scheme": "digest"
}
}
},
"x-original-swagger-version": "2.0"
}