Stacktree

Publique HTML em uma URL privada e impossível de adivinhar a partir de qualquer cliente MCP. Proteja por senha ou domínio de e-mail; substitua no lugar.

Documentação

Documentação da API Stacktree — recursos para desenvolvedores

Fonte: https://stacktr.ee/docs

[

  Documentação da Stacktree
](https://stacktr.ee/)

  [Agentes](https://stacktr.ee/agents)
  [Documentação](https://stacktr.ee/docs)
  [Casos de uso](https://stacktr.ee/use-cases)
  [Preços](https://stacktr.ee/pricing)
  [Blog](https://stacktr.ee/blog)

[Painel](https://app.stacktr.ee)

Pesquisar na documentação⌘K

  Primeiros passos

    - [Conectar um agente](#connect)

        [Instalador via CLI](#installer)

        - [Claude.ai](#claude-ai)

        - [Claude Code · Codex](#claude-code)

        - [Arquivo de configuração MCP](#mcp-config)

        - [Slack](#slack)

  Referência

    - [API HTTP](#api)

        [Autenticação](#auth)

        - [POST /sites](#post-sites)

        - [PUT /sites/:id](#put-sites)

        - [PATCH /sites/:id](#patch-sites)

        - [Listar · bruto · excluir · restaurar](#more-sites)

        - [Tokens de compartilhamento](#share-tokens)

        - [Chaves de API](#keys)

        - [Código de dispositivo](#device-code)

    - [Servidor MCP](#mcp)

    - [Pagamentos de agentes](#payments)

    - [Domínios personalizados](#domains)

    - [OAuth](#oauth)

    - [Limites](#limits)

        [Erros de plano](#plan-errors)

  Legível por máquina

    - [llms.txt](https://stacktr.ee/llms.txt)

    - [pricing.md](https://stacktr.ee/pricing.md)

    - [auth.md](https://stacktr.ee/auth.md)

    - [x402.md](https://stacktr.ee/x402.md)

[Changelog](https://stacktr.ee/changelog) · [Blog](https://stacktr.ee/blog)

[Painel](https://app.stacktr.ee) · [Preços](https://stacktr.ee/pricing)

Documentação da API Stacktree

O primitivo de publicação para HTML feito por agentes.

privado por padrão nativo de MCP substituição no lugar

Entregando isto a um agente de codificação? Dê a ele a especificação OpenAPI e pronto: api.stacktr.ee/openapi.json para a API HTTP, ou agents.stacktr.ee/openapi.json para a porta de entrada de pagamento por publicação. Servidor MCP: https://api.stacktr.ee/mcp. Índice legível por máquina: stacktr.ee/llms.txt.

Para um passo a passo guiado com sua chave de API real embutida nos trechos de código, abra app.stacktr.ee/connect.

Conectar um agente

Entregue ao agente

Se você tiver um agente aberto, dê a ele isto e ele fará o resto — instala, verifica e aprende a superfície de ferramentas:

`Fetch and follow the setup instructions at https://stacktr.ee/prompt.md`

Funciona em qualquer agente que possa buscar uma URL. As instruções são Markdown simples em stacktr.ee/prompt.md — leia-as antes de executá-las, se preferir.

npx stacktree-install — recomendado

Um único comando conecta todos os agentes de uma vez — Claude Code, Cursor, Codex, OpenCode, Amp — e adiciona a habilidade stacktree-publish para o Claude:

`npx stacktree-install`

Ele faz seu login via um código de uso único em app.stacktr.ee/connect/cli e gera uma chave de API automaticamente; passe uma chave existente como argumento (npx stacktree-install stk_live_…) para pular o login.

Claude.ai — conector personalizado

Sem CLI, sem copiar e colar chave de API.

- Abra [claude.ai/settings/connectors](https://claude.ai/settings/connectors) → Adicionar conector personalizado.

- Cole https://api.stacktr.ee/mcp como URL do servidor MCP remoto.

- Deixe o ID do Cliente OAuth/Secreto em branco — a Stacktree registra automaticamente via Registro Dinâmico de Cliente (RFC 7591).

- Clique em Adicionar → o Claude.ai redireciona você para a Stacktree para fazer login e aprovar. As ferramentas ficam então disponíveis em qualquer conversa.

Claude Code · Codex — CLI

Instalação em uma linha. Sintaxe idêntica entre os dois:

`claude mcp add stacktree -- npx -y stacktree-mcp
codex mcp add stacktree -- npx -y stacktree-mcp`

Ambos expõem as mesmas 25 ferramentas (veja Servidor MCP). Defina STACKTREE_API_KEY no seu shell — gere uma em app.stacktr.ee/api-keys.

Prefere uma habilidade? Instala SKILL.md + script auxiliar no diretório de habilidades do seu agente:

`npx skills@latest add stevysmith/stacktree-skill
export STACKTREE_API_KEY=stk_live_...`

Fonte: github.com/stevysmith/stacktree-skill · a coleção completa em stacktr.ee/skills

Arquivo de configuração MCP — Cursor / Claude Desktop / Windsurf / Zed

`{
  "mcpServers": {
    "stacktree": {
      "command": "npx",
      "args": ["-y", "stacktree-mcp"],
      "env": { "STACKTREE_API_KEY": "stk_live_..." }
    }
  }
}`

Coloque em ~/.cursor/mcp.json, ~/Library/Application Support/Claude/claude_desktop_config.json, ~/.codeium/windsurf/mcp_config.json ou na chave context_servers nas configurações do Zed.

Slack

Adicione o aplicativo do Slack (uma aprovação; a instalação gera para o espaço de trabalho sua própria identidade gratuita, sem necessidade de conta na Stacktree). Depois, ⋮ → Hospedar na Stacktree em qualquer mensagem com um arquivo .html ou .md — em canais ou DMs — publica um link privado de volta na conversa. Reenviar o mesmo nome de arquivo republica na mesma URL. /stacktree link migra os sites do espaço de trabalho para uma conta de painel. Detalhes: stacktr.ee/slack.

API HTTP

Autenticação

Três métodos, todos resolvem para o mesmo contexto de usuário:

  Authorization: Bearer stk_live_…Chave de API
  Crie em [app.stacktr.ee/api-keys](https://app.stacktr.ee/api-keys) — ou deixe um agente comprar a própria via [x402 ou MPP](#payments).

  Authorization: Bearer <clerk-session-jwt>sessão
  Token de sessão do Clerk, para chamadas originadas no painel.

  Authorization: Bearer <oauth-jwt>OAuth
  Token de acesso de `/oauth/token`, usado por conectores personalizados.

POST/sites Envie um único arquivo HTML/markdown ou um zip. multipart/form-data. Envios anônimos funcionam — sem cabeçalho de autenticação — e duram 24 horas.

  filearquivoobrigatório
  .html / .htm / .md / .zip

  public_slugstring
  Subdomínio público opcional; somente autenticado.

  passwordstring
  Proteção por código de acesso na exibição. Funciona em todos os planos, incluindo todas as 3 páginas do plano gratuito e publicações anônimas.

  expires_in_hoursnumber | "never"
  Padrão: 24h anônimo, sem expiração em plano pago. Gratuito é limitado a 7 dias. Um número acima do teto é ajustado para ele e a resposta informa isso (`expiry_clamped: true`). `"never"` em um plano com teto é recusado, não silenciosamente encurtado: `409 expiry_clamped`, nada é publicado, e o corpo carrega `would_expire_at_iso`. Isso é deliberado, porque um 201 é lido como sucesso e a permanência é repetida a uma pessoa antes que alguém verifique um sinalizador. Envie `accept_clamp=true` para aceitar o teto. Omita o campo completamente (ou envie vazio) e o padrão do próprio plano se aplica, tanto via MCP quanto via API bruta. Um valor que não seja um número de horas ou a palavra `"never"` — `"7d"`, `-5`, `"soon"` — é `400 invalid_expiry` e nada é publicado: antes era lido como "nenhum prazo solicitado", o que em um plano pago significava uma página permanente que o chamador não havia pedido.

  accept_clamp"true"
  Necessário apenas junto com `expires_in_hours=never` em um plano que limita a vida útil da página: indica que o teto é aceitável e publica.

  Idempotency-Keycabeçalho
  Torna uma nova tentativa segura. Qualquer string única, de 1 a 255 caracteres ASCII visíveis. A mesma chave com o mesmo corpo dentro de 24 horas retorna a página original (mesmo id, mesma URL, mesmos tokens) com `Idempotent-Replay: true`, e não gasta uma segunda página contra o limite vitalício do plano Gratuito. Um corpo diferente sob a mesma chave é `422 idempotency_key_reused`, nunca a página antiga. Duas requisições com a mesma chave não podem ambas publicar: o perdedor recebe `409 idempotency_key_in_progress` e deve tentar novamente. As chaves são limitadas por chamador. Em uma publicação anônima não há conta para limitar e o escopo é o endereço de rede, então a própria chave deve ser impossível de adivinhar (um UUID): uma curta é `400 idempotency_key_too_weak`, porque dois agentes atrás de um IP de escritório ambos usando uma chave de modelo compartilhado `"1"` entregariam ao segundo a página do primeiro e seu `claim_token`. Se a página que uma chave criou foi desde então excluída ou queimada, a nova tentativa é `409 idempotent_page_gone` em vez de um 201 para um link morto.

  burn_after_read"true"
  Excluir após a primeira visualização.

  agentation"true"
  Injetar barra de ferramentas de feedback na exibição.

  csp_strict"false"
  Desativar CSP estrito (padrão ativado). A política estrita permite Google Fonts e incorporações de Loom / YouTube / Vimeo / Wistia / Descript / Calendly, e bloqueia scripts remotos e imagens remotas. Uma publicação que contenha algo que a política bloquearia ainda é bem-sucedida e retorna um array `warnings` informando o que não será renderizado.

  e2e"true"
  Tratar o envio como texto cifrado; a chave de descriptografia fica no fragmento da URL e nunca é enviada à Stacktree.

  pii_checkoff | warn | block
  Padrão warn (a camada MCP substitui para block).
`curl -F file=@page.html \
     -F password=hunter2 \
     -F expires_in_hours=72 \
     -H "Authorization: Bearer stk_live_..." \
     https://api.stacktr.ee/sites`
`{
  "id": "…",
  "url": "https://stacktr.ee/p/abc123…/",
  "visibility": "unlisted",
  "expires_at": 1781234567,
  "expires_at_iso": "2026-06-08T12:02:47Z",
  "ttl_seconds": 604800,
  "expiry_clamped": false,
  "expiry_ceiling_hours": 168,
  "expiry_source": "plan_ceiling",
  "file_count": 1,
  "size_bytes": 1234,
  "has_password": true,
  "agentation": false
}`

PUT/sites/:idOrSlug Substitui os arquivos de um site no lugar — a URL nunca muda, e nenhuma segunda página é criada. Dois formatos de corpo: application/json com uma string html, que é o que os trilhos pagos já falam, ou multipart/form-data com os mesmos campos do POST (o único formato que aceita um zip, um PDF ou texto cifrado e2e). Três credenciais, uma por requisição: uma chave de conta ou token OAuth; o próprio claim_token da página enquanto ela não for reivindicada (Authorization: Claim <claim_token>, veja abaixo); ou, em uma página paga por carteira, um desafio de carteira assinado. Qualquer outra coisa é um 401. Sites criptografados de ponta a ponta devem ser substituídos com envios multipart e2e=true (sem rebaixamento silencioso para texto simples).

`curl -X PUT https://api.stacktr.ee/sites/my-deck \
     -H "Authorization: Bearer stk_live_..." \
     -H "Content-Type: application/json" \
     -d '{"html":"<!doctype html><h1>v2</h1>"}'`

Os campos opcionais são os mesmos de qualquer forma: expected_updated_at (recusar a gravação se a página mudou por baixo de você), pii_check, e em multipart e2e. Em JSON, filename substitui uma página publicada como ativo de máquina em seu próprio caminho em vez de realocá-la para index.html.

PATCH/sites/:idOrSlug Atualiza configurações sem reenviar arquivos. Corpo JSON.

  passwordstring | null
  Define ou remove a proteção por código de acesso. Funciona em todos os planos; remover uma sempre funciona também.

  expires_in_hoursnumber | null
  `null` (ou a string `"never"`) cancela a expiração em um plano pago. Em um plano com teto, é recusado (`409 expiry_clamped`, nada no PATCH foi aplicado) em vez de silenciosamente se tornar 7 dias; adicione `accept_clamp: true` para aceitar o teto. Um número acima do teto é ajustado, com `expiry_clamped: true` na resposta. Números podem ser enviados como strings (`"24"`) e significam o mesmo aqui que na publicação; qualquer coisa que não seja legível como horas nem `"never"` é `400 invalid_expiry` e nada é alterado.

  allowed_email_domainstring | null
  Os visualizadores verificam um email nesse domínio antes de a página ser renderizada. Somente planos pagos; Gratuito recebe `402 plan_viewer_gate_not_available`.

  public_slugstring | null
  Reivindica ou libera um subdomínio público.

  agentation · burn_after_read · csp_strictboolean
  Alterna os comportamentos de exibição documentados no POST.
`curl -X PATCH \
     -H "Authorization: Bearer stk_live_..." \
     -H "Content-Type: application/json" \
     -d '{"agentation": true, "expires_in_hours": null}' \
     https://api.stacktr.ee/sites/my-deck`

Listar · buscar · bruto · excluir · restaurar

  GET/sites
  Lista seus sites. Páginas que expiraram ou foram excluídas permanecem na lista em vez de desaparecer: elas carregam `deleted_at`, `delete_reason` e `restorable_until`. Verifique `deleted_at` antes de entregar a alguém um `url`: uma linha que o tenha definido é um link morto.

  GET/sites/:idOrSlug
  Um site, com manifesto de arquivos + `preview_url` absoluto.

  GET/raw/:token
  HTML da página sem head/scripts — texto limpo para realimentar um agente. Respeita proteções por senha.

  DELETE/sites/:idOrSlug
  Tira a página do ar imediatamente: o link está morto para todos que o possuem e o slot do plano é liberado na hora. O conteúdo é mantido por 30 dias, e `restorable_until` na resposta é o prazo após o qual é destruído definitivamente. No Gratuito, isso não devolve um slot de página vitalício, porque esse limite conta publicações, não páginas ativas. Excluir uma página que já está fora do ar retorna `already_deleted: true` em vez de um erro.

POST/sites/:idOrSlug/restore Coloca uma página excluída ou expirada de volta no mesmo URL, com o mesmo id, token, slug e histórico de leitura, para que links já enviados voltem a funcionar. Isso, e não outra publicação, é a resposta para um 409 site_deleted: republicar gera um URL diferente e gasta outra página vitalícia, enquanto restaurar não gasta nada. É um resgate, não uma renovação, então leia expires_at_iso e restored_for da resposta: uma página que ficou sem tempo em um plano com teto de expiração volta por 48 horas (restored_for: "grace", e restore_grace_hours informa o número), não por uma vida útil completa renovada. Uma página excluída pelo proprietário mantém o prazo que já tinha ("kept"), inclusive sem prazo algum. Retorna 404 após os 30 dias, e também para uma remoção por violação, que nunca pode ser restaurada.

Os números de visualizações são limitados pelo plano. GET /sites e GET /sites/:idOrSlug retornam metrics_locked: true, com view_count, unique_viewers e last_viewed_at como null, quando o plano não tem métricas de visualização (anônimo e Free). Um booleano opened chega em todos os planos, então você pode saber que alguém leu a página sem ver quantos o fizeram. A ocultação é feita no servidor, então um agente lendo este JSON vê exatamente o que o painel mostra.

Tokens de compartilhamento

`POST   https://api.stacktr.ee/sites/:idOrSlug/share-tokens   { "label": "alice", "max_uses": 5, "expires_in_hours": 168 }
GET    https://api.stacktr.ee/sites/:idOrSlug/share-tokens
DELETE https://api.stacktr.ee/share-tokens/:tokenId`

Retorna um URL com ?t=… anexado. Ignora a proteção por senha quando válido; revogável por token; contador opcional de uso máximo e expiração.

Feedback

`GET    https://api.stacktr.ee/sites/:idOrSlug/feedback
POST   https://api.stacktr.ee/feedback/:id/resolve           { "note": "fixed the header spacing" }
DELETE https://api.stacktr.ee/feedback/:id`

Anotações de visualizadores deixadas pela barra de ferramentas Agentation na página (ative com agentation no upload, PATCH ou set_agentation). Cada item traz o comentário mais o elemento anotado, texto selecionado, intenção e gravidade. Não resolvidos primeiro. O ciclo: leia o feedback → corrija a página com update_site (mesmo URL) → resolva.

Reações e engajamento

`GET    https://api.stacktr.ee/sites/:idOrSlug/reactions      { counts, total, reactors, messages }
GET    https://api.stacktr.ee/sites/:idOrSlug/engagement     { sessions, median_active_seconds, avg_scroll, read_to_end_pct, buckets }`

Como uma página foi recebida, lido pelo proprietário. Reações: ative a barra de reações na página por site (Configurações do painel) e os visualizadores reagem com um emoji ou deixam uma nota privada curta, sem conta. Engajamento (Studio e acima): métricas de leitura agregadas e sem PII: tempo típico na página, profundidade de rolagem, taxa de leitura até o fim e um mapa de calor de atenção com 10 faixas de permanência por profundidade da página. Sem gravação, sem replay de sessão. Ambos alimentam o sino de atividade do painel e o resumo diário opcional por e-mail.

Chaves de API

`POST   https://api.stacktr.ee/api-keys      { "label": "claude desktop" }
GET    https://api.stacktr.ee/api-keys
DELETE https://api.stacktr.ee/api-keys/:id`

Fluxo de código de dispositivo — coloque uma chave em um agente sem navegador

Concessão de Autorização de Dispositivo OAuth 2.0 (RFC 8628). É isso que npx stacktree-install executa, e pode ser chamado diretamente por qualquer agente: o agente imprime um URL e um código curto, um humano aprova no próprio dispositivo e o agente consulta até uma chave voltar. Use quando a conta já pertence a uma pessoa — um agente que não tem humano para perguntar deve comprar sua própria chave via x402 em POST https://api.stacktr.ee/provision.

`POST https://api.stacktr.ee/api-keys/device-code        { "client_hint": "my-agent" }
  → { device_code, user_code, verification_url, verification_url_complete, interval, expires_in }

# print verification_url_complete for the human, then poll every "interval" seconds:
POST https://api.stacktr.ee/api-keys/device-code/poll   { "device_code": "…" }
  → { "status": "pending" }                     keep polling
  → { "status": "authorized", "api_key": "stk_live_…" }   store it; shown once
  → { "status": "denied" | "expired" }          stop`

Sem autenticação em nenhuma das chamadas. Os códigos duram 10 minutos, a aprovação do humano gera a chave na conta dele e a chave é entregue exatamente uma vez — uma consulta que a perca significa reautorizar. Limitado por IP. A chave stk_live_ resultante funciona na API REST e no MCP igualmente.

Servidor MCP

Servidor MCP HTTP Streamable em https://api.stacktr.ee/mcp (especificação 2025-11-25), expondo 25 ferramentas. Duas credenciais, ambas aceitas no mesmo endpoint:

- Authorization: Bearer stk_live_… — uma chave de API. Sem navegador, sem fluxo OAuth, nada para registrar: a mesma chave que dirige a API REST dirige o MCP. Este é o caminho para um agente não supervisionado e para qualquer cliente que só possa enviar um cabeçalho estático. Um agente sem chave alguma pode comprar uma via [x402](#payments) em POST https://api.stacktr.ee/provision, ou se vincular à conta existente de um humano com o [fluxo de código de dispositivo](#device-code) abaixo.

- OAuth 2.1 + Registro Dinâmico de Cliente — para conectores agindo em nome de um humano conectado (claude.ai, Cursor e afins). Nada para pré-registrar; veja [OAuth](#oauth).

Cookies de sessão deliberadamente NÃO são aceitos aqui, então um navegador não pode ser feito para dirigir o MCP entre sites. Envie exatamente uma credencial.

`curl -X POST https://api.stacktr.ee/mcp \
  -H "Authorization: Bearer stk_live_..." \
  -H "Accept: application/json, text/event-stream" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'`

Ferramentas (25)

  publish_html&rarr; { id, url, slug, unlisted_token, … }
  Transforma HTML em um link que uma pessoa pode abrir no navegador.

  update_site&rarr; { id, url, file_count, size_bytes }
  Substitui o HTML de um site existente no lugar. O URL permanece o mesmo, então todos para quem você já enviou veem a nova versão sem receber nada.

  delete_site&rarr; { ok, restorable_until, already_deleted }
  Tira uma página do ar. O link morre imediatamente para todos que o têm, e o conteúdo é mantido por 30 dias: restore_site o coloca de volta no mesmo URL, com o mesmo id, token, slug e histórico de leitura, a qualquer momento nessa janela.

  restore_site&rarr; { ok, id, url, expires_at, … }
  Coloca uma página de volta no mesmo URL após ser excluída ou ficar sem tempo.

  claim_site&rarr; { ok, id, expires_at, expires_at_iso, … }
  Adota uma página publicada sem conta na conta à qual esta conexão está autenticada.

  set_password&rarr; { ok }
  Define ou limpa (null) uma senha de visualizador em um site. Funciona em todos os planos (o gratuito cobre suas 3 páginas).

  set_expiry&rarr; { ok, expires_at, expires_at_iso, ttl_seconds, … }
  Define expiração em horas a partir de agora, ou null para nunca. Um número maior que o permitido pelo plano é reduzido ao teto e a resposta informa isso (expiry_clamped: true).

  create_share_link
  Gera um link de compartilhamento endereçado a uma pessoa. Coloque o nome dela em `label` — cada abertura por este link volta atribuída a esse nome, visível na página no painel e no e-mail de confirmação de leitura.

  list_share_links
  Os links de compartilhamento em uma página, com quantas aberturas atribuídas cada um teve e quando foi aberto pela última vez. `opens` conta aberturas humanas da página por esse link; `use_count` é o contador bruto de aplicação para max_uses e não é uma métrica de leitura.

  revoke_share_link&rarr; { ok }
  Mata um link de compartilhamento. A página e todos os outros links continuam funcionando — é assim que você corta um destinatário sem reemitir nada para os outros.

  set_agentation&rarr; { ok }
  Alterna a barra de ferramentas de feedback Agentation na página. Quando ativa, os visualizadores podem anotar a página e seus comentários são coletados — leia-os com list_feedback, corrija a página com update_site e depois resolva com resolve_feedback.

  set_email_gate&rarr; { ok }
  Restringe o acesso do visualizador a um domínio de e-mail específico. Apenas planos pagos: em um plano gratuito, isso retorna HTTP 402 plan_viewer_gate_not_available.

  list_sites&rarr; { sites }
  Lista sites de propriedade do usuário autenticado, mais recentemente atualizados primeiro.

  get_me&rarr; { clerk_user_id, auth_method, plan, email, … }
  Quem esta conexão está publicando como, e o que seu plano realmente permite.

  list_client_spaces&rarr; { spaces }
  Lista os espaços de cliente nesta conta: slug, nome, page_count, última atividade, hostname (o endereço próprio do espaço, ex.: acme.theiragency.com, quando um está conectado) e portal_enabled (se o espaço serve um portal de cliente gerado nesse endereço).

  set_client&rarr; { ok }
  Arquiva um site existente sob um espaço de cliente (por nome ou slug, criado automaticamente), ou passe client: null para desanexá-lo como página flutuante.

  create_client_space&rarr; { ok, space }
  Cria um espaço de cliente antes de publicar qualquer coisa nele. Raramente necessário: publish_html com um argumento client cria automaticamente o espaço sob as mesmas regras de capitalização e slug, então use isso apenas quando o usuário estiver configurando um cliente antes do trabalho.

  update_client_space&rarr; { ok }
  Renomeia um espaço de cliente, arquiva ou desarquiva, ou define a proteção de visualizador que cobre todas as páginas do espaço.

  delete_client_space&rarr; { ok, detached_pages }
  Exclui um espaço de cliente. As páginas arquivadas nele NÃO são excluídas: elas se desanexam como páginas flutuantes e continuam funcionando em seus URLs existentes, então o trabalho entregue permanece acessível.

  get_design_guide&rarr; { guide, version }
  Busca o guia de design Stacktree para melhorar uma página publicada.

  get_site&rarr; { html }
  Lê o código-fonte HTML atual de um site que você possui, para editá-lo e chamar update_site para alterá-lo no lugar.

  get_content&rarr; { content, format }
  Lê o conteúdo de uma página de volta. O formato "html" (o padrão) retorna o index.html armazenado exato, byte por byte, que é a única forma que você pode editar e entregar ao update_site; o formato "text" retorna a mesma página reduzida a texto simples — sem marcação, CSS, scripts ou…

  list_feedback&rarr; { feedback }
  Lê o feedback do visualizador deixado em um site via barra de ferramentas Agentation (ative com set_agentation).

  resolve_feedback&rarr; { ok }
  Marca um item de feedback como resolvido após corrigir a página. Passe o id do item de feedback de list_feedback e, opcionalmente, uma nota curta descrevendo o que você mudou.

  link_wallet&rarr; { ok }
  Vincula sua carteira a uma conta Stacktree para que as páginas que você publica sejam de propriedade dela — e adote as que você já publicou.

Padrões MCP com privacidade em primeiro lugar

Os agentes agem autonomamente sem um humano revisando cada sinalização. A camada MCP aplica padrões mais rígidos que a API bruta:

  - Expiração ciente do plano. Omitir expires_in_hours assume o padrão do plano — 24h anônimo, 7 dias no Free, sem expiração em plano pago. Passe "never" para permanência, que um plano pago honra e um plano com teto recusa (409 expiry_clamped) em vez de silenciosamente virar 7 dias; accept_clamp assume o teto. O que você receber, expires_at_iso e ttl_seconds estarão na resposta.

  - Verificação de segurança em modo bloqueio (API bruta: aviso) — bloqueia publicação acidental de dados pessoais ou segredos. A verificação protege seu conteúdo; nada é coletado ou armazenado.

  - URL de token não listado, CSP estrito (Google Fonts + incorporações de vídeo nomeadas permitidas; scripts remotos e imagens bloqueados), X-Robots-Tag: noai — mesmos padrões da API bruta.

WebMCP (no navegador)

O painel registra os mesmos verbos em document.modelContext onde o navegador suporta (teste de origem do Chrome), então um agente no navegador ajudando um humano conectado pode chamá-los sem chave de API. Como e por quê.

Quer o mesmo padrão no seu próprio aplicativo? A paleta e o registro WebMCP são construídos sobre agentk, nossa extensão cmdk de código aberto: defina ferramentas uma vez como JSON Schema, humanos recebem formulários gerados, agentes recebem os esquemas.

Pagamentos de agente

Um agente paga sem humano e sem conta, de duas maneiras: por publicação ou com uma chave persistente comprada uma vez. Pagamento por publicação aceita x402 (USDC na Base ou Solana) e MPP (USDC.e no Tempo na porta da frente, o método evm na Base); a chave persistente é x402 (USDC na Base ou Solana) ou MPP na Base. Sem gás para o pagador em ambos os casos. Leia o array accepts do 402 em vez de codificar um trilho. Versão legível por máquina: x402.md.

Pagar por publicação (sem chave)

O caminho mais simples, quando não há chave e nenhum humano para criar uma. POST seu HTML em api.stacktr.ee/publish ou na porta da frente em agents.stacktr.ee/api/publish, receba um 402, pague $0,50 via x402 (USDC na Base ou Solana) ou MPP, e a página publica para um link privado com o URL na resposta. Sem etapa de provisionamento. Leia o array accepts do 402 em vez de codificar um trilho: a Base é sempre a primeira entrada, e o requisito difere por rede. Revisões gratuitas depois são sem chave para um pagador EVM (a carteira que pagou assina por elas) e baseadas em token de reivindicação para um pagador Solana. Os endpoints estão listados no x402scan e mppscan; especificações em api.stacktr.ee/openapi.json e agents.stacktr.ee/openapi.json, com um registro gratuito de prova de serviço em api.stacktr.ee/.well-known/x402-service.

Chave persistente: provisione uma vez, depois pague conforme o uso

GET/provision Lista os meios de pagamento aceitos.

POST/provision 402 → pague $1,00 via x402 (USDC na Base ou Solana) ou MPP → chave stk_live_ persistente, sem conta. A chave carrega limites do plano gratuito: 3 páginas no total, cada uma expirando após 7 dias, sem bloqueios por e-mail (códigos de acesso funcionam). Eleve-os com um desbloqueio abaixo.

GET/unlock O catálogo à la carte: tornar permanente $5 por página, domínio personalizado $5/30d, limites maiores $25/30d.

POST/unlock 402 → pague → direito ao recurso na sua chave.

POST/pay/sessions Sem carteira? Retorna um link de pagamento + QR do terminal. Um humano paga com cartão em dois toques — ou um agente com cartão virtual aprovado por humano (Stripe link-cli, contas US Link) preenche o próprio Stripe Checkout padrão. Consulte GET /pay/sessions/:code/poll.

Pagar acima do preço em uma sessão de pagamento (até $20) deixa um saldo pré-pago na chave, do qual ações pagas posteriores descontam silenciosamente. Saldos nunca expiram e são reembolsáveis mediante solicitação.

Reivindique o que um agente publicou

A carteira que paga na porta de entrada é registrada com cada página, então ela serve também como comprovante de reivindicação. Um humano pode vincular essa carteira pelo painel (gere um código, o agente o assina), ou o agente pode se autovincular com a ferramenta MCP link_wallet. Toda página que a carteira publicou torna-se então de propriedade e gerenciável.

Atualize com o token de reivindicação da própria página (sem chave, qualquer rede)

Toda página não reivindicada carrega um claim_token, retornado na resposta de publicação. Até a página ser reivindicada, esse token é a credencial de atualização da página: PUT /sites/:id com Authorization: Claim <claim_token> e um corpo JSON {"html": "…"} (multipart também funciona). Mesma URL, revisões gratuitas, sem conta, sem carteira e sem assinatura, então é o caminho tanto para um pagador na Solana quanto para uma publicação anônima gratuita. Cobre exatamente o conteúdo daquela página: não reivindica, não exclui, não altera configurações, não afeta outras páginas. Reivindicar rotaciona o token para a conta e o cabeçalho para de funcionar; também é recusado quando a página expira. Trate o token como algo tão sensível quanto a página: quem o possui pode substituir o conteúdo por trás de um link que você já enviou.

PUT/sites/:idOrSlug

Atualize com a própria carteira (sem chave)

A carteira pagante também é a credencial de atualização da página — sem reivindicação, sem conta, sem chave de API. POST /wallet-auth/challenge com {"wallet":"0x…"}, personal_sign a mensagem retornada, depois PUT /sites/:id com Authorization: Wallet challenge=…,sig=0x… e o corpo JSON. Mesma URL, revisões gratuitas; desafios são de uso único com TTL de 5 minutos. Apenas carteiras EOA EVM por enquanto (sem carteiras de contrato inteligente).

POST/wallet-auth/challenge

Tudo o que uma carteira pagou

Uma publicação paga por uma carteira retorna next.receipt_url, um link estável para uma página listando todas as páginas que aquela carteira pagou: título, URL, data, a liquidação on-chain, se o token de reivindicação ainda está ativo, a requisição exata que revisa cada uma, e um botão para movê-las todas para uma conta. O link é a credencial e o endereço do pagador nunca é aceito em seu lugar: endereços são públicos on-chain, então uma página indexada por endereço tornaria os títulos de páginas privadas de cada cliente x402 enumeráveis a partir de um explorador de blocos. Não é retornado por POST /wallet-auth/challenge pelo mesmo motivo, e está deliberadamente ausente do desafio 402, que indexadores rastreiam e republicam.

Domínios personalizados

Planos pagos (Solo 1 domínio, Studio 10, Firm 25), ou o desbloqueio x402 custom_domain. Traga seu próprio hostname (docs.acme.com e outros), aponte um CNAME para nossa origem de fallback Cloudflare for SaaS, prove a propriedade via registro TXT, e o tráfego para esse hostname serve seu site via HTTPS.

POST/custom-domains

`curl -X POST https://api.stacktr.ee/custom-domains \
     -H "Authorization: Bearer stk_live_..." \
     -H "Content-Type: application/json" \
     -d '{"hostname":"docs.acme.com","site_id":"abc123"}'`

A resposta inclui um verify_token e os registros DNS que você ainda precisa adicionar. Dois para um hostname novo; se uma reivindicação de domínio pai verificada já o cobre, instructions é null (subdomínio: o CNAME curinga faz o roteamento) ou apenas CNAME (o próprio nome reivindicado, cuja propriedade já é comprovada):

`{
  "hostname": "docs.acme.com",
  "site_id": "abc123",
  "verified": false,
  "instructions": {
    "cname": { "name": "docs.acme.com", "value": "proxy.stacktr.ee", "type": "CNAME" },
    "txt":   { "name": "_stacktree-verify.docs.acme.com", "value": "verify_", "type": "TXT" }
  }
}`

POST/custom-domains/:hostname/verify Após adicionar os registros DNS, chame verify. Fazemos lookup DNS do registro TXT; em caso de correspondência, registramos o hostname com CF for SaaS e o provisionamento SSL começa (~60 s).

`curl -X POST https://api.stacktr.ee/custom-domains/docs.acme.com/verify \
     -H "Authorization: Bearer stk_live_..."`
Atenção — CNAME somente DNS. Se seu DNS está na Cloudflare, o CNAME deve ser definido como somente DNS (nuvem cinza), não Proxied (laranja). Um CNAME proxied faz a Cloudflare reivindicar o hostname para sua própria zona e o roteamento SaaS da Stacktree nunca vê o SNI.

Re-vincule ou exclua

`PATCH  https://api.stacktr.ee/custom-domains/:hostname    # { "site_id": "..." }  — re-bind
DELETE https://api.stacktr.ee/custom-domains/:hostname    # unregister + drop row`

Liste seus domínios com GET https://api.stacktr.ee/custom-domains. Linhas não verificadas são removidas automaticamente após 7 dias.

OAuth (autores de conectores personalizados)

Para implementadores de hosts MCP — se você usa um cliente mantido (Claude.ai, Cursor, etc.), pule esta seção.

Descoberta

`GET https://api.stacktr.ee/.well-known/oauth-authorization-server
GET https://api.stacktr.ee/.well-known/oauth-protected-resource`

Ambos retornam documentos de metadados padrão RFC 8414 / RFC 9728.

Fluxo

OAuth 2.1 com PKCE (S256 obrigatório) e Registro Dinâmico de Cliente (RFC 7591). Endpoints:

POST/oauth/register
DCR — limitado a 10/IP/hora.

GET/oauth/authorize
Redireciona para página de consentimento gerenciada pela Clerk em app.stacktr.ee.

POST/oauth/token
Código → token de acesso (JWT HS256, TTL de 30 dias).

POST/oauth/revoke
Revogação RFC 7009.

Callback para superfícies Claude hospedadas: https://claude.ai/api/mcp/auth_callback.

Limites

Todo número abaixo é aplicado no servidor a partir de uma única tabela. GET /me retorna o objeto limits do próprio chamador; leia dele em vez de codificar um limite fixo em um cliente.

LimiteAnônimoGratuitoSolo $19Studio $79Firm $249
Páginas—3 no total25 ativasilimitadoilimitado
Vida da página24h7 dias, semprepermanentepermanentepermanente
Publicações / 24h20 por IP501.0001.000ilimitado
Tamanho por site10 MB25 MB250 MB250 MB1 GB
Arquivos / arquivo1.0001.0001.0001.0001.000
Códigos de acesso · bloqueios por e-mailsó código de acessosó código de acesso✓✓✓
Números de visualizadores——aberturas, visualizações, última abertura+ engajamento completo+ engajamento completo
Slug personalizado—✓✓✓✓
Domínios personalizados——11025
Espaços de cliente——110ilimitado
Selo Stacktreepermanecepermaneceremovidoremovidoremovido

A linha de espaços de cliente conta espaços ATIVADOS, ou seja, aqueles com hostname vinculado ou portal habilitado. Arquivar páginas sob um cliente é gratuito em todos os planos, incluindo o Gratuito: a unidade paga é o endereço, não o rótulo. Arquivar um espaço libera a vaga, e um hostname de espaço não consome uma vaga de domínio personalizado.

O Gratuito conta publicações, não páginas ativas. O 3 é lifetime_publishes, um contador que só aumenta: excluir uma página ou deixá-la expirar não devolve a vaga. O 25 do Solo é o outro modelo: páginas ativas, liberadas por exclusão. Toda página gratuita expira 7 dias após ser publicada, e passar de expires_in_hours: "never" é recusado em vez de cair silenciosamente no teto: um agente que recebe um 201 diz ao usuário que o link é permanente, então a resposta tem que ser um erro que ele não possa confundir com sucesso. accept_clamp a publica com os 7 dias.

Limite de DCR: 10 registros de cliente / IP / hora. Uma página expirada para de servir dentro da hora e a URL então diz que o link expirou, exatamente como antes; o que mudou é o que acontece depois. O conteúdo é mantido por 30 dias em vez de ser destruído naquele momento, então POST /sites/:idOrSlug/restore pode colocá-lo de volta na mesma URL, e só então é purgado do R2 e D1 definitivamente.

Enterprise é personalizado e anual (self-hosting, DPA, SLA, residência de dados). Pergunte em gm@stacktr.ee. Contas nos planos antigos Pro e Agent mantêm os limites com que foram assinadas; nenhum dos dois é mais vendido.

Sem plano? O desbloqueio higher_limits ($25 / 30 dias via x402) eleva uma identidade gratuita aos limites de frota: 1 GB por site, publicações diárias ilimitadas, sem teto de páginas, e páginas que não expiram. make_permanent ($5, uma página) cancela a expiração de uma única página.

Erros de plano

Cada um carrega um código error estável, o plan do chamador, um message humano, e quando relevante um limit. Apresente-os como um prompt de upgrade, não como uma string crua:

CódigoStatusSignificado
`plan_lifetime_limit_exceeded`402Todas as 3 páginas gratuitas usadas. Excluir uma não ajuda.
`plan_site_limit_exceeded`402Teto de páginas ativas atingido (Solo). Exclua uma, ou suba de plano.
`plan_password_not_available`402Códigos de acesso não estão neste plano (apenas planos desconhecidos; todo plano real os tem).
`plan_password_limit_exceeded`402Teto de páginas protegidas por código de acesso atingido.
`plan_viewer_gate_not_available`402Bloqueios por e-mail não estão neste plano.
`plan_viewer_gate_limit_exceeded`402Teto de páginas com bloqueio por e-mail atingido.
`plan_domain_not_available`402Domínios personalizados não estão neste plano.
`plan_domain_limit_exceeded`402Teto de domínios personalizados atingido.
`plan_space_not_available`402Ativar um espaço de cliente (endereço ou portal) não está neste plano. Arquivar páginas sob um cliente ainda funciona.
`plan_space_limit_exceeded`402Teto de espaços de cliente ativados atingido. Arquive ou desative um, ou suba de plano.
`plan_upload_limit_exceeded`429Teto diário de publicações atingido; reinicia em uma janela contínua de 24h.

Expiração é meia exceção. Uma vida de página maior que o teto do plano é limitada em vez de recusada: ela volta encurtada em expires_at, com expiry_clamped: true e sem erro. Pedir uma página que nunca expira em um plano com teto é recusado, 409 expiry_clamped, porque esse é o único caso em que a diferença é repetida a uma pessoa como "este link é permanente". accept_clamp assume o teto em um único campo.

Toda resposta que carrega uma página carrega seu prazo de seis maneiras: expires_at (segundos unix, inalterado), expires_at_iso (RFC 3339 UTC, o que se mostra a um humano), ttl_seconds (nunca negativo), expiry_clamped, expiry_ceiling_hours (24 anônimo, 168 Gratuito, null em planos sem teto) e expiry_source (request, plan_ceiling, plan_default ou stored).


Resumo markdown completo da superfície de marketing da Stacktree: https://stacktr.ee/llms-full.txt