Meta API
Reference for the meta.svc HTTP surface. For concepts see the Meta block docs.
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 |
Authentication
Section titled “Authentication”Meta accepts three credentials, tried in order, and the first that succeeds wins:
| Order | Credential |
|---|---|
| 1 | API key |
| 2 | Certificate JWT |
| 3 | Bearer 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.
Tenancy
Section titled “Tenancy”CPET 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.
Errors
Section titled “Errors”| Status | Meaning |
|---|---|
400 | Request parse or validation failure |
401 | No credential validated |
403 | The tenant may not access this repository |
404 | No such repository, bundle or artefact |
500 | Unexpected server error |