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.
Product routes — /product/{id}/…
Section titled “Product routes — /product/{id}/…”Files (the preferred surface)
Section titled “Files (the preferred surface)”| Method | Path | Purpose |
|---|---|---|
| GET | files | Directory listing (?path=&depth=) |
| GET | file/{path…} | Raw bytes + ETag |
| POST | batch | {"paths":[…]} → {"files":[{path,content,hash,size,error}]} |
| POST | resolve | {"path","have":{hash:path},"depth"} → server-side transitive import: resolution; returns only what the client is missing |
| GET | manifest | Merkle tree of the repo → {root_hash, entries:[{path,hash,size,mod_time,is_dir}]} — cheap “did anything change?” sync |
| Method | Path | Purpose |
|---|---|---|
| GET | git/refs, git/version | Refs / current HEAD |
| POST | git/status, git/diff, git/fetch, git/pull, git/reset, git/stage, git/commit, git/push | Porcelain over the working tree (local repos, used by the authoring UI) |
| PATCH | git/patch | Apply a patch |
| PATCH | git/commitfile | Write + stage + commit in one call — body {"path","file"} |
Service reads
Section titled “Service reads”| Method | Path | Purpose |
|---|---|---|
| GET | service/{service}/config | The critical endpoint — merged envelope for one block (see below) |
| GET | service/{service}/datastore | Merged datastore definition (params: format, array, filepath, injectproduct, injectservices, onlyinjected) |
| GET | service/{service}/type/{type}[/file[/{path…}]] | Type-mapped reads (being retired — prefer file/) |
Remote filesystem
Section titled “Remote filesystem”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).
Components
Section titled “Components”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)”| Method | Path | Purpose |
|---|---|---|
| PUT / DELETE | files | mkdir / rmdir |
| POST | file/{path…} | Upload (multipart field files) |
| POST | zip/{path…} | Upload a zip, expanded in place |
| POST / PUT | type/{type}/file/{path…} | Typed create / update |
| PUT | type/{type}/rename | Rename |
Streams (SSE)
Section titled “Streams (SSE)”| Stream | Purpose |
|---|---|
watch | File-level change stream (snapshot-diff based) |
events | Git HEAD push: snapshot, repo-updated {repo,ref,hash,prevHash,ts}, ping every 30s |
The service-config envelope
Section titled “The service-config envelope”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.
Instance routes
Section titled “Instance routes”| Method | Path | Purpose |
|---|---|---|
| GET | /repositories | Registered repositories |
| GET | /tenant-repositories | Per-tenant on-demand repositories |
| GET | /embedded-info | What products are compiled into this binary |
| POST | /license-activate | {"token"} → entitlement map |
| GET | /license-status | Current entitlements |
| POST | /license-deactivate | Drop a license |
Marketplace routes — /market/{id}/…
Section titled “Marketplace routes — /market/{id}/…”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.
Errors
Section titled “Errors”| Code | Meaning |
|---|---|
META_READONLY | Write against a read-only repo |
META_NOT_LOCAL | Git porcelain against a non-local repo |
META_MISSING_CUSTOMER | No X-Customer header and no JWT customer claim |
| ”given version is not allowed” | ?version= outside the repo’s allowedversions |
| 403 | Entitlement/access-rule denial |