Skip to content
Talk to our solutions team

HTTP API

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

Auth is a cascade — any one of: API key (X-Api-Key), certificate-derived JWT, or tenant JWT. Tenant headers X-Customer, X-Product, X-Env, X-Tenant populate context; X-Customer selects the customer whose repositories are visible. Per-repo JS 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 304s.

All read routes accept ?version=<name>&versionType=branch|tag.

MethodPathPurpose
GETfilesDirectory listing (?path=&depth=)
GETfile/{path…}Raw bytes + ETag
POSTbatch{"paths":[…]}{"files":[{path,content,hash,size,error}]}
POSTresolve{"path","have":{hash:path},"depth"} → server-side transitive import: resolution; returns only what the client is missing
GETmanifestMerkle tree of the repo → {root_hash, entries:[{path,hash,size,mod_time,is_dir}]} — cheap “did anything change?” sync
MethodPathPurpose
GETgit/refs, git/versionRefs / current HEAD
POSTgit/status, git/diff, git/fetch, git/pull, git/reset, git/stage, git/commit, git/pushPorcelain over the working tree (local repos, used by the authoring UI)
PATCHgit/patchApply a patch
PATCHgit/commitfileWrite + stage + commit in one call — body {"path","file"}
MethodPathPurpose
GETservice/{service}/configThe critical endpoint — merged envelope for one block (see below)
GETservice/{service}/datastoreMerged datastore definition (params: format, array, filepath, injectproduct, injectservices, onlyinjected)
GETservice/{service}/type/{type}[/file[/{path…}]]Type-mapped reads (being retired — prefer file/)

Read-only stat/read surface used by clients that mount meta as a filesystem:

GET fs/stat/{path…}{name,size,mode,mod_time,is_dir} · fs/readfile/{path…} · fs/readdir/{path…} · fs/exists/{path…} (never 404s).

GET categories, categories/all, category/{category…}, component/{name}[/full], component/{name}/files/{path…}, components[/path/{path…}].

Writes (authoring; repo must not be readonly)

Section titled “Writes (authoring; repo must not be readonly)”
MethodPathPurpose
PUT / DELETEfilesmkdir / rmdir
POSTfile/{path…}Upload (multipart field files)
POSTzip/{path…}Upload a zip, expanded in place
POST / PUTtype/{type}/file/{path…}Typed create / update
PUTtype/{type}/renameRename
StreamPurpose
watchFile-level change stream (snapshot-diff based)
eventsGit HEAD push: snapshot, repo-updated {repo,ref,hash,prevHash,ts}, ping every 30s

GET /product/{id}/service/{service}/config is called by every block on every poll. Response:

{
"load": true,
"service": { "…": "the block's folder config" },
"product": { "…": "product-level config" },
"data": { "…": "datastore definitions" },
"version": { "service": "", "product": "" },
"lastupdated": { "service": "", "product": "" }
}

load is true only when the timestamps differ from the caller’s servicelastupdated / productlastupdated query params — a cheap no-op poll otherwise.

Standalone service routes — /service/{name}/…

Section titled “Standalone service routes — /service/{name}/…”

Serves each block’s binary-embedded base definitions (GET /service/{name}/type/datastore, lastupdated). The server config’s services: block can override embeds for hotfixes.

MethodPathPurpose
GET/repositoriesRegistered repositories
GET/tenant-repositoriesPer-tenant on-demand repositories
GET/embedded-infoWhat products are compiled into this binary
POST/license-activate{"token"} → entitlement map
GET/license-statusCurrent entitlements
POST/license-deactivateDrop a license

POST git/fetch · GET git/zip · GET fileorfolderzip/{path…} · GET file/{path…} · PATCH paths (batch read) · GET components/{path…} · POST index · DELETE indexdocuments · DELETE index.

CodeMeaning
META_READONLYWrite against a read-only repo
META_NOT_LOCALGit porcelain against a non-local repo
META_MISSING_CUSTOMERNo X-Customer header and no JWT customer claim
”given version is not allowed”?version= outside the repo’s allowedversions
403Entitlement/access-rule denial