{"openapi":"3.0.4","info":{"title":"TestingAPIs","description":"**TestingAPIs** — hardcoded dummy APIs for testing HTTP clients, API tools and automation suites.\r\nAll data is in-memory and resets when the server restarts.\r\n\r\n### Works on every endpoint\r\n| Query param | Effect |\r\n|---|---|\r\n| `?delay=N` | Wait N seconds (max 10) before responding |\r\n| `?error=CODE` | Return a simulated error (400, 401, 403, 404, 408, 429, 500, 502, 503) with `X-Simulated: true` |\r\n\r\nList endpoints also accept `limit`, `page`, `offset`, `sort`, `order`, `q` and any field name as a filter,\r\nand return `X-Total-Count`, `X-Page`, `X-Per-Page` and `X-Total-Pages` headers.\r\n\r\n### Test credentials\r\n| Scheme | Value |\r\n|---|---|\r\n| Basic (`/api/auth/*`) | `apibee` / `password123` |\r\n| Basic (`/api/AuthTest`) | `Admin` / `Admin@1234` |\r\n| Bearer (static) | `apibee-token-123` · role tokens `admin-token`, `user-token`, `readonly-token` |\r\n| API key | `apibee-key-123` (header `X-API-Key` or query `api_key`) |\r\n| JWT | `POST /api/auth/jwt/login` with `admin`/`admin123` or `user`/`user123` · legacy `POST /api/User/Login` with `Michael`/`Thompson` |\r\n| OAuth 1.0a | consumer `apibee-consumer-key` / `apibee-consumer-secret`, token `apibee-access-token` / `apibee-token-secret`, or run request_token → authorize → access_token |\r\n| OAuth2 | client `apibee-client` / `apibee-secret`, public PKCE client `apibee-public`, users `apibee`/`password123` |\r\n| HMAC secret | `apibee-hmac-secret` |\r\n\r\n### Not shown here\r\n- **GraphQL**: `POST /graphql` (open `/graphql` in a browser for the GraphQL IDE)\r\n- **WebSockets**: `ws://{host}/ws/echo`, `ws://{host}/ws/ticker`\r\n- **Route catalog**: `GET /api` lists every live route","version":"v1"},"paths":{"/api":{"get":{"tags":["Catalog"],"summary":"List every API endpoint, grouped by controller.","description":"Built from the live route table, so it always matches the running build. Also points to the GraphQL and WebSocket endpoints.","operationId":"Catalog_Catalog","responses":{"200":{"description":"The endpoint catalog."}}}},"/api/health":{"get":{"tags":["Catalog"],"summary":"Check that the API is up (HEAD also supported).","operationId":"Catalog_Health_GET","responses":{"200":{"description":"Status, uptime in seconds and the current time."}}},"head":{"tags":["Catalog"],"summary":"Check that the API is up (HEAD also supported).","operationId":"Catalog_Health_HEAD","responses":{"200":{"description":"Status, uptime in seconds and the current time."}}}},"/api/health/live":{"get":{"tags":["Catalog"],"summary":"Report liveness.","operationId":"Catalog_Live","responses":{"200":{"description":"Always { status: \"alive\" }."}}}},"/api/health/ready":{"get":{"tags":["Catalog"],"summary":"Report readiness with a fixed set of dependency checks.","operationId":"Catalog_Ready","responses":{"200":{"description":"Ready, with per-dependency status."}}}},"/api/echo":{"delete":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_DELETE","responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"get":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_GET","responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"head":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_HEAD","responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"options":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_OPTIONS","responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"patch":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_PATCH","requestBody":{"description":"Any body; it is echoed back.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"hello":"world","n":1}},"text/plain":{"schema":{"type":"string"}}}},"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"post":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_POST","requestBody":{"description":"Any body; it is echoed back.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"hello":"world","n":1}},"text/plain":{"schema":{"type":"string"}}}},"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"put":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_PUT","requestBody":{"description":"Any body; it is echoed back.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"hello":"world","n":1}},"text/plain":{"schema":{"type":"string"}}}},"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}}},"/api/echo/{path}":{"delete":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_DELETE2","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"get":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_GET2","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"head":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_HEAD2","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"options":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_OPTIONS2","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"patch":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_PATCH2","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Any body; it is echoed back.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"hello":"world"}}}},"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"post":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_POST2","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Any body; it is echoed back.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"hello":"world"}}}},"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}},"put":{"tags":["Echo"],"summary":"Echoes back everything the server received: method, URL, query, headers, cookies, body and client info.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS on `/api/echo` and on any sub-path\n(`/api/echo/{**path}`); the sub-path is returned as `subPath`.\nUp to 1MB of body is echoed (UTF-8 text, or base64 for binary); larger bodies are counted in\n`contentLength` and flagged with `bodyTruncated`. JSON bodies are also returned parsed in `json`\n(or `jsonError` when malformed), and form bodies as `form` fields plus `files` metadata.\nExample: `POST /api/echo/orders/7?tag=a&tag=b` with a JSON body.","operationId":"Echo_Echo_PUT2","parameters":[{"name":"path","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Any body; it is echoed back.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"hello":"world"}}}},"responses":{"200":{"description":"The request as the server saw it (HEAD responses carry headers only)."}}}},"/api/echo/headers":{"get":{"tags":["Echo"],"summary":"Returns the request's headers.","operationId":"Echo_Headers","responses":{"200":{"description":"Header count and a name-to-value map."}}}},"/api/echo/ip":{"get":{"tags":["Echo"],"summary":"Returns the caller's IP address and port.","description":"Also reports the `X-Forwarded-For` and `X-Real-IP` headers when present (display only, not trusted).","operationId":"Echo_Ip","responses":{"200":{"description":"Client IP, port and forwarded headers."}}}},"/api/echo/user-agent":{"get":{"tags":["Echo"],"summary":"Returns the request's User-Agent header.","operationId":"Echo_UserAgent","responses":{"200":{"description":"The User-Agent value."}}}},"/api/methods/any":{"delete":{"tags":["Methods"],"summary":"Accepts any verb and describes the request.","description":"The body is read for POST, PUT, PATCH and DELETE, and ignored for GET, HEAD and OPTIONS.","operationId":"Methods_Any_DELETE","responses":{"200":{"description":"Method, query, content type and body."}}},"get":{"tags":["Methods"],"summary":"Accepts any verb and describes the request.","description":"The body is read for POST, PUT, PATCH and DELETE, and ignored for GET, HEAD and OPTIONS.","operationId":"Methods_Any_GET","responses":{"200":{"description":"Method, query, content type and body."}}},"head":{"tags":["Methods"],"summary":"Accepts any verb and describes the request.","description":"The body is read for POST, PUT, PATCH and DELETE, and ignored for GET, HEAD and OPTIONS.","operationId":"Methods_Any_HEAD","responses":{"200":{"description":"Method, query, content type and body."}}},"options":{"tags":["Methods"],"summary":"Accepts any verb and describes the request.","description":"The body is read for POST, PUT, PATCH and DELETE, and ignored for GET, HEAD and OPTIONS.","operationId":"Methods_Any_OPTIONS","responses":{"200":{"description":"Method, query, content type and body."}}},"patch":{"tags":["Methods"],"summary":"Accepts any verb and describes the request.","description":"The body is read for POST, PUT, PATCH and DELETE, and ignored for GET, HEAD and OPTIONS.","operationId":"Methods_Any_PATCH","requestBody":{"description":"Optional body; described in the response.","content":{"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Method, query, content type and body."}}},"post":{"tags":["Methods"],"summary":"Accepts any verb and describes the request.","description":"The body is read for POST, PUT, PATCH and DELETE, and ignored for GET, HEAD and OPTIONS.","operationId":"Methods_Any_POST","requestBody":{"description":"Optional body; described in the response.","content":{"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Method, query, content type and body."}}},"put":{"tags":["Methods"],"summary":"Accepts any verb and describes the request.","description":"The body is read for POST, PUT, PATCH and DELETE, and ignored for GET, HEAD and OPTIONS.","operationId":"Methods_Any_PUT","requestBody":{"description":"Optional body; described in the response.","content":{"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Method, query, content type and body."}}}},"/api/methods/delete":{"delete":{"tags":["Methods"],"summary":"Accepts only DELETE and echoes any body sent with it.","operationId":"Methods_Delete","responses":{"200":{"description":"Method, query, content type and body."},"405":{"description":"Any other verb."}}}},"/api/methods/get":{"get":{"tags":["Methods"],"summary":"Accepts only GET and describes the request.","operationId":"Methods_Get","responses":{"200":{"description":"Method, path, query and timestamp."},"405":{"description":"Any other verb; the `Allow` header lists GET."}}}},"/api/methods/head":{"head":{"tags":["Methods"],"summary":"Accepts only HEAD and answers with headers only.","description":"Look for the `X-Method` and `X-Message` response headers.","operationId":"Methods_Head","responses":{"200":{"description":"Empty body with `X-Method: HEAD`."},"405":{"description":"Any other verb."}}}},"/api/methods/options":{"options":{"tags":["Methods"],"summary":"Accepts only OPTIONS and lists the per-verb test endpoints.","description":"A plain OPTIONS request reaches this action. A CORS preflight (with `Origin` and\n            `Access-Control-Request-Method`) is answered by the CORS middleware instead.","operationId":"Methods_Options","responses":{"200":{"description":"An `Allow` header plus the endpoint list."},"405":{"description":"Any other verb."}}}},"/api/methods/patch":{"patch":{"tags":["Methods"],"summary":"Accepts only PATCH and echoes the body.","operationId":"Methods_Patch","requestBody":{"description":"Optional body; described in the response.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"a":1}}}},"responses":{"200":{"description":"Method, query, content type and body."},"405":{"description":"Any other verb."}}}},"/api/methods/post":{"post":{"tags":["Methods"],"summary":"Accepts only POST and echoes the body.","description":"Up to 1MB of body is echoed; larger bodies are counted and flagged with `bodyTruncated`.","operationId":"Methods_Post","requestBody":{"description":"Optional body; described in the response.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"a":1}}}},"responses":{"200":{"description":"Method, query, content type and body."},"405":{"description":"Any other verb."}}}},"/api/methods/put":{"put":{"tags":["Methods"],"summary":"Accepts only PUT and echoes the body.","operationId":"Methods_Put","requestBody":{"description":"Optional body; described in the response.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"a":1}}}},"responses":{"200":{"description":"Method, query, content type and body."},"405":{"description":"Any other verb."}}}},"/api/status/{code}":{"delete":{"tags":["Status"],"summary":"Responds with the requested HTTP status code.","description":"Accepts any verb. 204, 205 and 304 have no body. The response carries the headers that status normally has:\n3xx (except 304) `Location: /api/echo`; 401 `WWW-Authenticate`; 405 `Allow`; 407 `Proxy-Authenticate`;\n416 `Content-Range`; 426 `Upgrade`; 429 and 503 `Retry-After: 5`.","operationId":"Status_Status_DELETE","parameters":[{"name":"code","in":"path","description":"Status code to return, 200-599. Codes outside the IANA registry (e.g. 599) are allowed.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Or the requested code, with a `{ status, statusText, category, message }` body."},"400":{"description":"Code outside 200-599 (1xx cannot be sent as a final response)."}}},"get":{"tags":["Status"],"summary":"Responds with the requested HTTP status code.","description":"Accepts any verb. 204, 205 and 304 have no body. The response carries the headers that status normally has:\n3xx (except 304) `Location: /api/echo`; 401 `WWW-Authenticate`; 405 `Allow`; 407 `Proxy-Authenticate`;\n416 `Content-Range`; 426 `Upgrade`; 429 and 503 `Retry-After: 5`.","operationId":"Status_Status_GET","parameters":[{"name":"code","in":"path","description":"Status code to return, 200-599. Codes outside the IANA registry (e.g. 599) are allowed.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Or the requested code, with a `{ status, statusText, category, message }` body."},"400":{"description":"Code outside 200-599 (1xx cannot be sent as a final response)."}}},"head":{"tags":["Status"],"summary":"Responds with the requested HTTP status code.","description":"Accepts any verb. 204, 205 and 304 have no body. The response carries the headers that status normally has:\n3xx (except 304) `Location: /api/echo`; 401 `WWW-Authenticate`; 405 `Allow`; 407 `Proxy-Authenticate`;\n416 `Content-Range`; 426 `Upgrade`; 429 and 503 `Retry-After: 5`.","operationId":"Status_Status_HEAD","parameters":[{"name":"code","in":"path","description":"Status code to return, 200-599. Codes outside the IANA registry (e.g. 599) are allowed.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Or the requested code, with a `{ status, statusText, category, message }` body."},"400":{"description":"Code outside 200-599 (1xx cannot be sent as a final response)."}}},"options":{"tags":["Status"],"summary":"Responds with the requested HTTP status code.","description":"Accepts any verb. 204, 205 and 304 have no body. The response carries the headers that status normally has:\n3xx (except 304) `Location: /api/echo`; 401 `WWW-Authenticate`; 405 `Allow`; 407 `Proxy-Authenticate`;\n416 `Content-Range`; 426 `Upgrade`; 429 and 503 `Retry-After: 5`.","operationId":"Status_Status_OPTIONS","parameters":[{"name":"code","in":"path","description":"Status code to return, 200-599. Codes outside the IANA registry (e.g. 599) are allowed.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Or the requested code, with a `{ status, statusText, category, message }` body."},"400":{"description":"Code outside 200-599 (1xx cannot be sent as a final response)."}}},"patch":{"tags":["Status"],"summary":"Responds with the requested HTTP status code.","description":"Accepts any verb. 204, 205 and 304 have no body. The response carries the headers that status normally has:\n3xx (except 304) `Location: /api/echo`; 401 `WWW-Authenticate`; 405 `Allow`; 407 `Proxy-Authenticate`;\n416 `Content-Range`; 426 `Upgrade`; 429 and 503 `Retry-After: 5`.","operationId":"Status_Status_PATCH","parameters":[{"name":"code","in":"path","description":"Status code to return, 200-599. Codes outside the IANA registry (e.g. 599) are allowed.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Or the requested code, with a `{ status, statusText, category, message }` body."},"400":{"description":"Code outside 200-599 (1xx cannot be sent as a final response)."}}},"post":{"tags":["Status"],"summary":"Responds with the requested HTTP status code.","description":"Accepts any verb. 204, 205 and 304 have no body. The response carries the headers that status normally has:\n3xx (except 304) `Location: /api/echo`; 401 `WWW-Authenticate`; 405 `Allow`; 407 `Proxy-Authenticate`;\n416 `Content-Range`; 426 `Upgrade`; 429 and 503 `Retry-After: 5`.","operationId":"Status_Status_POST","parameters":[{"name":"code","in":"path","description":"Status code to return, 200-599. Codes outside the IANA registry (e.g. 599) are allowed.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Or the requested code, with a `{ status, statusText, category, message }` body."},"400":{"description":"Code outside 200-599 (1xx cannot be sent as a final response)."}}},"put":{"tags":["Status"],"summary":"Responds with the requested HTTP status code.","description":"Accepts any verb. 204, 205 and 304 have no body. The response carries the headers that status normally has:\n3xx (except 304) `Location: /api/echo`; 401 `WWW-Authenticate`; 405 `Allow`; 407 `Proxy-Authenticate`;\n416 `Content-Range`; 426 `Upgrade`; 429 and 503 `Retry-After: 5`.","operationId":"Status_Status_PUT","parameters":[{"name":"code","in":"path","description":"Status code to return, 200-599. Codes outside the IANA registry (e.g. 599) are allowed.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Or the requested code, with a `{ status, statusText, category, message }` body."},"400":{"description":"Code outside 200-599 (1xx cannot be sent as a final response)."}}}},"/api/status/list":{"get":{"tags":["Status"],"summary":"Lists every known HTTP status code with its reason phrase and category.","description":"Codes below 200 are listed for reference but cannot be requested (`supported: false`).","operationId":"Status_List","responses":{"200":{"description":"All known status codes, sorted."}}}},"/api/status/random":{"delete":{"tags":["Status"],"summary":"Responds with a status code picked at random from a weighted pool.","description":"Accepts any verb. The `X-Status-Pool` response header shows the parsed pool.","operationId":"Status_RandomStatus_DELETE","parameters":[{"name":"codes","in":"query","description":"Comma-separated `code[:weight]` entries, e.g. `200:3,500:1` (200 is three times as likely).\n            Codes must be 200-599, weights 1-100 (default 1), at most 20 entries. Default pool: `200,201,400,404,500`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Or whichever code was drawn; the body and headers match `/api/status/{code}`."},"400":{"description":"Invalid code, weight or pool size."}}},"get":{"tags":["Status"],"summary":"Responds with a status code picked at random from a weighted pool.","description":"Accepts any verb. The `X-Status-Pool` response header shows the parsed pool.","operationId":"Status_RandomStatus_GET","parameters":[{"name":"codes","in":"query","description":"Comma-separated `code[:weight]` entries, e.g. `200:3,500:1` (200 is three times as likely).\n            Codes must be 200-599, weights 1-100 (default 1), at most 20 entries. Default pool: `200,201,400,404,500`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Or whichever code was drawn; the body and headers match `/api/status/{code}`."},"400":{"description":"Invalid code, weight or pool size."}}},"head":{"tags":["Status"],"summary":"Responds with a status code picked at random from a weighted pool.","description":"Accepts any verb. The `X-Status-Pool` response header shows the parsed pool.","operationId":"Status_RandomStatus_HEAD","parameters":[{"name":"codes","in":"query","description":"Comma-separated `code[:weight]` entries, e.g. `200:3,500:1` (200 is three times as likely).\n            Codes must be 200-599, weights 1-100 (default 1), at most 20 entries. Default pool: `200,201,400,404,500`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Or whichever code was drawn; the body and headers match `/api/status/{code}`."},"400":{"description":"Invalid code, weight or pool size."}}},"options":{"tags":["Status"],"summary":"Responds with a status code picked at random from a weighted pool.","description":"Accepts any verb. The `X-Status-Pool` response header shows the parsed pool.","operationId":"Status_RandomStatus_OPTIONS","parameters":[{"name":"codes","in":"query","description":"Comma-separated `code[:weight]` entries, e.g. `200:3,500:1` (200 is three times as likely).\n            Codes must be 200-599, weights 1-100 (default 1), at most 20 entries. Default pool: `200,201,400,404,500`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Or whichever code was drawn; the body and headers match `/api/status/{code}`."},"400":{"description":"Invalid code, weight or pool size."}}},"patch":{"tags":["Status"],"summary":"Responds with a status code picked at random from a weighted pool.","description":"Accepts any verb. The `X-Status-Pool` response header shows the parsed pool.","operationId":"Status_RandomStatus_PATCH","parameters":[{"name":"codes","in":"query","description":"Comma-separated `code[:weight]` entries, e.g. `200:3,500:1` (200 is three times as likely).\n            Codes must be 200-599, weights 1-100 (default 1), at most 20 entries. Default pool: `200,201,400,404,500`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Or whichever code was drawn; the body and headers match `/api/status/{code}`."},"400":{"description":"Invalid code, weight or pool size."}}},"post":{"tags":["Status"],"summary":"Responds with a status code picked at random from a weighted pool.","description":"Accepts any verb. The `X-Status-Pool` response header shows the parsed pool.","operationId":"Status_RandomStatus_POST","parameters":[{"name":"codes","in":"query","description":"Comma-separated `code[:weight]` entries, e.g. `200:3,500:1` (200 is three times as likely).\n            Codes must be 200-599, weights 1-100 (default 1), at most 20 entries. Default pool: `200,201,400,404,500`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Or whichever code was drawn; the body and headers match `/api/status/{code}`."},"400":{"description":"Invalid code, weight or pool size."}}},"put":{"tags":["Status"],"summary":"Responds with a status code picked at random from a weighted pool.","description":"Accepts any verb. The `X-Status-Pool` response header shows the parsed pool.","operationId":"Status_RandomStatus_PUT","parameters":[{"name":"codes","in":"query","description":"Comma-separated `code[:weight]` entries, e.g. `200:3,500:1` (200 is three times as likely).\n            Codes must be 200-599, weights 1-100 (default 1), at most 20 entries. Default pool: `200,201,400,404,500`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Or whichever code was drawn; the body and headers match `/api/status/{code}`."},"400":{"description":"Invalid code, weight or pool size."}}}},"/api/redirect/{n}":{"get":{"tags":["Redirect"],"summary":"Starts a redirect chain of `n` hops that ends at `/api/echo`.","operationId":"Redirect_Chain","parameters":[{"name":"n","in":"path","description":"Number of redirects remaining, 1-20. Each hop uses a path-absolute Location (`/api/redirect/{n-1}`).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"302":{"description":"Redirect to the next hop."},"400":{"description":"`n` outside 1-20."}}}},"/api/redirect/absolute/{n}":{"get":{"tags":["Redirect"],"summary":"Starts a redirect chain of `n` hops that uses absolute URLs.","description":"The Location host is taken from the request's `Host` header.","operationId":"Redirect_Absolute","parameters":[{"name":"n","in":"path","description":"Number of redirects remaining, 1-20.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"302":{"description":"Redirect to the next hop, as a full URL."},"400":{"description":"`n` outside 1-20."}}}},"/api/redirect/loop":{"get":{"tags":["Redirect"],"summary":"Starts an infinite redirect loop between `/loop` and `/loop/back`.","description":"Use it to test a client's maximum-redirect limit.","operationId":"Redirect_Loop","responses":{"200":{"description":"OK"},"302":{"description":"Redirect to `/api/redirect/loop/back`."}}}},"/api/redirect/loop/back":{"get":{"tags":["Redirect"],"summary":"Continues the infinite redirect loop back to `/loop`.","operationId":"Redirect_LoopBack","responses":{"200":{"description":"OK"},"302":{"description":"Redirect to `/api/redirect/loop`."}}}},"/api/redirect/relative/{n}":{"get":{"tags":["Redirect"],"summary":"Starts a redirect chain of `n` hops that uses relative references.","description":"Location values such as `2` and `../../echo` must be resolved against the current URL by the client.","operationId":"Redirect_Relative","parameters":[{"name":"n","in":"path","description":"Number of redirects remaining, 1-20.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"302":{"description":"Redirect to the next hop."},"400":{"description":"`n` outside 1-20."}}}},"/api/redirect/status/{code}":{"delete":{"tags":["Redirect"],"summary":"Redirects to `/api/echo` with the chosen redirect status.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD. Use it to check client behaviour: after a POST, a 303 should be\nfollowed with GET (body dropped), while 307 and 308 must repeat the same method and body. `/api/echo` shows\nwhat arrived.","operationId":"Redirect_WithStatus_DELETE","parameters":[{"name":"code","in":"path","description":"Redirect status: 301, 302, 303, 307 or 308.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"301":{"description":"Moved Permanently."},"302":{"description":"Found."},"303":{"description":"See Other."},"307":{"description":"Temporary Redirect (method and body kept)."},"308":{"description":"Permanent Redirect (method and body kept)."},"400":{"description":"Unsupported code."}}},"get":{"tags":["Redirect"],"summary":"Redirects to `/api/echo` with the chosen redirect status.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD. Use it to check client behaviour: after a POST, a 303 should be\nfollowed with GET (body dropped), while 307 and 308 must repeat the same method and body. `/api/echo` shows\nwhat arrived.","operationId":"Redirect_WithStatus_GET","parameters":[{"name":"code","in":"path","description":"Redirect status: 301, 302, 303, 307 or 308.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"301":{"description":"Moved Permanently."},"302":{"description":"Found."},"303":{"description":"See Other."},"307":{"description":"Temporary Redirect (method and body kept)."},"308":{"description":"Permanent Redirect (method and body kept)."},"400":{"description":"Unsupported code."}}},"head":{"tags":["Redirect"],"summary":"Redirects to `/api/echo` with the chosen redirect status.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD. Use it to check client behaviour: after a POST, a 303 should be\nfollowed with GET (body dropped), while 307 and 308 must repeat the same method and body. `/api/echo` shows\nwhat arrived.","operationId":"Redirect_WithStatus_HEAD","parameters":[{"name":"code","in":"path","description":"Redirect status: 301, 302, 303, 307 or 308.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"301":{"description":"Moved Permanently."},"302":{"description":"Found."},"303":{"description":"See Other."},"307":{"description":"Temporary Redirect (method and body kept)."},"308":{"description":"Permanent Redirect (method and body kept)."},"400":{"description":"Unsupported code."}}},"patch":{"tags":["Redirect"],"summary":"Redirects to `/api/echo` with the chosen redirect status.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD. Use it to check client behaviour: after a POST, a 303 should be\nfollowed with GET (body dropped), while 307 and 308 must repeat the same method and body. `/api/echo` shows\nwhat arrived.","operationId":"Redirect_WithStatus_PATCH","parameters":[{"name":"code","in":"path","description":"Redirect status: 301, 302, 303, 307 or 308.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"301":{"description":"Moved Permanently."},"302":{"description":"Found."},"303":{"description":"See Other."},"307":{"description":"Temporary Redirect (method and body kept)."},"308":{"description":"Permanent Redirect (method and body kept)."},"400":{"description":"Unsupported code."}}},"post":{"tags":["Redirect"],"summary":"Redirects to `/api/echo` with the chosen redirect status.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD. Use it to check client behaviour: after a POST, a 303 should be\nfollowed with GET (body dropped), while 307 and 308 must repeat the same method and body. `/api/echo` shows\nwhat arrived.","operationId":"Redirect_WithStatus_POST","parameters":[{"name":"code","in":"path","description":"Redirect status: 301, 302, 303, 307 or 308.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"301":{"description":"Moved Permanently."},"302":{"description":"Found."},"303":{"description":"See Other."},"307":{"description":"Temporary Redirect (method and body kept)."},"308":{"description":"Permanent Redirect (method and body kept)."},"400":{"description":"Unsupported code."}}},"put":{"tags":["Redirect"],"summary":"Redirects to `/api/echo` with the chosen redirect status.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD. Use it to check client behaviour: after a POST, a 303 should be\nfollowed with GET (body dropped), while 307 and 308 must repeat the same method and body. `/api/echo` shows\nwhat arrived.","operationId":"Redirect_WithStatus_PUT","parameters":[{"name":"code","in":"path","description":"Redirect status: 301, 302, 303, 307 or 308.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"OK"},"301":{"description":"Moved Permanently."},"302":{"description":"Found."},"303":{"description":"See Other."},"307":{"description":"Temporary Redirect (method and body kept)."},"308":{"description":"Permanent Redirect (method and body kept)."},"400":{"description":"Unsupported code."}}}},"/api/redirect/to":{"delete":{"tags":["Redirect"],"summary":"Redirects to a local path on this server.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD.","operationId":"Redirect_To_DELETE","parameters":[{"name":"url","in":"query","description":"Target path. It must start with a single `/` (e.g. `/api/echo?x=1`) and be at most 2048 characters.\n            Absolute URLs, `//host`, `/\\host` and control characters are rejected to prevent open redirects.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Redirect status: 301, 302, 303, 307 or 308. Default 302.","schema":{"type":"integer","format":"int32","default":302}}],"responses":{"200":{"description":"OK"},"302":{"description":"Or the chosen redirect status, with `Location` set to `url`."},"400":{"description":"Missing or non-local `url`, or unsupported `status`."}}},"get":{"tags":["Redirect"],"summary":"Redirects to a local path on this server.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD.","operationId":"Redirect_To_GET","parameters":[{"name":"url","in":"query","description":"Target path. It must start with a single `/` (e.g. `/api/echo?x=1`) and be at most 2048 characters.\n            Absolute URLs, `//host`, `/\\host` and control characters are rejected to prevent open redirects.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Redirect status: 301, 302, 303, 307 or 308. Default 302.","schema":{"type":"integer","format":"int32","default":302}}],"responses":{"200":{"description":"OK"},"302":{"description":"Or the chosen redirect status, with `Location` set to `url`."},"400":{"description":"Missing or non-local `url`, or unsupported `status`."}}},"head":{"tags":["Redirect"],"summary":"Redirects to a local path on this server.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD.","operationId":"Redirect_To_HEAD","parameters":[{"name":"url","in":"query","description":"Target path. It must start with a single `/` (e.g. `/api/echo?x=1`) and be at most 2048 characters.\n            Absolute URLs, `//host`, `/\\host` and control characters are rejected to prevent open redirects.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Redirect status: 301, 302, 303, 307 or 308. Default 302.","schema":{"type":"integer","format":"int32","default":302}}],"responses":{"200":{"description":"OK"},"302":{"description":"Or the chosen redirect status, with `Location` set to `url`."},"400":{"description":"Missing or non-local `url`, or unsupported `status`."}}},"patch":{"tags":["Redirect"],"summary":"Redirects to a local path on this server.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD.","operationId":"Redirect_To_PATCH","parameters":[{"name":"url","in":"query","description":"Target path. It must start with a single `/` (e.g. `/api/echo?x=1`) and be at most 2048 characters.\n            Absolute URLs, `//host`, `/\\host` and control characters are rejected to prevent open redirects.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Redirect status: 301, 302, 303, 307 or 308. Default 302.","schema":{"type":"integer","format":"int32","default":302}}],"responses":{"200":{"description":"OK"},"302":{"description":"Or the chosen redirect status, with `Location` set to `url`."},"400":{"description":"Missing or non-local `url`, or unsupported `status`."}}},"post":{"tags":["Redirect"],"summary":"Redirects to a local path on this server.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD.","operationId":"Redirect_To_POST","parameters":[{"name":"url","in":"query","description":"Target path. It must start with a single `/` (e.g. `/api/echo?x=1`) and be at most 2048 characters.\n            Absolute URLs, `//host`, `/\\host` and control characters are rejected to prevent open redirects.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Redirect status: 301, 302, 303, 307 or 308. Default 302.","schema":{"type":"integer","format":"int32","default":302}}],"responses":{"200":{"description":"OK"},"302":{"description":"Or the chosen redirect status, with `Location` set to `url`."},"400":{"description":"Missing or non-local `url`, or unsupported `status`."}}},"put":{"tags":["Redirect"],"summary":"Redirects to a local path on this server.","description":"Accepts GET, POST, PUT, PATCH, DELETE and HEAD.","operationId":"Redirect_To_PUT","parameters":[{"name":"url","in":"query","description":"Target path. It must start with a single `/` (e.g. `/api/echo?x=1`) and be at most 2048 characters.\n            Absolute URLs, `//host`, `/\\host` and control characters are rejected to prevent open redirects.","schema":{"type":"string"}},{"name":"status","in":"query","description":"Redirect status: 301, 302, 303, 307 or 308. Default 302.","schema":{"type":"integer","format":"int32","default":302}}],"responses":{"200":{"description":"OK"},"302":{"description":"Or the chosen redirect status, with `Location` set to `url`."},"400":{"description":"Missing or non-local `url`, or unsupported `status`."}}}},"/api/cookies":{"get":{"tags":["Cookies"],"summary":"Returns the cookies the client sent.","operationId":"Cookies_List","responses":{"200":{"description":"Cookie count and a name-to-value map."}}}},"/api/cookies/delete":{"delete":{"tags":["Cookies"],"summary":"Deletes cookies by name, or every cookie the client sent.","description":"Accepts GET and DELETE. Each cookie is expired with `Path=/`.","operationId":"Cookies_Delete_DELETE","parameters":[{"name":"names","in":"query","description":"Comma-separated cookie names, at most 20. Omit to delete all cookies in the request.","schema":{"type":"string"}}],"responses":{"200":{"description":"The names that were deleted."},"400":{"description":"Invalid name or more than 20 names."}}},"get":{"tags":["Cookies"],"summary":"Deletes cookies by name, or every cookie the client sent.","description":"Accepts GET and DELETE. Each cookie is expired with `Path=/`.","operationId":"Cookies_Delete_GET","parameters":[{"name":"names","in":"query","description":"Comma-separated cookie names, at most 20. Omit to delete all cookies in the request.","schema":{"type":"string"}}],"responses":{"200":{"description":"The names that were deleted."},"400":{"description":"Invalid name or more than 20 names."}}}},"/api/cookies/login":{"post":{"tags":["Cookies"],"summary":"Logs in and sets the `apibee_session` cookie.","description":"Test accounts: `test` / `test123` (role user) and `admin` / `admin123` (role admin).\nThe cookie is HttpOnly, SameSite=Lax, Path=/, valid for one hour, and Secure only over HTTPS.","operationId":"Cookies_Login","requestBody":{"description":"Username and password.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CookiesControllerLoginBody"}},"text/json":{"schema":{"$ref":"#/components/schemas/CookiesControllerLoginBody"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/CookiesControllerLoginBody"}},"application/xml":{"schema":{"$ref":"#/components/schemas/CookiesControllerLoginBody"}},"text/xml":{"schema":{"$ref":"#/components/schemas/CookiesControllerLoginBody"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/CookiesControllerLoginBody"}}}},"responses":{"200":{"description":"Logged in; the session cookie is set."},"400":{"description":"Missing or malformed body."},"401":{"description":"Wrong username or password."}}}},"/api/cookies/logout":{"post":{"tags":["Cookies"],"summary":"Ends the session and expires the session cookie.","description":"The session is invalidated on the server, so replaying the old cookie fails.","operationId":"Cookies_Logout","responses":{"200":{"description":"Logged out (also when there was no session)."}}}},"/api/cookies/me":{"get":{"tags":["Cookies"],"summary":"Returns the profile of the user who owns the session cookie.","description":"Reads the `apibee_session` cookie set by `POST /api/cookies/login`.","operationId":"Cookies_Me","responses":{"200":{"description":"User profile and session expiry."},"401":{"description":"No cookie, unknown or expired session."}}}},"/api/cookies/set":{"get":{"tags":["Cookies"],"summary":"Sets one cookie per query parameter.","description":"Example: `/api/cookies/set?theme=dark&lang=en` sets `theme` and `lang` with `Path=/`.\nAt most 20 cookies; names must be RFC 6265 tokens (1-64 characters) and values at most 256 characters.","operationId":"Cookies_SetMany","responses":{"200":{"description":"The cookies that were set."},"400":{"description":"No query parameters, too many cookies, or an invalid name or value."}}}},"/api/cookies/set/{name}/{value}":{"get":{"tags":["Cookies"],"summary":"Sets one cookie with explicit attributes.","description":"The response includes the exact `Set-Cookie` header, plus a warning when `SameSite=None` is used without `Secure`.","operationId":"Cookies_SetOne","parameters":[{"name":"name","in":"path","description":"Cookie name: an RFC 6265 token, 1-64 characters.","required":true,"schema":{"type":"string"}},{"name":"value","in":"path","description":"Cookie value, at most 256 characters.","required":true,"schema":{"type":"string"}},{"name":"httpOnly","in":"query","description":"Adds `HttpOnly`. Default false.","schema":{"type":"boolean","default":false}},{"name":"secure","in":"query","description":"Adds `Secure`. Default false.","schema":{"type":"boolean","default":false}},{"name":"sameSite","in":"query","description":"`lax`, `strict`, `none` or `unspecified` (default, attribute omitted).","schema":{"type":"string"}},{"name":"maxAge","in":"query","description":"Lifetime in seconds, clamped to 0-31536000. Omit for a session cookie; 0 expires it immediately.","schema":{"type":"integer","format":"int32"}},{"name":"path","in":"query","description":"Cookie path. Must start with `/`, at most 128 characters, no `;`. Default `/`.","schema":{"type":"string","default":"/"}}],"responses":{"200":{"description":"The cookie and its attributes."},"400":{"description":"Invalid name, value, path or sameSite."}}}},"/api/cache/etag":{"get":{"tags":["Caching"],"summary":"Returns the versioned document with its ETag.","description":"Reads `If-None-Match`: when it matches the current ETag (weak comparison, `*` matches anything), the\nresponse is 304 with no body. The ETag has the form `\"doc-v{version}\"`. Also answers HEAD.","operationId":"Caching_GetETag_GET","parameters":[{"name":"If-None-Match","in":"header","description":"ETag from a previous response; a match returns 304 Not Modified.","schema":{"type":"string"}}],"responses":{"200":{"description":"The document, with `ETag` and `Cache-Control: no-cache`."},"304":{"description":"The client's copy is current."}}},"head":{"tags":["Caching"],"summary":"Returns the versioned document with its ETag.","description":"Reads `If-None-Match`: when it matches the current ETag (weak comparison, `*` matches anything), the\nresponse is 304 with no body. The ETag has the form `\"doc-v{version}\"`. Also answers HEAD.","operationId":"Caching_GetETag_HEAD","responses":{"200":{"description":"The document, with `ETag` and `Cache-Control: no-cache`."},"304":{"description":"The client's copy is current."}}},"put":{"tags":["Caching"],"summary":"Updates the document only if the client's ETag is current.","description":"Requires `If-Match` with the current ETag (strong comparison, so `W/` tags never match; `*` matches).\nA successful update increments the version and returns the new ETag. Use it to test lost-update protection.","operationId":"Caching_PutETag","parameters":[{"name":"If-Match","in":"header","description":"Current ETag. Missing returns 428, stale returns 412.","schema":{"type":"string"}}],"requestBody":{"description":"New title and/or content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CachingControllerDocumentUpdate"}},"text/json":{"schema":{"$ref":"#/components/schemas/CachingControllerDocumentUpdate"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/CachingControllerDocumentUpdate"}},"application/xml":{"schema":{"$ref":"#/components/schemas/CachingControllerDocumentUpdate"}},"text/xml":{"schema":{"$ref":"#/components/schemas/CachingControllerDocumentUpdate"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/CachingControllerDocumentUpdate"}}}},"responses":{"200":{"description":"Updated; the new ETag is in the header and body."},"400":{"description":"Neither title nor content supplied, or malformed body."},"412":{"description":"If-Match does not match the current ETag."},"428":{"description":"If-Match header missing."}}}},"/api/cache/etag/reset":{"post":{"tags":["Caching"],"summary":"Resets the ETag document to version 1 and its default content.","operationId":"Caching_ResetETag","responses":{"200":{"description":"Document reset."}}}},"/api/cache/last-modified":{"get":{"tags":["Caching"],"summary":"Returns a resource with a fixed Last-Modified date.","description":"Reads `If-Modified-Since`: a date on or after Wed, 01 Jan 2025 00:00:00 GMT gives a 304. Invalid dates are\nignored. Also answers HEAD.","operationId":"Caching_GetLastModified_GET","parameters":[{"name":"If-Modified-Since","in":"header","description":"HTTP date; returns 304 when the resource hasn't changed since.","schema":{"type":"string"},"example":"Wed, 01 Jan 2025 00:00:00 GMT"}],"responses":{"200":{"description":"The resource, with a `Last-Modified` header."},"304":{"description":"Not modified since the given date."}}},"head":{"tags":["Caching"],"summary":"Returns a resource with a fixed Last-Modified date.","description":"Reads `If-Modified-Since`: a date on or after Wed, 01 Jan 2025 00:00:00 GMT gives a 304. Invalid dates are\nignored. Also answers HEAD.","operationId":"Caching_GetLastModified_HEAD","responses":{"200":{"description":"The resource, with a `Last-Modified` header."},"304":{"description":"Not modified since the given date."}}}},"/api/cache/max-age/{seconds}":{"get":{"tags":["Caching"],"summary":"Returns a response that clients may cache for the given number of seconds.","description":"Sets `Cache-Control: public, max-age=N` and `Expires`. A caching client reuses the same `generatedAt` until it expires.","operationId":"Caching_MaxAge","parameters":[{"name":"seconds","in":"path","description":"Cache lifetime, clamped to 0-31536000 (one year).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Body with the generation timestamp."}}}},"/api/cache/no-store":{"get":{"tags":["Caching"],"summary":"Returns a response that must never be cached.","description":"Sets `Cache-Control: no-store, no-cache, must-revalidate`, `Pragma: no-cache` and `Expires: 0`. Each call returns a new `requestId`.","operationId":"Caching_NoStore","responses":{"200":{"description":"Body with a fresh request id."}}}},"/api/cache/vary":{"get":{"tags":["Caching"],"summary":"Returns a greeting in the language chosen by Accept-Language.","description":"Reads `Accept-Language` (quality values honoured) and supports en, es, fr, de and hi, falling back to en.\nSets `Vary: Accept-Language` and `Content-Language`. Example: `Accept-Language: fr-CA, es;q=0.9` gives French.","operationId":"Caching_Vary","parameters":[{"name":"Accept-Language","in":"header","description":"en, es, fr, de or hi.","schema":{"type":"string"},"example":"fr"}],"responses":{"200":{"description":"The chosen language and greeting."}}}},"/api/bodies/any":{"patch":{"tags":["Bodies"],"summary":"Detects a body's real type from its content and compares it with the declared Content-Type.","description":"Accepts POST, PUT and PATCH, up to 10MB. Recognises PNG, JPEG, GIF, PDF, ZIP and gzip by magic bytes, then JSON,\nHTML, XML, URL-encoded form, multipart and plain text; anything else is `application/octet-stream`.","operationId":"Bodies_Any_PATCH","requestBody":{"description":"Any body; the real type is detected and compared with Content-Type.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Declared and detected types, length and SHA-256."},"413":{"description":"Body larger than 10MB."}}},"post":{"tags":["Bodies"],"summary":"Detects a body's real type from its content and compares it with the declared Content-Type.","description":"Accepts POST, PUT and PATCH, up to 10MB. Recognises PNG, JPEG, GIF, PDF, ZIP and gzip by magic bytes, then JSON,\nHTML, XML, URL-encoded form, multipart and plain text; anything else is `application/octet-stream`.","operationId":"Bodies_Any_POST","requestBody":{"description":"Any body; the real type is detected and compared with Content-Type.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Declared and detected types, length and SHA-256."},"413":{"description":"Body larger than 10MB."}}},"put":{"tags":["Bodies"],"summary":"Detects a body's real type from its content and compares it with the declared Content-Type.","description":"Accepts POST, PUT and PATCH, up to 10MB. Recognises PNG, JPEG, GIF, PDF, ZIP and gzip by magic bytes, then JSON,\nHTML, XML, URL-encoded form, multipart and plain text; anything else is `application/octet-stream`.","operationId":"Bodies_Any_PUT","requestBody":{"description":"Any body; the real type is detected and compared with Content-Type.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}},"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Declared and detected types, length and SHA-256."},"413":{"description":"Body larger than 10MB."}}}},"/api/bodies/binary":{"post":{"tags":["Bodies"],"summary":"Reads a binary body and returns its size, hashes and detected type.","description":"Accepts `application/octet-stream`, `application/pdf`, `application/zip`, `image/png`, `image/jpeg` and `image/gif`, up to 10MB.","operationId":"Bodies_Binary","requestBody":{"description":"Raw bytes; returns size, hashes and detected type.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Size, SHA-256, MD5, first 16 bytes and the type detected from magic bytes."},"413":{"description":"Body larger than 10MB."},"415":{"description":"Any other Content-Type."}}}},"/api/bodies/form":{"post":{"tags":["Bodies"],"summary":"Parses a URL-encoded or multipart form.","description":"Repeated keys come back as arrays. Each uploaded file is reported with its size and SHA-256.","operationId":"Bodies_Form","requestBody":{"description":"Any form fields.","content":{"application/x-www-form-urlencoded":{"schema":{"type":"object"},"example":{"name":"Ada","role":"admin"}},"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Encoding, fields and file metadata."},"415":{"description":"Content-Type is not `application/x-www-form-urlencoded` or `multipart/form-data`."}}}},"/api/bodies/json":{"post":{"tags":["Bodies"],"summary":"Parses a JSON body and describes its structure.","description":"Accepts `application/json` and `application/*+json`.","operationId":"Bodies_Json","requestBody":{"description":"Any JSON value: object, array or scalar.","content":{"application/json":{"schema":{}},"application/*+json":{"schema":{}}}},"responses":{"200":{"description":"Root type, top-level keys or array length, and the parsed value."},"400":{"description":"Empty or malformed JSON."},"415":{"description":"Any other Content-Type."}}}},"/api/bodies/large":{"post":{"tags":["Bodies"],"summary":"Streams an upload of up to 10MB and reports its size, hash and timing.","description":"Any Content-Type is accepted. The body is hashed while it streams, so it is never held in memory.","operationId":"Bodies_Large","requestBody":{"description":"Up to 10 MB; larger returns 413.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Size, human-readable size, SHA-256 and duration."},"413":{"description":"Upload larger than 10MB."}}}},"/api/bodies/text":{"post":{"tags":["Bodies"],"summary":"Reads a plain-text body and counts its bytes, characters, lines and words.","description":"Up to 1MB is analysed; larger bodies are counted and flagged with `truncated`.","operationId":"Bodies_Text","requestBody":{"description":"Plain text; counts characters, lines and words.","content":{"text/plain":{"schema":{"type":"string"},"example":"Hello\nworld"}}},"responses":{"200":{"description":"Text statistics and the text itself."},"400":{"description":"Body is not valid UTF-8."},"415":{"description":"Content-Type is not `text/plain`."}}}},"/api/bodies/xml":{"post":{"tags":["Bodies"],"summary":"Parses an XML body into an element tree.","description":"Accepts `application/xml` and `text/xml`, up to 1MB. DTDs are rejected, which blocks XXE and\nentity-expansion attacks. Example body: `<order id=\"7\"><item>Pen</item></order>`.","operationId":"Bodies_Xml","requestBody":{"description":"Well-formed XML (DTDs are rejected).","content":{"application/xml":{"schema":{"type":"string"},"example":"<order id=\"7\"><item sku=\"A1\">2</item></order>"}}},"responses":{"200":{"description":"Root name, element count and the element tree."},"400":{"description":"Malformed XML or a DTD."},"413":{"description":"Body larger than 1MB."},"415":{"description":"Any other Content-Type."}}}},"/api/formats":{"get":{"tags":["Formats"],"summary":"List every available format and special-case endpoint.","operationId":"Formats_Index","responses":{"200":{"description":"Success."}}}},"/api/formats/atom":{"get":{"tags":["Formats"],"summary":"Return a sample Atom feed with two entries.","operationId":"Formats_Atom","responses":{"200":{"description":"Success."}}}},"/api/formats/bom":{"get":{"tags":["Formats"],"summary":"Return JSON prefixed with a UTF-8 byte-order mark.","description":"Strict JSON parsers reject the body unless the client strips the BOM (`EF BB BF`) first.","operationId":"Formats_Bom","responses":{"200":{"description":"Success."}}}},"/api/formats/brotli":{"get":{"tags":["Formats"],"summary":"Return a Brotli-compressed JSON body.","description":"Always compressed and sent with `Content-Encoding: br`, whatever the request's `Accept-Encoding` says.","operationId":"Formats_Brotli","responses":{"200":{"description":"Success."}}}},"/api/formats/charset/{name}":{"get":{"tags":["Formats"],"summary":"Return text encoded in a non-UTF-8 charset.","operationId":"Formats_Charset","parameters":[{"name":"name","in":"path","description":"`latin1` (alias `iso-8859-1`) returns ISO-8859-1 plain text; `utf16` (alias `utf-16`) returns UTF-16LE JSON with a BOM. Case-insensitive.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success."},"404":{"description":"Unknown charset."}}}},"/api/formats/css":{"get":{"tags":["Formats"],"summary":"Return a sample CSS stylesheet.","operationId":"Formats_Css","responses":{"200":{"description":"Success."}}}},"/api/formats/csv":{"get":{"tags":["Formats"],"summary":"Return a sample employee table as RFC 4180 `text/csv`.","operationId":"Formats_Csv","responses":{"200":{"description":"Success."}}}},"/api/formats/deflate":{"get":{"tags":["Formats"],"summary":"Return a deflate-compressed JSON body.","description":"Uses the zlib wrapper (RFC 1950), as HTTP's `deflate` coding requires. Always compressed, whatever the request's `Accept-Encoding` says.","operationId":"Formats_Deflate","responses":{"200":{"description":"Success."}}}},"/api/formats/empty":{"get":{"tags":["Formats"],"summary":"Return 200 OK with a zero-length body and no Content-Type.","operationId":"Formats_EmptyBody","responses":{"200":{"description":"Empty body."}}}},"/api/formats/gif":{"get":{"tags":["Formats"],"summary":"Return a 1×1 transparent GIF89a image.","operationId":"Formats_Gif","responses":{"200":{"description":"Success."}}}},"/api/formats/gzip":{"get":{"tags":["Formats"],"summary":"Return a gzip-compressed JSON body.","description":"Always compressed and sent with `Content-Encoding: gzip`, whatever the request's `Accept-Encoding` says.","operationId":"Formats_Gzip","responses":{"200":{"description":"Success."}}}},"/api/formats/html":{"get":{"tags":["Formats"],"summary":"Return a sample HTML page with a list, a table and a form.","operationId":"Formats_Html","responses":{"200":{"description":"Success."}}}},"/api/formats/ical":{"get":{"tags":["Formats"],"summary":"Return a sample iCalendar (`.ics`) event with CRLF line endings.","operationId":"Formats_ICal","responses":{"200":{"description":"Success."}}}},"/api/formats/javascript":{"get":{"tags":["Formats"],"summary":"Return a small runnable JavaScript snippet.","operationId":"Formats_JavaScript","responses":{"200":{"description":"Success."}}}},"/api/formats/json":{"get":{"tags":["Formats"],"summary":"Return a sample user object as `application/json`.","operationId":"Formats_Json","responses":{"200":{"description":"Success."}}}},"/api/formats/jsonp":{"get":{"tags":["Formats"],"summary":"Wrap the sample JSON in a JSONP callback.","description":"Served as `application/javascript`. The body is prefixed with `/**/` to guard against content-sniffing attacks.","operationId":"Formats_Jsonp","parameters":[{"name":"callback","in":"query","description":"JavaScript function name: an identifier, dots allowed, max 64 chars. Default `callback`; an empty value also uses the default.","schema":{"type":"string","default":"callback"}}],"responses":{"200":{"description":"Success."},"400":{"description":"`callback` is not a valid identifier or is too long."}}}},"/api/formats/malformed-json":{"get":{"tags":["Formats"],"summary":"Return deliberately invalid JSON labelled `application/json`.","description":"For negative testing: the body has a trailing comma and a truncated literal, so every JSON parser must fail on it.","operationId":"Formats_MalformedJson","responses":{"200":{"description":"Success."}}}},"/api/formats/markdown":{"get":{"tags":["Formats"],"summary":"Return a sample Markdown document with a table and a code block.","operationId":"Formats_Markdown","responses":{"200":{"description":"Success."}}}},"/api/formats/negotiate":{"get":{"tags":["Formats"],"summary":"Return the same user in the format chosen by the `Accept` header.","description":"Supported media types: `application/json`, `application/xml`, `text/xml`, `text/html`, `text/plain` and `text/csv`.\nTypes are tried in descending q-value order and `q=0` excludes a type. `*/*` and `application/*` map to JSON,\n`text/*` maps to plain text, and a missing `Accept` header yields JSON. Every response carries `Vary: Accept`.","operationId":"Formats_Negotiate","responses":{"200":{"description":"The user in the negotiated format."},"406":{"description":"No acceptable media type; the body lists the supported ones."}}}},"/api/formats/no-content":{"get":{"tags":["Formats"],"summary":"Return 204 No Content.","operationId":"Formats_NoBody","responses":{"200":{"description":"OK"},"204":{"description":"No body."}}}},"/api/formats/pdf":{"get":{"tags":["Formats"],"summary":"Return a minimal valid single-page PDF.","operationId":"Formats_Pdf","responses":{"200":{"description":"Success."}}}},"/api/formats/png":{"get":{"tags":["Formats"],"summary":"Generate a real, valid PNG image.","operationId":"Formats_Png","parameters":[{"name":"size","in":"query","description":"Width and height in pixels. Default 128; values outside 1–512 are clamped, not rejected.","schema":{"type":"integer","format":"int32","default":128}},{"name":"pattern","in":"query","description":"`gradient` (default) or `checkerboard`. Case-insensitive; unknown values fall back to `gradient`.","schema":{"type":"string","default":"gradient"}}],"responses":{"200":{"description":"An `image/png` body."},"400":{"description":"`size` is not an integer."}}}},"/api/formats/rss":{"get":{"tags":["Formats"],"summary":"Return a sample RSS 2.0 feed with two items.","operationId":"Formats_Rss","responses":{"200":{"description":"Success."}}}},"/api/formats/svg":{"get":{"tags":["Formats"],"summary":"Return a sample SVG image.","operationId":"Formats_Svg","responses":{"200":{"description":"Success."}}}},"/api/formats/text":{"get":{"tags":["Formats"],"summary":"Return a sample plain-text document.","operationId":"Formats_Text","responses":{"200":{"description":"Success."}}}},"/api/formats/tsv":{"get":{"tags":["Formats"],"summary":"Return the sample employee table as `text/tab-separated-values`.","operationId":"Formats_Tsv","responses":{"200":{"description":"Success."}}}},"/api/formats/wrong-content-type":{"get":{"tags":["Formats"],"summary":"Return valid JSON mislabelled as `text/html`.","operationId":"Formats_WrongContentType","responses":{"200":{"description":"Success."}}}},"/api/formats/xml":{"get":{"tags":["Formats"],"summary":"Return a sample user list as `application/xml`.","operationId":"Formats_Xml","responses":{"200":{"description":"Success."}}}},"/api/formats/yaml":{"get":{"tags":["Formats"],"summary":"Return a sample user object as `application/yaml`.","operationId":"Formats_Yaml","responses":{"200":{"description":"Success."}}}},"/api/files":{"get":{"tags":["Files"],"summary":"List the downloadable sample files with their size and SHA-256.","operationId":"Files_List","responses":{"200":{"description":"Success."}}}},"/api/files/{name}":{"get":{"tags":["Files"],"summary":"Download a sample file as an attachment.","description":"Sends `Content-Disposition: attachment` and supports single `Range` requests. HEAD returns the same headers without a body.","operationId":"Files_Download_GET","parameters":[{"name":"name","in":"path","description":"File name from `GET /api/files`, e.g. `sample.pdf`. Case-insensitive.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The file."},"206":{"description":"The requested byte range of the file."},"404":{"description":"No such file."}}},"head":{"tags":["Files"],"summary":"Download a sample file as an attachment.","description":"Sends `Content-Disposition: attachment` and supports single `Range` requests. HEAD returns the same headers without a body.","operationId":"Files_Download_HEAD","parameters":[{"name":"name","in":"path","description":"File name from `GET /api/files`, e.g. `sample.pdf`. Case-insensitive.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The file."},"206":{"description":"The requested byte range of the file."},"404":{"description":"No such file."}}}},"/api/files/{name}/inline":{"get":{"tags":["Files"],"summary":"Serve a sample file inline so a browser displays it.","operationId":"Files_Inline","parameters":[{"name":"name","in":"path","description":"File name from `GET /api/files`, e.g. `sample.png`. Case-insensitive.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The file, with `Content-Disposition: inline`."},"404":{"description":"No such file."}}}},"/api/files/bytes/{n}":{"get":{"tags":["Files"],"summary":"Download deterministic pseudo-random bytes.","description":"The `X-Content-SHA256` response header carries the body's hash for verification.","operationId":"Files_Bytes","parameters":[{"name":"n","in":"path","description":"Number of bytes, 0–10485760 (10 MB).","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"seed","in":"query","description":"Random seed, default 42. The same `n` and `seed` always return the same bytes.","schema":{"type":"integer","format":"int32","default":42}}],"responses":{"200":{"description":"Success."},"400":{"description":"`n` is outside 0–10485760."}}}},"/api/files/large":{"get":{"tags":["Files"],"summary":"Stream a large binary download without buffering it in memory.","description":"Content-Length is sent up front and the body is written in 64 KB chunks, which is handy for testing progress bars and timeouts.","operationId":"Files_Large","parameters":[{"name":"mb","in":"query","description":"Size in megabytes, 1–20, default 5.","schema":{"type":"integer","format":"int32","default":5}}],"responses":{"200":{"description":"Success."},"400":{"description":"`mb` is outside 1–20."}}}},"/api/files/range/{n}":{"get":{"tags":["Files"],"summary":"Download a verifiable byte pattern that supports HTTP Range requests.","description":"The byte at offset `i` is `i % 256`, so any slice can be checked. Single ranges such as `bytes=0-99`,\n`bytes=500-` and `bytes=-10` return 206; unsatisfiable ranges return 416, and multiple ranges are ignored (full 200).\nA fixed ETag and Last-Modified make `If-None-Match`, `If-Modified-Since` and `If-Range` work. HEAD returns headers only.","operationId":"Files_Range_GET","parameters":[{"name":"n","in":"path","description":"Total size in bytes, 1–10485760 (10 MB).","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"Range","in":"header","description":"Byte range, e.g. bytes=0-99. Returns 206, or 416 when unsatisfiable.","schema":{"type":"string"},"example":"bytes=0-99"}],"responses":{"200":{"description":"The full body."},"206":{"description":"The requested range."},"304":{"description":"Not modified (a conditional request matched)."},"400":{"description":"`n` is outside 1–10485760."},"416":{"description":"The range is not satisfiable."}}},"head":{"tags":["Files"],"summary":"Download a verifiable byte pattern that supports HTTP Range requests.","description":"The byte at offset `i` is `i % 256`, so any slice can be checked. Single ranges such as `bytes=0-99`,\n`bytes=500-` and `bytes=-10` return 206; unsatisfiable ranges return 416, and multiple ranges are ignored (full 200).\nA fixed ETag and Last-Modified make `If-None-Match`, `If-Modified-Since` and `If-Range` work. HEAD returns headers only.","operationId":"Files_Range_HEAD","parameters":[{"name":"n","in":"path","description":"Total size in bytes, 1–10485760 (10 MB).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The full body."},"206":{"description":"The requested range."},"304":{"description":"Not modified (a conditional request matched)."},"400":{"description":"`n` is outside 1–10485760."},"416":{"description":"The range is not satisfiable."}}}},"/api/edge-cases":{"get":{"tags":["EdgeCases"],"summary":"List the available edge-case endpoints.","operationId":"EdgeCases_Index","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/dates":{"get":{"tags":["EdgeCases"],"summary":"Return one instant in many date formats, plus invalid and boundary dates.","operationId":"EdgeCases_Dates","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/deep":{"get":{"tags":["EdgeCases"],"summary":"Return an object nested to the requested depth.","operationId":"EdgeCases_Deep","parameters":[{"name":"depth","in":"query","description":"Nesting depth, 1–500, default 100. Many serializers stop at a default maximum depth of 64.","schema":{"type":"integer","format":"int32","default":100}}],"responses":{"200":{"description":"Success."},"400":{"description":"`depth` is outside 1–500 or not an integer."}}}},"/api/edge-cases/duplicate-keys":{"get":{"tags":["EdgeCases"],"summary":"Return raw JSON text that contains duplicate keys.","description":"Most parsers keep the last value for a repeated key; strict parsers reject the document.","operationId":"EdgeCases_DuplicateKeys","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/empty-array":{"get":{"tags":["EdgeCases"],"summary":"Return exactly `[]`.","operationId":"EdgeCases_EmptyArray","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/empty-object":{"get":{"tags":["EdgeCases"],"summary":"Return exactly `{}`.","operationId":"EdgeCases_EmptyObject","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/large-array":{"get":{"tags":["EdgeCases"],"summary":"Return a large array of objects.","operationId":"EdgeCases_LargeArray","parameters":[{"name":"count","in":"query","description":"Number of items, 0–10000, default 1000. Also sent in the `X-Total-Count` header.","schema":{"type":"integer","format":"int32","default":1000}}],"responses":{"200":{"description":"Success."},"400":{"description":"`count` is outside 0–10000."}}}},"/api/edge-cases/mixed-array":{"get":{"tags":["EdgeCases"],"summary":"Return an array that mixes every JSON type.","operationId":"EdgeCases_MixedArray","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/nulls":{"get":{"tags":["EdgeCases"],"summary":"Return nulls alongside null-like values such as `\"null\"`, empty strings, 0 and false.","operationId":"EdgeCases_Nulls","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/numbers":{"get":{"tags":["EdgeCases"],"summary":"Return numeric edge cases: 64-bit limits, unsafe integers, -0 and float precision.","description":"Integers beyond 2^53 lose precision in JavaScript; string versions are included for comparison.","operationId":"EdgeCases_Numbers","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/special-keys":{"get":{"tags":["EdgeCases"],"summary":"Return an object with awkward keys: empty, dotted, `__proto__`, quoted, emoji and case variants.","operationId":"EdgeCases_SpecialKeys","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/strings":{"get":{"tags":["EdgeCases"],"summary":"Return string edge cases: unicode, emoji, RTL, zero-width, escapes, injection-looking text and a ~10 KB string.","operationId":"EdgeCases_Strings","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/top-level/{kind}":{"get":{"tags":["EdgeCases"],"summary":"Return a bare JSON scalar or array as the whole body.","operationId":"EdgeCases_TopLevel","parameters":[{"name":"kind","in":"path","description":"`string`, `number`, `boolean`, `null` or `array`. Case-insensitive.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success."},"404":{"description":"Unknown kind."}}}},"/api/edge-cases/types":{"get":{"tags":["EdgeCases"],"summary":"Return one of every JSON value type, including empty and look-alike values.","operationId":"EdgeCases_Types","responses":{"200":{"description":"Success."}}}},"/api/edge-cases/wide":{"get":{"tags":["EdgeCases"],"summary":"Return an object with many keys.","operationId":"EdgeCases_Wide","parameters":[{"name":"keys","in":"query","description":"Number of keys, 1–5000, default 1000.","schema":{"type":"integer","format":"int32","default":1000}}],"responses":{"200":{"description":"Success."},"400":{"description":"`keys` is outside 1–5000."}}}},"/api/utils/base64/decode":{"get":{"tags":["Utils"],"summary":"Decode a base64 string.","description":"If the decoded bytes are not valid UTF-8, `decoded` is null and `hex` holds the bytes.","operationId":"Utils_Base64Decode","parameters":[{"name":"value","in":"query","description":"Standard or URL-safe base64, with or without padding. Send `+` as `%2B` in the query string.","schema":{"type":"string","default":""}}],"responses":{"200":{"description":"Success."},"400":{"description":"`value` is not valid base64."}}}},"/api/utils/base64/encode":{"get":{"tags":["Utils"],"summary":"Base64-encode UTF-8 text.","operationId":"Utils_Base64Encode","parameters":[{"name":"text","in":"query","description":"Text to encode. Default empty.","schema":{"type":"string","default":""}},{"name":"urlSafe","in":"query","description":"Use the URL-safe alphabet (`-` and `_`) without padding. Default false.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Success."}}}},"/api/utils/hash":{"get":{"tags":["Utils"],"summary":"Hash UTF-8 text.","operationId":"Utils_Hash","parameters":[{"name":"text","in":"query","description":"Text to hash. Default empty.","schema":{"type":"string","default":""}},{"name":"algorithm","in":"query","description":"`md5`, `sha1`, `sha256` (default), `sha384` or `sha512`. Case-insensitive.","schema":{"type":"string","default":"sha256"}}],"responses":{"200":{"description":"Success."},"400":{"description":"Unknown algorithm."}}}},"/api/utils/hmac":{"get":{"tags":["Utils"],"summary":"Compute an HMAC of UTF-8 text.","operationId":"Utils_Hmac","parameters":[{"name":"text","in":"query","description":"Message to sign. Default empty.","schema":{"type":"string","default":""}},{"name":"key","in":"query","description":"Secret key. Default `apibee-secret`.","schema":{"type":"string","default":"apibee-secret"}},{"name":"algorithm","in":"query","description":"`md5`, `sha1`, `sha256` (default), `sha384` or `sha512`. Case-insensitive.","schema":{"type":"string","default":"sha256"}}],"responses":{"200":{"description":"Success."},"400":{"description":"Unknown algorithm."}}}},"/api/utils/jwt/decode":{"get":{"tags":["Utils"],"summary":"Decode a JWT without verifying its signature.","description":"Returns the header, the payload and readable `exp`/`iat`/`nbf` claims with an expiry flag. The signature is never verified, so never trust the claims.","operationId":"Utils_JwtDecode","parameters":[{"name":"token","in":"query","description":"The JWT. If omitted, the Bearer token from the `Authorization` header is used.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success."},"400":{"description":"No token, wrong number of parts, or a part is not base64url-encoded JSON."}}}},"/api/utils/lorem":{"get":{"tags":["Utils"],"summary":"Generate lorem ipsum text.","description":"Deterministic: five fixed paragraphs repeat in order.","operationId":"Utils_Lorem","parameters":[{"name":"paragraphs","in":"query","description":"Number of paragraphs, 1–50, default 3.","schema":{"type":"integer","format":"int32","default":3}},{"name":"format","in":"query","description":"`json` (default) for an object with a word count, or `text` for plain text.","schema":{"type":"string","default":"json"}}],"responses":{"200":{"description":"Success."},"400":{"description":"`paragraphs` is outside 1–50."}}}},"/api/utils/random/number":{"get":{"tags":["Utils"],"summary":"Generate random integers.","operationId":"Utils_RandomNumber","parameters":[{"name":"min","in":"query","description":"Inclusive lower bound. Default 0.","schema":{"type":"integer","format":"int32","default":0}},{"name":"max","in":"query","description":"Inclusive upper bound, at least `min`. Default 100.","schema":{"type":"integer","format":"int32","default":100}},{"name":"count","in":"query","description":"How many to generate, 1–100, default 1. One returns `number`; more return a `numbers` array.","schema":{"type":"integer","format":"int32","default":1}},{"name":"seed","in":"query","description":"Optional seed for repeatable output.","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Success."},"400":{"description":"`min` is greater than `max`, or `count` is out of range."}}}},"/api/utils/random/string":{"get":{"tags":["Utils"],"summary":"Generate a random string.","operationId":"Utils_RandomString","parameters":[{"name":"length","in":"query","description":"Length, 1–1000, default 16.","schema":{"type":"integer","format":"int32","default":16}},{"name":"charset","in":"query","description":"`alphanumeric` (default), `alpha`, `numeric`, `hex` or `symbols`. Case-insensitive.","schema":{"type":"string","default":"alphanumeric"}},{"name":"seed","in":"query","description":"Optional seed for repeatable output.","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Success."},"400":{"description":"`length` is out of range or the charset is unknown."}}}},"/api/utils/time":{"get":{"tags":["Utils"],"summary":"Return the current time in many formats.","operationId":"Utils_Time","parameters":[{"name":"tz","in":"query","description":"Optional time zone, as an IANA id (`Asia/Kolkata`) or a Windows id (`India Standard Time`). Default UTC.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success."},"400":{"description":"Unknown time zone."}}}},"/api/utils/url/decode":{"get":{"tags":["Utils"],"summary":"Percent-decode a string.","operationId":"Utils_UrlDecode","parameters":[{"name":"value","in":"query","description":"Value to decode. The server already decodes the query string once, so double-encode it (e.g. `%2520` for `%20`). A literal `+` is kept as-is.","schema":{"type":"string","default":""}}],"responses":{"200":{"description":"Success."}}}},"/api/utils/url/encode":{"get":{"tags":["Utils"],"summary":"Percent-encode text (RFC 3986).","operationId":"Utils_UrlEncode","parameters":[{"name":"text","in":"query","description":"Text to encode. Default empty.","schema":{"type":"string","default":""}}],"responses":{"200":{"description":"Success."}}}},"/api/utils/uuid":{"get":{"tags":["Utils"],"summary":"Generate one or more UUIDs.","operationId":"Utils_Uuid","parameters":[{"name":"count","in":"query","description":"How many to generate, 1–100, default 1. One returns `uuid`; more return a `uuids` array.","schema":{"type":"integer","format":"int32","default":1}},{"name":"version","in":"query","description":"`4` (random, default) or `7` (time-ordered).","schema":{"type":"integer","format":"int32","default":4}}],"responses":{"200":{"description":"Success."},"400":{"description":"`count` or `version` is out of range."}}}},"/api/auth":{"get":{"tags":["AuthSchemes"],"summary":"List every auth scheme with its test credentials.","operationId":"AuthSchemes_Schemes","responses":{"200":{"description":"Schemes, endpoints and credentials."}}}},"/api/auth/api-key/cookie":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with an API key in the api_key cookie.","description":"Header: `Cookie: api_key=apibee-key-123`.","operationId":"AuthSchemes_ApiKeyCookie","responses":{"200":{"description":"Authenticated."},"401":{"description":"No key sent, or the key is wrong."}}}},"/api/auth/api-key/header":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with an API key in the X-API-Key header.","description":"Header: `X-API-Key: apibee-key-123`.","operationId":"AuthSchemes_ApiKeyHeader","responses":{"200":{"description":"Authenticated."},"401":{"description":"No key sent, or the key is wrong."}},"security":[{"apiKeyHeader":[]}]}},"/api/auth/api-key/query":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with an API key in the api_key query parameter.","description":"Example: `GET /api/auth/api-key/query?api_key=apibee-key-123`.","operationId":"AuthSchemes_ApiKeyQuery","responses":{"200":{"description":"Authenticated."},"401":{"description":"No key sent, or the key is wrong."}},"security":[{"apiKeyQuery":[]}]}},"/api/auth/basic":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with HTTP Basic auth.","description":"Credentials: `apibee` / `password123`.\n\nHeader: `Authorization: Basic YXBpYmVlOnBhc3N3b3JkMTIz` (base64 of `apibee:password123`).","operationId":"AuthSchemes_Basic","responses":{"200":{"description":"Authenticated."},"401":{"description":"Header missing or malformed, or wrong credentials. Includes `WWW-Authenticate: Basic realm=\"apibee\"`."}},"security":[{"basic":[]}]}},"/api/auth/basic-hidden/{user}/{pass}":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with Basic auth, returning 404 instead of 401 on failure.","description":"Mimics servers that hide protected resources. No `WWW-Authenticate` challenge is sent.","operationId":"AuthSchemes_BasicHidden","parameters":[{"name":"user","in":"path","description":"Username the Authorization header must contain.","required":true,"schema":{"type":"string"}},{"name":"pass","in":"path","description":"Password the Authorization header must contain.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Header matches the URL credentials."},"404":{"description":"Header missing, malformed or different."}},"security":[{"basic":[]}]}},"/api/auth/basic/{user}/{pass}":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with Basic auth against credentials taken from the URL.","description":"httpbin style: `GET /api/auth/basic/foo/bar` with `Authorization: Basic base64(foo:bar)`.","operationId":"AuthSchemes_BasicPath","parameters":[{"name":"user","in":"path","description":"Username the Authorization header must contain.","required":true,"schema":{"type":"string"}},{"name":"pass","in":"path","description":"Password the Authorization header must contain.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Header matches the URL credentials."},"401":{"description":"Header missing, malformed or different. Includes a Basic challenge."}},"security":[{"basic":[]}]}},"/api/auth/bearer":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with a static bearer token.","description":"Header: `Authorization: Bearer apibee-token-123`.","operationId":"AuthSchemes_Bearer","responses":{"200":{"description":"Authenticated."},"401":{"description":"Token missing, or invalid (then `WWW-Authenticate: Bearer error=\"invalid_token\"`)."}},"security":[{"bearer":[]}]}},"/api/auth/csrf/submit":{"post":{"tags":["AuthSchemes"],"summary":"Submit a CSRF-protected form (double-submit cookie check).","description":"Requires the `XSRF-TOKEN` cookie from `GET /api/auth/csrf/token` and a matching `X-CSRF-Token` header. The token must carry this server's signature.","operationId":"AuthSchemes_CsrfSubmit","parameters":[{"name":"X-CSRF-Token","in":"header","description":"Token from GET /api/auth/csrf/token (the matching cookie is sent automatically by the browser).","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Any body.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"comment":"hello"}}}},"responses":{"200":{"description":"Cookie and header match, and the token was issued by this server."},"403":{"description":"Cookie or header missing, they don't match, or the token wasn't issued by this server."}}}},"/api/auth/csrf/token":{"get":{"tags":["AuthSchemes"],"summary":"Issue a CSRF token and set it as the XSRF-TOKEN cookie.","description":"Send the same value back in the `X-CSRF-Token` header when calling `POST /api/auth/csrf/submit`.\nTokens are signed by the server (`csrf_<random>.<hmac>`), so a value the server never issued fails even when the\ncookie and header match (the signed double-submit pattern).","operationId":"AuthSchemes_CsrfToken","responses":{"200":{"description":"Token issued; `Set-Cookie: XSRF-TOKEN=...`."}}}},"/api/auth/digest":{"get":{"tags":["AuthSchemes"],"summary":"Authenticate with HTTP Digest auth (MD5, qop=auth).","description":"Credentials: `apibee` / `password123`, realm `apibee`. A request without credentials gets 401 with a\n`WWW-Authenticate: Digest` challenge carrying `nonce` and `opaque`; clients such as `curl --digest`,\nPostman and `requests.auth.HTTPDigestAuth` then retry automatically.\n\n`response = MD5(HA1:nonce:nc:cnonce:qop:HA2)` where `HA1 = MD5(username:realm:password)` and\n`HA2 = MD5(method:uri)`. Without qop: `MD5(HA1:nonce:HA2)`. Nonces expire after 5 minutes; the 401 then includes `stale=true`.\nReplays are refused: with qop=auth each request must use a higher `nc` than the last one for that nonce, and\nwithout qop a nonce works once.","operationId":"AuthSchemes_Digest","responses":{"200":{"description":"Authenticated."},"401":{"description":"Missing or invalid Digest header, wrong credentials, or an unknown or stale nonce. Includes a fresh challenge."}}}},"/api/auth/hmac":{"post":{"tags":["AuthSchemes"],"summary":"Verify an HMAC-SHA256 request signature.","description":"Headers:\n\n`X-Timestamp`: current Unix time in seconds; must be within 300 seconds of server time.\n`X-Signature`: lowercase hex of `HMAC-SHA256(key: \"apibee-hmac-secret\", message: X-Timestamp + \".\" + raw request body)`. An optional `sha256=` prefix is accepted.\nBash: `SIG=$(printf '%s' \"$TS.$BODY\" | openssl dgst -sha256 -hmac apibee-hmac-secret | awk '{print $NF}')`\nEach signature is accepted once: sending the identical request again within the 5-minute window gets 401 (replay refused).\nTwo different requests need a different timestamp or body.","operationId":"AuthSchemes_Hmac","parameters":[{"name":"X-Timestamp","in":"header","description":"Unix time in seconds; must be within 5 minutes of the server clock.","required":true,"schema":{"type":"string"}},{"name":"X-Signature","in":"header","description":"Hex HMAC-SHA256 of \"{X-Timestamp}.{raw body}\" with secret `apibee-hmac-secret` (optional `sha256=` prefix).","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Any body; it is covered by X-Signature.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"event":"ping"}}}},"responses":{"200":{"description":"Signature valid."},"401":{"description":"Headers missing, timestamp not numeric or outside the tolerance, signature mismatch, or a replayed signature."}}}},"/api/auth/roles/admin":{"get":{"tags":["AuthSchemes"],"summary":"Allow only tokens with the admin role (401 vs 403 demo).","description":"Header: `Authorization: Bearer <token>` with one of the test tokens:\n`admin-token` (roles admin, user; scopes read, write, delete),\n`user-token` (role user; scopes read, write),\n`readonly-token` (no roles; scope read). Only `admin-token` passes.","operationId":"AuthSchemes_AdminOnly","responses":{"200":{"description":"Token has the admin role."},"401":{"description":"Token missing or not one of the test tokens."},"403":{"description":"Valid token without the admin role."}},"security":[{"bearer":[]}]}},"/api/auth/roles/resource":{"delete":{"tags":["AuthSchemes"],"summary":"Allow only tokens with the delete scope.","description":"Header: `Authorization: Bearer <token>`. Only `admin-token` has the delete scope;\n`user-token` and `readonly-token` get 403.","operationId":"AuthSchemes_DeleteResource","responses":{"200":{"description":"Token has the delete scope."},"401":{"description":"Token missing or not one of the test tokens."},"403":{"description":"Valid token without the delete scope."}},"security":[{"bearer":[]}]}},"/api/auth/roles/user":{"get":{"tags":["AuthSchemes"],"summary":"Allow only tokens with the user role.","description":"Header: `Authorization: Bearer <token>`. `admin-token` and `user-token` pass;\n`readonly-token` gets 403.","operationId":"AuthSchemes_UserOnly","responses":{"200":{"description":"Token has the user role."},"401":{"description":"Token missing or not one of the test tokens."},"403":{"description":"Valid token without the user role."}},"security":[{"bearer":[]}]}},"/api/auth/oauth1":{"get":{"tags":["OAuth1"],"summary":"Call a protected resource with an OAuth 1.0a signed request.","description":"Credentials: consumer key `apibee-consumer-key` / secret `apibee-consumer-secret`, and either the\nhardcoded access token `apibee-access-token` / `apibee-token-secret` or one issued by\n`POST /api/auth/oauth1/access_token`. Leave the token out for a two-legged (consumer-only) request.\n\nSignature methods: `HMAC-SHA1`, `HMAC-SHA256`, `HMAC-SHA512`, `PLAINTEXT`.\nSigning key: `consumer_secret&token_secret`.\nOAuth parameters go in `Authorization: OAuth ...`, the query string or a form body (one place only).\nAny query parameters are covered by the signature. `oauth_timestamp` must be within 5 minutes of server\ntime and each `oauth_nonce` can be used once.\nA 401 for a bad signature includes the server's signature base string, so you can diff it against yours.","operationId":"OAuth1_Get","responses":{"200":{"description":"Signature valid."},"400":{"description":"Missing or duplicated OAuth parameter, OAuth parameters in more than one place, unsupported version or signature method."},"401":{"description":"Unknown consumer key or token, expired token, timestamp outside the window, reused nonce or signature mismatch. Includes `WWW-Authenticate: OAuth realm=\"apibee\"`."}}},"post":{"tags":["OAuth1"],"summary":"Send a form to a protected resource with an OAuth 1.0a signed request.","description":"Same credentials and rules as `GET /api/auth/oauth1`. Fields of an\n`application/x-www-form-urlencoded` body are part of the signature; other body types are not signed.","operationId":"OAuth1_Post","requestBody":{"description":"Any form fields; they are covered by the OAuth signature.","content":{"application/x-www-form-urlencoded":{"schema":{"type":"object"},"example":{"status":"hello"}}}},"responses":{"200":{"description":"Signature valid."},"400":{"description":"Missing or duplicated OAuth parameter, OAuth parameters in more than one place, unsupported version or signature method."},"401":{"description":"Unknown consumer key or token, expired token, timestamp outside the window, reused nonce or signature mismatch. Includes `WWW-Authenticate: OAuth realm=\"apibee\"`."}}}},"/api/auth/oauth1/access_token":{"post":{"tags":["OAuth1"],"summary":"Step 3: exchange the authorized request token for an access token.","description":"Sign with the consumer credentials plus the request token and its secret, and include `oauth_verifier`\nfrom step 2. In Postman, put the request token and secret in \"Access Token\" / \"Token Secret\" and the verifier in \"Verifier\".\n\nResponse (`application/x-www-form-urlencoded`, or JSON with `Accept: application/json`):\n`oauth_token`, `oauth_token_secret`, `username`. The access token works on\n`/api/auth/oauth1` for 1 hour. Each request token can be exchanged once.","operationId":"OAuth1_AccessTokenStep","responses":{"200":{"description":"Access token issued."},"400":{"description":"oauth_token or oauth_verifier missing, or another protocol parameter problem."},"401":{"description":"Unknown, expired or already used request token, not yet authorized, wrong verifier, or a signature problem."}}}},"/api/auth/oauth1/authorize":{"get":{"tags":["OAuth1"],"summary":"Step 2: authorize the request token (auto-approved as user apibee).","description":"Not signed: this is the page a user would open in a browser. When the request token's `oauth_callback`\nis an http(s) URL on localhost or 127.0.0.1 (any port) or a Postman callback, it redirects there with\n`oauth_token` and `oauth_verifier`; for `oob` or any other callback the verifier is returned as JSON.\n\nNext: `POST /api/auth/oauth1/access_token` signed with the request token and its secret, plus `oauth_verifier`.","operationId":"OAuth1_Authorize","parameters":[{"name":"oauth_token","in":"query","description":"The request token from step 1.","schema":{"type":"string"}}],"responses":{"200":{"description":"Verifier returned as JSON (oob, or a callback that isn't allowlisted)."},"302":{"description":"Redirect to the callback with oauth_token and oauth_verifier."},"400":{"description":"oauth_token missing, unknown, expired or already exchanged."}}}},"/api/auth/oauth1/request_token":{"post":{"tags":["OAuth1"],"summary":"Step 1: get a temporary request token.","description":"Sign with the consumer credentials only (`apibee-consumer-key` / `apibee-consumer-secret`, no\n`oauth_token`) and include `oauth_callback`: an http(s) URL, or `oob` to get the verifier\nshown instead of redirected. In Postman, fill in \"Callback URL\" and leave the token fields empty.\n\nResponse (`application/x-www-form-urlencoded`, or JSON with `Accept: application/json`):\n`oauth_token`, `oauth_token_secret`, `oauth_callback_confirmed=true`. The request token expires after 10 minutes.\nNext: open `GET /api/auth/oauth1/authorize?oauth_token=...`.","operationId":"OAuth1_RequestTokenStep","responses":{"200":{"description":"Request token issued."},"400":{"description":"oauth_callback missing or invalid, oauth_token sent, or another protocol parameter problem."},"401":{"description":"Unknown consumer key, timestamp outside the window, reused nonce or signature mismatch."}}}},"/api/auth/oauth/authorize":{"get":{"tags":["OAuth"],"summary":"Start the authorization code flow and issue a code (auto-approved as user apibee).","description":"Codes are single use and expire after 10 minutes. Exchange them at `POST /api/auth/oauth/token`.","operationId":"OAuth_Authorize","parameters":[{"name":"response_type","in":"query","description":"Must be `code`.","schema":{"type":"string"}},{"name":"client_id","in":"query","description":"`apibee-client` (confidential) or `apibee-public` (public; PKCE required).","schema":{"type":"string"}},{"name":"redirect_uri","in":"query","description":"Where to send the code. Registered redirect URIs are http(s) URIs on localhost or 127.0.0.1 (any port) and the Postman callbacks; any other value is refused with 400 and no code is issued. Leave it out to get the code back as JSON.","schema":{"type":"string"}},{"name":"scope","in":"query","description":"Space-separated subset of the client's scopes (apibee-client: read write profile email; apibee-public: read profile email). Defaults to all of them.","schema":{"type":"string"}},{"name":"state","in":"query","description":"Opaque value echoed back unchanged.","schema":{"type":"string"}},{"name":"code_challenge","in":"query","description":"PKCE challenge: `BASE64URL(SHA256(code_verifier))` for S256, or the verifier itself for plain.","schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","description":"`S256` or `plain` (default plain).","schema":{"type":"string"}}],"responses":{"200":{"description":"Code returned as JSON (no redirect_uri sent)."},"302":{"description":"Redirect to redirect_uri with `code` and `state`."},"400":{"description":"invalid_client, unsupported_response_type, invalid_request (including an unregistered redirect_uri) or invalid_scope."}}}},"/api/auth/oauth/introspect":{"post":{"tags":["OAuth"],"summary":"Report whether a token is active (RFC 7662).","description":"Body (form or JSON): `token`. Unknown, expired and revoked tokens return `{\"active\": false}`.","operationId":"OAuth_Introspect","requestBody":{"description":"Token to inspect.","content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Token status and, when active, its scope, client, subject and expiry."}}}},"/api/auth/oauth/protected":{"get":{"tags":["OAuth"],"summary":"Return a resource that requires an OAuth access token.","description":"Header: `Authorization: Bearer <access_token>` from `POST /api/auth/oauth/token`.","operationId":"OAuth_Protected","responses":{"200":{"description":"Token valid; returns its client, subject, scope and remaining lifetime."},"401":{"description":"Token missing, invalid, revoked or expired."}},"security":[{"oauth2":[]},{"bearer":[]}]}},"/api/auth/oauth/revoke":{"post":{"tags":["OAuth"],"summary":"Revoke an access or refresh token (RFC 7009).","description":"Body (form or JSON): `token`. Returns 200 even for unknown tokens.","operationId":"OAuth_Revoke","requestBody":{"description":"Token to revoke.","content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string"},"token_type_hint":{"type":"string"}}}}}},"responses":{"200":{"description":"Revoked, or already unknown."},"400":{"description":"token missing."}}}},"/api/auth/oauth/token":{"post":{"tags":["OAuth"],"summary":"Exchange a grant for an access token.","description":"Body: `application/x-www-form-urlencoded` or JSON.\nClient auth: `Authorization: Basic base64(client_id:client_secret)`, or `client_id` and `client_secret` in the body.\nClients: `apibee-client` / `apibee-secret` (confidential), `apibee-public` (public, no secret).\nUsers: `apibee` / `password123`, `jane` / `jane123`.\n\ngrant_type values:\n`client_credentials`: optional `scope`; confidential client only; no refresh token.\n`password`: `username`, `password`, optional `scope`.\n`authorization_code`: `code`, `redirect_uri` (if one was sent to /authorize), `code_verifier` (if PKCE was used).\n`refresh_token`: `refresh_token`. Refresh tokens rotate: each use returns a new one and the old one stops working. Using a spent refresh token again revokes every token from the same grant (reuse detection, RFC 9700).\nAccess tokens expire after 3600 seconds.","operationId":"OAuth_Token","requestBody":{"description":"Standard OAuth2 token request (JSON with the same fields also works).","content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"username":{"type":"string"},"password":{"type":"string"},"code":{"type":"string"},"redirect_uri":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"scope":{"type":"string"}}},"example":{"grant_type":"client_credentials","client_id":"apibee-client","client_secret":"apibee-secret","scope":"read"}}}},"responses":{"200":{"description":"access_token, token_type, expires_in, refresh_token (not for client_credentials) and scope."},"400":{"description":"invalid_request, invalid_grant, invalid_scope, unauthorized_client or unsupported_grant_type."},"401":{"description":"invalid_client: unknown client or wrong secret."}}}},"/api/auth/oauth/userinfo":{"get":{"tags":["OAuth"],"summary":"Return the profile of the user behind an access token.","description":"Header: `Authorization: Bearer <access_token>`. The email is only included when the token has the email scope.","operationId":"OAuth_UserInfo","responses":{"200":{"description":"User profile."},"401":{"description":"Token missing, invalid, revoked or expired."},"403":{"description":"client_credentials tokens have no user."}},"security":[{"oauth2":[]},{"bearer":[]}]}},"/api/auth/jwt/admin":{"get":{"tags":["JwtAuth"],"summary":"Allow only JWTs with the admin role.","description":"Log in as `admin` / `admin123`. A token for `user` is authenticated but gets 403.","operationId":"JwtAuth_Admin","responses":{"200":{"description":"Token has the admin role."},"401":{"description":"Token missing, invalid or expired."},"403":{"description":"Valid token without the admin role."}},"security":[{"bearer":[]}]}},"/api/auth/jwt/expired":{"get":{"tags":["JwtAuth"],"summary":"Return a correctly signed JWT that expired an hour ago.","description":"Use it against `GET /api/auth/jwt/me` to test how a client handles 401 for expired tokens.","operationId":"JwtAuth_Expired","responses":{"200":{"description":"The expired token."}}}},"/api/auth/jwt/login":{"post":{"tags":["JwtAuth"],"summary":"Log in and receive a JWT access token and a refresh token.","description":"Users: `admin` / `admin123` (role admin), `user` / `user123` (role user).\nAccess tokens expire after 15 minutes. Send them as `Authorization: Bearer <accessToken>`.","operationId":"JwtAuth_Login","requestBody":{"description":"Username and password.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerLoginRequest"}},"text/json":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerLoginRequest"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerLoginRequest"}},"application/xml":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerLoginRequest"}},"text/xml":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerLoginRequest"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerLoginRequest"}}}},"responses":{"200":{"description":"accessToken, tokenType, expiresIn, refreshToken and user."},"400":{"description":"username or password missing."},"401":{"description":"Wrong username or password."}}}},"/api/auth/jwt/me":{"get":{"tags":["JwtAuth"],"summary":"Return the claims of the current JWT.","description":"Header: `Authorization: Bearer <accessToken>` from `POST /api/auth/jwt/login`.","operationId":"JwtAuth_Me","responses":{"200":{"description":"Username, role, profile and all claims."},"401":{"description":"Token missing, invalid or expired."}},"security":[{"bearer":[]}]}},"/api/auth/jwt/refresh":{"post":{"tags":["JwtAuth"],"summary":"Exchange a refresh token for new tokens.","description":"Refresh tokens are single use: each call returns a new one and the old one stops working. Presenting a refresh\ntoken that was already used is treated as theft: every refresh token from the same login is revoked, so the\nuser has to log in again (reuse detection, RFC 9700).","operationId":"JwtAuth_Refresh","requestBody":{"description":"The refresh token to use.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerRefreshRequest"}},"text/json":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerRefreshRequest"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerRefreshRequest"}},"application/xml":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerRefreshRequest"}},"text/xml":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerRefreshRequest"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/JwtAuthControllerRefreshRequest"}}}},"responses":{"200":{"description":"New access and refresh tokens."},"400":{"description":"refreshToken missing."},"401":{"description":"Refresh token invalid or expired, or already used (which also revokes its whole family)."}}}},"/api/RateLimit":{"get":{"tags":["RateLimit"],"summary":"Make a rate-limited request that counts toward the limit.","description":"Header (optional): `X-Client-Id: <any id>`; without it the remote IP is used.\nResponses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (Unix seconds).\nThe 6th request in a window gets 429 with `Retry-After` in seconds.","operationId":"RateLimit_Hit","parameters":[{"name":"X-Client-Id","in":"header","description":"Rate-limit bucket id (defaults to your IP). Use a unique value to get a fresh window.","schema":{"type":"string"},"example":"swagger-demo"}],"responses":{"200":{"description":"Request allowed."},"429":{"description":"Limit exceeded; retry after the Retry-After delay."}}}},"/api/RateLimit/reset":{"post":{"tags":["RateLimit"],"summary":"Reset the caller's window.","description":"Header (optional): `X-Client-Id`.","operationId":"RateLimit_Reset","parameters":[{"name":"X-Client-Id","in":"header","description":"Rate-limit bucket id (defaults to your IP).","schema":{"type":"string"},"example":"swagger-demo"}],"responses":{"200":{"description":"Window reset."}}}},"/api/RateLimit/status":{"get":{"tags":["RateLimit"],"summary":"Show the caller's current window without counting a request.","description":"Header (optional): `X-Client-Id`.","operationId":"RateLimit_Status","parameters":[{"name":"X-Client-Id","in":"header","description":"Rate-limit bucket id (defaults to your IP).","schema":{"type":"string"},"example":"swagger-demo"}],"responses":{"200":{"description":"Used, remaining, limit and seconds until the window resets."}}}},"/api/Payments":{"get":{"tags":["Payments"],"summary":"List payments with filtering, search, sorting and pagination.","description":"Filter on any field (for example `?status=refunded`, `?method=upi`, `?userId=101`), search with `?q=`,\nsort with `?sort=amount&order=desc`, and page with `?limit=` plus `?page=` or `?offset=`.\nTotals are in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Payments_GetAll","responses":{"200":{"description":"Matching payments."}}},"post":{"tags":["Payments"],"summary":"Create a payment. Requires an Idempotency-Key header.","description":"Header: `Idempotency-Key: <unique value, e.g. a UUID>` (max 255 characters, remembered for 24 hours).\n\nSame key and same body: the original response is replayed with `Idempotent-Replayed: true`. Bodies are compared\nafter canonicalizing, so key order and whitespace don't matter.\nSame key and a different body: 422. Same key while the first request is still processing: 409.\nA request that fails validation isn't remembered, so its key can be reused.\nTest data: `cardLast4` 0002 is always declined (status failed, still 201). bank_transfer payments start as pending.","operationId":"Payments_Create","parameters":[{"name":"processingSeconds","in":"query","description":"Hold the request open for this many seconds (max 5) so a duplicate can be sent while it is in flight.","schema":{"type":"integer","format":"int32","default":0}},{"name":"Idempotency-Key","in":"header","description":"Unique key per logical payment. Same key + same body replays the stored response; a different body returns 422.","required":true,"schema":{"type":"string"},"example":"3f2b9c1e-7d4a-4e8b-9a61-0c5d2e8f1a7b"}],"requestBody":{"description":"userId, orderId (optional), amount (greater than 0, max 1,000,000), currency (3-letter code), method (card, upi, paypal or bank_transfer), description, cardLast4 (4 digits, required for card).","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Payment created, or the original response replayed."},"400":{"description":"Idempotency-Key missing or too long, or the body is invalid."},"409":{"description":"A request with the same key is still being processed."},"422":{"description":"The key was already used with a different body."}}}},"/api/Payments/{id}":{"get":{"tags":["Payments"],"summary":"Get a payment by ID.","operationId":"Payments_GetById","parameters":[{"name":"id","in":"path","description":"Payment ID (1-12 for the seed payments).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The payment."},"404":{"description":"No payment with that ID."}}}},"/api/Payments/{id}/refund":{"post":{"tags":["Payments"],"summary":"Refund a succeeded payment.","operationId":"Payments_Refund","parameters":[{"name":"id","in":"path","description":"Payment ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Payment refunded."},"404":{"description":"No payment with that ID."},"409":{"description":"Already refunded, or not in succeeded status."}}}},"/api/stream/chunked/{n}":{"get":{"tags":["Streaming"],"summary":"Send a plain-text response in chunked transfer encoding.","description":"No Content-Length is sent, so HTTP/1.1 uses `Transfer-Encoding: chunked`; each line is flushed as its own\nchunk. Watch it with `curl -N \"https://api.testingapis.com/api/stream/chunked/5\"`.","operationId":"Streaming_Chunked","parameters":[{"name":"n","in":"path","description":"Number of chunks (1-100; out-of-range values are clamped).","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"intervalMs","in":"query","description":"Delay between chunks in milliseconds (0-5000, default 250).","schema":{"type":"integer","format":"int32","default":250}}],"responses":{"200":{"description":"Chunked text, one line per chunk."}}}},"/api/stream/drip":{"get":{"tags":["Streaming"],"summary":"Drip bytes slowly over a duration.","description":"Useful for testing read timeouts and progress handling. Content-Length is set to bytes.\nExample: `curl -N \"https://api.testingapis.com/api/stream/drip?durationMs=3000&bytes=30\"`","operationId":"Streaming_Drip","parameters":[{"name":"durationMs","in":"query","description":"Total time to spread the bytes over, in milliseconds (0-30000, default 2000).","schema":{"type":"integer","format":"int32","default":2000}},{"name":"bytes","in":"query","description":"Number of `*` bytes to send (1-10240, default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"`application/octet-stream` body of asterisks."}}}},"/api/stream/json-array/{n}":{"get":{"tags":["Streaming"],"summary":"Stream a JSON array one element at a time.","description":"The complete body is a valid JSON array, but it arrives incrementally, which is useful for testing streaming\nJSON parsers. Example: `curl -N \"https://api.testingapis.com/api/stream/json-array/10\"`","operationId":"Streaming_JsonArray","parameters":[{"name":"n","in":"path","description":"Number of elements (1-1000; out-of-range values are clamped).","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"intervalMs","in":"query","description":"Delay between elements in milliseconds (0-5000, default 100).","schema":{"type":"integer","format":"int32","default":100}}],"responses":{"200":{"description":"A JSON array, streamed."}}}},"/api/stream/ndjson/{n}":{"get":{"tags":["Streaming"],"summary":"Stream newline-delimited JSON, one object per line.","description":"Content type is `application/x-ndjson`. Swagger UI shows the result only after the stream ends; to watch\nlines arrive use `curl -N \"https://api.testingapis.com/api/stream/ndjson/20?intervalMs=200\"`.","operationId":"Streaming_NdJson","parameters":[{"name":"n","in":"path","description":"Number of lines (1-1000; out-of-range values are clamped).","required":true,"schema":{"type":"integer","format":"int32"}},{"name":"intervalMs","in":"query","description":"Delay between lines in milliseconds (0-5000, default 0).","schema":{"type":"integer","format":"int32","default":0}}],"responses":{"200":{"description":"NDJSON lines."}}}},"/api/stream/sse":{"get":{"tags":["Streaming"],"summary":"Stream Server-Sent Events.","description":"The stream opens with `retry: 3000`; each event has an `id`, `event: message` and a JSON\n`data` line, and the stream ends with `event: done`. Send a `Last-Event-ID: N` header to resume\nafter event N.\n\nSwagger UI buffers the whole response and cannot show events as they arrive. Use curl instead:```curl -N \"https://api.testingapis.com/api/stream/sse?count=5&interval=500\"```","operationId":"Streaming_Sse","parameters":[{"name":"count","in":"query","description":"Number of events to send (1-100, default 10).","schema":{"type":"integer","format":"int32","default":10}},{"name":"interval","in":"query","description":"Delay between events in milliseconds (100-5000, default 1000).","schema":{"type":"integer","format":"int32","default":1000}},{"name":"Last-Event-ID","in":"header","description":"Resume the stream after this event id.","schema":{"type":"string"},"example":"3"}],"responses":{"200":{"description":"A `text/event-stream` of events."}}}},"/api/stream/sse/stock":{"get":{"tags":["Streaming"],"summary":"Stream a deterministic stock ticker as Server-Sent Events.","description":"Each `event: tick` carries symbol, price, change, changePercent, volume and timestamp. The same tick number\nalways yields the same symbol and price. The stream ends with `event: done`.\n\nSwagger UI cannot display streams. Use curl instead:```curl -N \"https://api.testingapis.com/api/stream/sse/stock?count=5\"```","operationId":"Streaming_SseStock","parameters":[{"name":"count","in":"query","description":"Number of ticks to send (1-100, default 20).","schema":{"type":"integer","format":"int32","default":20}},{"name":"interval","in":"query","description":"Delay between ticks in milliseconds (100-5000, default 1000).","schema":{"type":"integer","format":"int32","default":1000}}],"responses":{"200":{"description":"A `text/event-stream` of ticks."}}}},"/ws/echo":{"get":{"tags":["WebSocket"],"summary":"Open a WebSocket that echoes every message back.","description":"On connect the server sends a JSON `welcome` message. Text and binary messages are echoed unchanged;\nsending the text `close` makes the server close with 1000 \"Bye!\". Messages over 64KB are rejected with\nclose code 1009.\n\nSwagger UI cannot open WebSockets. Use a WebSocket client instead:```wscat -c wss://api.testingapis.com/ws/echo```","operationId":"WebSocket_Echo","responses":{"101":{"description":"Switching Protocols: the WebSocket is open."},"200":{"description":"OK"},"400":{"description":"The request was plain HTTP rather than a WebSocket upgrade."}}}},"/ws/ticker":{"get":{"tags":["WebSocket"],"summary":"Open a WebSocket that pushes a stock tick every second.","description":"Each message is `{\"type\":\"tick\",\"data\":{...}}`. After the last tick the server sends\n`{\"type\":\"complete\"}` and closes with 1000 \"Ticker finished\". Closing from the client stops the ticker early.\n\nSwagger UI cannot open WebSockets. Use a WebSocket client instead:```wscat -c \"wss://api.testingapis.com/ws/ticker?count=10\"```","operationId":"WebSocket_Ticker","parameters":[{"name":"count","in":"query","description":"Number of ticks before the server closes (1-300, default 30).","schema":{"type":"integer","format":"int32","default":30}}],"responses":{"101":{"description":"Switching Protocols: the WebSocket is open."},"200":{"description":"OK"},"400":{"description":"The request was plain HTTP rather than a WebSocket upgrade."}}}},"/api/jobs":{"get":{"tags":["Jobs"],"summary":"List all jobs, newest first.","operationId":"Jobs_GetAll","parameters":[{"name":"status","in":"query","description":"Optional filter: `queued`, `running`, `completed`, `failed` or\n            `cancelled` (case-insensitive).","schema":{"type":"string"}}],"responses":{"200":{"description":"Array of jobs; `X-Total-Count` holds the count."}}},"post":{"tags":["Jobs"],"summary":"Start an asynchronous job.","description":"Example body: `{\"type\":\"report\",\"durationSeconds\":10}`\nReturns 202 with a `Location` header pointing at the job and a `Retry-After` hint. Poll that URL;\nthe job is queued for 2 seconds, then runs for `durationSeconds`. When it completes, fetch\n`resultUrl`.","operationId":"Jobs_Create","requestBody":{"description":"Job type and duration. An empty body starts a 10-second report job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobsControllerJobRequest"}},"text/json":{"schema":{"$ref":"#/components/schemas/JobsControllerJobRequest"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/JobsControllerJobRequest"}},"application/xml":{"schema":{"$ref":"#/components/schemas/JobsControllerJobRequest"}},"text/xml":{"schema":{"$ref":"#/components/schemas/JobsControllerJobRequest"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/JobsControllerJobRequest"}}}},"responses":{"200":{"description":"OK"},"202":{"description":"Job accepted; poll the Location URL."},"400":{"description":"Unknown type or duration out of range."}}}},"/api/jobs/{id}":{"delete":{"tags":["Jobs"],"summary":"Cancel a queued or running job.","operationId":"Jobs_Cancel","parameters":[{"name":"id","in":"path","description":"Job id.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job cancelled."},"404":{"description":"No job with that id."},"409":{"description":"The job has already finished."}}},"get":{"tags":["Jobs"],"summary":"Get a job's current status and progress.","description":"While the job is queued or running the response includes `Retry-After: 1`.","operationId":"Jobs_GetById","parameters":[{"name":"id","in":"path","description":"Job id, e.g. `job_0001` or the id returned by POST.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The job."},"404":{"description":"No job with that id."}}}},"/api/jobs/{id}/result":{"get":{"tags":["Jobs"],"summary":"Get the result of a completed job.","operationId":"Jobs_GetResult","parameters":[{"name":"id","in":"path","description":"Job id.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The job's result (shape depends on the job type)."},"404":{"description":"No job with that id."},"409":{"description":"The job is still queued or running, or it failed or was cancelled."}}}},"/api/pagination/cursor":{"get":{"tags":["Pagination"],"summary":"Page with an opaque cursor (Stripe style).","description":"The response is `{ object: \"list\", data, has_more, next_cursor }`. Keep requesting with `next_cursor` until `has_more` is false.","operationId":"Pagination_Cursor","parameters":[{"name":"cursor","in":"query","description":"The `next_cursor` value from the previous page. Omit it for the first page.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Page size (1-100, default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"One page."},"400":{"description":"The cursor is malformed."}}}},"/api/pagination/hal":{"get":{"tags":["Pagination"],"summary":"Page with HAL hypermedia links (0-based).","description":"Content type is `application/hal+json`. Items are under `_embedded.items`, each with a self link; `_links` holds self, first, prev, next and last.","operationId":"Pagination_Hal","parameters":[{"name":"page","in":"query","description":"Page number, starting at 0 (default 0).","schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","description":"Page size (1-100, default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"One page."}}}},"/api/pagination/items/{id}":{"get":{"tags":["Pagination"],"summary":"Get one item (the target of HAL self links).","operationId":"Pagination_GetItem","parameters":[{"name":"id","in":"path","description":"Item id (1-100).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The item."},"404":{"description":"No item with that id."}}}},"/api/pagination/keyset":{"get":{"tags":["Pagination"],"summary":"Page by key: return items with an id greater than `after_id`.","description":"The response is `{ data, has_more, next_after_id }`.","operationId":"Pagination_Keyset","parameters":[{"name":"after_id","in":"query","description":"Last id seen, sent as the `after_id` query parameter (default 0).","schema":{"type":"integer","format":"int32","default":0}},{"name":"limit","in":"query","description":"Page size (1-100, default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"One page."}}}},"/api/pagination/link":{"get":{"tags":["Pagination"],"summary":"Page with an RFC 5988 Link header (GitHub style, 1-based).","description":"The body is a plain array. Navigation is in the `Link` header (`rel=\"next\"`, `prev`, `first`,\n`last`, with absolute URLs), plus `X-Total-Count`. A page past the end returns an empty array.","operationId":"Pagination_Link","parameters":[{"name":"page","in":"query","description":"Page number, starting at 1 (default 1).","schema":{"type":"integer","format":"int32","default":1}},{"name":"per_page","in":"query","description":"Page size, sent as the `per_page` query parameter (1-100, default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"One page."}}}},"/api/pagination/offset":{"get":{"tags":["Pagination"],"summary":"Page with offset and limit.","description":"The response is `{ data, pagination: { offset, limit, total, hasMore } }` plus `X-Total-Count`.","operationId":"Pagination_Offset","parameters":[{"name":"offset","in":"query","description":"Number of items to skip (default 0; negative values become 0).","schema":{"type":"integer","format":"int32","default":0}},{"name":"limit","in":"query","description":"Page size (1-100, default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"One page."}}}},"/api/pagination/page":{"get":{"tags":["Pagination"],"summary":"Page with a Spring Data style envelope (0-based page numbers).","description":"The response has `content`, `pageable`, `totalElements`, `totalPages`, `first`, `last` and `empty`.","operationId":"Pagination_Page","parameters":[{"name":"page","in":"query","description":"Page number, starting at 0 (default 0).","schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","description":"Page size (1-100, default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"One page."}}}},"/api/chaos/abort":{"get":{"tags":["Chaos"],"summary":"Drop the connection without sending any response.","description":"<b>Warning:</b> this endpoint deliberately drops the connection. Clients see a network error, not an HTTP status,\n            and Swagger UI shows \"Failed to fetch\". Available for GET and POST.","operationId":"Chaos_Abort_GET","responses":{"200":{"description":"Never sent: the connection is dropped instead."}}},"post":{"tags":["Chaos"],"summary":"Drop the connection without sending any response.","description":"<b>Warning:</b> this endpoint deliberately drops the connection. Clients see a network error, not an HTTP status,\n            and Swagger UI shows \"Failed to fetch\". Available for GET and POST.","operationId":"Chaos_Abort_POST","responses":{"200":{"description":"Never sent: the connection is dropped instead."}}}},"/api/chaos/flaky":{"get":{"tags":["Chaos"],"summary":"Fail at random with 503 to test retries.","description":"Failures include `Retry-After: 1`. Available for GET and POST.","operationId":"Chaos_Flaky_GET","parameters":[{"name":"failRate","in":"query","description":"Probability of failure, 0 to 1 (default 0.5).","schema":{"type":"number","format":"double","default":0.5}}],"responses":{"200":{"description":"The request got through."},"400":{"description":"failRate is outside 0-1."},"503":{"description":"Simulated random failure."}}},"post":{"tags":["Chaos"],"summary":"Fail at random with 503 to test retries.","description":"Failures include `Retry-After: 1`. Available for GET and POST.","operationId":"Chaos_Flaky_POST","parameters":[{"name":"failRate","in":"query","description":"Probability of failure, 0 to 1 (default 0.5).","schema":{"type":"number","format":"double","default":0.5}}],"responses":{"200":{"description":"The request got through."},"400":{"description":"failRate is outside 0-1."},"503":{"description":"Simulated random failure."}}}},"/api/chaos/huge-headers":{"get":{"tags":["Chaos"],"summary":"Respond with many large headers.","description":"Some clients reject responses with too many headers. For example, Python's http.client caps responses at\n100 headers.","operationId":"Chaos_HugeHeaders","parameters":[{"name":"count","in":"query","description":"Number of `X-Chaos-Header-NNN` headers (1-100, default 50).","schema":{"type":"integer","format":"int32","default":50}},{"name":"size","in":"query","description":"Characters per header value (1-1000, default 200).","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Response with the extra headers."}}}},"/api/chaos/partial":{"get":{"tags":["Chaos"],"summary":"Send a truncated body, then drop the connection.","description":"<b>Warning:</b> this endpoint deliberately drops the connection. It promises a 10KB body\n            (`Content-Length: 10000`), sends about 70 bytes of incomplete JSON, then disconnects. Clients should report\n            an incomplete or truncated response.","operationId":"Chaos_Partial","responses":{"200":{"description":"Headers are sent, but the body is incomplete and the connection is dropped."}}}},"/api/chaos/random-latency":{"get":{"tags":["Chaos"],"summary":"Respond with a realistic latency spread.","description":"About 90% of calls take 10-100ms, 9% take 500-1500ms and 1% take 3-5s.","operationId":"Chaos_RandomLatency","responses":{"200":{"description":"Reports `latencyMs` and which bucket it came from."}}}},"/api/chaos/retry/{key}":{"delete":{"tags":["Chaos"],"summary":"Reset the attempt counter for a key.","operationId":"Chaos_ResetRetry","parameters":[{"name":"key","in":"path","description":"The counter name to reset.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Counter reset (or it never existed)."}}},"get":{"tags":["Chaos"],"summary":"Fail the first N attempts for a key, then succeed.","description":"A deterministic way to test retry logic: with `succeedAfter=3`, attempts 1-3 fail and attempt 4 succeeds.\nEvery response has an `X-Attempt` header, and failures add `Retry-After: 1`. Reset the counter with\n`DELETE /api/chaos/retry/{key}`. Available for GET and POST.","operationId":"Chaos_Retry_GET","parameters":[{"name":"key","in":"path","description":"Your own counter name (up to 64 characters). Each key counts attempts independently.","required":true,"schema":{"type":"string"}},{"name":"succeedAfter","in":"query","description":"Number of attempts that fail before success (0-20, default 3).","schema":{"type":"integer","format":"int32","default":3}},{"name":"failStatus","in":"query","description":"Status used for failures: 429, 500, 502, 503 or 504 (default 503).","schema":{"type":"integer","format":"int32","default":503}}],"responses":{"200":{"description":"This attempt succeeded."},"400":{"description":"Invalid key, succeedAfter or failStatus."},"503":{"description":"This attempt failed (or the chosen failStatus)."}}},"post":{"tags":["Chaos"],"summary":"Fail the first N attempts for a key, then succeed.","description":"A deterministic way to test retry logic: with `succeedAfter=3`, attempts 1-3 fail and attempt 4 succeeds.\nEvery response has an `X-Attempt` header, and failures add `Retry-After: 1`. Reset the counter with\n`DELETE /api/chaos/retry/{key}`. Available for GET and POST.","operationId":"Chaos_Retry_POST","parameters":[{"name":"key","in":"path","description":"Your own counter name (up to 64 characters). Each key counts attempts independently.","required":true,"schema":{"type":"string"}},{"name":"succeedAfter","in":"query","description":"Number of attempts that fail before success (0-20, default 3).","schema":{"type":"integer","format":"int32","default":3}},{"name":"failStatus","in":"query","description":"Status used for failures: 429, 500, 502, 503 or 504 (default 503).","schema":{"type":"integer","format":"int32","default":503}}],"responses":{"200":{"description":"This attempt succeeded."},"400":{"description":"Invalid key, succeedAfter or failStatus."},"503":{"description":"This attempt failed (or the chosen failStatus)."}}}},"/api/chaos/slow":{"get":{"tags":["Chaos"],"summary":"Wait a random time within a range, then respond.","operationId":"Chaos_Slow","parameters":[{"name":"minMs","in":"query","description":"Minimum wait in milliseconds (0-30000, default 1000).","schema":{"type":"integer","format":"int32","default":1000}},{"name":"maxMs","in":"query","description":"Maximum wait in milliseconds (0-30000, default 3000). If min is greater than max, they are swapped.","schema":{"type":"integer","format":"int32","default":3000}}],"responses":{"200":{"description":"Response after the wait, reporting `waitedMs`."}}}},"/api/chaos/timeout":{"get":{"tags":["Chaos"],"summary":"Hang for a number of seconds, then respond.","description":"Use this to test client timeouts. The wait stops as soon as the client disconnects.","operationId":"Chaos_Timeout","parameters":[{"name":"seconds","in":"query","description":"How long to hang (1-60, default 30).","schema":{"type":"integer","format":"int32","default":30}}],"responses":{"200":{"description":"Response after the wait."}}}},"/api/webhooks/{binId}":{"delete":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_DELETE","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"get":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_GET","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"head":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_HEAD","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"options":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_OPTIONS","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"patch":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_PATCH","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"requestBody":{"description":"Any payload; it is captured in the bin.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"event":"order.created","id":42}}}},"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"post":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_POST","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"requestBody":{"description":"Any payload; it is captured in the bin.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"event":"order.created","id":42}}}},"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"put":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_PUT","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"requestBody":{"description":"Any payload; it is captured in the bin.","content":{"application/json":{"schema":{"description":"Any JSON value"},"example":{"event":"order.created","id":42}}}},"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}}},"/api/webhooks/{binId}/{rest}":{"delete":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_DELETE2","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"rest","in":"path","description":"Optional extra path after the bin id, e.g. `orders/created`. It is recorded as `subPath`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"get":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_GET2","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"rest","in":"path","description":"Optional extra path after the bin id, e.g. `orders/created`. It is recorded as `subPath`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"head":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_HEAD2","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"rest","in":"path","description":"Optional extra path after the bin id, e.g. `orders/created`. It is recorded as `subPath`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"options":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_OPTIONS2","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"rest","in":"path","description":"Optional extra path after the bin id, e.g. `orders/created`. It is recorded as `subPath`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"patch":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_PATCH2","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"rest","in":"path","description":"Optional extra path after the bin id, e.g. `orders/created`. It is recorded as `subPath`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"requestBody":{"description":"Any payload; it is captured in the bin.","content":{"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"post":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_POST2","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"rest","in":"path","description":"Optional extra path after the bin id, e.g. `orders/created`. It is recorded as `subPath`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"requestBody":{"description":"Any payload; it is captured in the bin.","content":{"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}},"put":{"tags":["Webhooks"],"summary":"Capture any request sent to a bin.","description":"Accepts GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Text bodies are stored as UTF-8; other bodies are\nstored as base64. Bodies over 256KB are truncated (`bodyTruncated: true`). No outbound calls are ever made.","operationId":"Webhooks_Capture_PUT2","parameters":[{"name":"binId","in":"path","description":"Bin id from `POST /api/webhooks/bins`.","required":true,"schema":{"type":"string"}},{"name":"rest","in":"path","description":"Optional extra path after the bin id, e.g. `orders/created`. It is recorded as `subPath`.","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Status code to reply with (200-599, default 200). 204 and 304 reply without a body.","schema":{"type":"integer","format":"int32","default":200}}],"requestBody":{"description":"Any payload; it is captured in the bin.","content":{"application/json":{"schema":{"description":"Any JSON value"}}}},"responses":{"200":{"description":"Request captured (or the status chosen with status)."},"400":{"description":"status is out of range."},"404":{"description":"No bin with that id."}}}},"/api/webhooks/bins":{"post":{"tags":["Webhooks"],"summary":"Create a webhook bin that captures incoming requests.","description":"Point a webhook sender at the returned `url`, then read what arrived at `inspectUrl`. Up to 100 bins\nare kept; when the limit is reached, the oldest bin is evicted.","operationId":"Webhooks_CreateBin","requestBody":{"description":"Optional name for the bin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhooksControllerCreateBinRequest"}},"text/json":{"schema":{"$ref":"#/components/schemas/WebhooksControllerCreateBinRequest"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/WebhooksControllerCreateBinRequest"}},"application/xml":{"schema":{"$ref":"#/components/schemas/WebhooksControllerCreateBinRequest"}},"text/xml":{"schema":{"$ref":"#/components/schemas/WebhooksControllerCreateBinRequest"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/WebhooksControllerCreateBinRequest"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Bin created; the response includes its capture URL and inspect URL."},"400":{"description":"Name too long."}}}},"/api/webhooks/bins/{id}":{"delete":{"tags":["Webhooks"],"summary":"Delete a bin.","operationId":"Webhooks_DeleteBin","parameters":[{"name":"id","in":"path","description":"Bin id.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Bin deleted."},"404":{"description":"No bin with that id."}}},"get":{"tags":["Webhooks"],"summary":"Inspect a bin and the requests it captured.","description":"Shows up to 50 requests, newest first. Each includes method, path, query, headers, body and client IP.","operationId":"Webhooks_GetBin","parameters":[{"name":"id","in":"path","description":"Bin id.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The bin and its captured requests."},"404":{"description":"No bin with that id."}}}},"/api/webhooks/bins/{id}/requests":{"delete":{"tags":["Webhooks"],"summary":"Clear a bin's captured requests.","operationId":"Webhooks_ClearBin","parameters":[{"name":"id","in":"path","description":"Bin id.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Requests cleared."},"404":{"description":"No bin with that id."}}}},"/api/webhooks/samples":{"get":{"tags":["Webhooks"],"summary":"List the sample signed webhook events.","description":"All samples are signed with the secret `whsec_apibee_test_secret`.","operationId":"Webhooks_Samples","responses":{"200":{"description":"The signing secret and the list of available samples."}}}},"/api/webhooks/samples/{provider}":{"get":{"tags":["Webhooks"],"summary":"Get a signed sample event for testing signature verification.","description":"Signature schemes:\n<list type=\"bullet\"><item><description>Stripe: `Stripe-Signature: t=..,v1=hex(HMAC-SHA256(secret, \"t.body\"))`</description></item><item><description>GitHub: `X-Hub-Signature-256: sha256=hex(HMAC-SHA256(secret, body))`</description></item><item><description>Shopify: `X-Shopify-Hmac-Sha256: base64(HMAC-SHA256(secret, body))`</description></item></list>\nPayloads and signatures are deterministic.","operationId":"Webhooks_Sample","parameters":[{"name":"provider","in":"path","description":"`stripe`, `github` or `shopify` (case-insensitive).","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","description":"Omit to receive the raw signed body with the provider's signature headers. Use `envelope` to receive body, headers and secret as JSON.","schema":{"type":"string"}}],"responses":{"200":{"description":"The signed sample."},"404":{"description":"Unknown provider."}}}},"/api/v1/profile":{"get":{"tags":["Versioning"],"summary":"Get the profile in the deprecated v1 shape (selected by URL path).","description":"v1 uses flat fields. Every response carries `Deprecation: @1751328000`,\n`Sunset: Thu, 31 Dec 2026 23:59:59 GMT` and `Link: </api/v2/profile>; rel=\"successor-version\"`.","operationId":"Versioning_ProfileV1","responses":{"200":{"description":"v1 profile."}}}},"/api/v2/profile":{"get":{"tags":["Versioning"],"summary":"Get the profile in the current v2 shape (selected by URL path).","description":"v2 uses nested contact, address and preferences objects.","operationId":"Versioning_ProfileV2","responses":{"200":{"description":"v2 profile."}}}},"/api/versioned/profile":{"get":{"tags":["Versioning"],"summary":"Get the profile in the version chosen by header, query string or media type.","description":"Version selectors, in order of precedence:\n<list type=\"number\"><item><description>Header: `X-API-Version: 1`</description></item><item><description>Query: `?api-version=1`</description></item><item><description>Media type: `Accept: application/vnd.apibee.v1+json` (the response uses the same content type)</description></item><item><description>Default: the latest version (2)</description></item></list>\nThe response headers `X-API-Version` and `X-API-Version-Source` show which version was chosen and how.","operationId":"Versioning_Versioned","parameters":[{"name":"api-version","in":"query","description":"Version, sent as the `api-version` query parameter, e.g. `1`, `2`, `v2` or `2.0`.","schema":{"type":"string"}},{"name":"X-API-Version","in":"header","description":"API version to use (1 or 2). Takes precedence over ?api-version= and the Accept media type.","schema":{"type":"string"},"example":"2"}],"responses":{"200":{"description":"Profile in the requested version."},"400":{"description":"Unsupported version; the body lists supported versions."}}}},"/api/versions":{"get":{"tags":["Versioning"],"summary":"List supported API versions and how to select them.","operationId":"Versioning_Versions","responses":{"200":{"description":"Current version, supported versions and the selection options."}}}},"/api/soap/calculator":{"get":{"tags":["Soap"],"summary":"Get the calculator WSDL (with `?wsdl`) or usage information.","description":"`GET /api/soap/calculator?wsdl` returns a WSDL 1.1 document with SOAP 1.1 and 1.2 bindings, which SoapUI,\n            WCF or zeep can import. Without `?wsdl` you get JSON listing the operations and ready-to-send sample envelopes.","operationId":"Soap_CalculatorInfo","responses":{"200":{"description":"WSDL (`text/xml`) or usage JSON."}}},"post":{"tags":["Soap"],"summary":"Call a calculator operation: Add, Subtract, Multiply or Divide.","description":"SOAP 1.1: send `Content-Type: text/xml` and `SOAPAction: \"http://tempuri.org/Add\"` (optional; if\nsent, it must name the operation in the body).\n```\n<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap:Body>\n    <Add xmlns=\"http://tempuri.org/\"><intA>5</intA><intB>3</intB></Add>\n  </soap:Body>\n</soap:Envelope>\n```\nSOAP 1.2: send `Content-Type: application/soap+xml` with the same body, using the\n`http://www.w3.org/2003/05/soap-envelope` namespace.\n\nThe response is `<AddResponse><AddResult>8</AddResult></AddResponse>`, using the\nsame SOAP version as the request. Errors come back as SOAP Faults. SOAP 1.1 faults always use 500. SOAP 1.2 uses\n400 for Sender faults and 500 for Receiver faults. Divide by zero is a Server/Receiver fault. DTDs are rejected.","operationId":"Soap_Calculator","parameters":[{"name":"SOAPAction","in":"header","description":"SOAP 1.1 action, e.g. \"http://tempuri.org/Add\". Not used for SOAP 1.2.","schema":{"type":"string"},"example":"\"http://tempuri.org/Add\""}],"requestBody":{"description":"SOAP 1.1 envelope (send SOAPAction). SOAP 1.2 uses application/soap+xml.","content":{"text/xml":{"schema":{"type":"string"},"example":"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><Add xmlns=\"http://tempuri.org/\"><intA>5</intA><intB>3</intB></Add></soap:Body></soap:Envelope>"},"application/soap+xml":{"schema":{"type":"string"},"example":"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"><soap:Body><Multiply xmlns=\"http://tempuri.org/\"><intA>6</intA><intB>7</intB></Multiply></soap:Body></soap:Envelope>"}}},"responses":{"200":{"description":"SOAP response envelope."},"400":{"description":"SOAP 1.2 Sender fault (bad input)."},"415":{"description":"Content-Type is not `text/xml` or `application/soap+xml`."},"500":{"description":"SOAP Fault (all SOAP 1.1 faults; SOAP 1.2 Receiver faults)."}}}},"/api/soap/countries":{"get":{"tags":["Soap"],"summary":"Get the countries WSDL (with `?wsdl`) or usage information.","description":"`GET /api/soap/countries?wsdl` returns a WSDL 1.1 document with SOAP 1.1 and 1.2 bindings. Without\n            `?wsdl` you get JSON listing the operations, the available country codes and a sample envelope.","operationId":"Soap_CountriesInfo","responses":{"200":{"description":"WSDL (`text/xml`) or usage JSON."}}},"post":{"tags":["Soap"],"summary":"Call a countries operation: GetCountryInfo or ListCountries.","description":"Namespace `http://example.com/countries`. For SOAP 1.1 the optional SOAPAction is\n`\"http://example.com/countries/GetCountryInfo\"`.\n```\n<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n  <soap:Body>\n    <GetCountryInfo xmlns=\"http://example.com/countries\"><countryCode>IN</countryCode></GetCountryInfo>\n  </soap:Body>\n</soap:Envelope>\n````ListCountries` takes no arguments and returns the code and name of all 10 countries.","operationId":"Soap_CountriesService","requestBody":{"description":"SOAP 1.1 envelope for GetCountryInfo or ListCountries.","content":{"text/xml":{"schema":{"type":"string"},"example":"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><GetCountryInfo xmlns=\"http://example.com/countries\"><countryCode>JP</countryCode></GetCountryInfo></soap:Body></soap:Envelope>"}}},"responses":{"200":{"description":"SOAP response envelope."},"400":{"description":"SOAP 1.2 Sender fault (e.g. unknown country code)."},"415":{"description":"Content-Type is not `text/xml` or `application/soap+xml`."},"500":{"description":"SOAP 1.1 fault."}}}},"/api/validation/annotations":{"post":{"tags":["Validation"],"summary":"Validate a DataAnnotations model using the framework's automatic 400.","description":"Invalid models are rejected by `[ApiController]` before the action runs, with a standard ValidationProblemDetails body.","operationId":"Validation_Annotations","requestBody":{"description":"The signup to validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationControllerAnnotatedSignup"}},"text/json":{"schema":{"$ref":"#/components/schemas/ValidationControllerAnnotatedSignup"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/ValidationControllerAnnotatedSignup"}},"application/xml":{"schema":{"$ref":"#/components/schemas/ValidationControllerAnnotatedSignup"}},"text/xml":{"schema":{"$ref":"#/components/schemas/ValidationControllerAnnotatedSignup"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/ValidationControllerAnnotatedSignup"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Model is valid."},"400":{"description":"Validation errors (ValidationProblemDetails)."}}}},"/api/validation/problem":{"get":{"tags":["Validation"],"summary":"List the sample problem document types.","operationId":"Validation_ProblemTypes","responses":{"200":{"description":"Each type, its status code and its URL."}}}},"/api/validation/problem/{type}":{"get":{"tags":["Validation"],"summary":"Get a sample RFC 7807 problem document.","description":"The status code matches the problem. 401 adds `WWW-Authenticate`; 429 and 503 add `Retry-After`.","operationId":"Validation_ProblemSample","parameters":[{"name":"type","in":"path","description":"bad-request, unauthorized, payment-required, forbidden, not-found, conflict, validation, rate-limited, internal or unavailable (case-insensitive).","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Never returned: every sample uses its own error status."},"404":{"description":"Unknown problem type."}}}},"/api/validation/register":{"post":{"tags":["Validation"],"summary":"Register a user; invalid fields return 422 problem+json.","description":"Rules:\n<list type=\"bullet\"><item><description>username: 3-20 letters, digits or underscores; admin, root, apibee and test_user are taken</description></item><item><description>email: must be a valid address</description></item><item><description>password: 8+ characters with an uppercase letter, a lowercase letter, a digit and a special character</description></item><item><description>confirmPassword: if present, must match password</description></item><item><description>age: integer, 18-120</description></item><item><description>country: one of US, GB, IN, DE, FR, JP, CA, AU, BR</description></item><item><description>phone: optional, E.164 format</description></item><item><description>acceptTerms: must be `true`</description></item></list>\nErrors come back as RFC 7807 `application/problem+json`, with an `errors` map of field to messages. Nothing\nis stored, so the same payload always gets the same answer.","operationId":"Validation_Register","requestBody":{"description":"JSON object with username, email, password, optional confirmPassword, age, country, optional phone and acceptTerms.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"OK"},"201":{"description":"User registered (the password is never echoed back)."},"400":{"description":"Body is not a JSON object."},"422":{"description":"One or more fields failed validation."}}}},"/api/validation/strict":{"post":{"tags":["Validation"],"summary":"Accept only known fields; unknown fields return 400.","description":"Field names are case-sensitive. Unknown fields are checked before values are validated.","operationId":"Validation_Strict","requestBody":{"description":"JSON object with exactly: name (1-50 characters), email and quantity (integer 1-99).","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Payload accepted."},"400":{"description":"Unknown fields (problem+json with `unknownFields`), or the body is not an object."},"422":{"description":"Invalid values."}}}},"/api/Products":{"get":{"tags":["Products"],"summary":"List products with filtering, sorting, search and pagination.","description":"Common filters: `category`, `inStock`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Products_GetAll","responses":{"200":{"description":"The matching products.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductResponse"}}}}},"500":{"description":"Unexpected server error."}}},"post":{"tags":["Products"],"summary":"Create a product.","operationId":"Products_Create","requestBody":{"description":"The new product. Any client-supplied ID is replaced.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}},"text/json":{"schema":{"$ref":"#/components/schemas/Product"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Product"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Product"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Product"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Product"}}}},"responses":{"201":{"description":"Created; returns { message, data } with the generated ID.","content":{"application/json":{"schema":{"required":["message","data"],"type":"object","properties":{"message":{"type":"string"},"data":{"$ref":"#/components/schemas/ProductResponse"}},"additionalProperties":false}}}},"400":{"description":"title is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}}},"/api/Products/{id}":{"delete":{"tags":["Products"],"summary":"Delete a product.","operationId":"Products_Delete","parameters":[{"name":"id","in":"path","description":"Product ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"additionalProperties":false}}}},"404":{"description":"The product does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}},"get":{"tags":["Products"],"summary":"Get a product by ID.","operationId":"Products_GetById","parameters":[{"name":"id","in":"path","description":"Product ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductResponse"}}}},"404":{"description":"The product does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}},"put":{"tags":["Products"],"summary":"Update a product.","description":"Replaces title, price, description, category, image and inStock; rating is kept when omitted.","operationId":"Products_Update","parameters":[{"name":"id","in":"path","description":"Product ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The new field values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}},"text/json":{"schema":{"$ref":"#/components/schemas/Product"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Product"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Product"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Product"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Product"}}}},"responses":{"200":{"description":"Updated; returns { message, data }.","content":{"application/json":{"schema":{"required":["message","data"],"type":"object","properties":{"message":{"type":"string"},"data":{"$ref":"#/components/schemas/ProductResponse"}},"additionalProperties":false}}}},"404":{"description":"The product does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}}},"/api/Products/categories":{"get":{"tags":["Products"],"summary":"List product categories without duplicates.","operationId":"Products_GetCategories","responses":{"200":{"description":"Category names.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"500":{"description":"Unexpected server error."}}}},"/api/Products/category/{name}":{"get":{"tags":["Products"],"summary":"List the products in a category.","operationId":"Products_GetByCategory","parameters":[{"name":"name","in":"path","description":"Category name, case-insensitive, e.g. electronics.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Matching products (an empty array for an unknown category).","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ProductResponse"}}}}},"500":{"description":"Unexpected server error."}}}},"/api/Posts":{"get":{"tags":["Posts"],"summary":"List posts with filtering, sorting, search and pagination.","description":"Common filters: `userId`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Posts_GetAll","responses":{"200":{"description":"The matching posts.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PostResponse"}}}}},"500":{"description":"Unexpected server error."}}},"post":{"tags":["Posts"],"summary":"Create a post.","operationId":"Posts_Create","requestBody":{"description":"The new post. Any client-supplied ID is replaced.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}},"text/json":{"schema":{"$ref":"#/components/schemas/Post"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Post"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Post"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Post"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Post"}}}},"responses":{"201":{"description":"Created; returns { message, data } with the generated ID.","content":{"application/json":{"schema":{"required":["message","data"],"type":"object","properties":{"message":{"type":"string"},"data":{"$ref":"#/components/schemas/PostResponse"}},"additionalProperties":false}}}},"400":{"description":"title is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}}},"/api/Posts/{id}":{"delete":{"tags":["Posts"],"summary":"Delete a post.","operationId":"Posts_Delete","parameters":[{"name":"id","in":"path","description":"Post ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"additionalProperties":false}}}},"404":{"description":"The post does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}},"get":{"tags":["Posts"],"summary":"Get a post by ID.","operationId":"Posts_GetById","parameters":[{"name":"id","in":"path","description":"Post ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostResponse"}}}},"404":{"description":"The post does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}},"put":{"tags":["Posts"],"summary":"Update a post.","operationId":"Posts_Update","parameters":[{"name":"id","in":"path","description":"Post ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The new field values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}},"text/json":{"schema":{"$ref":"#/components/schemas/Post"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Post"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Post"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Post"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Post"}}}},"responses":{"200":{"description":"Updated; returns { message, data }.","content":{"application/json":{"schema":{"required":["message","data"],"type":"object","properties":{"message":{"type":"string"},"data":{"$ref":"#/components/schemas/PostResponse"}},"additionalProperties":false}}}},"404":{"description":"The post does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}}},"/api/Posts/{id}/comments":{"get":{"tags":["Posts"],"summary":"List the comments on a post.","operationId":"Posts_GetComments","parameters":[{"name":"id","in":"path","description":"Post ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The post's comments.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CommentResponse"}}}}},"404":{"description":"The post does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}}},"/api/Posts/user/{userId}":{"get":{"tags":["Posts"],"summary":"List the posts written by a user.","operationId":"Posts_GetByUser","parameters":[{"name":"userId","in":"path","description":"Author user ID (101-110 in the seed data).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Matching posts (an empty array if none).","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PostResponse"}}}}},"500":{"description":"Unexpected server error."}}}},"/api/Comments":{"get":{"tags":["Comments"],"summary":"List comments with filtering, sorting, search and pagination.","description":"Common filters: `postId`, `userId`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Comments_GetAll","responses":{"200":{"description":"The matching comments."},"500":{"description":"Unexpected server error."}}},"post":{"tags":["Comments"],"summary":"Create a comment.","operationId":"Comments_Create","requestBody":{"description":"The new comment. Any client-supplied ID is replaced.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}},"text/json":{"schema":{"$ref":"#/components/schemas/Comment"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Comment"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Comment"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Comment"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"body is missing."},"500":{"description":"Unexpected server error."}}}},"/api/Comments/{id}":{"delete":{"tags":["Comments"],"summary":"Delete a comment.","operationId":"Comments_Delete","parameters":[{"name":"id","in":"path","description":"Comment ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"The comment does not exist."},"500":{"description":"Unexpected server error."}}},"get":{"tags":["Comments"],"summary":"Get a comment by ID.","operationId":"Comments_GetById","parameters":[{"name":"id","in":"path","description":"Comment ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The comment."},"404":{"description":"The comment does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Todos":{"get":{"tags":["Todos"],"summary":"List todos with filtering, sorting, search and pagination.","description":"Common filters: `completed`, `priority`, `userId`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Todos_GetAll","responses":{"200":{"description":"The matching todos.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TodoResponse"}}}}},"500":{"description":"Unexpected server error."}}},"post":{"tags":["Todos"],"summary":"Create a todo.","operationId":"Todos_Create","requestBody":{"description":"The new todo. Any client-supplied ID is replaced.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Todo"}},"text/json":{"schema":{"$ref":"#/components/schemas/Todo"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Todo"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Todo"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Todo"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Todo"}}}},"responses":{"201":{"description":"Created; returns { message, data } with the generated ID.","content":{"application/json":{"schema":{"required":["message","data"],"type":"object","properties":{"message":{"type":"string"},"data":{"$ref":"#/components/schemas/TodoResponse"}},"additionalProperties":false}}}},"400":{"description":"title is missing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}}},"/api/Todos/{id}":{"delete":{"tags":["Todos"],"summary":"Delete a todo.","operationId":"Todos_Delete","parameters":[{"name":"id","in":"path","description":"Todo ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"required":["message"],"type":"object","properties":{"message":{"type":"string"}},"additionalProperties":false}}}},"404":{"description":"The todo does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}},"get":{"tags":["Todos"],"summary":"Get a todo by ID.","operationId":"Todos_GetById","parameters":[{"name":"id","in":"path","description":"Todo ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The todo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TodoResponse"}}}},"404":{"description":"The todo does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}},"put":{"tags":["Todos"],"summary":"Update a todo.","operationId":"Todos_Update","parameters":[{"name":"id","in":"path","description":"Todo ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The new field values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Todo"}},"text/json":{"schema":{"$ref":"#/components/schemas/Todo"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Todo"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Todo"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Todo"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Todo"}}}},"responses":{"200":{"description":"Updated; returns { message, data }.","content":{"application/json":{"schema":{"required":["message","data"],"type":"object","properties":{"message":{"type":"string"},"data":{"$ref":"#/components/schemas/TodoResponse"}},"additionalProperties":false}}}},"404":{"description":"The todo does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error."}}}},"/api/Carts":{"get":{"tags":["Carts"],"summary":"List carts with filtering, sorting, search and pagination.","description":"Common filters: `userId`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Carts_GetAll","responses":{"200":{"description":"The matching carts."},"500":{"description":"Unexpected server error."}}},"post":{"tags":["Carts"],"summary":"Create a cart.","operationId":"Carts_Create","requestBody":{"description":"The new cart. Any client-supplied ID is replaced.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cart"}},"text/json":{"schema":{"$ref":"#/components/schemas/Cart"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Cart"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Cart"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Cart"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Cart"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The request body is missing."},"500":{"description":"Unexpected server error."}}}},"/api/Carts/{id}":{"delete":{"tags":["Carts"],"summary":"Delete a cart.","operationId":"Carts_Delete","parameters":[{"name":"id","in":"path","description":"Cart ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"The cart does not exist."},"500":{"description":"Unexpected server error."}}},"get":{"tags":["Carts"],"summary":"Get a cart by ID.","operationId":"Carts_GetById","parameters":[{"name":"id","in":"path","description":"Cart ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The cart."},"404":{"description":"The cart does not exist."},"500":{"description":"Unexpected server error."}}},"put":{"tags":["Carts"],"summary":"Update a cart.","description":"Use this to add or remove items.","operationId":"Carts_Update","parameters":[{"name":"id","in":"path","description":"Cart ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The new field values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Cart"}},"text/json":{"schema":{"$ref":"#/components/schemas/Cart"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Cart"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Cart"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Cart"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Cart"}}}},"responses":{"200":{"description":"Updated; returns { message, data }."},"404":{"description":"The cart does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Orders":{"get":{"tags":["Orders"],"summary":"List orders with filtering, sorting, search and pagination.","description":"Common filters: `userId`, `status`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Orders_GetAll","responses":{"200":{"description":"The matching orders."},"500":{"description":"Unexpected server error."}}},"post":{"tags":["Orders"],"summary":"Create a order.","operationId":"Orders_Create","requestBody":{"description":"The new order. Any client-supplied ID is replaced.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}},"text/json":{"schema":{"$ref":"#/components/schemas/Order"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Order"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Order"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Order"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Order"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"items is missing or empty."},"500":{"description":"Unexpected server error."}}}},"/api/Orders/{id}":{"get":{"tags":["Orders"],"summary":"Get a order by ID.","operationId":"Orders_GetById","parameters":[{"name":"id","in":"path","description":"Order ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The order."},"404":{"description":"The order does not exist."},"500":{"description":"Unexpected server error."}}},"put":{"tags":["Orders"],"summary":"Update a order.","description":"Changes status, shippingAddress and deliveredAt when provided. Setting status to delivered stamps deliveredAt if it is empty.","operationId":"Orders_Update","parameters":[{"name":"id","in":"path","description":"Order ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The new field values.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}},"text/json":{"schema":{"$ref":"#/components/schemas/Order"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Order"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Order"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Order"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Order"}}}},"responses":{"200":{"description":"Updated; returns { message, data }."},"404":{"description":"The order does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Quotes":{"get":{"tags":["Quotes"],"summary":"List quotes with filtering, sorting, search and pagination.","description":"Common filters: `category`, `author`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Quotes_GetAll","responses":{"200":{"description":"The matching quotes."},"500":{"description":"Unexpected server error."}}}},"/api/Quotes/{id}":{"get":{"tags":["Quotes"],"summary":"Get a quote by ID.","operationId":"Quotes_GetById","parameters":[{"name":"id","in":"path","description":"Quote ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The quote."},"404":{"description":"The quote does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Quotes/random":{"get":{"tags":["Quotes"],"summary":"Get a random quote.","operationId":"Quotes_GetRandom","responses":{"200":{"description":"A random quote."},"404":{"description":"There are no quotes."},"500":{"description":"Unexpected server error."}}}},"/api/Recipes":{"get":{"tags":["Recipes"],"summary":"List recipes with filtering, sorting, search and pagination.","description":"Common filters: `cuisine`, `difficulty`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Recipes_GetAll","responses":{"200":{"description":"The matching recipes."},"500":{"description":"Unexpected server error."}}}},"/api/Recipes/{id}":{"get":{"tags":["Recipes"],"summary":"Get a recipe by ID.","operationId":"Recipes_GetById","parameters":[{"name":"id","in":"path","description":"Recipe ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The recipe."},"404":{"description":"The recipe does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Recipes/cuisines":{"get":{"tags":["Recipes"],"summary":"List cuisines without duplicates.","operationId":"Recipes_GetCuisines","responses":{"200":{"description":"Cuisine names."},"500":{"description":"Unexpected server error."}}}},"/api/Recipes/random":{"get":{"tags":["Recipes"],"summary":"Get a random recipe.","operationId":"Recipes_GetRandom","responses":{"200":{"description":"A random recipe."},"404":{"description":"There are no recipes."},"500":{"description":"Unexpected server error."}}}},"/api/Notifications":{"get":{"tags":["Notifications"],"summary":"List notifications with filtering, sorting, search and pagination.","description":"Common filters: `userId`, `read`, `type`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Notifications_GetAll","responses":{"200":{"description":"The matching notifications."},"500":{"description":"Unexpected server error."}}}},"/api/Notifications/{id}":{"get":{"tags":["Notifications"],"summary":"Get a notification by ID.","operationId":"Notifications_GetById","parameters":[{"name":"id","in":"path","description":"Notification ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The notification."},"404":{"description":"The notification does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Notifications/{id}/read":{"put":{"tags":["Notifications"],"summary":"Mark a notification as read.","operationId":"Notifications_MarkRead","parameters":[{"name":"id","in":"path","description":"Notification ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Updated; returns { message, data }."},"404":{"description":"The notification does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Notifications/read-all":{"put":{"tags":["Notifications"],"summary":"Mark all notifications as read, for one user or for everyone.","operationId":"Notifications_MarkAllRead","parameters":[{"name":"userId","in":"query","description":"Only this user's notifications (default: all users).","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Returns { message, updated } with the number of notifications changed."},"500":{"description":"Unexpected server error."}}}},"/api/Transactions":{"get":{"tags":["Transactions"],"summary":"List transactions with filtering, sorting, search and pagination.","description":"Common filters: `userId`, `type`, `category`. Any other property name also works as an exact, case-insensitive filter.\nPaging and sorting: `limit` (1-100), `page` (1-based, needs `limit`), `offset`, `sort` (property name),\n`order` (`asc` or `desc`) and `q` (search across title, name, body, description and text fields).\nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages headers.","operationId":"Transactions_GetAll","responses":{"200":{"description":"The matching transactions."},"500":{"description":"Unexpected server error."}}}},"/api/Transactions/{id}":{"get":{"tags":["Transactions"],"summary":"Get a transaction by ID.","operationId":"Transactions_GetById","parameters":[{"name":"id","in":"path","description":"Transaction ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The transaction."},"404":{"description":"The transaction does not exist."},"500":{"description":"Unexpected server error."}}}},"/api/Transactions/summary":{"get":{"tags":["Transactions"],"summary":"Get total income, expenses and balance.","description":"Income is the sum of positive amounts; expenses are reported as a positive total of negative amounts.","operationId":"Transactions_GetSummary","parameters":[{"name":"userId","in":"query","description":"Only this user's transactions (default: all users).","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Returns { userId, totalIncome, totalExpenses, balance, transactionCount }."},"500":{"description":"Unexpected server error."}}}},"/api/Employees":{"get":{"tags":["Employees"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Employees_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Employees"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Employees_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Employee"}},"text/json":{"schema":{"$ref":"#/components/schemas/Employee"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Employee"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Employee"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Employee"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Employee"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Employees/{id}":{"delete":{"tags":["Employees"],"summary":"Delete a record.","operationId":"Employees_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Employees"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Employees_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Employees"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Employees_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Employees"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Employees_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Employees"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Employees_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Employee"}},"text/json":{"schema":{"$ref":"#/components/schemas/Employee"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Employee"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Employee"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Employee"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Employee"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Employees/{id}/reports":{"get":{"tags":["Employees"],"summary":"List an employee's direct reports.","operationId":"Employees_GetReports","parameters":[{"name":"id","in":"path","description":"Manager employee ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Employees whose managerId is this ID (an empty array if none)."},"404":{"description":"The employee does not exist."}}}},"/api/Employees/bulk":{"delete":{"tags":["Employees"],"summary":"Delete several records by ID.","operationId":"Employees_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Employees"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Employees_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Employee"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Employees/count":{"get":{"tags":["Employees"],"summary":"Count all records.","operationId":"Employees_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/Employees/departments":{"get":{"tags":["Employees"],"summary":"List department names, sorted and without duplicates.","operationId":"Employees_GetDepartments","responses":{"200":{"description":"Department names."}}}},"/api/Employees/stats":{"get":{"tags":["Employees"],"summary":"Get salary statistics overall and per department.","operationId":"Employees_GetStats","responses":{"200":{"description":"Totals, active count, average salary, and count/average/min/max salary per department."}}}},"/api/Companies":{"get":{"tags":["Companies"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Companies_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Companies"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Companies_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}},"text/json":{"schema":{"$ref":"#/components/schemas/Company"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Company"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Company"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Company"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Company"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Companies/{id}":{"delete":{"tags":["Companies"],"summary":"Delete a record.","operationId":"Companies_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Companies"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Companies_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Companies"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Companies_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Companies"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Companies_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Companies"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Companies_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}},"text/json":{"schema":{"$ref":"#/components/schemas/Company"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Company"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Company"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Company"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Company"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Companies/{id}/employees":{"get":{"tags":["Companies"],"summary":"List a company's employees.","operationId":"Companies_GetEmployees","parameters":[{"name":"id","in":"path","description":"Company ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Employees whose companyId is this ID (an empty array if none)."},"404":{"description":"The company does not exist."}}}},"/api/Companies/bulk":{"delete":{"tags":["Companies"],"summary":"Delete several records by ID.","operationId":"Companies_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Companies"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Companies_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Company"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Company"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Company"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Company"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Company"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Company"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Companies/count":{"get":{"tags":["Companies"],"summary":"Count all records.","operationId":"Companies_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/People":{"get":{"tags":["People"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"People_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["People"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"People_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Person"}},"text/json":{"schema":{"$ref":"#/components/schemas/Person"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Person"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Person"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Person"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Person"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/People/{id}":{"delete":{"tags":["People"],"summary":"Delete a record.","operationId":"People_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["People"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"People_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["People"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"People_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["People"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"People_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["People"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"People_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Person"}},"text/json":{"schema":{"$ref":"#/components/schemas/Person"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Person"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Person"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Person"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Person"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/People/bulk":{"delete":{"tags":["People"],"summary":"Delete several records by ID.","operationId":"People_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["People"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"People_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Person"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/People/count":{"get":{"tags":["People"],"summary":"Count all records.","operationId":"People_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/Books":{"get":{"tags":["Books"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Books_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Books"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Books_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Book"}},"text/json":{"schema":{"$ref":"#/components/schemas/Book"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Book"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Book"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Book"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Book"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Books/{id}":{"delete":{"tags":["Books"],"summary":"Delete a record.","operationId":"Books_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Books"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Books_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Books"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Books_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Books"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Books_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Books"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Books_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Book"}},"text/json":{"schema":{"$ref":"#/components/schemas/Book"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Book"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Book"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Book"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Book"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Books/authors":{"get":{"tags":["Books"],"summary":"List authors with the number of books by each.","operationId":"Books_GetAuthors","responses":{"200":{"description":"Objects of the form { author, books }, sorted by author."}}}},"/api/Books/bulk":{"delete":{"tags":["Books"],"summary":"Delete several records by ID.","operationId":"Books_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Books"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Books_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Book"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Book"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Book"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Book"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Book"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Book"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Books/count":{"get":{"tags":["Books"],"summary":"Count all records.","operationId":"Books_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/Books/genres":{"get":{"tags":["Books"],"summary":"List genres, sorted and without duplicates.","operationId":"Books_GetGenres","responses":{"200":{"description":"Genre names."}}}},"/api/Books/isbn/{isbn}":{"get":{"tags":["Books"],"summary":"Get a book by ISBN.","operationId":"Books_GetByIsbn","parameters":[{"name":"isbn","in":"path","description":"ISBN-13, with or without hyphens.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The book."},"404":{"description":"No book with this ISBN does not exist."}}}},"/api/Movies":{"get":{"tags":["Movies"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Movies_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Movies"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Movies_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Movie"}},"text/json":{"schema":{"$ref":"#/components/schemas/Movie"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Movie"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Movie"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Movie"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Movie"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Movies/{id}":{"delete":{"tags":["Movies"],"summary":"Delete a record.","operationId":"Movies_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Movies"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Movies_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Movies"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Movies_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Movies"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Movies_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Movies"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Movies_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Movie"}},"text/json":{"schema":{"$ref":"#/components/schemas/Movie"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Movie"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Movie"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Movie"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Movie"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Movies/bulk":{"delete":{"tags":["Movies"],"summary":"Delete several records by ID.","operationId":"Movies_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Movies"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Movies_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Movie"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Movie"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Movie"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Movie"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Movie"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Movie"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Movies/count":{"get":{"tags":["Movies"],"summary":"Count all records.","operationId":"Movies_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/Movies/genres":{"get":{"tags":["Movies"],"summary":"List every genre used by any movie, sorted and without duplicates.","operationId":"Movies_GetGenres","responses":{"200":{"description":"Genre names."}}}},"/api/Movies/top":{"get":{"tags":["Movies"],"summary":"List the highest-rated movies.","operationId":"Movies_GetTop","parameters":[{"name":"limit","in":"query","description":"How many to return, clamped to 1-100 (default 10).","schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"Movies sorted by rating, highest first."},"400":{"description":"limit is not an integer."}}}},"/api/Movies/year/{year}":{"get":{"tags":["Movies"],"summary":"List movies released in a given year.","operationId":"Movies_GetByYear","parameters":[{"name":"year","in":"path","description":"Release year, e.g. 1994.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Matching movies (an empty array if none)."}}}},"/api/Countries":{"get":{"tags":["Countries"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Countries_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Countries"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Countries_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Country"}},"text/json":{"schema":{"$ref":"#/components/schemas/Country"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Country"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Country"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Country"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Country"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Countries/{id}":{"delete":{"tags":["Countries"],"summary":"Delete a record.","operationId":"Countries_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Countries"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Countries_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Countries"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Countries_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Countries"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Countries_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Countries"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Countries_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Country"}},"text/json":{"schema":{"$ref":"#/components/schemas/Country"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Country"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Country"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Country"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Country"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Countries/bulk":{"delete":{"tags":["Countries"],"summary":"Delete several records by ID.","operationId":"Countries_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Countries"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Countries_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Country"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Countries/code/{code}":{"get":{"tags":["Countries"],"summary":"Get a country by ISO 3166-1 code.","operationId":"Countries_GetByCode","parameters":[{"name":"code","in":"path","description":"Alpha-2 (JP) or alpha-3 (JPN) code, case-insensitive.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The country."},"404":{"description":"No country with this code does not exist."}}}},"/api/Countries/count":{"get":{"tags":["Countries"],"summary":"Count all records.","operationId":"Countries_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/Countries/region/{name}":{"get":{"tags":["Countries"],"summary":"List the countries in a region.","operationId":"Countries_GetByRegion","parameters":[{"name":"name","in":"path","description":"Region name, case-insensitive, e.g. europe.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Matching countries (an empty array for an unknown region)."}}}},"/api/Countries/regions":{"get":{"tags":["Countries"],"summary":"List regions with country counts and total population.","operationId":"Countries_GetRegions","responses":{"200":{"description":"Objects of the form { region, countries, population }, sorted by region."}}}},"/api/Events":{"get":{"tags":["Events"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Events_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Events"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Events_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}},"text/json":{"schema":{"$ref":"#/components/schemas/Event"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Event"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Event"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Event"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Events/{id}":{"delete":{"tags":["Events"],"summary":"Delete a record.","operationId":"Events_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Events"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Events_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Events"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Events_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Events"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Events_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Events"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Events_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}},"text/json":{"schema":{"$ref":"#/components/schemas/Event"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Event"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Event"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Event"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Events/bulk":{"delete":{"tags":["Events"],"summary":"Delete several records by ID.","operationId":"Events_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Events"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Events_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Event"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Events/count":{"get":{"tags":["Events"],"summary":"Count all records.","operationId":"Events_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/Events/upcoming":{"get":{"tags":["Events"],"summary":"List events starting on or after a date, soonest first.","operationId":"Events_GetUpcoming","parameters":[{"name":"from","in":"query","description":"ISO 8601 date or date-time (default: now, UTC).","schema":{"type":"string"}}],"responses":{"200":{"description":"Matching events sorted by start time."},"400":{"description":"from is not a valid date."}}}},"/api/Albums":{"get":{"tags":["Albums"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Albums_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Albums"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Albums_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Album"}},"text/json":{"schema":{"$ref":"#/components/schemas/Album"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Album"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Album"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Album"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Album"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Albums/{id}":{"delete":{"tags":["Albums"],"summary":"Delete a record.","operationId":"Albums_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Albums"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Albums_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Albums"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Albums_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Albums"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Albums_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Albums"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Albums_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Album"}},"text/json":{"schema":{"$ref":"#/components/schemas/Album"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Album"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Album"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Album"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Album"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Albums/{id}/photos":{"get":{"tags":["Albums"],"summary":"List the photos in an album.","operationId":"Albums_GetPhotos","parameters":[{"name":"id","in":"path","description":"Album ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Photos whose albumId is this ID (an empty array if none)."},"404":{"description":"The album does not exist."}}}},"/api/Albums/bulk":{"delete":{"tags":["Albums"],"summary":"Delete several records by ID.","operationId":"Albums_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Albums"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Albums_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Album"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Album"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Album"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Album"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Album"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Album"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Albums/count":{"get":{"tags":["Albums"],"summary":"Count all records.","operationId":"Albums_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/Photos":{"get":{"tags":["Photos"],"summary":"List records with filtering, sorting, search and pagination.","description":"Query parameters (all optional):\n            \n- `limit`: page size, 1-100 (default: all records).\n- `page`: 1-based page number; only applies together with `limit`.\n- `offset`: number of records to skip (used when `page` is not given).\n- `sort`: property name to sort by, e.g. `sort=title`.\n- `order`: `asc` (default) or `desc`.\n- `q`: case-insensitive search across title, name, body, description and text fields.\n- Any other property name filters by exact, case-insensitive value, e.g. `?department=engineering`.\n            \nTotals are returned in the X-Total-Count, X-Page, X-Per-Page and X-Total-Pages response headers.","operationId":"Photos_GetAll","responses":{"200":{"description":"The matching records (an empty array when nothing matches)."}}},"post":{"tags":["Photos"],"summary":"Create a record.","description":"The server assigns the next free ID; any ID in the body is ignored.","operationId":"Photos_Create","requestBody":{"description":"The record to create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Photo"}},"text/json":{"schema":{"$ref":"#/components/schemas/Photo"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Photo"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Photo"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Photo"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Photo"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with the generated ID."},"400":{"description":"The body is missing, malformed or fails validation."}}}},"/api/Photos/{id}":{"delete":{"tags":["Photos"],"summary":"Delete a record.","operationId":"Photos_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Deleted."},"404":{"description":"No record has this ID."}}},"get":{"tags":["Photos"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Photos_GetById_GET","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"head":{"tags":["Photos"],"summary":"Get a record by ID (HEAD returns the headers only).","operationId":"Photos_GetById_HEAD","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record has this ID."}}},"patch":{"tags":["Photos"],"summary":"Partially update a record with a JSON merge patch.","description":"Only the fields present in the body change, and nested objects are merged rather than replaced.\nThe ID and unknown fields are never applied; they are listed in `ignored`.\nThe patched record is validated before it is saved, so a rejected patch changes nothing.","operationId":"Photos_Patch","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"JSON object with the fields to change, e.g. { \"price\": 12.5 }.","content":{"application/json":{"schema":{}},"text/json":{"schema":{}},"application/*+json":{"schema":{}},"application/xml":{"schema":{}},"text/xml":{"schema":{}},"application/*+xml":{"schema":{}}}},"responses":{"200":{"description":"Patched; returns { message, changed, ignored, data }."},"400":{"description":"The body is not an object, sets a non-nullable field to null, has a wrongly typed value, or the result fails validation."},"404":{"description":"No record has this ID."}}},"put":{"tags":["Photos"],"summary":"Replace a record.","description":"Every field is overwritten with the body; the ID from the route wins over any ID in the body.","operationId":"Photos_Replace","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"The full replacement record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Photo"}},"text/json":{"schema":{"$ref":"#/components/schemas/Photo"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/Photo"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Photo"}},"text/xml":{"schema":{"$ref":"#/components/schemas/Photo"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/Photo"}}}},"responses":{"200":{"description":"Replaced; returns { message, data }."},"400":{"description":"The body is missing, malformed or fails validation."},"404":{"description":"No record has this ID."}}}},"/api/Photos/bulk":{"delete":{"tags":["Photos"],"summary":"Delete several records by ID.","operationId":"Photos_BulkDelete","parameters":[{"name":"ids","in":"query","description":"Comma-separated record IDs, e.g. 1,2,3.","schema":{"type":"string"}}],"responses":{"200":{"description":"Returns { message, deleted, notFound }; IDs that do not exist are listed in notFound."},"400":{"description":"The ids parameter is missing or is not a list of integers."}}},"post":{"tags":["Photos"],"summary":"Create up to 100 records in one request.","description":"All items are validated first; if any item is invalid nothing is stored and the error names its index.","operationId":"Photos_BulkCreate","requestBody":{"description":"JSON array of 1 to 100 records.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}}},"application/*+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}}},"application/*+xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"Created; returns { message, data } with every generated ID."},"400":{"description":"The array is empty, has more than 100 items, or an item fails validation."}}}},"/api/Photos/count":{"get":{"tags":["Photos"],"summary":"Count all records.","operationId":"Photos_Count","responses":{"200":{"description":"An object of the form { count }."}}}},"/api/User/addUser":{"post":{"tags":["User"],"summary":"Add a user.","operationId":"User_Create","requestBody":{"description":"The user to add. Its userId is ignored and replaced with a random ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}},"text/json":{"schema":{"$ref":"#/components/schemas/User"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/User"}},"application/xml":{"schema":{"$ref":"#/components/schemas/User"}},"text/xml":{"schema":{"$ref":"#/components/schemas/User"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/User"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"User created."}}}},"/api/User/delete/{id}":{"delete":{"tags":["User"],"summary":"Delete a user.","operationId":"User_Delete","parameters":[{"name":"id","in":"path","description":"User ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User deleted."},"404":{"description":"No user with that ID."}}}},"/api/User/getAllUsers":{"get":{"tags":["User"],"summary":"List all users.","operationId":"User_GetAll","responses":{"200":{"description":"All users."}}}},"/api/User/Login":{"post":{"tags":["User"],"summary":"Log in and receive a JWT for the Admin endpoint.","description":"Credentials: `Michael` / `Thompson` (role Admin). The token expires after 15 minutes.\nSend it as `Authorization: Bearer <token>` to `GET /api/Admin/authorize`.","operationId":"User_Login","requestBody":{"description":"Username and password.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLogin"}},"text/json":{"schema":{"$ref":"#/components/schemas/UserLogin"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/UserLogin"}},"application/xml":{"schema":{"$ref":"#/components/schemas/UserLogin"}},"text/xml":{"schema":{"$ref":"#/components/schemas/UserLogin"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/UserLogin"}}}},"responses":{"200":{"description":"Token and login time."},"404":{"description":"Unknown username or wrong password (plain-text body)."}}}},"/api/User/update/{id}":{"put":{"tags":["User"],"summary":"Update a user's name, email, job and city.","operationId":"User_Update","parameters":[{"name":"id","in":"path","description":"User ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"New name, email, job and city.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}},"text/json":{"schema":{"$ref":"#/components/schemas/User"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/User"}},"application/xml":{"schema":{"$ref":"#/components/schemas/User"}},"text/xml":{"schema":{"$ref":"#/components/schemas/User"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/User"}}}},"responses":{"200":{"description":"User updated."},"404":{"description":"No user with that ID."}}}},"/api/User/user/{id}":{"get":{"tags":["User"],"summary":"Get a user by ID.","operationId":"User_GetById","parameters":[{"name":"id","in":"path","description":"User ID (101-110 for the seed users).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The user."},"404":{"description":"No user with that ID."}}}},"/api/Admin/authorize":{"get":{"tags":["Admin"],"summary":"Greet an authenticated admin.","description":"Get a token from `POST /api/User/Login` (`Michael` / `Thompson`) and send\n`Authorization: Bearer <token>`. The role check is case-sensitive: tokens from\n`POST /api/auth/jwt/login` carry the lowercase role admin and get 403 here.","operationId":"Admin_AdminEndPoint","responses":{"200":{"description":"Greeting text."},"401":{"description":"Token missing, invalid or expired."},"403":{"description":"Valid token without the Admin role."}},"security":[{"bearer":[]}]}},"/api/AuthTest/secure-data":{"get":{"tags":["AuthTest"],"summary":"Return protected data behind Basic auth.","description":"Credentials: `Admin` / `Admin@1234`, sent as `Authorization: Basic QWRtaW46QWRtaW5AMTIzNA==`.","operationId":"AuthTest_GetSecureData","responses":{"200":{"description":"Protected data."},"401":{"description":"Header missing or wrong credentials (empty body)."}},"security":[{"basic":[]}]}},"/api/xml/UserXML/{id}":{"get":{"tags":["UserXML"],"summary":"Get a user by ID as XML.","operationId":"UserXML_GetById","parameters":[{"name":"id","in":"path","description":"User ID (101-104 for the seed users).","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The user."},"404":{"description":"No user with that ID."}}}},"/api/xml/UserXML/all":{"get":{"tags":["UserXML"],"summary":"List all users as XML.","operationId":"UserXML_GetAll","responses":{"200":{"description":"All users, as <Users><User>...</User></Users>."}}}},"/api/xml/UserXML/create":{"post":{"tags":["UserXML"],"summary":"Add a user from an XML body.","description":"Header: `Content-Type: application/xml`. Example body:\n`<UserRequest><Name>Ana</Name><Job>Pilot</Job><City>Lisbon</City></UserRequest>`","operationId":"UserXML_Create","requestBody":{"description":"A `<UserRequest>` element with Name, Job and City.","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/UserXmlRequest"}}}},"responses":{"200":{"description":"OK"},"201":{"description":"The created user, with a Location header pointing at it."},"400":{"description":"Body missing or not valid XML."},"415":{"description":"Content-Type is not application/xml."}}}},"/api/xml/UserXML/delete/{id}":{"delete":{"tags":["UserXML"],"summary":"Delete a user.","description":"Deleting a seed user (101-104) returns the normal response but the seed stays.","operationId":"UserXML_Delete","parameters":[{"name":"id","in":"path","description":"User ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"User deleted."},"404":{"description":"No user with that ID."}}}},"/api/xml/UserXML/update/{id}":{"put":{"tags":["UserXML"],"summary":"Update a user's name, job and city from an XML body.","description":"Updating a seed user (101-104) returns the updated user but doesn't change the stored seed.","operationId":"UserXML_Update","parameters":[{"name":"id","in":"path","description":"User ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"description":"A `<UserRequest>` element with Name, Job and City.","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/UserXmlRequest"}}}},"responses":{"200":{"description":"The updated user."},"404":{"description":"No user with that ID."}}}},"/api/formdata/{id}":{"get":{"tags":["FormData"],"summary":"Get a file record by ID.","operationId":"FormData_Get","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"The record."},"404":{"description":"No record with that ID."}}}},"/api/formdata/all":{"get":{"tags":["FormData"],"summary":"List all uploaded file records.","operationId":"FormData_GetAll","responses":{"200":{"description":"All records."}}}},"/api/formdata/delete/{id}":{"delete":{"tags":["FormData"],"summary":"Delete a file record.","operationId":"FormData_Delete","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"Record deleted."},"404":{"description":"No record with that ID."}}}},"/api/formdata/update/{id}":{"put":{"tags":["FormData"],"summary":"Update a record's file name and/or description.","description":"Content-Type: `multipart/form-data`. Both fields are optional.","operationId":"FormData_Update","parameters":[{"name":"id","in":"path","description":"Record ID.","required":true,"schema":{"type":"integer","format":"int32"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"Optional replacement file; only its name is stored.","format":"binary"},"description":{"type":"string","description":"Optional new description; empty keeps the current one."}}},"encoding":{"file":{"style":"form"},"description":{"style":"form"}}}}},"responses":{"200":{"description":"Record updated."},"404":{"description":"No record with that ID."}}}},"/api/formdata/upload":{"post":{"tags":["FormData"],"summary":"Upload a file with an optional description.","description":"Content-Type: `multipart/form-data` with fields `file` and `description`.","operationId":"FormData_Upload","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"The file to upload (required). Only its name is stored.","format":"binary"},"description":{"type":"string","description":"Optional description."}}},"encoding":{"file":{"style":"form"},"description":{"style":"form"}}}}},"responses":{"200":{"description":"OK"},"201":{"description":"File record created."},"400":{"description":"No file sent."}}}},"/api/Proxy/call":{"post":{"tags":["Proxy"],"summary":"Forward a request to an upstream URL and relay its response.","description":"Requires the `X-Proxy-Key` header to match the server's `Proxy:AccessKey` setting; the proxy is\n            disabled when no key is configured. Returns 200 with the upstream status, statusText and raw body (as a string)\n            whatever the upstream status was. Destinations on private, loopback, link-local or cloud-platform addresses\n            (including redirects to them) are refused.","operationId":"Proxy_Execute","parameters":[{"name":"X-Proxy-Key","in":"header","description":"Proxy access key (the server's Proxy:AccessKey setting). Missing or wrong returns 401.","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"endpointUrl (absolute http or https URL), methodName (GET, POST, ...) and an optional requestBody, sent as JSON except for GET and HEAD.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiRequestData"}},"text/json":{"schema":{"$ref":"#/components/schemas/ApiRequestData"}},"application/*+json":{"schema":{"$ref":"#/components/schemas/ApiRequestData"}},"application/xml":{"schema":{"$ref":"#/components/schemas/ApiRequestData"}},"text/xml":{"schema":{"$ref":"#/components/schemas/ApiRequestData"}},"application/*+xml":{"schema":{"$ref":"#/components/schemas/ApiRequestData"}}}},"responses":{"200":{"description":"Upstream status, statusText and body."},"400":{"description":"endpointUrl isn't an absolute http(s) URL, or methodName is missing."},"401":{"description":"The X-Proxy-Key header is missing or wrong."},"403":{"description":"The destination resolves to a private or reserved network address."},"502":{"description":"The upstream request failed or timed out (30 s)."},"503":{"description":"The proxy is disabled because the server has no Proxy:AccessKey configured."}}}},"/WeatherForecast":{"get":{"tags":["WeatherForecast"],"summary":"Get a random 5-day weather forecast.","operationId":"WeatherForecast_Get","responses":{"200":{"description":"Five daily forecasts.","content":{"text/plain":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WeatherForecast"}}},"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WeatherForecast"}}},"text/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WeatherForecast"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WeatherForecast"}}},"text/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WeatherForecast"}}}}}}}}},"components":{"schemas":{"Address":{"type":"object","properties":{"street":{"type":"string","description":"Street and house number."},"city":{"type":"string","description":"City."},"state":{"type":"string","description":"State, province or region (may be empty)."},"zip":{"type":"string","description":"Postal code."},"country":{"type":"string","description":"Country name."},"geo":{"$ref":"#/components/schemas/GeoLocation"}},"additionalProperties":false,"description":"Postal address shared by Employee and Person."},"Album":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"userId":{"type":"integer","description":"Owner user ID (positive; 101-110 in the seed data).","format":"int32"},"title":{"type":"string","description":"Album title (required)."}},"additionalProperties":false,"description":"A photo album."},"ApiRequestData":{"type":"object","properties":{"endpointUrl":{"type":"string"},"methodName":{"type":"string"},"requestBody":{"type":"string"}},"additionalProperties":false},"Book":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"title":{"type":"string","description":"Title (required)."},"author":{"type":"string","description":"Author (required)."},"isbn":{"type":"string","description":"ISBN-13 without hyphens."},"genre":{"type":"string","description":"Genre, e.g. fantasy."},"publishedYear":{"type":"integer","description":"Year first published.","format":"int32"},"pages":{"type":"integer","description":"Page count; zero or greater.","format":"int32"},"language":{"type":"string","description":"Original language."},"price":{"type":"number","description":"Price in USD; zero or greater.","format":"double"},"rating":{"type":"number","description":"Average rating from 0 to 5.","format":"double"},"available":{"type":"boolean","description":"Whether the book is in stock."},"tags":{"type":"array","items":{"type":"string"},"description":"Free-form tags."}},"additionalProperties":false,"description":"A book."},"CachingControllerDocumentUpdate":{"type":"object","properties":{"title":{"type":"string","description":"New title, or null to keep the current one.","nullable":true},"content":{"type":"string","description":"New content, or null to keep the current one.","nullable":true}},"additionalProperties":false,"description":"Fields to change on the cached document. At least one is required."},"Cart":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CartItem"}},"total":{"type":"number","format":"double"},"updatedAt":{"type":"string"}},"additionalProperties":false},"CartItem":{"type":"object","properties":{"productId":{"type":"integer","format":"int32"},"quantity":{"type":"integer","format":"int32"},"price":{"type":"number","format":"double"}},"additionalProperties":false},"Comment":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"postId":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"body":{"type":"string"},"createdAt":{"type":"string"}},"additionalProperties":false},"CommentResponse":{"required":["id","postId","userId","body","createdAt"],"type":"object","properties":{"id":{"type":"integer","format":"int32"},"postId":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"body":{"type":"string"},"createdAt":{"type":"string"}},"additionalProperties":false,"description":"Comment as the API returns it: every property is always present."},"Company":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"name":{"type":"string","description":"Company name (required)."},"industry":{"type":"string","description":"Industry (required)."},"founded":{"type":"integer","description":"Year founded (1800 to the current year, or 0 if unknown).","format":"int32"},"website":{"type":"string","description":"Website URL."},"headquarters":{"$ref":"#/components/schemas/CompanyHeadquarters"},"revenue":{"type":"number","description":"Annual revenue in USD; zero or greater.","format":"double"},"employeeCount":{"type":"integer","description":"Headcount; zero or greater.","format":"int32"}},"additionalProperties":false,"description":"A sample company."},"CompanyHeadquarters":{"type":"object","properties":{"city":{"type":"string","description":"City."},"country":{"type":"string","description":"Country."}},"additionalProperties":false,"description":"City and country of a company's headquarters."},"CookiesControllerLoginBody":{"type":"object","properties":{"username":{"type":"string","description":"Account name: `test` or `admin` (case-insensitive)."},"password":{"type":"string","description":"Account password: `test123` or `admin123` (case-sensitive)."}},"additionalProperties":false,"description":"Credentials for the cookie session login."},"Country":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"name":{"type":"string","description":"Common name (required)."},"code":{"type":"string","description":"ISO 3166-1 alpha-2 code (required, 2 letters)."},"code3":{"type":"string","description":"ISO 3166-1 alpha-3 code (3 letters)."},"capital":{"type":"string","description":"Capital city."},"region":{"type":"string","description":"Region: Africa, Americas, Asia, Europe or Oceania."},"population":{"type":"integer","description":"Approximate population; zero or greater.","format":"int64"},"area":{"type":"number","description":"Area in square kilometres; zero or greater.","format":"double"},"currency":{"$ref":"#/components/schemas/CountryCurrency"},"languages":{"type":"array","items":{"type":"string"},"description":"Official or main languages."},"callingCode":{"type":"string","description":"International dialling code, e.g. +81."},"flag":{"type":"string","description":"Flag emoji."},"timezones":{"type":"array","items":{"type":"string"},"description":"UTC offsets used."}},"additionalProperties":false,"description":"A country."},"CountryCurrency":{"type":"object","properties":{"code":{"type":"string","description":"ISO 4217 code, e.g. JPY."},"name":{"type":"string","description":"Currency name."},"symbol":{"type":"string","description":"Currency symbol."}},"additionalProperties":false,"description":"A currency."},"Employee":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"firstName":{"type":"string","description":"Given name (required)."},"lastName":{"type":"string","description":"Family name (required)."},"email":{"type":"string","description":"Work email (required, must contain @)."},"phone":{"type":"string","description":"Phone number."},"department":{"type":"string","description":"Department name (required)."},"title":{"type":"string","description":"Job title."},"salary":{"type":"number","description":"Annual salary; zero or greater.","format":"double"},"hireDate":{"type":"string","description":"Hire date (yyyy-MM-dd)."},"managerId":{"type":"integer","description":"ID of the employee's manager, or null at the top of the org chart.","format":"int32","nullable":true},"companyId":{"type":"integer","description":"ID of the employing company.","format":"int32"},"skills":{"type":"array","items":{"type":"string"},"description":"Skill tags."},"address":{"$ref":"#/components/schemas/Address"},"active":{"type":"boolean","description":"Whether the employee currently works there."}},"additionalProperties":false,"description":"An employee of one of the sample companies."},"Error":{"required":["status","error","message"],"type":"object","properties":{"status":{"type":"integer","format":"int32"},"error":{"type":"string"},"message":{"type":"string"}},"additionalProperties":false,"description":"The standard error body: the status code, its reason phrase and a message."},"Event":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"name":{"type":"string","description":"Event name (required)."},"category":{"type":"string","description":"Category, e.g. conference."},"venue":{"type":"string","description":"Venue name."},"city":{"type":"string","description":"City."},"startsAt":{"type":"string","description":"Start time, ISO 8601 UTC (required)."},"endsAt":{"type":"string","description":"End time, ISO 8601 UTC; must not be before StartsAt."},"price":{"type":"number","description":"Ticket price in USD; 0 means free.","format":"double"},"capacity":{"type":"integer","description":"Maximum attendees.","format":"int32"},"ticketsSold":{"type":"integer","description":"Tickets sold; cannot exceed Capacity.","format":"int32"},"organizer":{"type":"string","description":"Organizer name."},"tags":{"type":"array","items":{"type":"string"},"description":"Free-form tags."}},"additionalProperties":false,"description":"A ticketed event."},"GeoLocation":{"type":"object","properties":{"lat":{"type":"number","description":"Latitude in decimal degrees.","format":"double"},"lng":{"type":"number","description":"Longitude in decimal degrees.","format":"double"}},"additionalProperties":false,"description":"Latitude/longitude pair."},"JobsControllerJobRequest":{"type":"object","properties":{"type":{"type":"string","description":"Job type: `report`, `export`, `import` or `fail` (fails at 60%). Default `report`.","nullable":true},"durationSeconds":{"type":"integer","description":"How long the job runs after leaving the queue, in seconds (1-60, default 10).","format":"int32","nullable":true}},"additionalProperties":false,"description":"Body for starting a job."},"JwtAuthControllerLoginRequest":{"type":"object","properties":{"username":{"type":"string","description":"Username (case-insensitive): `admin` or `user`."},"password":{"type":"string","description":"Password (case-sensitive): `admin123` or `user123`."}},"additionalProperties":false,"description":"Login credentials."},"JwtAuthControllerRefreshRequest":{"type":"object","properties":{"refreshToken":{"type":"string","description":"The refreshToken from login or a previous refresh."}},"additionalProperties":false,"description":"Refresh request."},"Movie":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"title":{"type":"string","description":"Title (required)."},"director":{"type":"string","description":"Director (required)."},"year":{"type":"integer","description":"Release year (1888 to five years from now, or 0 if unknown).","format":"int32"},"genres":{"type":"array","items":{"type":"string"},"description":"Genres, e.g. Sci-Fi."},"runtimeMinutes":{"type":"integer","description":"Runtime in minutes; zero or greater.","format":"int32"},"rating":{"type":"number","description":"Rating from 0 to 10.","format":"double"},"cast":{"type":"array","items":{"type":"string"},"description":"Leading cast members."},"boxOffice":{"type":"integer","description":"Worldwide box office in USD.","format":"int64"},"poster":{"type":"string","description":"Poster image URL."}},"additionalProperties":false,"description":"A movie."},"Order":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderItem"}},"total":{"type":"number","format":"double"},"status":{"type":"string"},"shippingAddress":{"$ref":"#/components/schemas/ShippingAddress"},"orderedAt":{"type":"string"},"deliveredAt":{"type":"string","nullable":true}},"additionalProperties":false},"OrderItem":{"type":"object","properties":{"productId":{"type":"integer","format":"int32"},"title":{"type":"string"},"quantity":{"type":"integer","format":"int32"},"price":{"type":"number","format":"double"}},"additionalProperties":false},"Person":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"firstName":{"type":"string","description":"Given name (required)."},"lastName":{"type":"string","description":"Family name (required)."},"username":{"type":"string","description":"Username (required)."},"email":{"type":"string","description":"Email address (required, must contain @)."},"gender":{"type":"string","description":"Gender."},"dateOfBirth":{"type":"string","description":"Date of birth (yyyy-MM-dd)."},"phone":{"type":"string","description":"Phone number."},"avatar":{"type":"string","description":"Avatar image URL."},"address":{"$ref":"#/components/schemas/Address"},"company":{"$ref":"#/components/schemas/PersonCompany"}},"additionalProperties":false,"description":"Rich user profile (JSONPlaceholder/randomuser style). Separate from the legacy /api/user model."},"PersonCompany":{"type":"object","properties":{"name":{"type":"string","description":"Company name."},"title":{"type":"string","description":"Job title."}},"additionalProperties":false,"description":"Where a person works."},"Photo":{"type":"object","properties":{"id":{"type":"integer","description":"Unique ID, assigned by the server.","format":"int32"},"albumId":{"type":"integer","description":"ID of the album it belongs to (positive).","format":"int32"},"title":{"type":"string","description":"Caption (required)."},"url":{"type":"string","description":"Full-size image URL (absolute)."},"thumbnailUrl":{"type":"string","description":"Thumbnail image URL."}},"additionalProperties":false,"description":"A photo in an album."},"Post":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"title":{"type":"string"},"body":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"publishedAt":{"type":"string"},"likes":{"type":"integer","format":"int32"}},"additionalProperties":false},"PostResponse":{"required":["id","userId","title","body","tags","publishedAt","likes"],"type":"object","properties":{"id":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"title":{"type":"string"},"body":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"publishedAt":{"type":"string"},"likes":{"type":"integer","format":"int32"}},"additionalProperties":false,"description":"Post as the API returns it: every property is always present."},"Product":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"title":{"type":"string"},"price":{"type":"number","format":"double"},"description":{"type":"string"},"category":{"type":"string"},"image":{"type":"string"},"rating":{"$ref":"#/components/schemas/Rating"},"inStock":{"type":"boolean"},"createdAt":{"type":"string"}},"additionalProperties":false},"ProductResponse":{"required":["id","title","price","description","category","image","rating","inStock","createdAt"],"type":"object","properties":{"id":{"type":"integer","format":"int32"},"title":{"type":"string"},"price":{"type":"number","format":"double"},"description":{"type":"string"},"category":{"type":"string"},"image":{"type":"string"},"rating":{"$ref":"#/components/schemas/RatingResponse"},"inStock":{"type":"boolean"},"createdAt":{"type":"string"}},"additionalProperties":false,"description":"Product as the API returns it: every property is always present."},"Rating":{"type":"object","properties":{"rate":{"type":"number","format":"double"},"count":{"type":"integer","format":"int32"}},"additionalProperties":false},"RatingResponse":{"required":["rate","count"],"type":"object","properties":{"rate":{"type":"number","format":"double"},"count":{"type":"integer","format":"int32"}},"additionalProperties":false,"description":"Rating as the API returns it: every property is always present."},"ShippingAddress":{"type":"object","properties":{"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"},"country":{"type":"string"}},"additionalProperties":false},"Todo":{"type":"object","properties":{"id":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"title":{"type":"string"},"completed":{"type":"boolean"},"priority":{"type":"string"},"dueDate":{"type":"string"}},"additionalProperties":false},"TodoResponse":{"required":["id","userId","title","completed","priority","dueDate"],"type":"object","properties":{"id":{"type":"integer","format":"int32"},"userId":{"type":"integer","format":"int32"},"title":{"type":"string"},"completed":{"type":"boolean"},"priority":{"type":"string"},"dueDate":{"type":"string"}},"additionalProperties":false,"description":"Todo as the API returns it: every property is always present."},"User":{"type":"object","properties":{"userId":{"type":"integer","format":"int32"},"name":{"type":"string"},"email":{"type":"string"},"job":{"type":"string"},"city":{"type":"string"}},"additionalProperties":false},"UserLogin":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"}},"additionalProperties":false},"UserXmlRequest":{"type":"object","properties":{"name":{"type":"string"},"job":{"type":"string"},"city":{"type":"string"}},"additionalProperties":false},"ValidationControllerAnnotatedSignup":{"required":["countryCode","email","username"],"type":"object","properties":{"username":{"maxLength":20,"minLength":3,"type":"string","description":"Required, 3-20 characters."},"email":{"minLength":1,"type":"string","description":"Required, must be a valid email address.","format":"email"},"age":{"maximum":120,"minimum":18,"type":"integer","description":"Age, 18-120.","format":"int32"},"countryCode":{"minLength":1,"pattern":"^[A-Z]{2}$","type":"string","description":"Required, 2-letter uppercase ISO country code, e.g. `US`."},"website":{"type":"string","description":"Optional absolute http(s) or ftp URL.","format":"uri","nullable":true},"phone":{"type":"string","description":"Optional phone number.","format":"tel","nullable":true},"tags":{"maxItems":5,"minItems":1,"type":"array","items":{"type":"string"},"description":"Optional list of 1-5 tags.","nullable":true}},"additionalProperties":false,"description":"Signup model validated by DataAnnotations."},"WeatherForecast":{"type":"object","properties":{"date":{"type":"string","format":"date"},"temperatureC":{"type":"integer","format":"int32"},"temperatureF":{"type":"integer","format":"int32","readOnly":true},"summary":{"type":"string","nullable":true}},"additionalProperties":false},"WebhooksControllerCreateBinRequest":{"type":"object","properties":{"name":{"type":"string","description":"Optional display name (up to 100 characters). Defaults to `bin-xxxxxx`.","nullable":true}},"additionalProperties":false,"description":"Body for creating a webhook bin."}},"securitySchemes":{"basic":{"type":"http","description":"`apibee` / `password123` for /api/auth/*, `Admin` / `Admin@1234` for /api/AuthTest.","scheme":"basic"},"bearer":{"type":"http","description":"A JWT from /api/auth/jwt/login (or /api/User/Login), an OAuth access token, or a static token: `apibee-token-123`, `admin-token`, `user-token`, `readonly-token`.","scheme":"bearer","bearerFormat":"JWT or opaque token"},"apiKeyHeader":{"type":"apiKey","description":"`apibee-key-123`","name":"X-API-Key","in":"header"},"apiKeyQuery":{"type":"apiKey","description":"`apibee-key-123`","name":"api_key","in":"query"},"oauth2":{"type":"oauth2","description":"Authorization code + PKCE with public client `apibee-public` (user `apibee` / `password123`), or client credentials with `apibee-client` / `apibee-secret`.","flows":{"password":{"tokenUrl":"/api/auth/oauth/token","scopes":{"read":"Read access","profile":"User profile"}},"clientCredentials":{"tokenUrl":"/api/auth/oauth/token","scopes":{"read":"Read access","write":"Write access"}},"authorizationCode":{"authorizationUrl":"/api/auth/oauth/authorize","tokenUrl":"/api/auth/oauth/token","scopes":{"read":"Read access","write":"Write access","profile":"User profile"}}}}}},"tags":[{"name":"Catalog","description":"**Start here** · Discovery and health checks: a live catalog of every endpoint plus liveness and readiness probes."},{"name":"Echo","description":"**HTTP basics** · Request inspection (httpbin-style). Echoes back everything the server received, for any verb and any sub-path."},{"name":"Methods","description":"**HTTP basics** · One endpoint per HTTP verb. Each path accepts only its own verb, so any other verb gets 405 + Allow header."},{"name":"Status","description":"**HTTP basics** · Returns any HTTP status code on demand, with the headers that status normally carries."},{"name":"Redirect","description":"**HTTP basics** · Redirect chains, every redirect status, a local-only redirect-to, and an infinite loop for max-redirect tests.\nEvery chain ends at /api/echo so the client can see the final method and body it arrived with."},{"name":"Cookies","description":"**HTTP basics** · Cookie inspection, setting (with every attribute), deletion, and a cookie-based login session flow."},{"name":"Caching","description":"**HTTP basics** · HTTP caching and conditional requests: ETag / If-None-Match (304), If-Match (412 / 428),\nLast-Modified / If-Modified-Since, Cache-Control variants and Vary."},{"name":"Bodies","description":"**HTTP basics** · Request-body parsing per content type. Typed endpoints only accept their own Content-Type (415 otherwise)\nand report what they parsed; /any sniffs the payload; /large measures uploads up to 10MB."},{"name":"Formats","description":"**Formats & data** · Hardcoded responses in every common content type, plus content negotiation, pre-compressed bodies,\ncharsets and deliberately broken payloads for negative testing."},{"name":"Files","description":"**Formats & data** · File download testing: attachments vs inline, deterministic binary blobs, HTTP Range requests\nand large streamed downloads. All content is hardcoded or generated deterministically."},{"name":"EdgeCases","description":"**Formats & data** · JSON edge cases for stress-testing parsers, assertions and UI rendering. Most bodies are raw,\nhand-written JSON text so the exact bytes (literal emoji, -0, huge numbers, duplicate keys) survive."},{"name":"Utils","description":"**Formats & data** · Small utility endpoints handy for chaining requests in API tests: ids, time, encoding, hashing,\nrandom data, lorem ipsum and JWT inspection."},{"name":"AuthSchemes","description":"**Auth & security** · Auth schemes: one endpoint per common scheme (Basic, Bearer, API key in header/query/cookie, Digest,\nHMAC request signing, role and scope checks, double-submit CSRF; OAuth 1.0a is in OAuth1Controller) for testing how a client sends credentials.\nAll credentials are hardcoded and listed by `GET /api/auth`."},{"name":"OAuth1","description":"**Auth & security** · OAuth 1.0a (RFC 5849): the three-step flow (request token, user authorization, access token) and signed\nrequests to a protected resource. Verifies HMAC-SHA1, HMAC-SHA256, HMAC-SHA512 and PLAINTEXT signatures,\nthe timestamp window and nonce reuse. The consumer and one access token are hardcoded; authorization is\nauto-approved as user apibee. Postman: Authorization → OAuth 1.0."},{"name":"OAuth","description":"**Auth & security** · OAuth 2.0: an in-memory authorization server for testing client flows. Supports the authorization code grant\nwith PKCE, client credentials, password and refresh token grants, plus a protected resource, userinfo,\nintrospection (RFC 7662) and revocation (RFC 7009). Authorization is auto-approved as user apibee."},{"name":"JwtAuth","description":"**Auth & security** · JWT: log in for a signed JWT, call endpoints protected by `[Authorize]` and a role check, rotate\nrefresh tokens, and fetch an expired token for negative tests."},{"name":"RateLimit","description":"**Auth & security** · Rate limit: a real fixed-window limiter (5 requests per 60 seconds per client) for testing 429 and\nRetry-After handling. Clients are identified by the X-Client-Id header, or by IP without it."},{"name":"Payments","description":"**Auth & security** · Payments: hardcoded payments plus an Idempotency-Key demo on create (replay, 422 for a different body,\n409 while in flight) and refunds. Card ending 0002 is always declined. The seed payments always stay; of the\npayments created through the API, only the newest 200 are kept, so a shared test API can't fill up."},{"name":"Streaming","description":"**API patterns** · Streaming responses: Server-Sent Events, NDJSON, chunked transfer, byte drip and a streamed JSON array.\nResponse buffering is disabled and every event is flushed, so clients see data as it is produced.\nEvery stream stops as soon as the client disconnects."},{"name":"WebSocket","description":"**API patterns** · WebSocket test endpoints (app.UseWebSockets is registered in Program.cs):\n  /ws/echo   — echoes every text/binary message; send \"close\" to be disconnected.\n  /ws/ticker — pushes a deterministic stock tick every second (?count=, max 300).\nPlain HTTP requests get a 400 explaining how to connect."},{"name":"Jobs","description":"**API patterns** · Async job pattern (202 Accepted + polling). Status is computed from elapsed time, so no background workers:\n  queued (first 2s) -> running (progress 0-99%) -> completed | failed (\"fail\" jobs die at 60%) | cancelled.\nThe store is in-memory, capped at 200 jobs (oldest non-seed jobs are evicted), and resets on restart."},{"name":"Pagination","description":"**API patterns** · The same 100-item dataset exposed through six common pagination styles, so clients can test each one:\noffset/limit, Spring page envelope, Stripe cursor, GitHub Link header, keyset (after_id) and HAL (_links)."},{"name":"Chaos","description":"**API patterns** · Failure injection for testing retries, timeouts and resilience: random failures, deterministic\nfail-N-times-then-succeed, slow/hanging responses, dropped connections, truncated bodies and huge headers.\nAll waits end early if the client disconnects."},{"name":"Webhooks","description":"**API patterns** · Webhook testing:\n  * Bins — create a bin, point a webhook sender at /api/webhooks/{binId}, then inspect what arrived.\n    Capped at 100 bins (oldest evicted), 50 requests per bin (newest kept) and 256KB per captured body.\n    Bins are private: there is no list of bins, so only someone who has a bin's id can read what it captured.\n    Headers added by the hosting platform's proxies are dropped before a request is stored.\n  * Samples — hardcoded Stripe / GitHub / Shopify event payloads with valid signature headers, for\n    testing signature verification. This controller never makes outbound HTTP calls."},{"name":"Versioning","description":"**API patterns** · API versioning in its common forms. The same profile comes back in two shapes:\n  v1 (deprecated: flat fields; sends Deprecation / Sunset / Link successor-version headers) and v2 (nested).\nSelect the version by URL path (/api/v1, /api/v2) or, on /api/versioned/profile, by the X-API-Version\nheader, the ?api-version= query, or Accept: application/vnd.apibee.v2+json (checked in that order)."},{"name":"Soap","description":"**API patterns** · SOAP services for testing SOAP clients (SoapUI, Postman, WCF, zeep...). Both SOAP 1.1 (text/xml + SOAPAction)\nand SOAP 1.2 (application/soap+xml) are accepted; the response uses the same version as the request.\n  /api/soap/calculator — Add / Subtract / Multiply / Divide on intA + intB (namespace http://tempuri.org/). ?wsdl available.\n  /api/soap/countries  — GetCountryInfo(countryCode) / ListCountries over hardcoded data. ?wsdl available.\nThe operation element must be in the service's namespace; anything else is a Client fault.\nErrors come back as SOAP Faults (1.1: always 500; 1.2: Sender faults 400, Receiver faults 500)."},{"name":"Validation","description":"**API patterns** · Request validation in its common styles:\n  /register    — hand-written rules, 422 application/problem+json (RFC 7807) with per-field errors.\n  /strict      — rejects unknown fields (400) as well as invalid ones (422).\n  /annotations — DataAnnotations model; [ApiController] produces the framework's automatic 400.\n  /problem/{type} — sample problem documents for each common error status.\nNothing is stored, so the same payload always gets the same answer."},{"name":"Products","description":"**Resources** · E-commerce products with categories, prices, ratings and stock. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Posts","description":"**Resources** · Blog posts written by users 101-110, with tags, likes and nested comments. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Comments","description":"**Resources** · Comments on posts. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Todos","description":"**Resources** · To-do items with priority, due date and completion state. Shared with the GraphQL todo mutations. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Carts","description":"**Resources** · Shopping carts whose items reference real product IDs. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Orders","description":"**Resources** · Orders with line items, shipping address and a status of pending, processing, shipped, delivered or cancelled. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Quotes","description":"**Resources** · Read-only quotes in programming, motivation, wisdom, humor and design categories."},{"name":"Recipes","description":"**Resources** · Read-only recipes with ingredients, instructions, cuisine and difficulty."},{"name":"Notifications","description":"**Resources** · User notifications (mentions, likes, follows, system and order updates) with read state. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Transactions","description":"**Resources** · Read-only bank transactions (income and expenses) with merchant, category and running balance."},{"name":"Employees","description":"**Resources** · Employees of the sample companies, with an org chart (managerId), departments and salary stats. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Companies","description":"**Resources** · Sample companies; employees link to them through companyId. Hardcoded in-memory data: writes last until the app restarts."},{"name":"People","description":"**Resources** · Rich user profiles with nested address, geo coordinates and company, at /api/people. The legacy /api/user endpoints are separate. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Books","description":"**Resources** · Books with real ISBN-13s, genres, ratings and availability. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Movies","description":"**Resources** · Well-known movies with directors, genres, cast, ratings and box office. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Countries","description":"**Resources** · Countries with ISO codes, capitals, regions, currencies, languages and timezones. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Events","description":"**Resources** · Conferences, concerts, workshops and other events, some sold out and some free. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Albums","description":"**Resources** · Photo albums in JSONPlaceholder style; each seed album has five photos. Hardcoded in-memory data: writes last until the app restarts."},{"name":"Photos","description":"**Resources** · Photos with full-size and thumbnail URLs; each belongs to an album through albumId. Hardcoded in-memory data: writes last until the app restarts."},{"name":"User","description":"**Original snap-test** · Users: the original JSON CRUD over 10 hardcoded users (IDs 101-110), plus the JWT login used by the Admin endpoint."},{"name":"Admin","description":"**Original snap-test** · Admin: an endpoint protected by a JWT with the Admin role."},{"name":"AuthTest","description":"**Original snap-test** · Auth test: an endpoint protected by HTTP Basic auth."},{"name":"UserXML","description":"**Original snap-test** · XML users: CRUD over 4 seed users (IDs 101-104) that accepts and returns application/xml.\nEvery response, errors included, is XML. Updating or deleting a seed user returns the normal response but leaves\nthe seed as it was, so the shared examples keep working; users you create are changed and deleted for real.\nCreated users get IDs from 1001 up, and only the newest 100 are kept."},{"name":"FormData","description":"**Original snap-test** · Form data: multipart/form-data file uploads, with CRUD over the uploaded file records."},{"name":"Proxy","description":"**Original snap-test** · Proxy: forward an HTTP request to any URL and return the upstream status and body."},{"name":"WeatherForecast","description":"**Original snap-test** · Weather forecast: the ASP.NET Core template sample, with random data."}]}