453 classic BOFH excuses as a free JSON API. No auth. No nonsense.
bofh.bombeck.io · OpenAPI Spec
# JSON (default)
curl https://bofh.bombeck.io/v1/excuses/random
# Plain text — just the excuse
curl -H "Accept: text/plain" https://bofh.bombeck.io/v1/excuses/random{
"data": { "id": 42, "excuse": "Solar flares" },
"meta": { "total": 453 },
"error": null
}const res = await fetch("https://bofh.bombeck.io/v1/excuses/random");
const { data } = await res.json();
console.log(data.excuse);import requests
r = requests.get("https://bofh.bombeck.io/v1/excuses/random")
print(r.json()["data"]["excuse"])resp, _ := http.Get("https://bofh.bombeck.io/v1/excuses/random")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))echo "Excuse: $(curl -sH 'Accept: text/plain' https://bofh.bombeck.io/v1/excuses/random)"Base URL: https://bofh.bombeck.io
OpenAPI: /openapi.json
All responses follow the envelope { data, meta, error }.
Set Accept: text/plain on any excuse endpoint to get raw text instead of JSON.
| Method | Path | Description |
|---|---|---|
GET |
/v1/excuses/random |
One random excuse |
GET |
/v1/excuses/random?count=N |
N random excuses (1–50) |
GET |
/v1/excuses/:id |
Excuse by ID (1–453) |
GET |
/v1/excuses |
All 453 excuses |
GET |
/health |
Health check |
GET |
/openapi.json |
OpenAPI 3.1 specification |
Single excuse — GET /v1/excuses/random
{
"data": { "id": 42, "excuse": "Solar flares" },
"meta": { "total": 453 },
"error": null
}Multiple excuses — GET /v1/excuses/random?count=3
{
"data": [
{ "id": 112, "excuse": "clock speed" },
{ "id": 7, "excuse": "Cosmic rays" },
{ "id": 301, "excuse": "Failure to adjust for stripes" }
],
"meta": { "count": 3, "total": 453 },
"error": null
}Plain text — curl -H "Accept: text/plain" .../v1/excuses/random
Solar flares
{
"data": null,
"meta": null,
"error": { "code": "NOT_FOUND", "message": "excuse #999 not found" }
}| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR |
Invalid parameters |
| 404 | NOT_FOUND |
Excuse or route not found |
| 429 | RATE_LIMITED |
Too many requests |
| 500 | INTERNAL_ERROR |
Server error |
- 1,000 requests per 15 minutes per IP
- Standard
RateLimit-*headers in all responses /healthis excluded from rate limiting
docker run -d -p 3000:3000 -e ATTACKS_API_KEY=your-secret ghcr.io/mbombeck/bofh:latestgit clone https://github.com/MBombeck/bofh.git
cd bofh
npm ci && npm run build
ATTACKS_API_KEY=your-secret npm start| Variable | Required | Default | Description |
|---|---|---|---|
PORT |
No | 3000 |
Server port |
NODE_ENV |
No | production |
Environment |
ATTACKS_API_KEY |
Yes | — | Key for internal /internal/attacks endpoint |
CORS_ORIGINS |
No | * |
Allowed CORS origins (comma-separated) |
LANDING_HOST |
No | bofh.bombeck.io |
Hostname for the landing page |
SENTRY_DSN |
No | — | Sentry/GlitchTip DSN |
LOG_LEVEL |
No | info |
debug / info / warn / error |
The Bastard Operator From Hell is a fictional rogue sysadmin created by Simon Travaglia in 1992. The original excuse list of 453 entries was compiled by Jeff Ballard.
- Simon Travaglia — Creator of the Bastard Operator From Hell
- Jeff Ballard — Original BOFH excuse list compiler
- Built by Marc Bombeck