System
Operational and marketing-site endpoints. Grouped together because none of them fit into a first-class product surface.
Health
GET /v1/health-check
Health probe. Returns status and uptime if the database is reachable.
- Auth: Public
- Cache:
public, max-age=30
Response — 200 OK
{
"status": "OK",
"uptime": "up 3 days, 4 hours, 12 minutes"
}
Errors
| Code | Meaning |
|---|---|
500 | Cannot connect to the database. |
Mailing list
POST /v1/subscribe
Subscribe an email address to the
KATFORGE mailing list. Sends a verification email; the address only receives marketing material after the user clicks the verification link.
- Auth: Public
- Rate limit: 5 / 60s
/v1/subscribeRequest
{
"email": "anders@example.com",
"channels": [ "product", "marketing" ]
}
| Field | Type | Constraints |
|---|---|---|
email | string | required, valid email. |
channels | array<string>|null | optional. |
Response — 200 OK, empty body.
GET /v1/verify
Verify a mailing-list subscription via the token link in the verification email. Always redirects to a status page on the marketing site.
- Auth: Public
/v1/verifyQuery params: email, token.
Response — 302 redirect to:
- Success:
<frontend>/status/verify?result=success - Error:
<frontend>/status/verify?result=error&code={missing_arguments|invalid_arguments}
GET /v1/unsubscribe
Unsubscribe an email address. Linked from the unsubscribe footer of outgoing emails.
- Auth: Public
Query params: email, token.
Response — 302 redirect to:
- Success:
<frontend>/status/unsubscribe?result=success - Error:
<frontend>/status/unsubscribe?result=error&code={missing_arguments|invalid_arguments|not_found}
Contact
POST /v1/leads/contact
Submit a contact form. Stores the message in the leads table and forwards it to the
KATFORGE inbox.
- Auth: Public
- Rate limit: 5 / 60s
Request
{
"fullname": "Anders",
"email": "anders@example.com",
"discovery": "search",
"subject": "How do I…",
"message": "I'm trying to integrate the SDK with my React Native app and…"
}
| Field | Type | Constraints |
|---|---|---|
fullname | string | required, not blank, max 255 chars. |
email | string | required, valid email. |
discovery | string | required. How the sender heard about search, friend, social_media). |
subject | string | required, not blank. |
message | string | required, 10–5000 chars. |
Response — 201 Created, empty body.
Errors
| Code | Meaning |
|---|---|
422 | Validation failed. |
Feedback
POST /v1/leads/feedback
Submit in-game feedback. Distinct from /v1/leads/contact: contacts capture acquisition data and trigger reply emails; feedback captures user opinions tagged by kind and source, with optional route and free-form context. Stored in the feedback table.
- Auth: Optional. When a bearer token is supplied,
user_idandplayer_idare stamped from it. Guests submit anonymously and may attach anemailfor follow-up. - Rate limit: 5 / 60s
Request
{
"kind": "bug",
"source": "stumper",
"message": "The pause button doesn't work on iOS Safari.",
"email": "anders@example.com",
"route": "/play",
"context": {
"viewport": "390x844",
"mode": "practice"
}
}
| Field | Type | Constraints |
|---|---|---|
kind | string | required. One of bug, idea, praise, other. |
source | string | required, max 64 chars. App identifier (stumper, lextris, geargoblins, katforge). |
message | string | required, 5–5000 chars. |
email | string | optional, valid email, max 255 chars. Recommended for guest submissions. |
route | string | optional, max 512 chars. The route or screen the user was on. |
context | object | optional. Free-form metadata stored as JSON for triage. |
Response — 201 Created, empty body.
Errors
| Code | Meaning |
|---|---|
422 | Validation failed. |