{
  "service": "http.placeholder.com",
  "description": "Free HTTP request and response test endpoints (httpbin-compatible where sensible).",
  "endpoints": [
    {
      "group": "inspect",
      "path": "/get",
      "methods": "GET",
      "description": "Echo query args, headers, origin IP and URL.",
      "example": "https://http.placeholder.com/get?foo=bar"
    },
    {
      "group": "inspect",
      "path": "/post",
      "methods": "POST",
      "description": "Echo args, headers and the body (data, form, files, json).",
      "example": "https://http.placeholder.com/post"
    },
    {
      "group": "inspect",
      "path": "/put",
      "methods": "PUT",
      "description": "Same as /post for PUT.",
      "example": "https://http.placeholder.com/put"
    },
    {
      "group": "inspect",
      "path": "/patch",
      "methods": "PATCH",
      "description": "Same as /post for PATCH.",
      "example": "https://http.placeholder.com/patch"
    },
    {
      "group": "inspect",
      "path": "/delete",
      "methods": "DELETE",
      "description": "Same as /post for DELETE.",
      "example": "https://http.placeholder.com/delete"
    },
    {
      "group": "inspect",
      "path": "/anything[/{path}]",
      "methods": "any",
      "description": "Echo any method and path, always as JSON.",
      "example": "https://http.placeholder.com/anything/a/b?x=1"
    },
    {
      "group": "inspect",
      "path": "/headers",
      "methods": "GET",
      "description": "Echo request headers.",
      "example": "https://http.placeholder.com/headers"
    },
    {
      "group": "inspect",
      "path": "/ip",
      "methods": "GET",
      "description": "Caller IP address.",
      "example": "https://http.placeholder.com/ip"
    },
    {
      "group": "inspect",
      "path": "/user-agent",
      "methods": "GET",
      "description": "Caller User-Agent.",
      "example": "https://http.placeholder.com/user-agent"
    },
    {
      "group": "inspect",
      "path": "/uuid",
      "methods": "GET",
      "description": "A random UUID4.",
      "example": "https://http.placeholder.com/uuid"
    },
    {
      "group": "status",
      "path": "/status/{codes}",
      "methods": "GET POST PUT PATCH DELETE",
      "description": "Respond with a status code; comma list picks one at random, code:weight weights it, ?seed= makes it repeatable.",
      "example": "https://http.placeholder.com/status/200:0.9,500:0.1?seed=42"
    },
    {
      "group": "redirect",
      "path": "/redirect/{n}",
      "methods": "GET",
      "description": "Redirect n times, then /get (?absolute=true for absolute URLs).",
      "example": "https://http.placeholder.com/redirect/3"
    },
    {
      "group": "redirect",
      "path": "/relative-redirect/{n}",
      "methods": "GET",
      "description": "Relative redirect n times.",
      "example": "https://http.placeholder.com/relative-redirect/3"
    },
    {
      "group": "redirect",
      "path": "/absolute-redirect/{n}",
      "methods": "GET",
      "description": "Absolute redirect n times.",
      "example": "https://http.placeholder.com/absolute-redirect/3"
    },
    {
      "group": "redirect",
      "path": "/redirect-to?url=&status_code=",
      "methods": "any",
      "description": "Redirect to a relative path or an http.placeholder.com URL (no other hosts).",
      "example": "https://http.placeholder.com/redirect-to?url=/get&status_code=307"
    },
    {
      "group": "auth",
      "path": "/basic-auth/{user}/{passwd}",
      "methods": "GET",
      "description": "HTTP Basic auth challenge (401 when wrong).",
      "example": "https://http.placeholder.com/basic-auth/user/passwd"
    },
    {
      "group": "auth",
      "path": "/hidden-basic-auth/{user}/{passwd}",
      "methods": "GET",
      "description": "Basic auth that answers 404 when wrong.",
      "example": "https://http.placeholder.com/hidden-basic-auth/user/passwd"
    },
    {
      "group": "auth",
      "path": "/bearer",
      "methods": "GET",
      "description": "Requires an Authorization: Bearer token.",
      "example": "https://http.placeholder.com/bearer"
    },
    {
      "group": "cookies",
      "path": "/cookies",
      "methods": "GET",
      "description": "Echo cookies sent.",
      "example": "https://http.placeholder.com/cookies"
    },
    {
      "group": "cookies",
      "path": "/cookies/set?name=value",
      "methods": "GET",
      "description": "Set host-only cookies, then redirect to /cookies.",
      "example": "https://http.placeholder.com/cookies/set?flavour=oat"
    },
    {
      "group": "cookies",
      "path": "/cookies/set/{name}/{value}",
      "methods": "GET",
      "description": "Set one cookie, then redirect to /cookies.",
      "example": "https://http.placeholder.com/cookies/set/flavour/oat"
    },
    {
      "group": "cookies",
      "path": "/cookies/delete?name",
      "methods": "GET",
      "description": "Expire cookies, then redirect to /cookies.",
      "example": "https://http.placeholder.com/cookies/delete?flavour"
    },
    {
      "group": "caching",
      "path": "/cache",
      "methods": "GET",
      "description": "304 when If-Modified-Since or If-None-Match is sent.",
      "example": "https://http.placeholder.com/cache"
    },
    {
      "group": "caching",
      "path": "/cache/{n}",
      "methods": "GET",
      "description": "Cache-Control: public, max-age=n.",
      "example": "https://http.placeholder.com/cache/60"
    },
    {
      "group": "caching",
      "path": "/etag/{etag}",
      "methods": "GET",
      "description": "ETag with If-None-Match (304) and If-Match (412) handling.",
      "example": "https://http.placeholder.com/etag/abc123"
    },
    {
      "group": "timing",
      "path": "/delay/{seconds}",
      "methods": "GET POST PUT PATCH DELETE",
      "description": "Wait, then echo.",
      "example": "https://http.placeholder.com/delay/2"
    },
    {
      "group": "timing",
      "path": "/drip?duration=&numbytes=&code=&delay=",
      "methods": "GET",
      "description": "Trickle bytes over a duration.",
      "example": "https://http.placeholder.com/drip?duration=3&numbytes=30"
    },
    {
      "group": "timing",
      "path": "/sse?count=&interval=",
      "methods": "GET",
      "description": "Server-sent events, then an 'end' event.",
      "example": "https://http.placeholder.com/sse?count=5&interval=1"
    },
    {
      "group": "data",
      "path": "/bytes/{n}",
      "methods": "GET",
      "description": "n random bytes (?seed= for repeatable output).",
      "example": "https://http.placeholder.com/bytes/1024?seed=1"
    },
    {
      "group": "data",
      "path": "/stream-bytes/{n}",
      "methods": "GET",
      "description": "n random bytes, chunked (?chunk_size=, at most 4096 chunks; ?seed=).",
      "example": "https://http.placeholder.com/stream-bytes/4096?chunk_size=512"
    },
    {
      "group": "data",
      "path": "/stream/{n}",
      "methods": "GET",
      "description": "n lines of NDJSON.",
      "example": "https://http.placeholder.com/stream/5"
    },
    {
      "group": "data",
      "path": "/range/{n}",
      "methods": "GET",
      "description": "n bytes supporting a single Range request (206/416).",
      "example": "https://http.placeholder.com/range/1024"
    },
    {
      "group": "formats",
      "path": "/gzip",
      "methods": "GET",
      "description": "gzip-encoded JSON.",
      "example": "https://http.placeholder.com/gzip"
    },
    {
      "group": "formats",
      "path": "/deflate",
      "methods": "GET",
      "description": "deflate-encoded JSON.",
      "example": "https://http.placeholder.com/deflate"
    },
    {
      "group": "formats",
      "path": "/brotli",
      "methods": "GET",
      "description": "brotli-encoded JSON.",
      "example": "https://http.placeholder.com/brotli"
    },
    {
      "group": "formats",
      "path": "/encoding/utf8",
      "methods": "GET",
      "description": "UTF-8 sample text.",
      "example": "https://http.placeholder.com/encoding/utf8"
    },
    {
      "group": "formats",
      "path": "/json",
      "methods": "GET",
      "description": "Sample JSON document.",
      "example": "https://http.placeholder.com/json"
    },
    {
      "group": "formats",
      "path": "/xml",
      "methods": "GET",
      "description": "Sample XML document.",
      "example": "https://http.placeholder.com/xml"
    },
    {
      "group": "formats",
      "path": "/html",
      "methods": "GET",
      "description": "A fixed sample HTML page.",
      "example": "https://http.placeholder.com/html"
    },
    {
      "group": "formats",
      "path": "/robots.txt",
      "methods": "GET",
      "description": "robots.txt.",
      "example": "https://http.placeholder.com/robots.txt"
    },
    {
      "group": "formats",
      "path": "/deny",
      "methods": "GET",
      "description": "Page disallowed by robots.txt.",
      "example": "https://http.placeholder.com/deny"
    },
    {
      "group": "headers",
      "path": "/response-headers?X-Name=value",
      "methods": "GET",
      "description": "Add harmless response headers (X-* and a short allowlist; never Content-Type, Location, Set-Cookie or CSP).",
      "example": "https://http.placeholder.com/response-headers?X-Test=1&Server-Timing=db;dur=53"
    }
  ],
  "limits": {
    "body_bytes": 1048576,
    "fields": 100,
    "json_depth": 64,
    "delay_seconds": 10,
    "redirects": 20,
    "bytes": 10485760,
    "stream_lines": 100,
    "range_bytes": 102400,
    "drip_bytes": 10240,
    "drip_seconds": 10,
    "sse_events": 100,
    "sse_seconds": 60,
    "cache_max_age": 86400,
    "cookies_per_request": 5,
    "cookie_value_chars": 128,
    "response_headers": 10,
    "status_choices": 20
  },
  "notes": [
    "Echo output is always JSON. No HTML or content type is ever taken from the request.",
    "CORS is open (Access-Control-Allow-Origin: *) without credentials.",
    "Responses are Cache-Control: no-store except /cache, /cache/{n} and /etag/{etag}.",
    "Nothing is stored and request contents are not logged.",
    "Client IP comes from CF-Connecting-IP (Cloudflare)."
  ]
}
