Skip to content
Talk to our solutions team

Meta API

Reference for the meta.svc HTTP surface. For concepts see the Meta block docs.

Meta serves a product’s files by path, as they are. It does not know what the files mean: each block reads its own folders through its meta client and interprets them itself. There are no typed, component or service-config reads.

The API is mounted at the server root. /health and /ready are plain endpoints; everything else goes through the middleware chain: auth → error status → conditional requests → compression (gzip/zstd).

Customer. Every product route names the product in the path. The customer comes from the caller’s tenant token, or from X-Customer under an API key; meta serve defaults it when it serves one customer. Per-repo access rules (access.read / access.write) and license entitlements apply after authentication.

Conditional requests. Every file read returns a SHA-256 ETag; send If-None-Match to get a 304.

Versions. Read routes accept ?version=<name>&versionType=branch|tag to read a branch or tag instead of what the repository serves (for a remote repository, as its mirror last fetched it). A folder has one version. A write that names a version is refused with 400: a write goes to the working tree.

.git is never served, listed, written or removed, at any depth.

MethodPathPurpose
GETfile/{path…}Raw bytes + ETag; 404 when the product has no such file
GETfilesA listing (?path=&depth=)
POSTbatch{"paths":[…]} → {"files":[{path,content,hash,size,error}]}; a missing file is an entry with error (not found, invalid path, unreadable), not a failed batch
GETmanifest?path= → {root_hash, entries:[{path,hash,size,mod_time,is_dir}]}: a cheap “did anything change?” check; a folder the product does not have is an empty manifest
GETfs/stat/{path…}{name,size,mode,mod_time,is_dir}; 404 when absent
GETfs/readdir/{path…}The entries directly in a folder, same shape

mod_time is Unix milliseconds. file/{path…} reads a file and fs/stat answers whether a path exists: the fs/readfile and fs/exists routes that duplicated them are gone.

GET /product/stream?id={id} is an event stream: server-sent events when asked for (Accept: text/event-stream; a browser EventSource asks), one JSON object per line (application/x-ndjson) otherwise:

EventPayloadWhen
snapshot{repo, ref, hash, ts}On connect: a client that reconnects compares hash
repo-updated{repo, ref, hash, prevHash, ts}The product’s content moved: a fetch of a remote repository, an edit on disk of a checkout or folder, a write through this API
pingEvery 30 s

hash is the commit a git repository serves, or a stamp of a working tree’s or folder’s files. ref is empty for a folder.

Writes (the repository must not be readonly)

Section titled “Writes (the repository must not be readonly)”
MethodPathPurpose
PUTfiles?path=Create a folder; 409 if it exists
DELETEfiles?path=Remove a folder; 404 if absent; the product root cannot be removed (400)
POSTfile/{path…}Upload (multipart field files)
POSTzip/{path…}Upload a zip, expanded in place
MethodPathPurpose
GETgit/refsBranches and tags: a remote repository’s as last fetched; none for a folder
GETgit/versionThe commit the repository serves
POSTgit/status, git/diffA local checkout’s working tree
POSTgit/stage, git/reset, git/commitgit add ({"paths"}, "." for all), unstage, commit ({"message","paths"?})
PATCHgit/commitfileWrite, stage and commit one file: {"path","file","message"?}
PATCHgit/patchApply a text patch to one file: {"path","patch"}
POSTgit/fetch, git/pull, git/pushAgainst a remote of a local checkout

An operation that needs a working tree (everything but git/refs and git/version) needs a local checkout (400 otherwise), and a write one that is not read-only (403). git/version of a folder is 400: it has no commit.

GET file/{path…} · PATCH paths (several files as a zip) · GET git/zip · GET fileorfolderzip/{path…} · POST git/fetch.

MethodPathPurpose
GETrepositoriesThe repositories meta holds: an operator sees every customer’s, anyone else their own
GETtenant-repositoriesThe calling tenant’s on-demand repositories
GETembedded-infoThe products compiled into this binary; an encrypted payload reports only that it is encrypted
GETlicense-statusThe calling customer’s entitlements
POSTlicense-activate{"token"} → entitlement map (not served by meta serve)
POSTlicense-deactivateDrop a license (operators)

Meta accepts three credentials, tried in order, and the first that succeeds wins:

OrderCredential
1API key
2Certificate JWT
3Bearer token

A credential that is simply absent falls through to the next. The last is strict: a request that reaches it without a valid token is rejected.

Meta is served over a protocol layer rather than plain HTTP handlers, so authentication runs as middleware over the request metadata rather than per route. The effect is the same cascade every other service reaches through its HTTP guard.

CEPT is populated from request metadata before authentication runs, so tenant resolution and credential validation are separate steps. A request can therefore resolve a tenant and still be rejected for credentials, which is why a tenancy failure and an auth failure look different.

A caller’s mistake answers its own status; only a server fault is a 500, so a 4xx is never worth retrying.

StatusMeaning
400Invalid request: a missing field, a path that escapes the product, a write naming a version, git porcelain against a repository that is not a local checkout
401No credential validated
403A read-only repository, a failed access rule or entitlement
404No such product, file or folder
409Already exists (creating a folder that is there)
500Unexpected server error