"<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><meta name=\"theme-color\" content=\"#f7f4ec\"><link rel=\"icon\" href=\"data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🤯</text></svg>\"><title>WTFaaS — What The Fuck as a Service</title><meta name=\"description\" content=\"Tiny answers for errors, excuses, decisions, status updates, blame, ETAs, reasons, acknowledgments, and placeholder data.\"><link rel=\"canonical\" href=\"https://wtfaas.dev/\"><meta property=\"og:title\" content=\"WTFaaS — What The Fuck as a Service\"><meta property=\"og:description\" content=\"Tiny answers for life's and software's tiny WTF moments.\"><style>:root{--bg:#f7f4ec;--surface:#fffdf8;--ink:#1d1d1b;--muted:#66645f;--line:#d8d3c8;--accent:#e94f37;--accent-ink:#fffaf2;--code:#20201d;--code-ink:#f4f0e7;--radius:6px;--url-bg:#ebe7dd;--hover-bg:#efebe1;color-scheme:light;--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--bg);color:var(--ink);font:17px/1.5 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif}.wrap{width:min(1160px,calc(100% - 32px));margin:auto}.site-head{border-bottom:1px solid var(--line);padding:15px 0}.head-inner{display:flex;justify-content:space-between;align-items:center;gap:20px}.wordmark{font-size:25px;font-weight:850;letter-spacing:-1.5px;text-decoration:none;color:var(--ink)}.wordmark small{font:12px var(--mono);letter-spacing:0;color:var(--accent);margin-left:3px}.nav{display:flex;align-items:center;gap:17px;font:13px var(--mono)}a{color:inherit;text-underline-offset:3px}.nav a{text-decoration:none}.nav a:hover{text-decoration:underline}.theme{border:1px solid var(--line);border-radius:4px;background:transparent;color:var(--ink);font:13px var(--mono);padding:5px 8px;cursor:pointer}.eyebrow{font:12px var(--mono);font-weight:700;color:var(--accent);letter-spacing:.08em;text-transform:uppercase}.hero{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(320px,.9fr);gap:52px;padding:68px 0 58px;border-bottom:1px solid var(--line)}h1{margin:7px 0 14px;font-size:clamp(52px,7vw,76px);line-height:.94;letter-spacing:-.075em}h1 sup{font:14px var(--mono);letter-spacing:0;color:var(--accent);vertical-align:top}.lede{max-width:650px;margin:0;font-size:clamp(19px,2.2vw,25px);line-height:1.35;letter-spacing:-.025em}.actions{display:flex;gap:10px;margin-top:25px}.button{display:inline-block;border:1px solid var(--ink);border-radius:var(--radius);padding:8px 11px;text-decoration:none;font:13px var(--mono);font-weight:700;cursor:pointer}.button.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}.terminal{align-self:end;background:var(--code);color:var(--code-ink);border:1px solid #3b3a35;border-radius:var(--radius);overflow:hidden;box-shadow:5px 5px 0 var(--line)}.term-top{display:flex;justify-content:space-between;align-items:center;padding:8px 11px;border-bottom:1px solid #3b3a35;color:#aaa69d;font:11px var(--mono)}.copy{border:0;background:transparent;color:inherit;text-decoration:underline;font:11px var(--mono);cursor:pointer}.terminal pre{margin:0;padding:15px;white-space:pre-wrap;max-height:min(60vh,600px);overflow:auto;font:13px/1.6 var(--mono)}.prompt{color:#f4af4a}.output{color:#b8d690}.section{padding:52px 0;border-bottom:1px solid var(--line)}.section-title{font-size:clamp(29px,4vw,40px);line-height:1;letter-spacing:-.05em;margin:5px 0 0}.section-title + .calls,.section-title + .details{margin-top:24px}.section-intro{max-width:650px;margin:10px 0 24px;color:var(--muted)}.playground{display:grid;grid-template-columns:320px minmax(0,1fr);border:1px solid var(--line);border-radius:var(--radius);background:var(--surface)}.controls{padding:22px;border-right:1px solid var(--line)}label{display:block;margin:0 0 5px;font:11px var(--mono);font-weight:700;text-transform:uppercase;letter-spacing:.06em}select,input{width:100%;padding:9px;border:1px solid var(--line);border-radius:4px;background:var(--bg);color:var(--ink);font:14px var(--mono)}.field{margin-bottom:14px}.run{width:100%;border:0;border-radius:4px;padding:10px;background:var(--accent);color:var(--accent-ink);font:700 13px var(--mono);cursor:pointer}.response{min-width:0;padding:20px}.response-meta{display:flex;justify-content:space-between;gap:12px;color:var(--muted);font:12px var(--mono)}.url{margin:12px 0;background:var(--url-bg);padding:8px;overflow:auto;white-space:nowrap;font:12px var(--mono)}.response pre{min-height:185px;margin:0;white-space:pre-wrap;overflow:auto;font:13px/1.55 var(--mono)}.directory{border-top:1px solid var(--line)}.module{display:grid;grid-template-columns:120px minmax(180px,1fr) 200px 36px;gap:14px;align-items:center;border-bottom:1px solid var(--line);padding:13px 6px;text-decoration:none}.module:hover{background:var(--hover-bg)}.module-name{font:700 17px var(--mono)}.module-desc{color:var(--muted);font-size:15px}.module code{font:12px var(--mono);color:var(--accent)}.arrow{color:var(--accent);font-size:22px;text-align:right}.calls{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.call{display:flex;align-items:center;justify-content:space-between;gap:8px;border:1px solid var(--line);background:var(--surface);padding:10px 11px;min-width:0}.call code{overflow:auto;white-space:nowrap;font:12px var(--mono)}.note-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:55px}.why{font-size:clamp(23px,3vw,32px);line-height:1.25;letter-spacing:-.035em;margin:0}.steps{counter-reset:step;list-style:none;padding:0;margin:0}.steps li{position:relative;padding:0 0 18px 42px}.steps li:before{counter-increment:step;content:\"0\" counter(step);position:absolute;left:0;top:1px;color:var(--accent);font:700 14px var(--mono)}.steps strong{display:block;font:700 16px var(--mono)}.steps p{margin:2px 0;color:var(--muted);font-size:15px}.details{background:var(--code);color:var(--code-ink);padding:20px;border-radius:var(--radius);overflow:auto;font:13px/1.65 var(--mono)}.details .dim{color:#aaa69d}.footer{display:flex;justify-content:space-between;gap:20px;padding:25px 0 34px;color:var(--muted);font-size:14px}.footer-links{display:flex;gap:14px;font:12px var(--mono)}.explorer{position:relative;display:grid;grid-template-columns:212px minmax(0,1fr);border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);margin-top:26px}.tabin{position:absolute;width:1px;height:1px;opacity:0}.rail{border-right:1px solid var(--line);padding:10px}.rail label{display:flex;flex-direction:column;gap:1px;border:1px solid transparent;border-radius:4px;padding:6px 9px;cursor:pointer;font:700 14px var(--mono)}.rail label:hover{background:var(--hover-bg)}.rail label small{font:11px var(--mono);font-weight:400;color:var(--muted)}.panes{min-width:0;padding:22px}.panel{display:none;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0 30px;align-content:start}.tagline{grid-column:1/-1;max-width:760px;margin:0 0 6px;font-size:17px;line-height:1.4}.pblock{margin-top:18px;min-width:0}.pblock.wide{grid-column:1/-1}.pblock h4{margin:0 0 8px;font:700 11px var(--mono);text-transform:uppercase;letter-spacing:.08em;color:var(--accent)}.mini{margin:0;border-top:1px solid var(--line)}.mini dt{padding:8px 0 0;font:700 12px var(--mono);word-break:break-word}.mini dd{margin:0;padding:1px 0 8px;border-bottom:1px solid var(--line);color:var(--muted);font-size:14px;line-height:1.45}.chips{display:flex;flex-wrap:wrap;gap:7px}.chip{border:1px solid var(--line);border-radius:99px;background:var(--bg);padding:5px 11px;font:12px var(--mono);text-decoration:none;white-space:nowrap}.chip:hover{background:var(--hover-bg);border-color:var(--accent)}.chip b{color:var(--accent)}.chip small{color:var(--muted);margin-left:6px;font-size:11px}.runner{grid-column:1/-1;display:flex;gap:8px;align-items:center;border-top:1px solid var(--line);padding:12px 14px;background:var(--url-bg)}.runner .verb{font:700 12px var(--mono);color:var(--accent)}.runner input,.runner select{width:auto;padding:8px}#path{flex:1 1 auto;min-width:0}#seed{flex:0 1 170px}#format{flex:0 0 auto}.runner button{border:0;border-radius:4px;padding:9px 16px;background:var(--accent);color:var(--accent-ink);font:700 13px var(--mono);cursor:pointer}.runout{grid-column:1/-1;border-top:1px solid var(--line);padding:14px}.runout pre{max-height:230px;margin:10px 0 0;white-space:pre-wrap;overflow:auto;font:13px/1.55 var(--mono)}.runout .dim{color:var(--accent)}.mini code,.tagline code,.section-intro code{font:12px var(--mono);color:var(--accent)}.pricing{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;margin-top:26px}.tier{display:flex;flex-direction:column;min-width:0;border:1px solid var(--line);border-radius:var(--radius);background:var(--surface);padding:22px}.tier.featured{border-color:var(--accent);box-shadow:5px 5px 0 var(--line)}.tier-name{font:700 12px var(--mono);text-transform:uppercase;letter-spacing:.08em}.badge{margin-left:8px;border:1px solid var(--accent);border-radius:99px;padding:2px 7px;color:var(--accent);font:700 10px var(--mono);letter-spacing:.06em}.tier-price{display:flex;align-items:baseline;flex-wrap:wrap;gap:8px;margin:14px 0 0}.tier-price b{font-size:clamp(28px,3vw,38px);line-height:1;letter-spacing:-.05em}.tier-price s{color:var(--muted);font:15px var(--mono)}.tier-price span{color:var(--muted);font:12px var(--mono)}.tier-note{margin:10px 0 18px;color:var(--muted);font-size:14px}.tier ul{flex:1;list-style:none;margin:0 0 20px;padding:0;border-top:1px solid var(--line)}.tier li{position:relative;padding:7px 0 7px 19px;border-bottom:1px solid var(--line);font-size:14px;line-height:1.4}.tier li:before{content:\"→\";position:absolute;left:0;top:7px;color:var(--accent);font:12px var(--mono)}.tier li code{font:12px var(--mono);color:var(--accent)}.tier .button{text-align:center}.tier button[disabled]{width:100%;border:1px dashed var(--line);border-radius:var(--radius);background:transparent;padding:9px 11px;color:var(--muted);font:700 13px var(--mono);cursor:not-allowed}.pricing-note{max-width:820px;margin:18px 0 0;color:var(--muted);font-size:14px}#t-wtf:checked~.rail label[for=t-wtf]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-wtf:checked~.rail label[for=t-wtf] small{color:var(--accent-ink);opacity:.75}#t-wtf:focus-visible~.rail label[for=t-wtf]{outline:3px solid #f4af4a;outline-offset:-3px}#t-wtf:checked~.panes #p-wtf{display:grid}#t-excuse:checked~.rail label[for=t-excuse]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-excuse:checked~.rail label[for=t-excuse] small{color:var(--accent-ink);opacity:.75}#t-excuse:focus-visible~.rail label[for=t-excuse]{outline:3px solid #f4af4a;outline-offset:-3px}#t-excuse:checked~.panes #p-excuse{display:grid}#t-decide:checked~.rail label[for=t-decide]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-decide:checked~.rail label[for=t-decide] small{color:var(--accent-ink);opacity:.75}#t-decide:focus-visible~.rail label[for=t-decide]{outline:3px solid #f4af4a;outline-offset:-3px}#t-decide:checked~.panes #p-decide{display:grid}#t-status:checked~.rail label[for=t-status]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-status:checked~.rail label[for=t-status] small{color:var(--accent-ink);opacity:.75}#t-status:focus-visible~.rail label[for=t-status]{outline:3px solid #f4af4a;outline-offset:-3px}#t-status:checked~.panes #p-status{display:grid}#t-ack:checked~.rail label[for=t-ack]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-ack:checked~.rail label[for=t-ack] small{color:var(--accent-ink);opacity:.75}#t-ack:focus-visible~.rail label[for=t-ack]{outline:3px solid #f4af4a;outline-offset:-3px}#t-ack:checked~.panes #p-ack{display:grid}#t-blame:checked~.rail label[for=t-blame]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-blame:checked~.rail label[for=t-blame] small{color:var(--accent-ink);opacity:.75}#t-blame:focus-visible~.rail label[for=t-blame]{outline:3px solid #f4af4a;outline-offset:-3px}#t-blame:checked~.panes #p-blame{display:grid}#t-eta:checked~.rail label[for=t-eta]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-eta:checked~.rail label[for=t-eta] small{color:var(--accent-ink);opacity:.75}#t-eta:focus-visible~.rail label[for=t-eta]{outline:3px solid #f4af4a;outline-offset:-3px}#t-eta:checked~.panes #p-eta{display:grid}#t-reason:checked~.rail label[for=t-reason]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-reason:checked~.rail label[for=t-reason] small{color:var(--accent-ink);opacity:.75}#t-reason:focus-visible~.rail label[for=t-reason]{outline:3px solid #f4af4a;outline-offset:-3px}#t-reason:checked~.panes #p-reason{display:grid}#t-placeholder:checked~.rail label[for=t-placeholder]{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}#t-placeholder:checked~.rail label[for=t-placeholder] small{color:var(--accent-ink);opacity:.75}#t-placeholder:focus-visible~.rail label[for=t-placeholder]{outline:3px solid #f4af4a;outline-offset:-3px}#t-placeholder:checked~.panes #p-placeholder{display:grid}:focus-visible{outline:3px solid #f4af4a;outline-offset:3px}@media(max-width:720px){.wrap{width:min(100% - 24px,1160px)}.nav a:not(:last-of-type){display:none}.hero,.note-grid,.playground{grid-template-columns:1fr}.hero{gap:30px;padding:42px 0}.controls{border-right:0;border-bottom:1px solid var(--line)}.module{grid-template-columns:100px 1fr 25px}.module code{display:none}.pricing{grid-template-columns:1fr}.explorer{grid-template-columns:1fr}.rail{display:flex;gap:6px;overflow-x:auto;border-right:0;border-bottom:1px solid var(--line)}.rail label{flex:0 0 auto}.rail label small{display:none}.panel{grid-template-columns:1fr}.panes{padding:16px}.runner{flex-wrap:wrap}#seed{flex:1 1 120px}.footer{display:block}.footer-links{margin-top:10px}.section{padding:38px 0}}@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{transition:none!important}}@media(prefers-color-scheme:dark){:root:not([data-theme]){--bg:#171715;--surface:#1f1f1c;--ink:#f5f1e8;--muted:#a7a39a;--line:#383731;--accent:#ef644e;--code:#10100f;--code-ink:#f5f1e8;--url-bg:#292925;--hover-bg:#282824;color-scheme:dark}}:root[data-theme=\"dark\"]{--bg:#171715;--surface:#1f1f1c;--ink:#f5f1e8;--muted:#a7a39a;--line:#383731;--accent:#ef644e;--code:#10100f;--code-ink:#f5f1e8;--url-bg:#292925;--hover-bg:#282824;color-scheme:dark}</style></head><body><header class=\"site-head\"><div class=\"wrap head-inner\"><a class=\"wordmark\" href=\"/\">WTFaaS<small>.dev</small></a><nav class=\"nav\" aria-label=\"Main navigation\"><a href=\"#modules\">Modules</a><a href=\"#modules\">Try it</a><a href=\"#pricing\">Pricing</a><a href=\"https://github.com/wfinken/wtfaas\">GitHub</a><a href=\"/openapi.json\">OpenAPI</a><button class=\"theme\" id=\"theme\" aria-label=\"Toggle color theme\">◐ theme</button></nav></div></header><main><section class=\"wrap hero\"><div><div class=\"eyebrow\">A small HTTP API for small emergencies</div><h1>WTFaaS<sup>*</sup></h1><p class=\"lede\"><strong>What The Fuck as a Service.</strong><br>Tiny answers for life's and software's tiny WTF moments.</p><div class=\"actions\"><a class=\"button primary\" href=\"#modules\">Explore the modules</a><a class=\"button\" href=\"https://github.com/wfinken/wtfaas\">View on GitHub</a></div></div><div class=\"terminal\"><div class=\"term-top\"><span>a random endpoint, right now</span><button class=\"copy\" data-copy=\"curl https://wtfaas.dev/reason/delay\">copy</button></div><pre><span class=\"prompt\">$</span> curl https://wtfaas.dev/reason/delay<br><br>{<br>  &quot;module&quot;: &quot;reason&quot;,<br>  &quot;category&quot;: &quot;delay&quot;,<br>  &quot;message&quot;: &quot;We need to verify the result before release.&quot;,<br>  &quot;tone&quot;: &quot;professional&quot;,<br>  &quot;meta&quot;: {<br>    &quot;seed&quot;: null,<br>    &quot;deterministic&quot;: false<br>  }<br>}</pre></div></section><section class=\"wrap section\" id=\"modules\"><span id=\"try\"></span><span id=\"wtf\"></span>\n<div class=\"eyebrow\">Try it</div>\n<h2 class=\"section-title\">Send a real request.</h2>\n<p class=\"section-intro\">Pick a module, click any category to load it into the box, then run it. Edit the path by hand if you would rather type, and add a seed when you want the same answer twice.</p>\n<div class=\"explorer\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-wtf\" data-run=\"/wtf/http/502\" checked><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-excuse\" data-run=\"/excuse/deploy\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-decide\" data-run=\"/decide?choices=ship,wait,rollback\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-status\" data-run=\"/status/investigating\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-ack\" data-run=\"/ack/received\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-blame\" data-run=\"/blame/outage\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-eta\" data-run=\"/eta/software?estimate=2d\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-reason\" data-run=\"/reason/delay\"><input class=\"tabin\" type=\"radio\" name=\"mod\" id=\"t-placeholder\" data-run=\"/placeholder/ecommerce/product\">\n<div class=\"rail\" role=\"tablist\"><label for=\"t-wtf\"><span>wtf</span><small>errors & jargon</small></label><label for=\"t-excuse\"><span>excuse</span><small>a way out</small></label><label for=\"t-decide\"><span>decide</span><small>pick for me</small></label><label for=\"t-status\"><span>status</span><small>what’s happening</small></label><label for=\"t-ack\"><span>ack</span><small>confirm receipt</small></label><label for=\"t-blame\"><span>blame</span><small>name a culprit</small></label><label for=\"t-eta\"><span>eta</span><small>estimates, honestly</small></label><label for=\"t-reason\"><span>reason</span><small>explain yourself</small></label><label for=\"t-placeholder\"><span>placeholder</span><small>fixture data</small></label></div>\n<div class=\"panes\"><div class=\"panel\" id=\"p-wtf\">\n<p class=\"tagline\">Hand it an HTTP status, a system error code, or an acronym. It answers with one plain sentence plus the structured facts around it.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /wtf/http/:code</dt><dd>the 12 statuses below, with likely causes and next checks</dd><dt>GET /wtf/error/:code</dt><dd>errno-style failures you find in a log</dd><dt>GET /wtf/acronym/:term</dt><dd>jargon lookup</dd><dt>GET /wtf/:term</dt><dd>shorthand for the acronym form, except for terms that collide with a lookup kind</dd></dl></div>\n\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>type</dt><dd>Which lookup answered: <code>http</code>, <code>error</code>, or <code>acronym</code>.</dd><dt>name / term</dt><dd>The canonical identity, normalised. <code>/wtf/cors</code> and <code>/wtf/acronym/CORS</code> both come back as <code>CORS</code>.</dd><dt>expansion</dt><dd>Acronyms only. What the letters actually stand for.</dd><dt>meaning</dt><dd>The definition. Fixed text — it never varies between requests.</dd><dt>wtf</dt><dd>The plain-language line, and the only field the wording pool touches.</dd><dt>likely_causes</dt><dd>HTTP statuses only. The usual suspects behind that code.</dd><dt>try</dt><dd>HTTP statuses only. Concrete things to check next.</dd><dt>common_mistake</dt><dd>Acronyms only. The wrong assumption people keep making about it.</dd></dl></div>\n<div class=\"pblock wide\"><h4>http statuses</h4><div class=\"chips\"><a class=\"chip\" href=\"/wtf/http/400?format=json\"><b>400</b><small>Bad Request</small></a><a class=\"chip\" href=\"/wtf/http/401?format=json\"><b>401</b><small>Unauthorized</small></a><a class=\"chip\" href=\"/wtf/http/403?format=json\"><b>403</b><small>Forbidden</small></a><a class=\"chip\" href=\"/wtf/http/404?format=json\"><b>404</b><small>Not Found</small></a><a class=\"chip\" href=\"/wtf/http/408?format=json\"><b>408</b><small>Request Timeout</small></a><a class=\"chip\" href=\"/wtf/http/409?format=json\"><b>409</b><small>Conflict</small></a><a class=\"chip\" href=\"/wtf/http/418?format=json\"><b>418</b><small>I'm a Teapot</small></a><a class=\"chip\" href=\"/wtf/http/429?format=json\"><b>429</b><small>Too Many Requests</small></a><a class=\"chip\" href=\"/wtf/http/500?format=json\"><b>500</b><small>Internal Server Error</small></a><a class=\"chip\" href=\"/wtf/http/502?format=json\"><b>502</b><small>Bad Gateway</small></a><a class=\"chip\" href=\"/wtf/http/503?format=json\"><b>503</b><small>Service Unavailable</small></a><a class=\"chip\" href=\"/wtf/http/504?format=json\"><b>504</b><small>Gateway Timeout</small></a></div></div><div class=\"pblock wide\"><h4>error codes</h4><div class=\"chips\"><a class=\"chip\" href=\"/wtf/error/ECONNRESET?format=json\"><b>ECONNRESET</b></a><a class=\"chip\" href=\"/wtf/error/ECONNREFUSED?format=json\"><b>ECONNREFUSED</b></a><a class=\"chip\" href=\"/wtf/error/ETIMEDOUT?format=json\"><b>ETIMEDOUT</b></a><a class=\"chip\" href=\"/wtf/error/ENOTFOUND?format=json\"><b>ENOTFOUND</b></a><a class=\"chip\" href=\"/wtf/error/EADDRINUSE?format=json\"><b>EADDRINUSE</b></a><a class=\"chip\" href=\"/wtf/error/ENOENT?format=json\"><b>ENOENT</b></a><a class=\"chip\" href=\"/wtf/error/OOM?format=json\"><b>OOM</b></a></div></div><div class=\"pblock wide\"><h4>acronyms</h4><div class=\"chips\"><a class=\"chip\" href=\"/wtf/cors?format=json\"><b>CORS</b><small>Cross-Origin Resource Sharing</small></a><a class=\"chip\" href=\"/wtf/dns?format=json\"><b>DNS</b><small>Domain Name System</small></a><a class=\"chip\" href=\"/wtf/tls?format=json\"><b>TLS</b><small>Transport Layer Security</small></a><a class=\"chip\" href=\"/wtf/jwt?format=json\"><b>JWT</b><small>JSON Web Token</small></a><a class=\"chip\" href=\"/wtf/oauth?format=json\"><b>OAuth</b><small>Open Authorization</small></a><a class=\"chip\" href=\"/wtf/acronym/http?format=json\"><b>HTTP</b><small>Hypertext Transfer Protocol</small></a></div></div>\n</div><div class=\"panel\" id=\"p-excuse\">\n<p class=\"tagline\">A reason you can send to a person, scaled to the situation. Nobody has to invent a family emergency.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /excuse/:category</dt><dd>one excuse from that scenario’s pool</dd></dl></div>\n<div class=\"pblock\"><h4>Parameters</h4><dl class=\"mini\"><dt>tone</dt><dd>Echoed back as <code>tone</code> and shifts which wording you land on. Free text, 32 characters.</dd></dl></div>\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>excuse</dt><dd>The excuse. Also repeated as <code>message</code>, so the text format finds it.</dd><dt>plausibility</dt><dd>A fixed self-assessment, <code>0.78</code>. It is a joke, not a score.</dd><dt>follow_up_risk</dt><dd>Likewise fixed at <code>0.25</code>. The odds someone asks a second question.</dd><dt>tone</dt><dd>Whatever you passed, or <code>professional</code>.</dd></dl></div>\n<div class=\"pblock wide\"><h4>scenarios</h4><div class=\"chips\"><a class=\"chip\" href=\"/excuse/camera-off?format=json\"><b>camera-off</b></a><a class=\"chip\" href=\"/excuse/cancel?format=json\"><b>cancel</b></a><a class=\"chip\" href=\"/excuse/code-review?format=json\"><b>code-review</b></a><a class=\"chip\" href=\"/excuse/deadline?format=json\"><b>deadline</b></a><a class=\"chip\" href=\"/excuse/deploy?format=json\"><b>deploy</b></a><a class=\"chip\" href=\"/excuse/email?format=json\"><b>email</b></a><a class=\"chip\" href=\"/excuse/late?format=json\"><b>late</b></a><a class=\"chip\" href=\"/excuse/leave-early?format=json\"><b>leave-early</b></a><a class=\"chip\" href=\"/excuse/meeting?format=json\"><b>meeting</b></a><a class=\"chip\" href=\"/excuse/missed-call?format=json\"><b>missed-call</b></a><a class=\"chip\" href=\"/excuse/outage?format=json\"><b>outage</b></a><a class=\"chip\" href=\"/excuse/reply?format=json\"><b>reply</b></a><a class=\"chip\" href=\"/excuse/school?format=json\"><b>school</b></a><a class=\"chip\" href=\"/excuse/work?format=json\"><b>work</b></a></div></div>\n</div><div class=\"panel\" id=\"p-decide\">\n<p class=\"tagline\">Offload a small decision. It commits to an answer and says something about it, which is more than most meetings manage.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /decide?choices=a,b,c</dt><dd>picks one of your options</dd><dt>GET /decide/a/b/c</dt><dd>the same thing with the options in the path</dd><dt>GET /decide/yes-no</dt><dd>a binary answer with a confidence</dd><dt>GET /decide/coin</dt><dd>heads or tails</dd></dl></div>\n<div class=\"pblock\"><h4>Parameters</h4><dl class=\"mini\"><dt>choices</dt><dd>Two to twenty comma-separated options, each at most 128 characters. Anything outside that returns <code>400 INVALID_CHOICES</code>.</dd></dl></div>\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>choice</dt><dd>The option it landed on. <code>/decide/yes-no</code> calls it <code>answer</code> instead.</dd><dt>index</dt><dd>Where that option sat in the list you sent.</dd><dt>choices</dt><dd>Your options, parsed and trimmed, so you can check what it actually read.</dd><dt>confidence</dt><dd>Yes/no answers only. Always <code>0.73</code>.</dd><dt>message</dt><dd>The decision phrased as a sentence.</dd></dl></div>\n<div class=\"pblock wide\"><h4>fixed decks</h4><div class=\"chips\"><a class=\"chip\" href=\"/decide/yes-no?format=json\"><b>yes-no</b></a><a class=\"chip\" href=\"/decide/coin?format=json\"><b>coin</b></a><a class=\"chip\" href=\"/decide?choices=ship,wait,rollback&format=json\"><b>choices</b><small>your own list</small></a></div></div>\n</div><div class=\"panel\" id=\"p-status\">\n<p class=\"tagline\">A compact line for a status page, a channel topic, or a dashboard tile, with the machine-readable bits attached.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /status/:category</dt><dd>one status line, plus severity and state</dd></dl></div>\n\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>message</dt><dd>The status sentence.</dd><dt>state</dt><dd>A normalised state. Mostly the category, except <code>broken → down</code> and <code>done → complete</code>.</dd><dt>severity</dt><dd><code>5</code> for <code>broken</code>, <code>2</code> for everything else.</dd><dt>emoji</dt><dd>A glyph for the four categories that have one, otherwise <code>•</code>.</dd></dl></div>\n<div class=\"pblock wide\"><h4>categories</h4><div class=\"chips\"><a class=\"chip\" href=\"/status/blocked?format=json\"><b>blocked</b></a><a class=\"chip\" href=\"/status/broken?format=json\"><b>broken</b></a><a class=\"chip\" href=\"/status/degraded?format=json\"><b>degraded</b></a><a class=\"chip\" href=\"/status/deploying?format=json\"><b>deploying</b></a><a class=\"chip\" href=\"/status/done?format=json\"><b>done</b></a><a class=\"chip\" href=\"/status/friday?format=json\"><b>friday</b></a><a class=\"chip\" href=\"/status/investigating?format=json\"><b>investigating</b></a><a class=\"chip\" href=\"/status/maintenance?format=json\"><b>maintenance</b></a><a class=\"chip\" href=\"/status/offline?format=json\"><b>offline</b></a><a class=\"chip\" href=\"/status/waiting?format=json\"><b>waiting</b></a><a class=\"chip\" href=\"/status/working?format=json\"><b>working</b></a></div></div>\n</div><div class=\"panel\" id=\"p-ack\">\n<p class=\"tagline\">Ten shades of “got it”, so you can stop typing “noted” by hand.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /ack/:category</dt><dd>one acknowledgement</dd></dl></div>\n\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>message</dt><dd>The acknowledgement.</dd><dt>acknowledged</dt><dd><code>true</code> for every category except <code>rejected</code>.</dd></dl></div>\n<div class=\"pblock wide\"><h4>categories</h4><div class=\"chips\"><a class=\"chip\" href=\"/ack/approved?format=json\"><b>approved</b></a><a class=\"chip\" href=\"/ack/begrudging?format=json\"><b>begrudging</b></a><a class=\"chip\" href=\"/ack/done?format=json\"><b>done</b></a><a class=\"chip\" href=\"/ack/noted?format=json\"><b>noted</b></a><a class=\"chip\" href=\"/ack/received?format=json\"><b>received</b><small>/receipt</small></a><a class=\"chip\" href=\"/ack/rejected?format=json\"><b>rejected</b></a><a class=\"chip\" href=\"/ack/seen?format=json\"><b>seen</b></a><a class=\"chip\" href=\"/ack/thanks?format=json\"><b>thanks</b></a><a class=\"chip\" href=\"/ack/understood?format=json\"><b>understood</b></a><a class=\"chip\" href=\"/ack/will-do?format=json\"><b>will-do</b></a></div></div>\n</div><div class=\"panel\" id=\"p-blame\">\n<p class=\"tagline\">A plausible suspect and something to actually check. The only module that hands back a next step.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /blame/:category</dt><dd>a culprit and a diagnostic check</dd><dt>GET /blame</dt><dd>falls back to the <code>general</code> category</dd></dl></div>\n\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>message</dt><dd>The theory, in a sentence.</dd><dt>culprit</dt><dd>The component being accused.</dd><dt>check</dt><dd>A real diagnostic step for that theory.</dd><dt>confidence</dt><dd>Always <code>0.74</code>. It is a bit, not telemetry.</dd></dl></div>\n<div class=\"pblock wide\"><h4>categories</h4><div class=\"chips\"><a class=\"chip\" href=\"/blame/backend?format=json\"><b>backend</b></a><a class=\"chip\" href=\"/blame/ci?format=json\"><b>ci</b></a><a class=\"chip\" href=\"/blame/database?format=json\"><b>database</b></a><a class=\"chip\" href=\"/blame/deadline?format=json\"><b>deadline</b></a><a class=\"chip\" href=\"/blame/deploy?format=json\"><b>deploy</b></a><a class=\"chip\" href=\"/blame/frontend?format=json\"><b>frontend</b></a><a class=\"chip\" href=\"/blame/general?format=json\"><b>general</b></a><a class=\"chip\" href=\"/blame/meeting?format=json\"><b>meeting</b></a><a class=\"chip\" href=\"/blame/network?format=json\"><b>network</b></a><a class=\"chip\" href=\"/blame/outage?format=json\"><b>outage</b></a><a class=\"chip\" href=\"/blame/performance?format=json\"><b>performance</b></a></div></div>\n</div><div class=\"panel\" id=\"p-eta\">\n<p class=\"tagline\">Take a stated duration and return what it tends to mean once the work starts.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /eta/:category?estimate=2d</dt><dd>normalises the estimate and inflates it by audience</dd><dt>GET /eta</dt><dd>falls back to <code>software</code> and <code>2d</code></dd></dl></div>\n<div class=\"pblock\"><h4>Parameters</h4><dl class=\"mini\"><dt>estimate</dt><dd>One duration: a number of up to four digits and a unit of <code>s</code>, <code>m</code>, <code>h</code>, <code>d</code>, or <code>w</code>. Anything else returns <code>400 INVALID_DURATION</code>.</dd></dl></div>\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>stated_eta</dt><dd>Your estimate, spelled out — “2 days”.</dd><dt>interpreted_eta</dt><dd>A range after the category’s inflation factor. <code>honest</code> is the one category that never inflates.</dd><dt>normalized_seconds</dt><dd>The estimate in seconds, for anything doing arithmetic.</dd><dt>input</dt><dd>The raw string you sent, echoed for logging.</dd><dt>message</dt><dd>The estimate as a sentence.</dd></dl></div>\n<div class=\"pblock wide\"><h4>audiences</h4><div class=\"chips\"><a class=\"chip\" href=\"/eta/software?format=json\"><b>software</b></a><a class=\"chip\" href=\"/eta/deploy?format=json\"><b>deploy</b></a><a class=\"chip\" href=\"/eta/contractor?format=json\"><b>contractor</b></a><a class=\"chip\" href=\"/eta/meeting?format=json\"><b>meeting</b></a><a class=\"chip\" href=\"/eta/download?format=json\"><b>download</b></a><a class=\"chip\" href=\"/eta/migration?format=json\"><b>migration</b></a><a class=\"chip\" href=\"/eta/support?format=json\"><b>support</b></a><a class=\"chip\" href=\"/eta/manager?format=json\"><b>manager</b></a><a class=\"chip\" href=\"/eta/honest?format=json\"><b>honest</b><small>no inflation</small></a></div></div>\n</div><div class=\"panel\" id=\"p-reason\">\n<p class=\"tagline\">The grown-up sibling of Excuse: a defensible reason for an action you have already taken.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /reason/:category</dt><dd>one reason for that action</dd></dl></div>\n<div class=\"pblock\"><h4>Parameters</h4><dl class=\"mini\"><dt>tone</dt><dd>Echoed back as <code>tone</code> and shifts the wording. Defaults to <code>professional</code>.</dd></dl></div>\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>message</dt><dd>The reason.</dd><dt>tone</dt><dd>Whatever you passed, or <code>professional</code>.</dd></dl></div>\n<div class=\"pblock wide\"><h4>actions</h4><div class=\"chips\"><a class=\"chip\" href=\"/reason/cancel?format=json\"><b>cancel</b></a><a class=\"chip\" href=\"/reason/decline?format=json\"><b>decline</b></a><a class=\"chip\" href=\"/reason/delay?format=json\"><b>delay</b></a><a class=\"chip\" href=\"/reason/leave-early?format=json\"><b>leave-early</b></a><a class=\"chip\" href=\"/reason/maintenance?format=json\"><b>maintenance</b></a><a class=\"chip\" href=\"/reason/pause?format=json\"><b>pause</b></a><a class=\"chip\" href=\"/reason/rate-limit?format=json\"><b>rate-limit</b></a><a class=\"chip\" href=\"/reason/reject?format=json\"><b>reject</b></a><a class=\"chip\" href=\"/reason/reschedule?format=json\"><b>reschedule</b></a><a class=\"chip\" href=\"/reason/rollback?format=json\"><b>rollback</b></a><a class=\"chip\" href=\"/reason/skip-meeting?format=json\"><b>skip-meeting</b></a></div></div>\n</div><div class=\"panel\" id=\"p-placeholder\">\n<p class=\"tagline\">Fictional content shaped like the real thing, for demos and tests. It reads as plausible copy instead of Latin.</p>\n<div class=\"pblock\"><h4>Routes</h4><dl class=\"mini\"><dt>GET /placeholder/:category</dt><dd>the category’s default shape</dd><dt>GET /placeholder/:category/:kind</dt><dd>a specific shape</dd><dt>GET /placeholder/:category?count=n</dt><dd>n items, 1 to 25</dd></dl></div>\n<div class=\"pblock\"><h4>Parameters</h4><dl class=\"mini\"><dt>count</dt><dd>An integer from 1 to 25. Outside that returns <code>400 INVALID_COUNT</code>.</dd><dt>kind</dt><dd>Path segment. One of <code>card</code>, <code>text</code>, <code>product</code>, <code>issue</code>, <code>profile</code>, <code>review</code>, <code>article</code>, <code>commit</code>, <code>status</code>, <code>company</code>. It decides the field names; the category decides the subject matter.</dd></dl></div>\n<div class=\"pblock\"><h4>Response fields</h4><dl class=\"mini\"><dt>data</dt><dd><strong>An object when <code>count</code> is 1, an array when it is more.</strong> Branch on that, not on the category.</dd><dt>kind</dt><dd>The shape that was used, including the default one when you did not ask for a kind.</dd><dt>category</dt><dd>Echoed so batched responses stay self-describing.</dd></dl></div>\n<div class=\"pblock wide\"><h4>categories</h4><div class=\"chips\"><a class=\"chip\" href=\"/placeholder/startup?format=json\"><b>startup</b></a><a class=\"chip\" href=\"/placeholder/saas?format=json\"><b>saas</b><small>text</small></a><a class=\"chip\" href=\"/placeholder/ecommerce?format=json\"><b>ecommerce</b><small>product</small></a><a class=\"chip\" href=\"/placeholder/github?format=json\"><b>github</b><small>issue</small></a><a class=\"chip\" href=\"/placeholder/status-page?format=json\"><b>status-page</b></a><a class=\"chip\" href=\"/placeholder/blog?format=json\"><b>blog</b></a><a class=\"chip\" href=\"/placeholder/news?format=json\"><b>news</b></a><a class=\"chip\" href=\"/placeholder/legal?format=json\"><b>legal</b></a><a class=\"chip\" href=\"/placeholder/medical?format=json\"><b>medical</b></a><a class=\"chip\" href=\"/placeholder/finance?format=json\"><b>finance</b></a><a class=\"chip\" href=\"/placeholder/restaurant?format=json\"><b>restaurant</b></a><a class=\"chip\" href=\"/placeholder/portfolio?format=json\"><b>portfolio</b></a><a class=\"chip\" href=\"/placeholder/dashboard?format=json\"><b>dashboard</b></a><a class=\"chip\" href=\"/placeholder/social?format=json\"><b>social</b></a><a class=\"chip\" href=\"/placeholder/reviews?format=json\"><b>reviews</b></a><a class=\"chip\" href=\"/placeholder/users?format=json\"><b>users</b></a><a class=\"chip\" href=\"/placeholder/products?format=json\"><b>products</b></a></div></div>\n</div></div>\n<form class=\"runner\" id=\"runner\">\n<span class=\"verb\">GET</span>\n<input id=\"path\" aria-label=\"Request path\" spellcheck=\"false\" value=\"/wtf/http/502\">\n<input id=\"seed\" aria-label=\"Seed\" maxlength=\"128\" placeholder=\"seed (optional)\">\n<select id=\"format\" aria-label=\"Response format\"><option value=\"json\">JSON</option><option value=\"text\">Text</option><option value=\"html\">HTML</option></select>\n<button type=\"submit\">Run</button>\n</form>\n<div class=\"runout\">\n<div class=\"response-meta\"><span id=\"status\">Ready when you are.</span><button class=\"copy\" id=\"copy-curl\" type=\"button\">copy curl</button></div>\n<pre id=\"result\" aria-live=\"polite\">Your response lands here.\n\nTry a seed to get the same answer twice, switch the format to see it as plain text, or point the path at something that does not exist — the 404 lists everything that does.</pre>\n</div>\n</div>\n</section><section class=\"wrap section note-grid\"><div><div class=\"eyebrow\">Why this exists</div><p class=\"why\">Most apps eventually need a sentence.<br><br>A status message. An acknowledgment. A placeholder. A reason. A tiny explanation.<br><br>WTFaaS is a pile of those tiny things, wrapped in a clean HTTP API.</p></div><ol class=\"steps\"><li><strong>No AI required</strong><p>Curated corpora and small deterministic algorithms. Fast, cheap, and unsurprising.</p></li><li><strong>Edge-hosted</strong><p>It runs on Cloudflare Workers. Most requests should mostly be network latency.</p></li><li><strong>Deterministic when needed</strong><p>Add <code>?seed=demo</code> for tests, screenshots, fixtures, and repeatable bot behavior.</p></li></ol></section><section class=\"wrap section\" id=\"pricing\">\n<div class=\"eyebrow\">Pricing</div>\n<h2 class=\"section-title\">Pick a tier.</h2>\n<p class=\"section-intro\">One of these is real.</p>\n<div class=\"pricing\"><div class=\"tier\">\n<div class=\"tier-name\">Free</div>\n<div class=\"tier-price\"><b>$0</b><span>forever</span></div>\n<p class=\"tier-note\">Everything the API does today, which is everything the API does.</p>\n<ul><li>All 9 modules and 113 categories</li><li>2,260 curated replies, 20 per category</li><li>JSON, plain text, and HTML</li><li>Deterministic seeding with <code>?seed=</code></li><li>Edge-cached seeded responses</li><li>OpenAPI schema and <code>/modules</code> catalogue</li><li>100 requests per hour, no account, no key</li><li>MIT licensed — fork it and self-host</li></ul>\n<a class=\"button primary\" href=\"#modules\">Start sending requests</a>\n</div><div class=\"tier featured\">\n<div class=\"tier-name\">Pro<span class=\"badge\">Coming soon</span></div>\n<div class=\"tier-price\"><s>$500</s><b>$5</b><span>/month</span></div>\n<p class=\"tier-note\">A price reduction of 99%, achieved by not having built it yet.</p>\n<ul><li>Unlimited requests</li><li>GraphQL access</li><li>99.99% uptime SLA</li><li>Priority edge routing</li><li>Custom reply corpora</li><li>Webhook delivery</li><li>Usage analytics</li><li>Support with a response time</li></ul>\n<button type=\"button\" disabled>Coming soon</button>\n</div><div class=\"tier\">\n<div class=\"tier-name\">Enterprise<span class=\"badge\">Coming soon</span></div>\n<div class=\"tier-price\"><b>Contact sales</b></div>\n<p class=\"tier-note\">For organisations that need a procurement process around an excuse generator.</p>\n<ul><li>SSO via SAML 2.0</li><li>OAuth 2.0 and OIDC</li><li>SCIM user provisioning</li><li>Role-based access control</li><li>Audit logs and data residency</li><li>Dedicated tenancy</li><li>Custom SLAs and security review</li><li>Named solutions architect</li></ul>\n<button type=\"button\" disabled>Contact sales</button>\n</div></div>\n<p class=\"pricing-note\">The Free tier is the whole product. Everything to the right of it is a bit — there is no billing, no sales team, and nothing to contact. If you need one of those features, the licence is MIT and the corpus is a folder of text files.</p>\n</section><section class=\"wrap section\"><div class=\"eyebrow\">Developer details</div><h2 class=\"section-title\">Boring protocol. Useful payloads.</h2><div class=\"details\"><span class=\"dim\"># routes</span><br>GET /wtf/http/:code       GET /wtf/error/:code<br>GET /wtf/acronym/:term    GET /wtf/:term<br>GET /excuse/:category     GET /status/:category<br>GET /decide?choices=a,b,c GET /ack/:category<br>GET /blame/:category      GET /reason/:category<br>GET /eta/:category?estimate=2d<br>GET /placeholder/:category/:kind<br><br><span class=\"dim\"># the rest of it</span><br>GET /random               GET /modules<br>GET /health               GET /openapi.json<br><br><span class=\"dim\"># formats</span><br>Accept: application/json  Accept: text/plain  Accept: text/html<br><br><span class=\"dim\"># reproducibility</span><br>?seed=demo</div></section></main><footer class=\"wrap footer\"><span>Built because hardcoding “Received, thanks” one more time felt unreasonable.</span><span class=\"footer-links\"><a href=\"https://github.com/wfinken/wtfaas\">GitHub</a><a href=\"/modules\">API docs</a><a href=\"/openapi.json\">OpenAPI</a><a href=\"/health\">Health</a><a href=\"https://github.com/wfinken/wtfaas/blob/main/LICENSE\">MIT</a></span></footer><script>(()=>{const q=s=>document.querySelector(s),path=q('#path'),seed=q('#seed'),format=q('#format'),result=q('#result'),status=q('#status');let current='/wtf/http/502?format=json';\nconst copy=async(text,button)=>{try{await navigator.clipboard.writeText(text);const old=button.textContent;button.textContent='copied';setTimeout(()=>button.textContent=old,1100)}catch{}};\ndocument.querySelectorAll('[data-copy]').forEach(b=>b.addEventListener('click',()=>copy(b.dataset.copy,b)));\nq('#copy-curl').addEventListener('click',e=>copy(\"curl 'https://wtfaas.dev\"+current+\"'\",e.currentTarget));\nconst pretty=text=>{try{return JSON.stringify(JSON.parse(text),null,2)}catch{return text}};\nconst run=async()=>{const raw=path.value.trim().replace(/\\s+/g,'');\n// Leading slashes are collapsed so the runner can only ever call this origin.\nconst [route,query='']=('/'+raw.replace(/^\\/+/,'')).split('?');const params=new URLSearchParams(query);params.set('format',format.value);\nconst trimmed=seed.value.trim();if(trimmed)params.set('seed',trimmed);else params.delete('seed');\nconst full=route+'?'+params;current=full;status.textContent='GET '+full+' · loading…';result.textContent='';\ntry{const res=await fetch(full,{headers:{Accept:format.value==='text'?'text/plain':format.value==='html'?'text/html':'application/json'}});const text=await res.text();\nstatus.textContent='GET '+full+' · '+res.status+' '+res.statusText;result.textContent=format.value==='json'?pretty(text):text}\ncatch{status.textContent='GET '+full+' · network error';result.textContent='The request did not make it back. Check your connection and try again.'}};\nq('#runner').addEventListener('submit',e=>{e.preventDefault();run()});\n// Every documented category is a real link; with scripting on it runs here instead of navigating away.\ndocument.addEventListener('click',e=>{const link=e.target.closest('.chip');if(!link||e.metaKey||e.ctrlKey||e.shiftKey)return;e.preventDefault();path.value=link.getAttribute('href').replace(/[?&]format=json$/,'');run();q('#runner').scrollIntoView({block:'nearest'})});\ndocument.querySelectorAll('.tabin').forEach(input=>input.addEventListener('change',()=>{path.value=input.dataset.run;run()}));\nconst key='wtfaas-theme',system=window.matchMedia('(prefers-color-scheme: dark)'),button=q('#theme');let selected=null;try{const saved=localStorage.getItem(key);if(saved==='light'||saved==='dark')selected=saved}catch{}const apply=t=>{document.documentElement.dataset.theme=t;button.textContent=t==='dark'?'☀ light':'◐ dark';button.setAttribute('aria-label','Switch to '+(t==='dark'?'light':'dark')+' theme')};apply(selected||(system.matches?'dark':'light'));system.addEventListener('change',e=>{if(!selected)apply(e.matches?'dark':'light')});button.addEventListener('click',()=>{selected=document.documentElement.dataset.theme==='dark'?'light':'dark';apply(selected);try{localStorage.setItem(key,selected)}catch{}})})();</script></body></html>"