The OSO API is how a program uses this site. It authenticates with a key, never a cookie, and lives under /api/v1/. Anything you can do on the forum, on profiles and in your messages, a key can do too, and nothing more.
This is the API for oldschoolops.com. A game server's own control panel has a separate one, described in GameCP API.
Getting a Key
Account, then API keys. A key is shown once and stored only as a hash, so there is no way to look it up again. Keys expire after a year unless you say otherwise.
A key acts as you. Your groups, your staff level, any restriction a moderator has placed on your account and whether each part of the site is open are all checked on every request, exactly as they are when you use the site in a browser, rather than fixed when the key was made. So a key never sees a board your account cannot see, and it stops posting the moment your account cannot post.
A key cannot change your password, email address, name or two-factor setting, and cannot manage your sessions or other keys. Those need you, in a browser.
Using It
Send the key as a header, never in a URL: query strings end up in server logs, in Referer headers and in your shell history. Requests with a body send JSON.
curl -H "Authorization: Bearer oso_..." https://oldschoolops.com/api/v1/forum
curl -H "Authorization: Bearer oso_..." -H "Content-Type: application/json" \
-d '{"body": "Thanks, that fixed it."}' \
https://oldschoolops.com/api/v1/forum/threads/some-thread-12/posts
If you have registered but not yet confirmed your email address, a key can read but not write, the same as the site.
Endpoints
You
| Method and path | What it does |
|---|---|
GET /api/v1/me | Who the key acts as: name, groups, permissions and which parts of the site are open to you. |
GET /api/v1/account/profile | Your profile and appearance settings, with the titles and name styles you may pick. |
POST /api/v1/account/profile | Change any of title, bio, location, website, accent, preset, wall_open, timezone, title_key, name_style, watch_on_reply, watch_on_create. Fields you leave out are kept. |
GET /api/v1/account/notifications | Which events reach you on the site and by email. |
POST /api/v1/account/notifications | {"events": {"forum.reply": {"email": false}}}. Events you leave out are kept; events that cannot be switched off are refused. |
GET /api/v1/notifications | Your notifications and unread count. |
POST /api/v1/notifications/{id}/read | Mark one read. |
POST /api/v1/notifications/read-all | Mark them all read. |
The forum
| Method and path | What it does |
|---|---|
GET /api/v1/forum | Every board you can see, by section, with unread state. |
GET /api/v1/forum/feed | Threads across every board you can see, most recently active first. page. |
GET /api/v1/forum/search | Threads matching q. |
GET /api/v1/forum/boards/{slug} | One board's threads and subforums. page, tag. Marks the board read, as opening it does. |
GET /api/v1/forum/threads/{slug} | One page of a thread: every post with its reactions and who reacted. page. Counts as a view, exactly as opening the thread does. |
GET /api/v1/forum/posts/{id} | One post. |
POST /api/v1/forum/boards/{slug}/threads | Start a thread: title, body, optional tag. |
POST /api/v1/forum/threads/{slug}/posts | Reply: body, and reply_to with a post id to answer that post. |
POST /api/v1/forum/posts/{id}/edit | Change a post's body. Your own, or any on a board you moderate. |
POST /api/v1/forum/posts/{id}/delete | Remove a post, with a reason. Removing the opening post removes the thread. |
POST /api/v1/forum/threads/{slug}/watch | {"watching": true} or false. |
POST /api/v1/forum/read-all | Mark the whole forum read. |
Post bodies come back as the text that was written, in the same markup you post with. A removed post comes back with removed: true and no body, unless you moderate that board.
Reactions and comments
These work on anything that takes them. kind is one of forum_post, forum_thread, profile, comment, bug, idea, changelog, news, and ref is its id. An idea's may be given as IDEA-12. A reaction on an idea is not a vote.
| Method and path | What it does |
|---|---|
GET /api/v1/reactions | kind, ref: the tally and who reacted, most recent first. |
POST /api/v1/reactions | kind, ref, emoji: toggle your reaction. |
GET /api/v1/comments | kind, ref: the comments, each with its reactions. |
POST /api/v1/comments | kind, ref, body. |
POST /api/v1/comments/{id}/edit | Change your own comment's body. |
POST /api/v1/comments/{id}/delete | Remove your own comment, with an optional reason. |
People and messages
| Method and path | What it does |
|---|---|
GET /api/v1/members | The newest members. |
GET /api/v1/profiles/{name} | A profile, its awards and titles, and the comments on its wall. |
POST /api/v1/profiles/{name}/comments | Write on a wall: body. |
GET /api/v1/messages | Your conversations, newest first, with unread counts. |
GET /api/v1/messages/{name} | The latest hundred messages with one person. Marks them read, as opening the conversation does. |
POST /api/v1/messages/{name} | Send a message: body. |
Bug reports
| Method and path | What it does |
|---|---|
GET /api/v1/bugs | Recent reports. Optional status, game and page. |
GET /api/v1/bugs/{ref} | One report; comments=1 adds its comments. |
GET /api/v1/bugs/similar | Whether something has been reported already, without filing anything. |
POST /api/v1/bugs | File a report. |
GET /api/v1/bugs/mine | The reports you filed. Optional game. |
GET /api/v1/bugs/components | What the report form offers, and which games have a tracker. |
POST /api/v1/bugs/{ref}/me-too | Add what you saw to an existing report instead of filing a duplicate. |
similar before POST is the half of de-duplication that stops a duplicate existing at all: it answers "has this been reported" without writing a row. A report against GoMMO Client names the game it was playing in tool_game, as the report form asks. Staff accounts can also move, reply to, assign and note reports; the routes are listed on the API keys page.
Ideas
{ref} is the idea's id as the site shows it, such as IDEA-12.
| Method and path | What it does |
|---|---|
GET /api/v1/ideas | Ideas, newest page first. Optional tag, status, sort (top, new or updated) and page. |
GET /api/v1/ideas/search | Ideas matching q, by their words or an IDEA- id. Search before you suggest. |
GET /api/v1/ideas/{ref} | One idea with the team's response; comments=1 adds its comments. |
POST /api/v1/ideas | Suggest an idea: tag (a game, a tool or site), title, body, optional why. |
POST /api/v1/ideas/{ref}/comments | Comment on an idea: body. |
Votes are cast on the website only. A key can read the vote count and whether you have voted, but POST /api/v1/ideas/{ref}/vote answers 403: sign in on the site to vote. Staff accounts can also move an idea and write the team's response; those routes are on the API keys page.
Responses
Field names are a contract. Timestamps are RFC 3339 in UTC. A post looks like this:
{
"id": 4127,
"thread": "pit-bosses-never-healed-311",
"ordinal": 3,
"author": {"id": 18, "name": "Somebody"},
"body": "Same here, on **every** boss.",
"reply_to": 4120,
"created_at": "2026-10-01T09:12:00Z",
"reactions": [{"emoji": "like", "count": 2, "mine": true, "by": "Someone Else"}],
"reactors": [{"name": "Someone Else", "emoji": "like"}, {"name": "You", "emoji": "like"}],
"can_edit": false,
"url": "https://oldschoolops.com/forum/t/pit-bosses-never-healed-311?page=1#p3"
}
Errors
Every error is JSON with an error message.
| Status | Means |
|---|---|
| 400 | The request is missing something, or a value is not one the site accepts |
| 401 | No key, or the key was not accepted |
| 403 | Your account may not do that: a locked thread, a closed wall, a restriction on your account |
| 404 | No such thing, or nothing your account can see |
| 422 | Refused as a repeat of something already posted |
| 429 | Too many requests |
Something your account cannot see answers 404, the same as something that does not exist. A rejected key returns 401 whether it is unknown, revoked or expired.
Revoking
Account, then API keys, then Revoke. It stops working immediately.
Connected Apps
GoMMO Manager and GoMMO Studio sign in without a key you copy: each opens /connect/manager or /connect/studio in your browser, you approve it once, and the site hands the app its own key through a loopback redirect with PKCE. A GoMMO Studio key files reports about GoMMO Studio only. That key acts as you like any other, lapses like a browser sign-in (14 days idle, 90 days at most), and is listed under Account, then Connected apps, where Disconnect withdraws it.