Catalog
Package catalog is one place to browse every project, app and site built here.
Package catalog is one place to browse every project, app and site built here.
| Base URL | https://api.hanzo.ai |
| Operations | 8 |
| Auth | Authorization: Bearer $HANZO_API_KEY |
catalog
PUT /v1/catalog/entries/{wildcard1}
Replace a catalog entry, keeping its slug
Loads the addressed entry, applies the body over it and answers the stored result. The slug is the entry's IDENTITY and is re-stamped from the path after decoding, so a slug in the body is ignored and a rename is impossible through this address. The slug is matched as a trailing wildcard rather than one path segment because a model's slug IS its callable id and those contain a slash — a segment parameter would stop at it and leave most catalog rows unaddressable. PLATFORM admin only; an unknown slug is 404.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
wildcard1 | path | string | yes |
DELETE /v1/catalog/entries/{wildcard1}
Remove a catalog entry
Deletes the entry with the addressed slug and answers 204. The slug is matched as a trailing wildcard, not a single segment, because a model slug contains a slash. PLATFORM admin only — an org-level admin is refused 403 — and an unknown slug is 404, so the call is safe to repeat but not silently idempotent.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
wildcard1 | path | string | yes |
GET /v1/catalog/entries
The raw catalog entries, including the unpublished ones
Returns every catalog row as stored — the admin view, which unlike the public projection includes entries that are not published. It is cross-tenant platform data, so the gate is a PLATFORM admin: an org-level admin is refused 403 no matter how privileged they are inside their own org, enforced by the handler itself and not only by the route's token middleware.
POST /v1/catalog/entries
Add a catalog entry
Creates a catalog row from the body and answers it at 201. The slug is required and is the globally-unique catalog key, so a second entry claiming a slug already in use is refused 409 rather than shadowing the first. PLATFORM admin only — this is cross-tenant pricing and packaging data, and an org-level admin is refused 403.
POST /v1/catalog/models/refresh
Refresh the model catalog by reading the upstream provider
Pulls the upstream model list and lands it through the same upsert the push door uses, so the rule that a sync owns cost and an administrator owns price holds no matter which door a row came through. It takes no body — the upstream is READ rather than told. If that upstream cannot be read the call answers 502 and writes NOTHING: a sync that cannot see its source must never conclude the source is empty, because that conclusion would withdraw every model on sale. The gate is a PLATFORM principal so the scheduled job's service token qualifies.
POST /v1/catalog/models
Land a syncer's view of the model catalog: upstream costs and machine facts
Takes a batch of model rows and upserts each one's upstream COST and machine-observable facts, answering what was created and changed. It deliberately touches nothing a human owns — not the retail price, not the markup, not the entitlement tier — so a sync can never overwrite an administrator's pricing decision. The gate is a PLATFORM principal rather than a platform ADMIN, because the caller is normally a scheduled job holding the internal service token, which carries platform scope but no admin claim.
POST /v1/catalog/seed
Seed the embedded catalog, without disturbing edits already made
Upserts the shipped catalog seed and answers how many entries it created. It is idempotent and non-destructive — an entry an administrator has since edited is left alone — so it is safe to run against a live catalog to fill in what is missing. PLATFORM admin only; an org-level admin is refused 403.
GET /v1/catalog
Browse searches AND browses the cross-org catalog: every project, app and site the fleet has built, whichever org built it.
It reads TWO corpora and returns them as one page — the published,
world-readable catalog that every caller sees, plus the caller's OWN org's
private entries when the request carries a validated principal. Each row says
which it came from in scope, so a client can warn before sharing a link. An
anonymous caller simply gets the published one; no filter can ever widen a
caller into another tenant's corpus, because the query that would return it is
never run for them.
A request with no q is a browse rather than a search, and both answer the same shape: the page, the total before paging, and the facet counts over the whole matching set.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
q | query | string | — | Q is the free-text query the lexical index scores relevance on. |
org | query | string | — | Org narrows to one builder org: hanzo | lux | zoo. |
kind | query | string | — | Kind narrows to repo | site. |
origin | query | string | — | Origin narrows to what a row IS to you: template | community | third-party | product. |
archetype | query | string | — | Archetype narrows to one project archetype. |
language | query | string | — | Language narrows to one implementation language. |
template | query | string | — | Template narrows a lane to ONE lineage: the id of the parent everything returned was forked from. |
forkable | query | string | — | Forkable is tri-state: "true" selects the forkable rows, "false" selects the rest, and anything else — including absent… |
limit | query | string | — | Limit caps the page at 200, default 50. |
offset | query | string | — | Offset is where the page starts, default 0, with the same tolerance. |
How is this guide?