doughmination.uk · API backend

APIs

The backend for c.stupid.cat. A few small Cloudflare Workers that power the site's Discord presence, guestbook, and contribution heatmap. Everything here is read-mostly, CORS-open, and documented below.

🍩 dough-restful

live restful.doughmination.uk

Discord presence + profile/badges, in one unified shape.

A combined presence API (Lanyard-style) and profile & badges API (dstn.to-style), served from a single Cloudflare Worker + Durable Object and backed by one Discord bot. It exposes a REST endpoint and a Lanyard-compatible WebSocket, returning the same unified JSON either way. Presence is only visible for users who share a server with the bot, same model as Lanyard.

Endpoints

GET/Service info + endpoint list.
GET/v1/users/:idUnified record | presence + profile + badges + connected accounts.
GET/v1/users/:id/presencePresence only (status, activities).
GET/v1/users/:id/profileProfile + badges only.
WS/socketWebSocket stream (Lanyard protocol). /ws works too.

:id is a Discord snowflake. Add ?fresh=1 to bypass the cache and force a live refetch.

Request

# unified record
curl https://restful.doughmination.uk/v1/users/1226207941484646401

Response

{
  "success": true,
  "data": {
    "user": { "id": "…", "username": "clove" },
    "presence": { "status": "online" },
    "badges": [ … ],
    "source": { "presence": "gateway" }
  }
}
Cloudflare Worker Durable Object TypeScript WebSocket source ↗

📓 guestbook

live guestbook.doughmination.uk

The guestbook behind c.stupid.cat, no database, just KV.

A tiny Worker that stores guestbook entries as a single JSON array in Workers KV, think of it as a JSON file living on Cloudflare's edge. Read entries with pagination, or post a new one. Spam is kept out with a honeypot field (url2, leave it empty), a per-IP rate limit, and optional Turnstile captcha.

Endpoints

GET/?limit=50&offset=0List entries, newest first. Returns { entries, total, limit, offset }.
POST/Add an entry. JSON body: { name, message, website?, turnstileToken?, url2? }.

Field limits: name ≤ 40, message ≤ 500, website ≤ 200 chars. Stored as plain text, the page renders it, never the API.

List entries

curl 'https://guestbook.doughmination.uk/?limit=2'
{
  "entries": [
    {
      "id": "…",
      "name": "Clove",
      "message": "hi from the edge!",
      "ts": 1750000000000
    }
  ],
  "total": 1, "limit": 2, "offset": 0
}

Sign it

curl -X POST https://guestbook.doughmination.uk/ \
  -H 'Content-Type: application/json' \
  -d '{"name":"Clove",
       "message":"hello!"}'
Cloudflare Worker Workers KV TypeScript Turnstile source ↗

📊 contribapi

live contrib.doughmination.uk

One contribution heatmap, merged from every forge.

A tiny, extensible Worker that pulls contribution calendars from GitHub and any number of Forgejo instances (git.gay, Codeberg, …) and merges them into one JSON object, keyed by source. The site uses it to draw a single heatmap that counts commits everywhere, not just GitHub. Responses are cached at the edge for an hour.

Endpoints

GET/Merged heatmap. One key per forge; each is an array of { timestamp, contributions } days. Cached 1h.

Request

curl https://contrib.doughmination.uk/

Response

{
  "github": [
    { "timestamp": 1750032000,
      "contributions": 4 }
  ],
  "gitdotgay": [
    { "timestamp": 1750032000,
      "contributions": 2 }
  ]
}
Cloudflare Worker TypeScript Zod GitHub + Forgejo source ↗