# api

status: checking… · base: hatesocial.lol

## what is this?

public REST API for hatesocial.lol. read letters, submit messages, check status.

most endpoints are public — no auth needed.

generate a personal API token to use X-API-Token header, track your requests, and get a persistent identity.

base url:https://hatesocial.lol
format:JSON — all responses are JSON
auth:X-API-Token: sk_... or Authorization: Bearer sk_...
rate limit:10 req/min on /submit · 120 req/min global
cors:all origins allowed on public endpoints

## response format

// success
{ "ok": true, ...data }

// error
{ "ok": false, "error": "error_code" }

// errors have "ok": false and an "error" field

## public endpoints

GET/api/healthpublic
server alive check — returns 200 if running
GET /api/health
→ { "ok": true, "time": 1744000000000 }
GET/api/letters/listpublic
all approved letters from shoutbox, newest first
GET /api/letters/list
// optional: X-API-Token: sk_...

→ {
  "ok": true,
  "count": 14,
  "items": [{
    "id":         "abc123_lx4k",
    "message":    "hello!",
    "createdAt":  1744000000000,
    "answered":   true,
    "answer":     "hi back!",
    "answeredAt": 1744000060000
  }]
}
POST/api/letters/submitpublic
submit anonymous letter — enters moderation queue, not visible until approved
POST /api/letters/submit
Content-Type: application/json

{ "message": "your message here" }

→ 200  { "ok": true }
→ 400  { "ok": false, "error": "too_short_or_too_long", "min": 2, "max": 500 }
→ 429  { "ok": false, "error": "rate_limited", "retryAfter": 60 }
GET/api/gifspublic
current available GIF options for the letterbox
GET /api/gifs

→ {
  "ok": true,
  "gifs": {
    "1": "https://media.tenor.com/...",
    "2": "https://media.tenor.com/...",
    "3": "https://media1.tenor.com/...",
    "4": "https://media1.tenor.com/..."
  }
}
GET/api/statuspublic
server + redis status, letter counts
GET /api/status

→ {
  "ok": true,
  "letters": { "pending": 2, "approved": 14 },
  "time": 1744000000000
}

## quick test

curl https://hatesocial.lol/api/letters/list
curl https://hatesocial.lol/api/gifs
curl -X POST https://hatesocial.lol/api/letters/submit \
  -H "Content-Type: application/json" \
  -d '{"message":"hello from the api!"}'

## api tokens

generate a token to identify your requests. stored server-side — unique per request.

use it via X-API-Token: sk_... or Authorization: Bearer sk_....

tokens track your total requests and last used time. you can revoke them anytime.

your token label (optional):

— click generate —

tokens are stored server-side and are unique every time.

## token endpoints

POST/api/tokens/createpublic
create a new API token. body: { "name": "my project" }
POST /api/tokens/create
Content-Type: application/json

{ "name": "my project" }

→ 201 {
  "ok":        true,
  "token":     "sk_a1b2c3d4...",
  "name":      "my project",
  "createdAt": 1744000000000,
  "rateLimit": 60,
  "note":      "save this token — it won't be shown again"
}
GET/api/tokens/merequires token
get info about the currently authenticated token
GET /api/tokens/me
X-API-Token: sk_...

→ {
  "ok":         true,
  "role":       "user",
  "name":       "my project",
  "createdAt":  1744000000000,
  "lastUsedAt": 1744000060000,
  "requests":   42,
  "rateLimit":  60
}
POST/api/tokens/revokerequires token
revoke your own token. sends empty body, uses token from header.
POST /api/tokens/revoke
X-API-Token: sk_...

→ { "ok": true, "message": "token revoked" }

## gif management

GIFs are stored in Redis and can be changed at any time by the owner — via API or Telegram bot.

currently active GIFs: loading…

loading…
GET/api/gifspublic
returns current gif config
GET /api/gifs
→ { "ok": true, "gifs": { "1": "...", "2": "...", "3": "...", "4": "..." } }
POST/api/gifs/setadmin only
update a gif by ID (1-4). URL must be from an allowed host (tenor, giphy, discord).
POST /api/gifs/set
Authorization: Bearer <admin-token>
Content-Type: application/json

{ "id": "1", "url": "https://media.tenor.com/..." }

→ 200 { "ok": true, "gifs": { ...updated config } }
→ 400 { "ok": false, "error": "invalid_gif_url", "allowed_hosts": [...] }

tip: use /gifs and /setgif N URL in the Telegram bot to manage GIFs without touching the API directly.

## private endpoints

owner-only. require Authorization: Bearer <admin-token>. not accessible externally.

GET/api/letters/pendingadmin
POST/api/letters/approveadmin
POST/api/letters/rejectadmin
POST/api/letters/answeradmin
POST/api/letters/edit-answeradmin
POST/api/letters/delete-answeradmin
POST/api/letters/deleteadmin
POST/api/gifs/setadmin
GET/api/tokens/listadmin

## live status

/api/health
redis
/api/letters/list
pending letters
approved letters
checked