API › Programs

Voses and versions

Create, read and iterate programs over HTTP, with lineage and typed changelogs.

The content loop over raw HTTP: fetch a program, push a private vos with lineage, iterate against a tracked base, read the typed changelog. This is the contract vos fetch, vos push and vos pull ride; use it directly when a CLI is not in the room.

Read

Text
GET /api/vos/{id}            metadata: title, params, currentVersionId, contentUrls
GET /api/vos/{id}/config     { "config": VosConfigJson }
GET /api/vos/{id}/output     the compiled program

Public voses need no auth. The metadata answers { "vos": { … } }, and contentUrls sits inside it. Never construct byte URLs yourself; follow contentUrls, never the raw thumbnailUrl or previewUrl storage paths.

Create

Text
POST /api/vos
Authorization: Bearer vos_sk_...
{
  "title": "Aurora Ribbons, dusk",
  "slug": "aurora-ribbons-dusk",
  "visibility": "private",
  "config": { ... },
  "remixOfId": "{source vos id}",
  "folderId": "{folder id}"
}
→ 201 { "vos": { "id", ... } }

The push compiles server-side, so a push is also a validation: a config that does not compile answers 400 with the compile error. remixOfId records lineage and renders as remix credit; folderId files the work onto the user's shelf (see Folders and recipes). The preview render queues automatically.

Lineage is stored as remixedFromId and read back as remixedFrom. It is a chain, not a star: a copy names the vos it was copied from, one hop, so a → b → c stays legible as three separate acts.

Duplicating your own vos

Text
POST /api/vos/{id}/duplicate
→ 201 { "vos": { "id", "title": "Copy of …", … }, "version": { … } }

A private sibling on the same shelf, head only, in the source's folder. Owner only: someone else's work is remixed instead, which is a POST /api/vos with remixOfId. It copies the config, the compiled artifact and (for a take) its doc.json, so a duplicated take keeps every edit. Metered like any other create.

Without any credential there is the claimable push: a program, and the files it draws with.

Text
POST /api/claim/uploads                       (no auth)
→ 201 { "uploadToken": "vos_cu_…", "expiresAt", "limits" }

POST /api/claim/uploads/files                 Bearer the uploadToken
     { "filename", "size", "contentType"?, "durationSeconds"? }
PUT  /api/claim/uploads/files/{uploadId}/parts/{n}
POST /api/claim/uploads/files/{uploadId}/complete   { "parts": [ … ] }
→ 201 { "asset": { "id", "ref": "asset:…", "fileUrl", "kind", … } }

POST /api/claim        { "title": "...", "config": { ... },
                         "uploadToken"?, "prompt"?, "share"? }
→ 201 { "claimUrl", "expiresAt", "vos": { "id" }, "files"? }

The files go first, through the same part protocol as the account's upload door, each read and typed by its bytes. Name each one in the config by the ref it answered; the claim spends the session. At most 12 files and 50 MB, sound up to 5 minutes, video up to 60 seconds. prompt is shown on the watch page, so send only what the person wrote and said to show; share: true makes the claim page lead with Claim and share. vos push --claimable does all of this.

Hand claimUrl to the human and nowhere else. It lasts 72 hours; unclaimed work is deleted with its files. Until the claim, those files are read only through the claim link.

Iterate

Text
GET  /api/vos/{id}                              note currentVersionId
GET  /api/vos/{id}/changes?since={yourBase}     the typed changelog
POST /api/vos/{id}/versions
     { "config": { ... },
       "baseVersionId": "{currentVersionId}",
       "label": "tighter ring pulse",
       "note": "0.4s felt slow; 0.3s reads snappier" }
GET  /api/vos/{id}/versions                     the attributed history
POST /api/vos/{id}/versions { "restoreOf": "{versionId}" }

Always send baseVersionId, and always stamp label and note; the version history reads as a conversation. The changes payload carries each intervening version's origin, label, note, typed ops and a prose summary, plus the computed protected node set.

The two rejections you must handle, 409 stale_base (the body carries the changelog you should have pulled) and 409 protected_conflict (humans win by default), are specified in Versions and conflicts.

Update metadata

Text
PATCH /api/vos/{id}    { "title" | "tags" | "visibility": "private" | "unlisted"
                         | "config" (send baseVersionId too) }

A config PATCH recompiles and takes the same base and protection guards as a version push. It creates a version, so it also takes the same label, note and client attribution the versions POST takes; stamp them there too. Keys cannot set "public".

Delete

Text
DELETE /api/vos/{id}    the vos and every version of it, for good

The owner's key may delete; a remix or folder grant may not. There is no undo, so ask the human before you delete their work.

Hand back

The human reviews at vos.so/vos/{id} and edits at vos.so/studio?vos={id}; tell them both URLs. Their saves join the same version chain your pushes do.

  • Overview and auth for credentials, clamps and errors.
  • /llms-remix.txt for this contract in its canonical terse form, including the remix knob and font recipes.