ShipGames
Docs

The ship API

Ship a game from a script, a CI job or an AI agent, and edit your own games. One token, plain HTTPS, JSON back.

Token

Make a token on your account page and send it on every request:

Authorization: Bearer sgk_...

A token ships builds and edits your own games. It never signs in, never reaches anyone else's games, never does admin work. Revoke it on the account page and it stops at once.

Ship a build

POST/api/v1/ship

One file: a single .html page, or a .zip of the game's built folder with index.html at the top. Leave out game for a new game; give your game's slug to add a build.

Multipart (curl's -F)

curl -H "Authorization: Bearer $SHIPGAMES_TOKEN" \
  -F file=@game.zip -F note="Faster enemies, a new boss" \
  -F game=space-rocks \
  https://shipgames.io/api/v1/ship

The file as the body

curl -H "Authorization: Bearer $SHIPGAMES_TOKEN" \
  -H "Content-Type: application/zip" --data-binary @game.zip \
  "https://shipgames.io/api/v1/ship?note=First%20playable"

Content-Type text/html for a page, application/zip for a zip. Fields go in the query: note, game, title, filename, ring, devices.

JSON (handy for AI agents)

POST /api/v1/ship
Content-Type: application/json

{"html": "<!doctype html>...", "note": "First playable"}
{"file_base64": "UEsDBB...", "filename": "game.zip", "note": "...", "game": "space-rocks"}

The answer

{
  "ok": true,
  "game": "space-rocks",
  "title": "Space Rocks",
  "build": 2,
  "new_game": false,
  "ring": "listed",
  "review": "approved",
  "page": "https://shipgames.io/g/space-rocks",
  "play": "https://play.shipgames.io/space-rocks/k.../2/",
  "message": "\"Space Rocks\": build 2 is live. ..."
}

page is the link to send people: the game page with Play, builds, stats and devlog. play opens the build on its own.

Your games

GET/api/v1/games

Every game you own: slug, title, ring, review state, builds, plays, players, the page and the latest Play link.

GET/api/v1/games/{slug}

One game's stats: plays, players, time played, median session, return rate, phone share, comments, subscribers, each build's numbers and the build-to-build line. ?build=3 for one build.

GET/api/v1/me

Who the token belongs to.

Ring, devlog, title

POST/api/v1/games/{slug}/ring
{"ring": "listed"}

private (only people with the link), circle (signed-in makers), listed (on the home), launched (listed with the badge). A new maker's first game stays private until it's reviewed.

POST/api/v1/games/{slug}/devlog
{"title": "Build 3: the boss", "body": "What I changed and why.", "build": 3}
{"entry_id": 42, "title": "...", "body": "..."}

Adds an entry, or rewrites one with entry_id. GET the same path lists the latest 50 with their ids.

POST/api/v1/games/{slug}
{"title": "Space Rocks DX", "tagline": "Split every rock", "about": "...", "age_rating": "teen", "devices": "both"}

age_rating: everyone, teen or mature (a click-through on the page, and off the list unless its rating filter is on).

devices: where it plays, computer, phone or both (a new game is both). The games list filters on it, and phone visitors see phone games first. Ship takes devices too.

24-hour themes

GET/api/v1/themes

The 24-hour themes: title, state (upcoming, open, closed), reveal and close times, rules, and the prompt once it's revealed (never before). GET /api/v1/themes/{id} adds the ranked entries once revealed (?sort=played for most played).

POST/api/v1/themes/{id}/enter

{"game": "your-slug"} (and optionally "build"): enters one of your games while the theme is open. Its first build must have shipped inside the 24 hours (a GitHub repo's first push too). Entering again before the close moves the entry to a newer build.

Feedback and updates

These need a token with the feedback scope (tokens made on the account page have it unless you untick it; older tokens are ship only).

GET/api/v1/feedback

Comments on your games, newest first: who, which build, working and one_thing_to_try (or their own words in text), your replies. ?game=slug, ?build=3, ?unanswered=1; ?which=by_me for the comments you wrote.

POST/api/v1/feedback/{id}/reply
{"text": "Thanks! The boss is easier in build 4."}
GET/api/v1/updates

Your Updates inbox: new builds and devlog entries of games and makers you follow, replies to your comments, comments on your games. ?unread=1. POST /api/v1/updates/read with {"ids": [1, 2]} (or nothing, for all) marks them read.

Rules

Errors

{"ok": false, "error": "No index.html at the top of the game. ..."}

400 the upload or the request is wrong (the error says what to fix) · 401 no token, or it was revoked · 404 not one of your games · 409 the game waits for review · 413 too big · 429 slow down.

MCP connector

The same powers inside an AI assistant. The connector link:

https://shipgames.io/mcp

Streamable HTTP, the current MCP spec. Tools: ship_build (the game as html, file_base64 up to 15 MB, or a file_url it downloads, up to 50 MB; plus a note), list_my_games, get_game_stats, set_ring, update_devlog, enter_theme; with the feedback scope also list_feedback, reply_feedback and list_updates.

Sign-in is OAuth: the app opens ShipGames, you sign in with your passkey and tap Allow, and the app gets a token of its own (listed on your account page as a connected app). Apps without OAuth can send a token you made as Authorization: Bearer sgk_.... Steps for Claude, ChatGPT and Cursor: Ship a game.

CLI

shipgames login                 # paste a token from /account
shipgames ship ./dist -m "First playable"
shipgames ship game.html -m "Faster rocks"
shipgames games

A folder is zipped for you. The next ship from the same folder adds a build to the same game. Not on npm yet: run it from the ShipGames repo with node cli/shipgames.mjs.