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.
// success
{ "ok": true, ...data }
// error
{ "ok": false, "error": "error_code" }
// errors have "ok": false and an "error" fieldGET /api/health
→ { "ok": true, "time": 1744000000000 }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/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/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/status
→ {
"ok": true,
"letters": { "pending": 2, "approved": 14 },
"time": 1744000000000
}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!"}'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):
tokens are stored server-side and are unique every time.
{ "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/me
X-API-Token: sk_...
→ {
"ok": true,
"role": "user",
"name": "my project",
"createdAt": 1744000000000,
"lastUsedAt": 1744000060000,
"requests": 42,
"rateLimit": 60
}POST /api/tokens/revoke
X-API-Token: sk_...
→ { "ok": true, "message": "token revoked" }GIFs are stored in Redis and can be changed at any time by the owner — via API or Telegram bot.
currently active GIFs:
GET /api/gifs
→ { "ok": true, "gifs": { "1": "...", "2": "...", "3": "...", "4": "..." } }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.
owner-only. require Authorization: Bearer <admin-token>. not accessible externally.