Creator API
Use this host-facing API for creator automation. Browser games must use the SDK host bridge; never ship a creator token in a game build. Unless noted, successful responses are JSON and errors are { "error": "message" }.
Publish development updates from the devlog API and CLI.
Authentication
export INKWELL_TOKEN='ink_sk_…'
export INKWELL_API='https://inkwell.ing'
curl -fsS "$INKWELL_API/api/v1/me" -H "Authorization: Bearer $INKWELL_TOKEN"Creator keys are accepted for owned-game management. Account settings, key generation and GitHub linking require an authenticated browser session. Treat the token as a password.
Create a game
POST /api/v1/games requires slug and title. Optional fields are description, genreTags, longDescriptionMarkdown, websiteUrl, discordUrl and visibility. Creation visibility is private or unlisted; make the game public after publishing a build. Website accepts HTTP(S); Discord requires an HTTPS Discord invitation. Omit links to preserve them on update, or use null or an empty string to clear them.
curl -fsS -X POST "$INKWELL_API/api/v1/games" -H "Authorization: Bearer $INKWELL_TOKEN" -H 'Content-Type: application/json' --data '{
"slug": "my-game",
"title": "My Game",
"description": "A short public summary.",
"genreTags": ["Action", "Multiplayer"],
"longDescriptionMarkdown": "# My Game\nDescend together.",
"visibility": "unlisted"
}'// 201 response (timestamps and internal fields omitted here)
{
game: {
slug: 'my-game',
title: 'My Game',
description: 'A short public summary.',
genreTags: ['Action', 'Multiplayer'],
visibility: 'unlisted'
},
quota: { /* current daily usage */ }
}Read and update metadata
GET /api/v1/games lists owned games. GET /api/v1/games/:slug returns the game and media.PATCH accepts any editable creation field except slug; omitted fields are unchanged and explicit empty text clears optional text.
curl -fsS -X PATCH "$INKWELL_API/api/v1/games/my-game" -H "Authorization: Bearer $INKWELL_TOKEN" -H 'Content-Type: application/json' --data '{"description":"Now with co-op.","visibility":"public"}'Title is 1–120 characters; slug is 3–64 lowercase letters, numbers and single hyphen-separated segments; summary is 240 characters; Markdown is 20,000 characters; use at most five unique genre tags of 30 characters each.
Upload a cover or screenshot
Send the raw image bytes—not JSON or multipart data—to POST /api/v1/games/:slug/media?kind=cover|screenshot. The Content-Type and file signature must agree. Optional alt is at most 180 characters. Optional focalX and focalY are percentages from 0 to 100 and control responsive cropping.
curl -fsS -X POST "$INKWELL_API/api/v1/games/my-game/media?kind=cover&alt=My%20Game%20cover&focalX=42&focalY=55" -H "Authorization: Bearer $INKWELL_TOKEN" -H 'Content-Type: image/png' --data-binary @cover.png
# 201: { "media": { … }, "url": "/media/PUBLIC_ID" }JPEG, PNG, WebP and GIF are accepted. A replacement cover supersedes the old cover. See the media guide for dimensions and crop behaviour.
Diagnostics and logs
GET /api/v1/games/:slug/status returns publication, loading, analytics, backend, connection and deployment health. GET /api/v1/games/:slug/logs accepts optional level, limit and ISO before parameters. Backend logs include request IDs when emitted inside an action or HTTP request.
inkwell status --game my-game
inkwell logs --game my-game --level error --followBuild upload and publication
Prefer the CLI: it hashes files, selects multipart or resumable chunks, resumes verified uploads and avoids replaying publication mutations. The underlying protocol is available when another client must be implemented.
POST /api/v1/games/:slug/buildswith{ manifest, client? }.- Upload every manifest entry to the returned
uploadUrl. POSTthe returnedfinalizeUrlwith{ "publish": false }.- Preview the returned URL.
POST /api/v1/builds/:buildId/publishwith no body.
{
manifest: [{
path: 'index.html',
size: 1240,
sha256: '64 lowercase hex characters',
contentType: 'text/html; charset=utf-8'
}],
client: {
entrypoint: 'index.html',
capabilities: { threads: false },
startup: { mode: 'handshake', timeoutMs: 120000 }
}
}A single small file may be uploaded with PUT /api/v1/builds/:buildId/files?path=index.html and the raw bytes. Its size and SHA-256 must exactly match the manifest. Multipart batches use matching repeated path and file fields. Files over the batch limit use the resumable chunk endpoints. Use GET /api/v1/limits for live values.
Status codes and safe retries
400 is invalid input, 401 is authentication, 403 is policy/access, 404 is absent or deliberately inaccessible, 409 is a state conflict and 429 is rate limiting with Retry-After. It is safe to repeat content-addressed file/chunk uploads. Do not blindly repeat game creation, finalization, publication or backend deployment after an uncertain response.