Hanzo

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 URLhttps://api.hanzo.ai
Operations8
AuthAuthorization: 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.

ParameterInTypeRequiredDescription
wildcard1pathstringyes

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.

ParameterInTypeRequiredDescription
wildcard1pathstringyes

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.

ParameterInTypeRequiredDescription
qquerystringQ is the free-text query the lexical index scores relevance on.
orgquerystringOrg narrows to one builder org: hanzo | lux | zoo.
kindquerystringKind narrows to repo | site.
originquerystringOrigin narrows to what a row IS to you: template | community | third-party | product.
archetypequerystringArchetype narrows to one project archetype.
languagequerystringLanguage narrows to one implementation language.
templatequerystringTemplate narrows a lane to ONE lineage: the id of the parent everything returned was forked from.
forkablequerystringForkable is tri-state: "true" selects the forkable rows, "false" selects the rest, and anything else — including absent…
limitquerystringLimit caps the page at 200, default 50.
offsetquerystringOffset is where the page starts, default 0, with the same tolerance.

All Hanzo APIs · Interactive reference

How is this guide?

On this page