Hanzo

Marketplace

Package marketplace is the shop for tools and agents: browse, install into your project, publish your own free or priced.

Package marketplace is the shop for tools and agents: browse, install into your project, publish your own free or priced.

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

Specification

HIP-1137 · Marketplace — Listings and Installs — Draft · read the specification →

/v1/marketplace is the shop for tools and agents: browse, install into your project, publish your own free or priced. It is a thin layer over the unified tool plane — discovery reads the tool registry, install and uninstall ARE the registry's activation writes — plus a listing store that says what a tool costs and which wallet is paid. Marketplace never dispatches a tool and never moves money itself. It is implemented in hanzoai/cloud at apps/marketplace (HIP-0106).

Motivation

A marketplace that keeps its own installed-tools table drifts from the registry that actually dispatches, and a price that lives only in one process's memory is not enforced anywhere else. Both defects were real here: the price table, the charger and the wallet resolver were process-globals, the fleet runs one process per app, so in the settling process the table was nil — and reading a nil table as "nothing is priced" made every listed tool free the moment the fleet split (apps/marketplace/marketplace.go:16-30).

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 One store, and what is deliberately not in it

The listing store is one encrypted SQLite file, the deployment's own marketplace (apps/marketplace/store.go:51), keyed by (publisher_org, id) — a publisher only ever mutates its own listings. Installs are NOT in it: install and uninstall are the tool registry's activation writes for the caller's (org, project), so there is one store and one truth for what is active (apps/marketplace/marketplace.go:8-15).

§2 The address

Six operations under /v1/marketplace, all typed: discovery (catalog plus listing overlay plus installed flag), the caller org's own listings, publish, unpublish, install, uninstall. A published listing must name a tool that already resolves in the publisher's own scope, so a listing can never advertise a capability that does not exist; a priced listing must name the payout wallet, so a monetized offer is never unpayable; the price is exact to 18 decimal places, so a per-call price below a cent is a real price and not a rounded-away zero.

§3 Money: the table here, the rail elsewhere

Marketplace itself is free (cloud.Free, plugin/marketplace/main.go). A monetized listing is enforced per call by the x402 rail, and the enforcement is four internal-plane operations, each served by the process that owns the answer: tools asks x402 to settle; x402 asks marketplace what it costs and who is paid; x402 asks wallets to resolve the payee; x402 asks commerce to credit it (apps/marketplace/marketplace.go:32-39). The in-process seam stays the fast path where an owner is co-resident; both paths are the same policy and both fail closed, asserted against each other by a one-process test and a five-process test (apps/marketplace/marketplace.go:41-44).

On the plane, the price answer carries the row's recipient, never a request's: a buyer that could state either would buy at its own price or redirect the credit. priced=false means FREE and is an ANSWER — an unlisted tool lands there — while a store failure is an ERROR, because "I could not look it up" must never read as "it costs nothing" (apps/marketplace/rpc.go:22-33,47-50). The price op reads no tenant and requires none: a price is the shop window, the same figure for everyone.

§4 Tenancy

Every REST operation is org-gated on the validated principal (HIP-0026), parked by the bridge the composer installs once at the root. The payee is structurally the publisher's: PublisherOrg is the payee org, and the wallet id resolves only within the org that is asked for, which makes a cross-org credit unconstructible rather than merely unlikely (apps/marketplace/store.go:25-31).

§5 Events, observability, stage, upstream

It publishes nothing on the bus and emits nothing beyond the request span every route gets. The stage is beta (manifest/apps.go:430, Stage: Beta): reached by flag until promoted (HIP-0139 §8). It derives from no upstream.

Rationale

The alternative to "install is activation" is a marketplace-owned installs table, which is a second copy of the registry's fact — the defect the plugin contract names — and it would disagree first exactly where it matters, on whether a priced tool is active. The alternative to asking the owning process for the price was replicating the table into the rail's process, a cache that turns every price change into a coherence problem on the money path.

Security Considerations

The money path is the exposure, and its two failure shapes are opposite. Fail open: a missing price table read as "free" dispensed paid tools for nothing — closed by making absence an error and free an explicit answer. Redirection: a caller-influenced recipient or price turns the rail into a payout to the attacker — closed by binding both to the listing row, publisher-owned and publisher-org-payable only. The listing store's own writes are bounded by the (publisher_org, id) key, so a tenant can unpublish only what it published.

Four surfaces

SurfaceReaches this capability asCoverage
RESTmarketplace at its own prefix6 operations
CLIhanzo marketplace …6 of 6
SDKMarketplaceApi in every published client6 methods
MCPtool marketplace on https://api.hanzo.ai/v1/mcp6 operations, 1 under the document's own id — ask describe for the rest

Quickstart

export HANZO_API_KEY=sk-...   # console.hanzo.ai → API keys

Then the first call — a read that needs nothing but the key. GET /v1/marketplace, operation get_marketplace:

hanzo marketplace get

Answers 200 with object — ok.

Endpoints

EndpointWhat it does
POST /v1/marketplace/installInstall activates one tool for the caller's own org and project.
DELETE /v1/marketplace/listings/{id}Unpublish withdraws one of the caller org's listings from the marketplace and answers 204.
GET /v1/marketplace/listingsReturns the listings the caller's own org has published — what this org is offering, not what it can buy.
POST /v1/marketplace/listingsPublish offers one tool on the marketplace, optionally monetized.
POST /v1/marketplace/uninstallUninstall deactivates one tool for the caller's own org and project, so it stops being dispatchable there.
GET /v1/marketplaceDiscover lists every tool and agent the caller can reach in their own org and project, enriched with any public listing's title, category and price,…

All Hanzo APIs · Interactive reference

How is this guide?

On this page