"<!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\"><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;--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;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-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:#ebe7dd;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:#efebe1}.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)}: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}.calls{grid-template-columns:1fr}.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{--bg:#171715;--surface:#1f1f1c;--ink:#f5f1e8;--muted:#a7a39a;--line:#383731;--accent:#ef644e;--code:#10100f;--code-ink:#f5f1e8}.url{background:#292925}.module:hover{background:#282824}.terminal{box-shadow:5px 5px 0 #383731}}</style></head><body><header class=\"site-head\"><div class=\"wrap head-inner\"><a class=\"wordmark\" href=\"/\">WTFaaS<small>.dev</small></a><nav aria-label=\"Main navigation\"><a href=\"#try\">Try it</a><a href=\"#modules\">Docs</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=\"#try\">Try the API</a><a class=\"button\" href=\"https://github.com/wfinken/wtfaas\">View on GitHub</a></div></div><div class=\"terminal\"><div class=\"term-top\"><span>one request, one answer</span><button class=\"copy\" data-copy=\"curl https://wtfaas.dev/blame/outage\">copy</button></div><pre><span class=\"prompt\">$</span> curl https://wtfaas.dev/blame/outage<br><br>{ \"culprit\": \"DNS\",<br>  \"message\": \"DNS remains a person of interest.\" }</pre></div></section><section class=\"wrap section\" id=\"try\"><div class=\"eyebrow\">Live API playground</div><h2 class=\"section-title\">Ask it something.</h2><p class=\"section-intro\">It is a real request. Choose a module, give it a seed if repeatability matters, then copy what worked.</p><div class=\"playground\"><form class=\"controls\" id=\"playground\"><div class=\"field\"><label for=\"module\">Module</label><select id=\"module\"><option value=\"wtf/http/502\">WTF — HTTP 502</option><option value=\"blame/outage\">Blame — outage</option><option value=\"excuse/deploy\">Excuse — deploy</option><option value=\"decide?choices=ship,wait,rollback\">Decide — ship / wait / rollback</option><option value=\"status/investigating\">Status — investigating</option><option value=\"ack/received\">Ack — received</option><option value=\"eta/software?estimate=2d\">ETA — software</option><option value=\"reason/delay\">Reason — delay</option><option value=\"placeholder/ecommerce/product\">Placeholder — product</option></select></div><div class=\"field\"><label for=\"seed\">Seed (optional)</label><input id=\"seed\" maxlength=\"128\" placeholder=\"demo\"></div><div class=\"field\"><label for=\"format\">Format</label><select id=\"format\"><option value=\"json\">JSON</option><option value=\"text\">Plain text</option><option value=\"html\">HTML</option></select></div><button class=\"run\" type=\"submit\">Run request →</button></form><div class=\"response\"><div class=\"response-meta\"><span id=\"status\">GET · 200 OK</span><button class=\"copy\" id=\"copy-curl\">copy curl</button></div><div class=\"url\" id=\"url\">/wtf/http/502</div><pre id=\"result\" aria-live=\"polite\">{<br>  \"module\": \"wtf\",<br>  \"code\": 502,<br>  \"name\": \"Bad Gateway\",<br>  \"wtf\": \"The server asked another server for help.\"<br>}</pre></div></div></section><section class=\"wrap section\" id=\"modules\"><div class=\"eyebrow\">The directory</div><h2 class=\"section-title\">Nine small utilities.</h2><p class=\"section-intro\">They do specific things. That is the whole appeal.</p><div class=\"directory\"><a class=\"module\" href=\"/wtf/http/502\"><span class=\"module-name\">WTF</span><span class=\"module-desc\">Explain an error, acronym, or confusing thing.</span><code>/wtf/http/502</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/excuse/deploy\"><span class=\"module-name\">Excuse</span><span class=\"module-desc\">Get a plausible excuse without inventing a tragedy.</span><code>/excuse/deploy</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/decide?choices=ship,wait,rollback\"><span class=\"module-name\">Decide</span><span class=\"module-desc\">Pick something so you do not have to.</span><code>/decide?choices=ship,wait,rollback</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/status/investigating\"><span class=\"module-name\">Status</span><span class=\"module-desc\">Say what is happening, compactly.</span><code>/status/investigating</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/ack/received\"><span class=\"module-name\">Ack</span><span class=\"module-desc\">Confirm receipt without writing “noted” again.</span><code>/ack/received</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/blame/outage\"><span class=\"module-name\">Blame</span><span class=\"module-desc\">Name a likely culprit, then suggest a check.</span><code>/blame/outage</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/eta/software?estimate=2d\"><span class=\"module-name\">ETA</span><span class=\"module-desc\">Translate an estimate into reality-ish.</span><code>/eta/software?estimate=2d</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/reason/delay\"><span class=\"module-name\">Reason</span><span class=\"module-desc\">Explain why, responsibly.</span><code>/reason/delay</code><span class=\"arrow\">→</span></a><a class=\"module\" href=\"/placeholder/ecommerce/product\"><span class=\"module-name\">Placeholder</span><span class=\"module-desc\">Generate useful, clearly fictional content.</span><code>/placeholder/ecommerce/product</code><span class=\"arrow\">→</span></a></div></section><section class=\"wrap section\"><div class=\"eyebrow\">Things you can ask it</div><h2 class=\"section-title\">A few practical calls.</h2><div class=\"calls\"><div class=\"call\"><code>curl /wtf/http/502</code><button class=\"copy\" data-copy=\"curl https://wtfaas.dev/wtf/http/502\">copy</button></div><div class=\"call\"><code>curl /excuse/deploy</code><button class=\"copy\" data-copy=\"curl https://wtfaas.dev/excuse/deploy\">copy</button></div><div class=\"call\"><code>curl /ack/received</code><button class=\"copy\" data-copy=\"curl https://wtfaas.dev/ack/received\">copy</button></div><div class=\"call\"><code>curl /eta/software?estimate=2d</code><button class=\"copy\" data-copy=\"curl 'https://wtfaas.dev/eta/software?estimate=2d'\">copy</button></div></div></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\"><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 /excuse/:category<br>GET /decide?choices=a,b,c GET /status/:category<br>GET /ack/:category        GET /blame/:category<br>GET /eta/:category?estimate=2d<br>GET /reason/:category     GET /placeholder/:category<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),form=q('#playground'),module=q('#module'),seed=q('#seed'),format=q('#format'),url=q('#url'),result=q('#result'),status=q('#status');let current='/wtf/http/502?format=json';const copy=async(text,button)=>{try{await navigator.clipboard.writeText(text);const old=button.textContent;button.textContent='copied';setTimeout(()=>button.textContent=old,1100)}catch{}};document.querySelectorAll('[data-copy]').forEach(b=>b.addEventListener('click',()=>copy(b.dataset.copy,b)));q('#copy-curl').addEventListener('click',e=>copy('curl https://wtfaas.dev'+current,e.currentTarget));form.addEventListener('submit',async e=>{e.preventDefault();let path='/'+module.value,join=path.includes('?')?'&':'?';path+=join+'format='+encodeURIComponent(format.value);if(seed.value.trim())path+='&seed='+encodeURIComponent(seed.value.trim());current=path;url.textContent=path;status.textContent='GET · loading…';result.textContent='';try{const res=await fetch(path,{headers:{Accept:format.value==='text'?'text/plain':format.value==='html'?'text/html':'application/json'}});const text=await res.text();status.textContent='GET · '+res.status+' '+res.statusText;result.textContent=text}catch{status.textContent='GET · network error';result.textContent='The request did not make it back. Check your connection and try again.'}});const key='wtfaas-theme',saved=localStorage.getItem(key),apply=t=>{document.documentElement.style.colorScheme=t;q('#theme').textContent=t==='dark'?'☀ light':'◐ theme'};if(saved)apply(saved);q('#theme').addEventListener('click',()=>{const next=document.documentElement.style.colorScheme==='dark'?'light':'dark';localStorage.setItem(key,next);apply(next)})})();</script></body></html>"