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
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/shipThe 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
Every game you own: slug, title, ring, review state, builds, plays, players, the page and the latest Play link.
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.
Who the token belongs to.
Ring, devlog, title
{"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.
{"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.
{"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
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).
{"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).
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.
{"text": "Thanks! The boss is easier in build 4."}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
- The same checks as dragging a game onto /ship: at most 50 MB and 500 files,
index.htmlat the top (a single top folder is unwrapped), web files only (HTML, JS, CSS, images, sound, fonts, WebAssembly, game data), no server-side code, safe paths only, and each file must be what its name says. - New games start as a private link. A new maker's first game waits in the review queue; once it's approved, your later games skip it.
- Limits: 60 requests a minute per token; 20 uploads an hour per maker.
- Every build gets the play recorder: anonymous stats from the first session.
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/mcpStreamable 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 gamesA 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.