← Documentation

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 --follow

Build 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.

  1. POST /api/v1/games/:slug/builds with { manifest, client? }.
  2. Upload every manifest entry to the returned uploadUrl.
  3. POST the returned finalizeUrl with { "publish": false }.
  4. Preview the returned URL.
  5. POST /api/v1/builds/:buildId/publish with 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.