Hanzo

Get

Get — 26 operations on https://api.hanzo.ai.

The REST reference for Get — 26 operations, generated from the OpenAPI document.

Base URLhttps://api.hanzo.ai
Operations26
AuthAuthorization: Bearer $HANZO_API_KEY

analytics

GET /v1/event.js

The Hanzo event tag — the one-line install for a surface with no bundler

Serves the browser tag that autocaptures pageviews (initial and SPA) and uncaught errors onto the canonical wire at POST /v1/event.

Install is one line, and it is the same line for a Hanzo property and for a customer's own page:

<script defer src="https://api.hanzo.ai/v1/event.js" data-key="pk-…"></script>

data-key is the publishable key the project mints; data-product optionally names the emitting surface. The key may also ride the src as ?key= for a host that strips data attributes.

WITHOUT A KEY THE TAG SENDS NOTHING. A keyless beacon is accepted 200 into $public, a reserved tenant the owning org cannot read — so silence is the honest failure, and the tag picks it rather than reporting success into a tenant nobody reads.

commerce

GET /_/commerce/healthz

Answers ok whenever the commerce subsystem is mounted. It is registered before the module embed boots, so it keeps answering even when the embed failed and every business route serves the fail-closed 503 — which is the point: it reports that the process is reachable, never that the money plane is healthy. Unauthenticated, and under /_ so the ingress withholds it publicly.

A named handler, not a closure, so zipdoc can lift this prose into the registry.

GET /_/commerce/providers

List the payment providers configured for your own tenant

Returns the caller's own tenant row projected to a public view with the KMS paths stripped, so a provider's name and enabled flag are visible and its credential location never is. The tenant is derived from the IAM owner claim and from nothing else — there is no tenant parameter to supply, so a cross-tenant read is not expressible. A tenant admin or a platform admin may call it; a plain authenticated user is refused 403 and an anonymous one 401. A caller whose owner claim has no tenant row gets a 404 byte-identical to the one a cross-tenant probe would get.

git

GET /{org}/{project}/{repo}/info/refs

Advertise a repository's refs to a git client

The ref-advertisement phase of git's smart-HTTP protocol — the first request a clone, a fetch and a push all make. ?service= selects which: git-upload-pack advertises for a fetch, git-receive-pack for a push, and any other value is 400.

ANONYMOUS ONLY FOR FETCH, AND ONLY ON A PUBLIC REPOSITORY. The push advertisement always requires an authenticated org, and where a path org is present it must equal the authenticated one. A private repository reached without its org is 404, indistinguishable from one that does not exist. Addressed at the git host's root with the PROJECT as a middle path segment — the canonical-URL form of the project-scoped remote, since a git client has no header to carry a project. Served only on the dedicated git host; elsewhere it falls through. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.

ParameterInTypeRequiredDescription
orgpathstringyes
projectpathstringyes
repopathstringyes

GET /{org}/{repo}/blob/{wildcard1}

View a file in a repository

One file's contents at one revision, with its size and line count. A BINARY file is reported as binary rather than dumped into the page. The path after /blob/ is the file and ?ref= selects the branch, tag or commit. An unknown ref or a path that is not a file in it is 404. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served only on the dedicated git host, where a browse URL matches the clone URL; on the API and console hosts it falls through to their own routes, so it can never shadow them.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes
wildcard1pathstringyes

GET /{org}/{repo}/commits

Read a repository's commit log

The hundred most recent commits on one ref, each with its author, message and date. ?ref= selects the branch, tag or commit, defaulting to the repository's default branch; an unknown one is 404. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served only on the dedicated git host, where a browse URL matches the clone URL; on the API and console hosts it falls through to their own routes, so it can never shadow them.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes

GET /{org}/{repo}/info/refs

Advertise a repository's refs to a git client

The ref-advertisement phase of git's smart-HTTP protocol — the first request a clone, a fetch and a push all make. ?service= selects which: git-upload-pack advertises for a fetch, git-receive-pack for a push, and any other value is 400.

ANONYMOUS ONLY FOR FETCH, AND ONLY ON A PUBLIC REPOSITORY. The push advertisement always requires an authenticated org, and where a path org is present it must equal the authenticated one. A private repository reached without its org is 404, indistinguishable from one that does not exist. Addressed at the git host's root, so git clone https://<git-host>/<org>/<repo>.git works with the canonical URL and no prefix. Served ONLY on the dedicated git host; on the API and console hosts it falls through, so a bare /:org/:repo can never shadow another surface. This is git's own wire protocol, not an API call to make by hand: point a git client at the clone URL and it makes this request itself.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes

GET /{org}/{repo}/tree/{wildcard1}

Browse a directory inside a repository

The contents of one directory at one revision, with breadcrumbs back up and links onward into subdirectories and files. The path after /tree/ is the directory and ?ref= selects the branch, tag or commit, defaulting to the repository's own default branch. An unknown ref is 404, as is a repository with no commits. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served only on the dedicated git host, where a browse URL matches the clone URL; on the API and console hosts it falls through to their own routes, so it can never shadow them.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes
wildcard1pathstringyes

GET /{org}/{repo}

Open a repository's home page

A repository at a glance: its branches, the tree at the tip, its most recent commits, its README rendered, and the HTTPS and SSH clone URLs. ?ref= selects a branch, tag or commit; the default branch is used when it is omitted. A repository with no commits yet renders its clone instructions rather than an error, which is what a caller who has just created one needs to see. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served only on the dedicated git host, where a browse URL matches the clone URL; on the API and console hosts it falls through to their own routes, so it can never shadow them.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes

GET /explore

Discover public repositories across every org

The open, unauthenticated face of the git host: every PUBLIC repository in the fleet, org-qualified, so a project can be found and cloned with no account at all — signing in is for private repos and for writes. Repositories live in per-org stores with no global index, so this unions each org's public rows and is bounded to a fixed number of stores per request, keeping discovery quick however many orgs exist. A fleet with no orgs yet is an empty page, not an error. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served only on the dedicated git host, where a browse URL matches the clone URL; on the API and console hosts it falls through to their own routes, so it can never shadow them.

GET /git/{org}/{repo}/blob/{wildcard1}

View a file in a repository

One file's contents at one revision, with its size and line count. A BINARY file is reported as binary rather than dumped into the page. The path after /blob/ is the file and ?ref= selects the branch, tag or commit. An unknown ref or a path that is not a file in it is 404. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served on every host, which is how the console embeds the git browser under /git.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes
wildcard1pathstringyes

GET /git/{org}/{repo}/commits

Read a repository's commit log

The hundred most recent commits on one ref, each with its author, message and date. ?ref= selects the branch, tag or commit, defaulting to the repository's default branch; an unknown one is 404. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served on every host, which is how the console embeds the git browser under /git.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes

GET /git/{org}/{repo}/tree/{wildcard1}

Browse a directory inside a repository

The contents of one directory at one revision, with breadcrumbs back up and links onward into subdirectories and files. The path after /tree/ is the directory and ?ref= selects the branch, tag or commit, defaulting to the repository's own default branch. An unknown ref is 404, as is a repository with no commits. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served on every host, which is how the console embeds the git browser under /git.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes
wildcard1pathstringyes

GET /git/{org}/{repo}

Open a repository's home page

A repository at a glance: its branches, the tree at the tip, its most recent commits, its README rendered, and the HTTPS and SSH clone URLs. ?ref= selects a branch, tag or commit; the default branch is used when it is omitted. A repository with no commits yet renders its clone instructions rather than an error, which is what a caller who has just created one needs to see. A public repository is readable by anyone; a private one only by its own org. A repository that does not exist and one belonging to another org answer the SAME 404, so the page is never an existence oracle. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served on every host, which is how the console embeds the git browser under /git.

ParameterInTypeRequiredDescription
orgpathstringyes
repopathstringyes

GET /git/explore

Discover public repositories across every org

The open, unauthenticated face of the git host: every PUBLIC repository in the fleet, org-qualified, so a project can be found and cloned with no account at all — signing in is for private repos and for writes. Repositories live in per-org stores with no global index, so this unions each org's public rows and is bounded to a fixed number of stores per request, keeping discovery quick however many orgs exist. A fleet with no orgs yet is an empty page, not an error. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served on every host, which is how the console embeds the git browser under /git.

GET /git

Browse your org's repositories

The repository list for the signed-in caller's org — each repo with its description, default branch, size and last update. SIGNED OUT it renders the public explore page instead of refusing, because most Hanzo repos are open source and the open face is the default one; signed in, the caller's own org shows its private repositories alongside its public ones. This is a server-rendered browser page, not JSON — the console repo-browser reads the same repository through the JSON ops under /v1/git. Repository names, paths and file contents all render through auto-escaping templates rather than being concatenated into HTML. Served on every host, which is how the console embeds the git browser under /git.

iam

GET /.well-known/jwks

Publishes the public keys that verify the tokens issued here — the one URL you point a service at so it can check a token itself, offline, without calling back and without holding any secret of ours.

Keys appear here before they start signing and stay after they stop, so a rotation never leaves a live token unverifiable. Nothing private is ever published.

GET /.well-known/oauth-authorization-server

Returns the OpenID Connect discovery document — the one URL you point a standards-compliant client at so it can find every other endpoint on its own, instead of you configuring them by hand.

It advertises only what is actually implemented, so a client that reads it cannot ask for a flow that will fail: the authorization-code flow, PKCE with S256, the supported grants, and the signing algorithms whose public keys the JWKS really publishes.

The issuer is derived from the host you asked on and is the same value the tokens carry, so a client that pins the issuer never sees it change.

GET /.well-known/openid-configuration

Returns the OpenID Connect discovery document — the one URL you point a standards-compliant client at so it can find every other endpoint on its own, instead of you configuring them by hand.

It advertises only what is actually implemented, so a client that reads it cannot ask for a flow that will fail: the authorization-code flow, PKCE with S256, the supported grants, and the signing algorithms whose public keys the JWKS really publishes.

The issuer is derived from the host you asked on and is the same value the tokens carry, so a client that pins the issuer never sees it change.

o11y

GET /ws/query_progress

Watch one running query's progress over a websocket

The same progress read as /v1/o11y/query_progress, delivered over a websocket: the Upgrade IS the contract, so there is no JSON response to declare and no typed operation to make of it.

It sits outside /v1/o11y on purpose — the upgrade handshake is a transport concern, not a resource — and it was unreachable from the composed binary until the route table named it, because the old wildcard covered only the o11y prefix.

A validated, org-scoped principal is required.

openapi

GET /v1/openapi.json

The API description this SDK was generated from

Serves the OpenAPI document for the routes this process actually answers — generated from the live router at request time, not from a checked-in file that can disagree with it.

On an app it is that app's own surface; on the fleet's front door it is the woven document for every mounted app. Unauthenticated by design: a client has to be able to read the contract before it holds a credential, and the document grants nothing.

Rendered once and served as bytes thereafter, so the route table's immutability is what makes a repeat request a memcpy rather than a re-encode of a megabyte document.

skills

GET /.well-known/agent-skills/{skill}/SKILL.md

One skill's document, as markdown

Serves a single agent skill's SKILL.md as text/markdown — the instructions a client follows once index.json has told it the skill exists, and byte for byte the document that index.json's sha256 for that skill was computed over.

The skill segment is a flat, service-prefixed id (ai_models): one path segment with no separators, so a request can never address anything outside the embedded catalogue. An id of any other shape, or a skill the serving brand does not carry, is {"error":…} at 404 — the same answer, so a probe learns nothing about which is which.

Brand resolution and caching are index.json's: the Host picks the catalogue, and the response is Cache-Control: public, max-age=300. Public — no bearer, no tenant scope.

ParameterInTypeRequiredDescription
skillpathstringyes

GET /.well-known/agent-skills/index.json

The brand's master catalogue of agent skills

The Agent Skills Discovery catalogue an AI client reads to learn what this deployment can do: every skill, with the sha256 of the SKILL.md that is actually served for it, so a client can verify the document it then fetches.

The catalogue is GENERATED from the per-service OpenAPI specs and embedded in the binary; this route serves those bytes verbatim and never re-derives them, which is what makes the digests hold. Which brand's catalogue you get is decided per request from the Host — api.hanzo.ai answers the Hanzo catalogue, api.lux.network the Lux one, api.zoo.ngo the Zoo one — never one brand's skills on another's surface; a Host whose brand has no embedded catalogue falls back to the deployment brand, then to hanzo.

Public by design: the discovery surface carries no secrets, so there is no bearer and no tenant scope. Answers Cache-Control: public, max-age=300, and a catalogue that is not embedded is {"error":…} at 404.

tasks

GET /tasks/{wildcard1}

The tasks console's assets and client-side routes

Serves the console's static assets on GET, and returns the application shell for any path that is not a file — client-side routing means a deep link into the console is a shell load, not a 404.

A path that looks like a missing asset therefore answers 200 with HTML rather than 404; look at the content type, not the status, when a resource seems to be missing.

This is the task console itself — HTML and hashed assets, not an API. Only GET and HEAD are served; every other method is refused 405. Hashed assets are returned immutable and cached for a year, while the shell is always revalidated, so a new deployment replaces a stale console on the next request.

ParameterInTypeRequiredDescription
wildcard1pathstringyes

GET /tasks

The tasks console

Serves the console's application shell on GET, which is the entry point a browser loads before it calls anything under /v1/tasks/.

This is the task console itself — HTML and hashed assets, not an API. Only GET and HEAD are served; every other method is refused 405. Hashed assets are returned immutable and cached for a year, while the shell is always revalidated, so a new deployment replaces a stale console on the next request.

team

GET /collaborator

Open the live collaborative-editing socket

Upgrades to the hocuspocus WebSocket the Team editor syncs its Y.js documents over: binary frames of document name, message type and payload, with ONE socket multiplexing every document a tab has open. The server is a relay and an ordered update log, not a CRDT engine — it replays the log to each joining peer and broadcasts every update to the rest, which converges because Y.js updates are commutative and idempotent. There is no body; the response is a protocol upgrade.

IT SITS OUTSIDE /v1 ON PURPOSE. The client derives both collaborator lanes from one configured URL — this socket at its root, the markup-snapshot RPC one segment in — so the path is fixed by the editor library's contract rather than chosen by this service.

AUTH IS IN-BAND, PER DOCUMENT, NOT ON THE UPGRADE. The handshake gates only on browser Origin (403 outside the team surfaces; no Origin at all is admitted, which is what a non-browser sends), and then the first frame for a document must be an Auth message carrying the same session or workspace token every other team route verifies — a browser WebSocket cannot set an Authorization header, which is why the token rides inside the protocol. Anything else on an unauthenticated document is answered with one permission denial and nothing further.

Every document is authorized on its own: the document's workspace must be the token's workspace when the token pins one, and the caller must be a member of it. A mismatch, an unknown workspace and a non-member deny alike with "document not found". Rooms are keyed by org and workspace and the persisted log's key embeds both, so a foreign document id can neither join a room nor read a blob.

The server pings every twenty seconds and drops a socket silent for sixty, so a backgrounded tab — whose JS timers are throttled but whose network stack still auto-pongs — stays connected instead of dying into a reconnect loop.


All Hanzo APIs · Interactive reference

How is this guide?

On this page