Kotlin/JVM with Spring Boot 4.1.1. Base path /v1. All bodies are JSON unless
stated otherwise. Contract bodies are parsed and validated by the shared
:packages:design-contract ContractJson and ContractValidator.
Contract object shapes: json_contract.md.
When IKK_API_TOKEN is set, every route except /healthz requires
Authorization: Bearer <token>. When it is empty (the local default), those
routes are open. Every response includes X-Request-ID; a valid incoming
X-Request-ID is preserved.
The local server binds to 127.0.0.1:8000 by default. IKK_BIND_ADDRESS
changes the bind address, and PORT changes the port. Browser access is
limited to the comma-separated IKK_ALLOWED_ORIGINS list, whose local default
is http://127.0.0.1:5173,http://localhost:5173.
Process and database readiness.
200 → { "status": "ok" }
Create a project.
{ "name": "Inbox app" }201 → { "id": "p_7", "name": "Inbox app", "createdAt": "...", "updatedAt": "...", "latestCheckpoint": "cp_000" }
Project metadata.
200 → { "id", "name", "createdAt", "updatedAt", "latestCheckpoint" }
404 → not found
Current contract, all nodes.
200 → contract object
404 → not found
Validate and replace the complete working contract atomically. A valid missing
project id is created on first import, which is how the local Web editor
bootstraps demo. The first occurrence of a checkpoint name is stored as an
immutable snapshot; later working edits with that same name do not overwrite
the frozen snapshot. The submitted contract's checkpoint must not be older
than the project's current checkpoint. A stale submission is rejected in full
and does not partially replace nodes or create a snapshot.
200 → { "projectId": "p_7", "checkpoint": "cp_005", "components": 4 }
400 → invalid project id
409 → { "error": "stale_checkpoint", "message": "...", "requestId": "...", "details": [] }
422 → contract failed strict parsing or validation
Batch upsert. Each incoming node version must be strictly greater than its
stored version; updatedAt is metadata, not a cross-device clock.
{ "nodes": [ { "id", "type", "schemaVersion": 1, "version", "updatedAt", "payload" } ] }200 → { "accepted": ["n1"], "rejected": [], "checksums": { "n1": "sha256:..." } }
409 → { "error": "stale_version", "message": "...", "requestId": "...", "details": [ { "id": "n1", "reason": "stale_version", "server": { } } ] }
422 → validation failure
Checksums are computed server-side and returned; clients do not send them.
Remove a node.
204 → deleted
404 → not found
Validate the request body without writing. If the body is omitted, validate the project's currently stored contract.
200 → { "valid": true, "violations": [], "screen": "Home", "components": 4 }
200 → { "valid": false, "violations": [ { "rule": "V10", "where": "ellipse_2", "message": "..." } ], "screen": "Home", "components": 4 }
Validate a complete contract without first creating a project and without writing anything. The response shape is the same as project validation.
Freeze the current contract.
201 → { "checkpoint": "cp_006", "createdAt": "..." }
422 → contract invalid
List, newest first.
200 → { "checkpoints": [ { "checkpoint", "createdAt" } ] }
Contract as frozen at that checkpoint.
200 → contract object
404 → not found
Cut a checkpoint, run codegen, return artifacts.
{ "targets": ["kotlin", "css", "html"] }200 →
{
"checkpoint": "cp_006",
"artifacts": [
{ "name": "HomeLayout.generated.kt", "target": "kotlin", "bytes": 1840 },
{ "name": "home.generated.css", "target": "css", "bytes": 920 },
{ "name": "home.generated.html", "target": "html", "bytes": 480 }
]
}422 → contract invalid
Only the requested targets remain current: a successful partial generation removes artifacts from older checkpoints for omitted targets, so the artifact endpoint can never return a mixed-checkpoint set.
Fetch one generated file.
200 → file body with text/css, text/html, or text/plain
404 → not generated
Upload an image for an ImageNode.
multipart/form-data, field file
201 → { "ref": "asset_12", "mime": "image/png", "bytes": 48210 }
413 → too large
415 → unsupported type
Fetch an asset.
200 → binary, original content type
404 → not found
All non-2xx share one shape:
{ "error": "stale_version", "message": "...", "requestId": "req_8f3a", "details": [] }| Status | Meaning |
|---|---|
400 |
Malformed request |
401 |
Missing or invalid credentials |
404 |
Not found |
409 |
Conflict — stale node version |
413 |
Payload too large |
415 |
Unsupported media type |
422 |
Contract validation failed |
500 |
Unhandled |