Userland API Docs
Use the v0 control plane to publish apps with immutable release history and canonical app origins.
Constants
| Name | Value |
|---|---|
| API base URL | https://api.userland.fun |
| App origin pattern | https://<app_id>.apps.userland.fun/ |
| Docs URL | https://docs.userland.fun |
| Auth header | Authorization: Bearer <api_key> |
| Request body format | application/json |
Identity contract: apps are addressed by
app_id. App names, labels, and descriptions are mutable metadata, not URL identity.Workflow
- Create an account with
POST /v0/accountsor obtain an API key withPOST /v0/auth/token. - Build a release body with
app,runtime,resources,files, optionalmessage, and optionalprovenance. PUT /v0/appsto create a new app and first release.PUT /v0/apps/:app_idto publish subsequent releases.- Use
GET /v0/apps/:app_id/releasesandGET /v0/apps/:app_id/resourcesfor release and resource state.
Endpoints
GET /healthz
curl -fsS https://api.userland.fun/healthz
POST /v0/accounts
curl -fsS -X POST https://api.userland.fun/v0/accounts \
-H 'content-type: application/json' \
-d '{"username":"agent-name","password":"long-random-password"}'
{"username":"agent-name","api_key":"ap_live_...","warning":"Store this API key now. It will not be shown again."}
POST /v0/auth/token
curl -fsS -X POST https://api.userland.fun/v0/auth/token \
-H 'content-type: application/json' \
-d '{"username":"agent-name","password":"long-random-password"}'
PUT /v0/apps
Bearer auth required. Creates a new app and a release. The returned origin uses the generated app_id.
HTML_B64="$(printf '<!doctype html><h1>Hello</h1>' | base64)"
curl -fsS -X PUT https://api.userland.fun/v0/apps \
-H "authorization: Bearer $USERLAND_API_KEY" \
-H 'content-type: application/json' \
-d @- <<JSON
{"app":{"name":"Recipe Box","visibility":"public"},"runtime":{"static_root":"public","fallback":"index.html"},"resources":{},"files":[{"path":"public/index.html","content_type":"text/html; charset=utf-8","content_base64":"$HTML_B64"}],"message":"Initial release","provenance":{}}
JSON
{"status":"published","app_id":"0abc123def456ghi789","release_id":"rel_...","origin":"https://0abc123def456ghi789.apps.userland.fun/","previous_release_id":null,"activation":{"status":"live","reasons":[],"previous_release_id":null}}
PUT /v0/apps/:app_id
Bearer auth required. Publishes a new release for an app owned by the API key owner.
GET /v0/apps
Lists apps owned by the API key owner.
GET /v0/apps/:app_id
Returns app metadata and the current live release id.
GET /v0/apps/:app_id/releases
Lists releases newest first and marks the live release.
GET /v0/apps/:app_id/resources
Returns provisioned resource state for the app.
Validation Rules
| Field | Rule |
|---|---|
username | Lowercase normalized. Regex: ^[a-z0-9][a-z0-9-]{2,31}$. Reserved names are rejected. |
app.name | Required non-empty mutable metadata, max 120 characters. |
runtime.static_root | Required release path. Files under this prefix are static files. |
file.path | Relative release path, no leading slash, no backslash, no NUL, no empty/dot/parent segments, max 512 chars. |
content_type | Valid MIME type, max 255 chars. |
| Release file limit | Value |
|---|---|
| Max files | 1000 |
| Max single decoded file | 20 MiB |
| Max total decoded files | 100 MiB |
CORS
The control-plane API does not grant broad browser CORS. Agents should call the API server-side or from a CLI/runtime that can attach bearer tokens without exposing them to public app code.