Zero to Hundred

Busca e comparação de software público. Acesso à conta com escopo para rascunhos próprios; revise e publique no site Zero to Hundred.

Servidor MCP hospedado

npx add-mcp 'https://zerotohundred.ai/api/mcp'

Instala no Claude Code, Codex, Cursor e outros

Documentação

There are 4 ways to send a draft listing to Zero to Hundred. A prefill URL for web platforms, a stable REST API for custom backends, OAuth 2.1 + PKCE for partner apps, and an official MCP server for AI coding tools. Connector callers create drafts; the Builder reviews and publishes in the wizard.

Overview

The connector platform is three layers. Pick the one that fits how your platform works. They all land in the same place: a status="draft" listing the Builder finishes in the Zero to Hundred wizard.

Prefill URL

Web platforms (no backend)

Build one link, drop it in your Share menu. No SDK, no keys. The Builder signs into Zero to Hundred mid-flow and the wizard mounts pre-filled.

REST API

Custom backends

POST a draft with a bearer token. Personal Access Tokens for individual Builders, OAuth 2.1 + PKCE for partner apps acting on a Builder's behalf.

MCP server

AI coding tools

The published local server can create a software draft from a compatible MCP client. The Builder reviews and publishes it on the website.

Public discovery

Search live public software without signing in or sending a token. Use the REST endpoint directly or call z2h_search_marketplace through either MCP server.

curl --get https://zerotohundred.ai/api/v1/discover \
  --data-urlencode "search=invoicing" \
  --data-urlencode "type=tool" \
  --data-urlencode "limit=5"

The JSON response contains items, nextCursor and hasMore. Results contain public listing metadata, not source archives. Search matches words in listing text. An empty result does not prove that no suitable software exists.

REST accepts limit from 1 to 50 and defaults to 20. Repeat filter keys to select multiple values. With a search, the default sort is relevance. If hasMore is true and nextCursor is null, narrow the search. Other sorts support the returned cursor. Requests are rate-limited per IP; on 429, wait for the Retry-After interval.

Prefill URL

The lightest integration: a single link. No auth, no SDK. Add ?prefill=connector to the wizard URL and pass the fields you know as query params. The Builder lands there, signs in (Clerk preserves the query string), and the wizard opens pre-filled. Attribute the funnel with source=<your-platform>. Every draft created this way lands with created_via set to your name.

https://zerotohundred.ai/listings/new?prefill=connector
  &source=your-platform
  &title=My%20Cool%20App
  &shortDescription=Drop-in%20analytics%20for%20indie%20apps
  &demoUrl=https%3A%2F%2Fmycoolapp.example.com
  &repoUrl=https%3A%2F%2Fgithub.com%2Falice%2Fmycoolapp
  &techStack=nextjs,supabase,tailwind
  &type=tool
  &operatingStatus=ready_to_launch
  &domains=analytics,productivity
FieldTypeNotes
prefillrequiredMust be "connector" to activate the prefilled flow.
sourcestringFunnel attribution → created_via. Capped at 40 chars.
titlestringListing title. Truncated to 200 chars.
shortDescriptionstringOne-line pitch. Truncated to 160 chars.
longDescriptionstringFull description.
demoUrlurlAccepted only if http(s)-shaped.
repoUrlurlGitHub repo → sourceRepoUrl. Note: the param is repoUrl, not sourceRepoUrl.
techStackcsvComma-separated, max 10.
askingPricenumberDigits with up to 2 decimals.
typeenumOne of the 9 listing types (see Field values).
operatingStatusenumOne of the 3 operating statuses.
domainscsvComma-separated, max 5.

Everything is re-validated server-side. The prefill only seeds the form; the Builder confirms before anything is written. A ready-to-drop React button for a Share menu lives in the partner kit.

Authentication

The REST API takes a bearer token in the Authorization header. Cookies are never accepted on authenticated listing routes. Public discovery needs no account or token. There are two token types:

Authorization: Bearer z2h_pat_<prefix>_<secret>   # Personal Access Token
Authorization: Bearer z2h_oat_<secret>            # OAuth access token (1h TTL)
  • Personal Access Token. A Builder creates an account or signs in on the website, then mints one at /account/developers. Best for individual Builders and CLI/agent use.
  • OAuth access token. A partner app obtains one via the OAuth 2.1 + PKCE flow to act on a Builder's behalf.

Request only the scopes your integration uses. Owned reads need listings:read; draft creation, edits and source uploads need listings:write. Request both when you need both workflows. Account creation and sign-in happen on the website. MCP tools do not collect passwords or create accounts.

Scopes: listings:write, listings:read, and listings:publish. The publish scope is reserved. It needs the async source scan and isn't grantable at v1.

Failure semantics: a missing or unresolvable token returns a uniform 401 { "error": "Unauthorized" } (with WWW-Authenticate: Bearer). It is the same response for missing/invalid/expired/revoked, so a token can't be probed. A valid token missing the required scope returns 403 { "error": "Forbidden", "reason": "missing_scope:..." }.

REST API

Base path https://zerotohundred.ai/api/v1. Every response carries CORS headers (Access-Control-Allow-Origin: *, methods GET, POST, PATCH, OPTIONS, and Expose-Headers: Retry-After so cross-origin clients can read the rate-limit backoff). OPTIONS preflight returns 204. Connector callers only ever create draft rows. Public reads never see them.

POST/api/v1/listings

Create a draft listing. Scope listings:write. Rate limit 10 requests / 60s, keyed per token.

Compatibility notice: source code default

Draft creation now defaults sourceCodeIncluded to false when you omit it. Previously, omission defaulted to true. Update your client to send sourceCodeIncluded: true only after the Builder confirms that the listing includes source code. A repository URL alone does not make that choice. This applies to new REST drafts authenticated with a Personal Access Token or OAuth access token. Existing listings retain their saved choice.

curl -X POST https://zerotohundred.ai/api/v1/listings \
  -H "Authorization: Bearer z2h_pat_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "My SaaS",
    "shortDescription": "One-line pitch",
    "longDescription": "What it does, in ~100 words.",
    "type": "micro_saas",
    "operatingStatus": "ready_to_launch",
    "domains": ["analytics", "productivity"],
    "askingPrice": 199,
    "demoUrl": "https://example.com",
    "sourceRepoUrl": "https://github.com/me/myapp",
    "techStack": ["nextjs", "tailwind"],
    "source": "api"
  }'

Body

FieldTypeNotes
titlestring · required1 to 200 chars.
shortDescriptionstring · required≤ 160 chars.
longDescriptionstring · required≥ 20 chars.
typeenum · requiredSee Field values.
operatingStatusenum · requiredSee Field values.
domainsstring[]Defaults [].
askingPricenumberNon-negative.
demoUrlurlhttp/https only.
thumbnailUrlurlhttp/https only.
imageUrlsurl[]Max 5, each http/https.
techStackstring[]Defaults [].
testEnvUrl / testEnvInstructionsstringOptional reviewer test env.
testEnvCredentialsstringEncrypted at rest; never returned.
sourceCodeIncludedbooleanREST drafts default to false. Set true only when the Builder confirms source is included.
sourceRepoUrlurlgithub.com/<owner>/<repo>; owner must match your connected GitHub handle.
sourcestringAccepted for compatibility but ignored. The server records PAT creates as api and OAuth creates under the registered client ID.

201 Created

{
  "id": "...", "slug": "...", "status": "draft",
  "createdAt": "<ISO8601>",
  "editUrl": "https://zerotohundred.ai/listings/<slug>/edit",
  "publishUrl": "https://zerotohundred.ai/listings/<slug>/edit?step=review"
}

Errors: 400 (invalid JSON, Zod validation with issues[], bad URL, or GitHub-ownership mismatch), 401 / 403, 429, 500.

List your own listings, newest first. Scope listings:read. No rate limit. Keyset pagination: pass limit (default 25, max 100) and the opaque cursor from the previous page.

GET https://zerotohundred.ai/api/v1/listings?limit=25&cursor=<opaque>

200 OK
{
  "items": [
    { "id","slug","title","status","type","operatingStatus",
      "askingPrice","demoUrl","thumbnailUrl","createdVia",
      "createdAt","updatedAt","editUrl","publishUrl" }
  ],
  "nextCursor": "<opaque>|null"
}

nextCursor is non-null only when more rows exist past this page. Stop when it's null.

GET/api/v1/listings/{slug}

Read one listing you own. Scope listings:read. A slug you don't own returns 404 (anti-probe, never 403). Returns the full object; testEnvCredentials is never included.

Update a draft. Scope listings:write. Rate limit 10 / 60s per token. Drafts only. A non-draft listing returns 409. All body fields are optional; unknown keys are rejected. Send a field as null to clear it only for askingPrice, demoUrl, videoUploadUrl, thumbnailUrl or sourceRepoUrl. The legacy testEnvUrl, testEnvCredentials and testEnvInstructions fields also accept null. Omitted fields stay unchanged. Send an empty array to clear an array field.

PATCH https://zerotohundred.ai/api/v1/listings/<slug>
{ "askingPrice": 149, "techStack": ["nextjs","trpc"] }

200 OK
{ "id","slug","status":"draft","editUrl","publishUrl" }

Source archive uploads

Attach source to a draft you own with listings:write. The REST endpoints below accept a PAT or a REST OAuth grant. Hosted MCP exposes the same sequence through z2h_request_source_upload and z2h_confirm_source_upload.

Select the archive first. Show the Builder this exact statement and require their explicit acceptance for that archive before requesting or confirming an upload:

I own or have the rights to sell the codebase I am about to upload.

The current ownershipVersion is 2026-09-27. Connecting an account or creating a draft does not establish acceptance. If the archive changes, ask the Builder to accept the statement for the replacement archive.

FieldTypeNotes
contentTypestringapplication/zip, application/x-zip-compressed, application/gzip, application/x-gzip, or application/x-tar.
sizeBytespositive integerArchive size in bytes, at most 104857600 bytes, or 100 MiB. The server also checks the stored file's actual size and archive signature.
ownershipAcceptedtrueSend only after the Builder explicitly accepts the statement for the selected archive.
ownershipVersionstring2026-09-27

Request a signed upload URL. Replace the slug with your draft's slug and 1048576 with your archive's size in bytes. JSON request bodies are limited to 8 KiB.

curl --fail-with-body --request POST "https://zerotohundred.ai/api/v1/listings/<slug>/source-bundle" \
  --header "Authorization: Bearer z2h_pat_..." \
  --header "Content-Type: application/json" \
  --data '{
    "contentType": "application/zip",
    "sizeBytes": 1048576,
    "ownershipAccepted": true,
    "ownershipVersion": "2026-09-27"
  }'

200 OK
{
  "signedUrl": "<private signed upload URL>",
  "objectKey": "<returned object key>",
  "contentType": "application/zip"
}

Upload the archive bytes

Keep signedUrl and objectKey private. Set SIGNED_URL locally to the exact returned URL and PUT the selected archive before the URL expires. Use the returned contentType. The ZIP example sends only the archive bytes and its content type to storage. Do not send your account bearer token to the signed URL.

curl --fail-with-body --request PUT "$SIGNED_URL" \
  --header "Content-Type: application/zip" \
  --data-binary @./source.zip

After the PUT succeeds, confirm using the returned object key and the same archive metadata and accepted statement version.

curl --fail-with-body --request POST "https://zerotohundred.ai/api/v1/listings/<slug>/source-bundle/confirm" \
  --header "Authorization: Bearer z2h_pat_..." \
  --header "Content-Type: application/json" \
  --data '{
    "objectKey": "<returned object key>",
    "contentType": "application/zip",
    "sizeBytes": 1048576,
    "ownershipAccepted": true,
    "ownershipVersion": "2026-09-27"
  }'

200 OK
{ "ok": true }

Confirmation verifies the stored archive, attaches it to the draft and records the accepted wording. It sets sourceCodeIncluded to true and replaces any repository source attachment. Confirming the same attached object again returns ok: true without another change.

Errors include 400 for invalid JSON, metadata or archive bytes, 401 for invalid authentication, 403 for a missing scope, 404 for a missing or unowned listing, and 409 when the draft or source eligibility changes. On 429, wait before retrying. A successful PUT alone does not attach source; confirmation must succeed.

These API operations accept drafts only. If your MCP host cannot read the selected file and PUT its bytes, open the listing's editUrl and upload in the web wizard. The Builder finishes source review and publication there after the required gates pass.

OAuth 2.1 + PKCE

For partner apps acting on a Builder's behalf. Authorization-code + PKCE only. No implicit flow, no password grant. Register an app to get a client_id; choose public (PKCE-only, no secret, for browser/CLI/native clients) or confidential (a client_secret you keep server-side).

The following flow creates a REST API grant and omits resource. Hosted MCP requires a separate resource-bound grant, described below. Register your client and its exact redirect URI before starting either flow. The authorization server does not advertise automatic client registration.

1 · Authorize

Send the Builder to the consent screen. This is a page route at /oauth/authorize (not under /api/v1). PKCE is required. A request without code_challenge is rejected.

GET https://zerotohundred.ai/oauth/authorize
  ?client_id=<your-client-id>
  &redirect_uri=<exact-registered-uri>
  &response_type=code
  &scope=listings:write%20listings:read
  &state=<csrf-token>
  &code_challenge=<base64url(sha256(verifier))>
  &code_challenge_method=S256

→ redirects to: <redirect_uri>?code=<code>&state=<state>
   (or ?error=access_denied&state=<state> on deny)

redirect_uri must match a registered URI exactly (no wildcards). The auth code is single-use and expires in 10 minutes.

2 · Exchange the code for tokens

POST /api/v1/oauth/token (accepts form or JSON; rate-limited 10 / 60s per client).

POST https://zerotohundred.ai/api/v1/oauth/token
grant_type=authorization_code
&client_id=<your-client-id>
&code=<code>
&redirect_uri=<same-as-authorize>
&code_verifier=<pkce-verifier>
# confidential clients ALSO send &client_secret=...
# public clients MUST omit client_secret

200 OK
{ "access_token": "z2h_oat_...", "refresh_token": "...",
  "token_type": "Bearer", "expires_in": 3600,
  "scope": "listings:read listings:write" }

Um cliente público que envia um client_secret é rejeitado (sem rebaixamento silencioso); um cliente confidencial que o omite é rejeitado. Erros usam o formato RFC 6749: invalid_request, invalid_client (401), invalid_grant, unsupported_grant_type.

3 · Atualização e revogação

Atualize com grant_type=refresh_token. Tokens de atualização rotacionam: o antigo é revogado e um novo par é emitido. Repetir um token de atualização revogado revoga todas as concessões ativas para aquele Builder + aplicativo (detecção de comprometimento em cadeia). Revogue qualquer token (acesso ou atualização) via POST /api/v1/oauth/revoke com token=.... Ele retorna 200 { "ok": true } incondicionalmente (RFC 7009).

Autorização MCP hospedada

O endpoint hospedado é https://zerotohundred.ai/api/mcp. Os clientes podem descobrir seu recurso protegido e servidor de autorização nestas URLs públicas:

GET https://zerotohundred.ai/.well-known/oauth-protected-resource/api/mcp
GET https://zerotohundred.ai/.well-known/oauth-authorization-server

Para uma concessão MCP OAuth, envie o resource=https://zerotohundred.ai/api/mcp canônico na autorização, troca de código e em cada atualização. Mantenha exatamente o mesmo valor em cada etapa. Por exemplo, um cliente público registrado usa:

GET https://zerotohundred.ai/oauth/authorize
  ?client_id=<your-client-id>
  &redirect_uri=<exact-registered-uri>
  &response_type=code
  &scope=listings:read%20listings:write
  &state=<csrf-token>
  &code_challenge=<base64url(sha256(verifier))>
  &code_challenge_method=S256
  &resource=https%3A%2F%2Fzerotohundred.ai%2Fapi%2Fmcp

POST https://zerotohundred.ai/api/v1/oauth/token
grant_type=authorization_code
&client_id=<your-client-id>
&code=<code>
&redirect_uri=<same-as-authorize>
&code_verifier=<pkce-verifier>
&resource=https%3A%2F%2Fzerotohundred.ai%2Fapi%2Fmcp

POST https://zerotohundred.ai/api/v1/oauth/token
grant_type=refresh_token
&client_id=<your-client-id>
&refresh_token=<current-refresh-token>
&resource=https%3A%2F%2Fzerotohundred.ai%2Fapi%2Fmcp

Envie solicitações de token como dados de formulário ou JSON. Um cliente confidencial também envia seu client_secret na troca de código e na atualização. Use o token de acesso resultante para autenticar chamadas a /api/mcp. Tokens OAuth vinculados a MCP não podem autenticar chamadas REST diretas de listagem, e concessões OAuth REST não podem autenticar ferramentas MCP hospedadas do Builder. PATs com escopo suportam ambas as interfaces.

Servidor MCP

Adicione https://zerotohundred.ai/api/mcp como uma conexão HTTP Streamable hospedada em um host que a suporte. Busca, comparação e o painel do marketplace não precisam de token. Ferramentas do Builder precisam de um PAT com escopo ou da conexão MCP OAuth descrita acima. Uma conexão de host privada ou personalizada é separada de uma listagem pública de diretório ou aprovação de provedor.

O pacote MCP, @zerotohundred/mcp-server, conecta ferramentas de codificação locais ao Zero to Hundred. Suas ferramentas do Builder leem um Personal Access Token de Z2H_API_KEY. Sem esse token, essas ferramentas retornam um link de configuração em vez de chamar a API. O servidor registra listagens criadas por PAT como api; rótulos de origem fornecidos pelo cliente não estabelecem atribuição de integração.

O servidor local oferece busca pública no marketplace e ferramentas do Builder para rascunhos de propriedade do usuário. Ele pode solicitar um upload de arquivo de origem assinado e confirmar o arquivo após seu cliente MCP enviá-lo. O endpoint hospedado /api/mcp oferece as mesmas ferramentas de listagem com uma concessão OAuth ou Personal Access Token com escopo. Nenhuma ferramenta MCP publica uma listagem; o Builder a revisa e publica no assistente web.

Claude Code, busca pública

claude mcp add z2h -- npx -y @zerotohundred/mcp-server

Claude Code, acesso do Builder

Para usar ferramentas do Builder, configure o PAT no ambiente do servidor e reinicie-o. Para uma nova configuração local:

claude mcp add z2h \
  --env Z2H_API_KEY=YOUR_TOKEN \
  -- npx -y @zerotohundred/mcp-server

Configuração local stdio

Use o formato e local de configuração MCP do seu host. Este servidor executa com command, args e um env opcional contendo o PAT. Omita env para busca pública apenas.

{
  "mcpServers": {
    "z2h": {
      "command": "npx",
      "args": ["-y", "@zerotohundred/mcp-server"],
      "env": { "Z2H_API_KEY": "YOUR_TOKEN" }
    }
  }
}

Ferramentas

O pacote local expõe 7 ferramentas. O MCP hospedado expõe todas as 9 ferramentas abaixo. O painel hospedado depende do suporte a MCP Apps no host; clientes sem ele podem usar a busca de texto e os resultados de comparação.

FerramentaFazChamadasDisponível através de
z2h_search_marketplaceBusca listagens públicas ativas sem tokenGET /api/v1/discoverLocal e hospedado
z2h_compare_marketplace_listingsAtualiza e compara 2 a 4 slugs públicos sem tokenDescoberta públicaHospedado
z2h_show_marketplaceMostra cartões públicos para até 20 slugs sem tokenRecurso público MCP AppHospedado
z2h_create_draft_listingCria um rascunhoPOST /api/v1/listingsLocal e hospedado
z2h_list_my_listingsLista suas listagensGET /api/v1/listingsLocal e hospedado
z2h_get_listingLê uma que você possui por slugGET /api/v1/listings/{slug}Local e hospedado
z2h_update_draft_listingAtualiza um rascunhoPATCH /api/v1/listings/{slug}Local e hospedado
z2h_request_source_uploadObtém uma URL de upload assinada para um rascunho de sua propriedadePOST /api/v1/listings/{slug}/source-bundleLocal e hospedado
z2h_confirm_source_uploadVerifica e anexa o arquivo enviadoPOST /api/v1/listings/{slug}/source-bundle/confirmLocal e hospedado

Não existe ferramenta publish. A publicação executa uma varredura assíncrona de origem e permanece no assistente, onde o Builder revisa o rascunho primeiro.

Valores de campo

type (10 valores)

full_product · micro_saas · tool · template · ai_agent
component · bot · extension · automation · design_system

operatingStatus (3 valores)

ready_to_launch · live · live_with_revenue

domains (34 valores, kebab-case)

ai · analytics · art-design · conference · developer-tools
e-commerce-marketplace · education · entertainment · environmental
fashion · finance · food · gaming · graphic-design · health
interior-design · marketing · membership · non-profit · political
productivity · real-estate · religious · services · social
technology · travel · wedding · other

mode é sempre license (pague uma vez, possua para sempre), e listagens criadas por conectores sempre começam como draft.

Construa uma integração

Gere um Personal Access Token para chamar a API REST ou configurar o servidor MCP, ou adicione um botão de URL pré-preenchida no seu menu Compartilhar. Nenhuma chave necessária.