Stacktree
Publica HTML en una URL privada e imposible de adivinar desde cualquier cliente MCP. Protege con contraseña o dominio de correo electrónico; reemplaza en el mismo lugar.
Documentación
Documentación de la API de Stacktree — recursos para desarrolladores
Fuente: https://stacktr.ee/docs
[
Documentación de Stacktree
](https://stacktr.ee/)
[Agentes](https://stacktr.ee/agents)
[Documentación](https://stacktr.ee/docs)
[Casos de uso](https://stacktr.ee/use-cases)
[Precios](https://stacktr.ee/pricing)
[Blog](https://stacktr.ee/blog)
[Panel de control](https://app.stacktr.ee)
Buscar en la documentación⌘K
Primeros pasos
- [Conectar un agente](#connect)
[Instalador CLI](#installer)
- [Claude.ai](#claude-ai)
- [Claude Code · Codex](#claude-code)
- [Archivo de configuración MCP](#mcp-config)
- [Slack](#slack)
Referencia
- [API HTTP](#api)
[Autenticación](#auth)
- [POST /sites](#post-sites)
- [PUT /sites/:id](#put-sites)
- [PATCH /sites/:id](#patch-sites)
- [Listar · raw · eliminar · restaurar](#more-sites)
- [Tokens de compartición](#share-tokens)
- [Claves de API](#keys)
- [Código de dispositivo](#device-code)
- [Servidor MCP](#mcp)
- [Pagos de agentes](#payments)
- [Dominios personalizados](#domains)
- [OAuth](#oauth)
- [Límites](#limits)
[Errores de plan](#plan-errors)
Legible 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)
[Registro de cambios](https://stacktr.ee/changelog) · [Blog](https://stacktr.ee/blog)
[Panel de control](https://app.stacktr.ee) · [Precios](https://stacktr.ee/pricing)
Documentación de la API de Stacktree
La primitiva de publicación para HTML hecho por agentes.
privado por defecto nativo de MCP reemplazo en el lugar
¿Se lo entregas a un agente de codificación? Dale la especificación OpenAPI y listo: api.stacktr.ee/openapi.json para la API HTTP, o agents.stacktr.ee/openapi.json para la puerta de entrada de pago por publicación. Servidor MCP: https://api.stacktr.ee/mcp. Índice legible por máquina: stacktr.ee/llms.txt.
Para un recorrido guiado con tu clave de API real integrada en los fragmentos, abre app.stacktr.ee/connect.
Conectar un agente
Entrégaselo al agente
Si tienes un agente abierto, dale esto y él hace el resto: instala, verifica y aprende la superficie de herramientas:
`Fetch and follow the setup instructions at https://stacktr.ee/prompt.md`
Funciona en cualquier agente que pueda obtener una URL. Las instrucciones son Markdown simple en stacktr.ee/prompt.md — léelas antes de ejecutarlas si lo prefieres.
npx stacktree-install — recomendado
Un solo comando conecta todos los agentes a la vez — Claude Code, Cursor, Codex, OpenCode, Amp — e instala la habilidad stacktree-publish para Claude:
`npx stacktree-install`
Te registra mediante un código de un solo uso en app.stacktr.ee/connect/cli y genera una clave de API automáticamente; pasa una clave existente como argumento (npx stacktree-install stk_live_…) para omitir el inicio de sesión.
Claude.ai — conector personalizado
Sin CLI, sin copiar y pegar claves de API.
- Abre [claude.ai/settings/connectors](https://claude.ai/settings/connectors) → Añadir conector personalizado.
- Pega https://api.stacktr.ee/mcp como URL del servidor MCP remoto.
- Deja el ID de cliente OAuth/Secreto en blanco — Stacktree se auto-registra mediante Registro Dinámico de Clientes (RFC 7591).
- Haz clic en Añadir → Claude.ai te redirige a Stacktree para iniciar sesión y aprobar. Las herramientas están disponibles en cualquier conversación.
Claude Code · Codex — CLI
Instalación de una línea. Sintaxis idéntica entre ambos:
`claude mcp add stacktree -- npx -y stacktree-mcp
codex mcp add stacktree -- npx -y stacktree-mcp`
Ambos exponen las mismas 25 herramientas (consulta Servidor MCP). Establece STACKTREE_API_KEY en tu shell — genera una en app.stacktr.ee/api-keys.
¿Prefieres una habilidad? Instala SKILL.md + script auxiliar en el directorio de habilidades de tu agente:
`npx skills@latest add stevysmith/stacktree-skill
export STACKTREE_API_KEY=stk_live_...`
Fuente: github.com/stevysmith/stacktree-skill · la colección completa en stacktr.ee/skills
Archivo de configuración MCP — Cursor / Claude Desktop / Windsurf / Zed
`{
"mcpServers": {
"stacktree": {
"command": "npx",
"args": ["-y", "stacktree-mcp"],
"env": { "STACKTREE_API_KEY": "stk_live_..." }
}
}
}`
Colócalo en ~/.cursor/mcp.json, ~/Library/Application Support/Claude/claude_desktop_config.json, ~/.codeium/windsurf/mcp_config.json, o en la clave context_servers en la configuración de Zed.
Slack
Añade la aplicación de Slack (una aprobación; la instalación crea su propia identidad gratuita para el espacio de trabajo, sin necesidad de cuenta de Stacktree). Luego ⋮ → Alojar en Stacktree en cualquier mensaje con un archivo .html o .md — en canales o DMs — publica un enlace privado de vuelta en la conversación. Volver a subir el mismo nombre de archivo republica en la misma URL. /stacktree link migra los sitios del espacio de trabajo a una cuenta de panel de control. Detalles: stacktr.ee/slack.
API HTTP
Autenticación
Tres métodos, todos resuelven al mismo contexto de usuario:
Authorization: Bearer stk_live_…Clave de API
Crea en [app.stacktr.ee/api-keys](https://app.stacktr.ee/api-keys) — o deja que un agente compre la suya mediante [x402 o MPP](#payments).
Authorization: Bearer <clerk-session-jwt>sesión
Token de sesión de Clerk, para llamadas originadas en el panel de control.
Authorization: Bearer <oauth-jwt>OAuth
Token de acceso de `/oauth/token`, utilizado por conectores personalizados.
POST/sites
Sube un solo archivo HTML/markdown o un zip. multipart/form-data. Las subidas anónimas funcionan — sin encabezado de autenticación — y duran 24 horas.
filefilerequerido
.html / .htm / .md / .zip
public_slugcadena
Subdominio público opcional; solo autenticado.
passwordcadena
Bloqueo por código de acceso al servir. Funciona en todos los planes, incluidas las 3 páginas del plan gratuito y las publicaciones anónimas.
expires_in_hoursnúmero | "never"
Predeterminado: 24 h anónimo, sin caducidad en un plan de pago. Gratis está limitado a 7 días. Un número por encima del límite se ajusta a él y la respuesta lo indica (`expiry_clamped: true`). `"never"` en un plan con límite se rechaza, no se acorta silenciosamente: `409 expiry_clamped`, nada se publica, y el cuerpo lleva `would_expire_at_iso`. Esto es deliberado, porque un 201 se lee como éxito y la permanencia se repite a una persona antes de que alguien revise una bandera. Envía `accept_clamp=true` para aceptar el límite. Omite el campo por completo (o envíalo vacío) y se aplica el predeterminado del plan, igual por MCP que por la API cruda. Un valor que no sea un número de horas o la palabra `"never"` — `"7d"`, `-5`, `"soon"` — es `400 invalid_expiry` y nada se publica: antes se leía como "sin plazo solicitado", lo que en un plan de pago significaba una página permanente que el llamador no había pedido.
accept_clamp"true"
Solo necesario junto con `expires_in_hours=never` en un plan que limita la vida de la página: indica que el límite es aceptable y publica.
Idempotency-Keyencabezado
Hace seguro un reintento. Cualquier cadena única, de 1 a 255 caracteres ASCII visibles. La misma clave con el mismo cuerpo dentro de 24 horas devuelve la página original (mismo id, misma URL, mismos tokens) con `Idempotent-Replay: true`, y no gasta una segunda página contra el límite de por vida de Gratis. Un cuerpo diferente bajo la misma clave es `422 idempotency_key_reused`, nunca la página anterior. Dos solicitudes con una clave no pueden publicar ambas: el perdedor recibe `409 idempotency_key_in_progress` y debe reintentar. Las claves están limitadas por llamador. En una publicación anónima no hay cuenta a la que limitar y el ámbito es la dirección de red, por lo que la clave debe ser imposible de adivinar (un UUID): una corta es `400 idempotency_key_too_weak`, porque dos agentes detrás de una IP de oficina que usan una plantilla compartida `"1"` entregarían al segundo la página del primero y su `claim_token`. Si la página que creó una clave ha sido eliminada o quemada desde entonces, el reintento es `409 idempotent_page_gone` en lugar de un 201 para un enlace muerto.
burn_after_read"true"
Eliminar después de la primera vista.
agentation"true"
Inyectar barra de herramientas de retroalimentación al servir.
csp_strict"false"
Desactivar CSP estricto (activado por defecto). La política estricta permite Google Fonts y embebidos de Loom / YouTube / Vimeo / Wistia / Descript / Calendly, y bloquea scripts remotos e imágenes remotas. Una publicación que contenga algo que la política bloquearía aún tiene éxito y devuelve un array `warnings` indicando qué no se renderizará.
e2e"true"
Tratar la subida como texto cifrado; la clave de descifrado vive en el fragmento de URL y nunca se envía a Stacktree.
pii_checkoff | warn | block
Predeterminado warn (la capa MCP lo sobrescribe a 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
Reemplaza los archivos de un sitio en el lugar — la URL nunca cambia, y no se crea una segunda página. Dos formas de cuerpo: application/json con una cadena html, que es lo que los rieles de pago ya hablan, o multipart/form-data con los mismos campos que POST (la única forma que lleva un zip, un PDF o texto cifrado e2e). Tres credenciales, una por solicitud: una clave de cuenta o token OAuth; el claim_token de la propia página mientras no esté reclamada (Authorization: Claim <claim_token>, consulta abajo); o, en una página pagada con billetera, un desafío de billetera firmado. Cualquier otra cosa es un 401. Los sitios cifrados E2E deben reemplazarse con subidas multipart e2e=true (sin degradación silenciosa a texto plano).
`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>"}'`
Los campos opcionales son los mismos en ambos casos: expected_updated_at (rechazar la escritura si la página cambió por debajo de ti), pii_check, y en multipart e2e. En JSON, filename reemplaza una página publicada como activo de máquina en su propia ruta en lugar de reubicarla en index.html.
PATCH/sites/:idOrSlug
Actualiza la configuración sin volver a subir archivos. Cuerpo JSON.
passwordcadena | null
Establecer o eliminar el bloqueo por código de acceso. Funciona en todos los planes; eliminar uno siempre funciona también.
expires_in_hoursnúmero | null
`null` (o la cadena `"never"`) cancela la caducidad en un plan de pago. En un plan con límite se rechaza (`409 expiry_clamped`, nada en el PATCH se aplicó) en lugar de convertirse silenciosamente en 7 días; añade `accept_clamp: true` para aceptar el límite. Un número por encima del límite se ajusta, con `expiry_clamped: true` en la respuesta. Los números pueden enviarse como cadenas (`"24"`) y significan lo mismo aquí que al publicar; cualquier cosa que no sea legible como horas ni `"never"` es `400 invalid_expiry` y nada se cambia.
allowed_email_domaincadena | null
Los espectadores verifican un correo en ese dominio antes de que la página se renderice. Solo planes de pago; Gratis recibe `402 plan_viewer_gate_not_available`.
public_slugcadena | null
Reclamar o liberar un subdominio público.
agentation · burn_after_read · csp_strictbooleano
Alterna los comportamientos de tiempo de servicio documentados bajo 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 · obtener · raw · eliminar · restaurar
GET/sites
Lista tus sitios. Las páginas que caducaron o se eliminaron permanecen en la lista en lugar de desaparecer: llevan `deleted_at`, `delete_reason` y `restorable_until`. Verifica `deleted_at` antes de entregar un `url` a alguien: una fila que lo tenga establecido es un enlace muerto.
GET/sites/:idOrSlug
Un sitio, con manifiesto de archivos + `preview_url` absoluto.
GET/raw/:token
HTML de la página sin head/scripts — texto limpio para re-alimentar a un agente. Respeta los bloqueos por contraseña.
DELETE/sites/:idOrSlug
Derriba la página ahora: el enlace está muerto para todos los que lo tienen y la ranura del plan se libera inmediatamente. El contenido se conserva durante 30 días, y `restorable_until` en la respuesta es la fecha límite después de la cual se destruye para siempre. En Gratis esto no devuelve una ranura de página de por vida, porque ese límite cuenta publicaciones, no páginas vivas. Eliminar una página que ya está caída devuelve `already_deleted: true` en lugar de un error.
POST/sites/:idOrSlug/restore
Devuelve una página eliminada o caducada a la misma URL, con el mismo id, token, slug e historial de lectura, de modo que los enlaces ya enviados vuelvan a funcionar. Esto, y no otra publicación, es la respuesta a un 409 site_deleted: volver a publicar genera una URL diferente y gasta otra página de por vida, mientras que restaurar no gasta nada. Es un rescate, no una renovación, así que lee expires_at_iso y restored_for de la respuesta: una página que se quedó sin tiempo en un plan con un límite de caducidad vuelve por 48 horas (restored_for: "grace", y restore_grace_hours indica el número), no con una vida completa nueva. Una página eliminada por el propietario conserva el plazo que ya tenía ("kept"), incluida la ausencia de plazo. Devuelve 404 una vez pasados los 30 días, y también para un retiro por infracción, que nunca se puede restaurar.
Los números de visitas están limitados por plan. `GET /sites` y `GET /sites/:idOrSlug` devuelven `metrics_locked: true`, con `view_count`, `unique_viewers` y `last_viewed_at` como `null`, cuando el plan no tiene métricas de visitas (anónimo y Free). Un booleano `opened` llega en todos los planes, así que puedes saber si alguien leyó la página sin ver cuántos lo hicieron. La redacción se hace en el servidor, por lo que un agente que lea este JSON ve exactamente lo que muestra el panel.
Tokens de compartir
`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`
Devuelve una URL con ?t=… añadido. Omite la protección por contraseña cuando es válido; revocable por token; contador opcional de uso máximo y caducidad.
Comentarios
`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`
Anotaciones de los visitantes dejadas mediante la barra de herramientas Agentation en la página (actívala con agentation al subir, con PATCH o con set_agentation). Cada elemento incluye el comentario más el elemento anotado, el texto seleccionado, la intención y la gravedad. Primero los no resueltos. El ciclo: lee los comentarios → corrige la página con update_site (misma URL) → resuelve.
Reacciones e interacción
`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 }`
Cómo recibió la página, visto por el propietario. Reacciones: activa la barra de reacciones en la página por sitio (Ajustes del panel) y los visitantes reaccionan con un emoji o dejan una nota breve privada, sin cuenta. Interacción (Studio y superiores): métricas de lectura agregadas y sin PII: tiempo típico en la página, profundidad de desplazamiento, tasa de lectura hasta el final y un mapa de calor de atención de 10 segmentos según la profundidad de la página. Sin grabación ni repetición de sesiones. Ambas alimentan la campana de actividad del panel y el resumen diario opcional por correo.
Claves 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`
Código de dispositivo: lleva una clave a un agente sin navegador
Concesión de autorización de dispositivo OAuth 2.0 (RFC 8628). Esto es lo que ejecuta npx stacktree-install, y cualquier agente puede llamarlo directamente: el agente imprime una URL y un código corto, una persona lo aprueba en su propio dispositivo y el agente consulta hasta que llega una clave. Úsalo cuando la cuenta ya pertenezca a una persona; un agente que no tenga a nadie a quien preguntar debería comprar su propia clave mediante x402 en 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`
Sin autenticación en ninguna de las dos llamadas. Los códigos duran 10 minutos, la aprobación de la persona genera la clave en su cuenta y la clave se entrega exactamente una vez: si una consulta la pierde, hay que volver a autorizar. Límite de velocidad por IP. La clave stk_live_ resultante funciona tanto en la API REST como en MCP.
Servidor MCP
Servidor MCP HTTP transmisible en https://api.stacktr.ee/mcp (especificación 2025-11-25), que expone 25 herramientas. Dos credenciales, ambas aceptadas en el mismo endpoint:
- Authorization: Bearer stk_live_… — una clave de API. Sin navegador, sin baile OAuth, nada que registrar: la misma clave que impulsa la API REST impulsa MCP. Este es el camino para un agente desatendido y para cualquier cliente que solo pueda enviar una cabecera estática. Un agente sin clave puede comprar una mediante [x402](#payments) en POST https://api.stacktr.ee/provision, o vincularse a la cuenta existente de una persona con el [flujo de código de dispositivo](#device-code) a continuación.
- OAuth 2.1 + registro dinámico de clientes — para conectores que actúan en nombre de una persona con sesión iniciada (claude.ai, Cursor y similares). Nada que pre-registrar; consulta [OAuth](#oauth).
Las cookies de sesión NO se aceptan deliberadamente aquí, por lo que no se puede hacer que un navegador impulse MCP entre sitios. Envía exactamente una 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":{}}'`
Herramientas (25)
publish_html→ { id, url, slug, unlisted_token, … }
Convierte HTML en un enlace que una persona pueda abrir en un navegador.
update_site→ { id, url, file_count, size_bytes }
Reemplaza el HTML de un sitio existente en su lugar. La URL sigue siendo la misma, por lo que todos a quienes ya se lo enviaste ven la nueva versión sin que se les envíe nada.
delete_site→ { ok, restorable_until, already_deleted }
Retira una página. El enlace muere de inmediato para todos los que lo tienen, y el contenido se conserva durante 30 días: restore_site lo devuelve a la misma URL, con el mismo id, token, slug e historial de lectura, en cualquier momento de esa ventana.
restore_site→ { ok, id, url, expires_at, … }
Devuelve una página a la misma URL después de que se eliminara o se quedara sin tiempo.
claim_site→ { ok, id, expires_at, expires_at_iso, … }
Adopta una página publicada sin cuenta en la cuenta con la que esta conexión está autenticada.
set_password→ { ok }
Establece o elimina (null) un código de acceso para visitantes en un sitio. Funciona en todos los planes (el gratuito cubre sus 3 páginas).
set_expiry→ { ok, expires_at, expires_at_iso, ttl_seconds, … }
Establece la caducidad en horas desde ahora, o null para nunca. Un número mayor que el permitido por el plan se reduce al límite y la respuesta lo indica (expiry_clamped: true).
create_share_link
Genera un enlace para compartir dirigido a una persona. Pon su nombre en `label`: cada apertura a través de este enlace se atribuye a ese nombre, visible en la página del panel y en el correo de confirmación de lectura.
list_share_links
Los enlaces para compartir de una página, con cuántas aperturas atribuidas ha tenido cada uno y cuándo se abrió por última vez. `opens` cuenta las aperturas humanas de la página a través de ese enlace; `use_count` es el contador bruto de cumplimiento para max_uses y no es una métrica de lectura.
revoke_share_link→ { ok }
Elimina un enlace para compartir. La página y todos los demás enlaces siguen funcionando: así se corta a un destinatario sin reemitir nada a los demás.
set_agentation→ { ok }
Activa o desactiva la barra de herramientas de comentarios Agentation en la página. Cuando está activada, los visitantes pueden anotar la página y sus comentarios se recopilan: léelos con list_feedback, corrige la página con update_site y luego resuelve con resolve_feedback.
set_email_gate→ { ok }
Restringe el acceso de los visitantes a un dominio de correo específico. Solo planes de pago: en un plan gratuito esto devuelve HTTP 402 plan_viewer_gate_not_available.
list_sites→ { sites }
Lista los sitios propiedad del usuario autenticado, primero los más recientes.
get_me→ { clerk_user_id, auth_method, plan, email, … }
Quién publica con esta conexión y qué permite realmente su plan.
list_client_spaces→ { spaces }
Lista los espacios de cliente de esta cuenta: slug, nombre, page_count, última actividad, hostname (la dirección propia del espacio, p. ej. acme.theiragency.com, cuando hay una conectada) y portal_enabled (si el espacio sirve un portal de cliente generado en esa dirección).
set_client→ { ok }
Archiva un sitio existente bajo un espacio de cliente (por nombre o slug, se crea automáticamente), o pasa client: null para desvincularlo como página flotante.
create_client_space→ { ok, space }
Crea un espacio de cliente antes de publicar nada en él. Rara vez es necesario: publish_html con un argumento client crea automáticamente el espacio con las mismas reglas de mayúsculas y slug, así que úsalo solo cuando el usuario esté preparando un cliente antes del trabajo.
update_client_space→ { ok }
Renombra un espacio de cliente, lo archiva o desarchiva, o establece la protección para visitantes que cubre todas las páginas del espacio.
delete_client_space→ { ok, detached_pages }
Elimina un espacio de cliente. Las páginas archivadas en él NO se eliminan: se desvinculan como páginas flotantes y siguen funcionando en sus URL existentes, por lo que el trabajo entregado sigue siendo accesible.
get_design_guide→ { guide, version }
Obtiene la guía de diseño de Stacktree para mejorar una página publicada.
get_site→ { html }
Lee el código HTML actual de un sitio que posees, para poder editarlo y llamar a update_site para cambiarlo en su lugar.
get_content→ { content, format }
Lee el contenido de una página. El formato "html" (el predeterminado) devuelve el index.html almacenado exacto, byte por byte, que es la única forma que puedes editar y entregar a update_site; el formato "text" devuelve la misma página reducida a texto plano: sin marcado, CSS, scripts ni…
list_feedback→ { feedback }
Lee los comentarios de los visitantes dejados en un sitio mediante la barra de herramientas Agentation (actívala con set_agentation).
resolve_feedback→ { ok }
Marca un elemento de comentario como atendido después de corregir la página. Pasa el id del elemento de comentario de list_feedback y, opcionalmente, una nota breve que describa lo que cambiaste.
link_wallet→ { ok }
Vincula tu cartera a una cuenta de Stacktree para que las páginas que publiques sean de tu propiedad allí, y adopta las que ya publicaste.
Valores predeterminados de MCP centrados en la privacidad
Los agentes actúan de forma autónoma sin que una persona revise cada marca. La capa MCP aplica valores predeterminados más estrictos que la API bruta:
- Caducidad según el plan. Omitir expires_in_hours toma el valor predeterminado del plan: 24 h anónimo, 7 días en Free, sin caducidad en un plan de pago. Pasa "never" para permanencia, que un plan de pago honra y un plan con límite rechaza (409 expiry_clamped) en lugar de convertirse silenciosamente en 7 días; accept_clamp toma el límite. Lo que obtengas, expires_at_iso y ttl_seconds están en la respuesta.
- Escaneo de seguridad en modo bloqueo (API bruta: aviso): bloquea la publicación accidental de datos personales o secretos. El escaneo protege tu contenido; no se recopila ni almacena nada.
- URL de token no listado, CSP estricto (Google Fonts y videos incrustados con nombre permitidos; scripts e imágenes remotos bloqueados), X-Robots-Tag: noai — los mismos valores predeterminados que la API bruta.
WebMCP (en el navegador)
El panel registra los mismos verbos en document.modelContext cuando el navegador lo admite (prueba de origen de Chrome), de modo que un agente en el navegador que ayude a una persona con sesión iniciada pueda llamarlos sin clave de API. Cómo y por qué.
¿Quieres el mismo patrón en tu propia aplicación? La paleta y el registro WebMCP se basan en agentk, nuestra extensión de código abierto de cmdk: define las herramientas una vez como JSON Schema, las personas obtienen formularios generados y los agentes obtienen los esquemas.
Pagos de agentes
Un agente paga sin persona ni cuenta, de dos maneras: por publicación o con una clave persistente comprada una vez. El pago por publicación acepta x402 (USDC en Base o Solana) y MPP (USDC.e en Tempo en la puerta principal, el método evm en Base); la clave persistente es x402 (USDC en Base o Solana) o MPP en Base. Sin gas para el pagador en ambos casos. Lee el array accepts del 402 en lugar de codificar un rail. Versión legible por máquina: x402.md.
Pago por publicación (sin clave)
El camino más simple, cuando no hay clave ni persona para crearla. Envía tu HTML por POST a api.stacktr.ee/publish o a la puerta principal en agents.stacktr.ee/api/publish, recibe un 402, paga $0.50 mediante x402 (USDC en Base o Solana) o MPP, y la página se publica en un enlace privado con la URL en la respuesta. Sin paso de aprovisionamiento. Lee el array accepts del 402 en lugar de codificar un rail: Base siempre es la primera entrada y el requisito difiere según la red. Las revisiones gratuitas posteriores no requieren clave para un pagador EVM (la cartera que pagó las firma) y se basan en token de reclamación para un pagador de Solana. Los endpoints se enumeran en x402scan y mppscan; las especificaciones en api.stacktr.ee/openapi.json y agents.stacktr.ee/openapi.json, con un registro gratuito de prueba de servicio en api.stacktr.ee/.well-known/x402-service.
Clave persistente: aprovisiona una vez y luego paga según uso
GET/provision Enumera los canales de pago aceptados.
POST/provision
402 → paga $1.00 mediante x402 (USDC en Base o Solana) o MPP → clave persistente `stk_live_`, sin cuenta. La clave incluye límites de nivel gratuito: 3 páginas en total, cada una con caducidad a los 7 días, sin bloqueos por correo electrónico (los códigos de acceso sí funcionan). Elimínalos con un desbloqueo a continuación.
GET/unlock
El catálogo a la carta: hacer permanente $5 por página, dominio personalizado $5/30d, límites superiores $25/30d.
POST/unlock
402 → paga → derecho de función en tu clave.
POST/pay/sessions
¿Sin cartera? Devuelve un enlace de pago y un código QR para terminal. Una persona paga con tarjeta en dos toques — o un agente con una tarjeta virtual aprobada por un humano (Stripe link-cli, cuentas US Link) completa el propio Stripe Checkout estándar. Consulta `GET /pay/sessions/:code/poll`.
Pagar por encima del precio en una sesión de pago (hasta $20) deja un saldo prepagado en la clave que las acciones de pago posteriores consumen silenciosamente. Los saldos nunca caducan y son reembolsables a petición.
Reclama lo que un agente publicó
La cartera que paga en la puerta principal se registra con cada página, por lo que también sirve como comprobante de reclamo. Una persona puede vincular esa cartera desde el panel (genera un código, el agente lo firma), o el agente puede auto-vincularse con la herramienta MCP link_wallet. Cada página que la cartera publicó pasa a ser propiedad y gestionable.
Actualiza con el token de reclamo de la propia página (sin clave, cualquier cadena)
Cada página no reclamada lleva un claim_token, devuelto en su respuesta de publicación. Hasta que la página se reclame, ese token es la credencial de actualización de la página: PUT /sites/:id con Authorization: Claim <claim_token> y un cuerpo JSON {"html": "…"} (multipart también funciona). Misma URL, revisiones gratuitas, sin cuenta, sin cartera y sin firma, por lo que es la vía tanto para un pagador de Solana como para una publicación anónima gratuita. Cubre exactamente el contenido de esa página: no reclama, no elimina, no configura, ni afecta a ninguna otra página. Reclamar rota el token hacia la cuenta y la cabecera deja de funcionar; también se rechaza una vez que la página caduca. Trata el token como algo tan sensible como la página: quien lo tenga puede reemplazar el contenido detrás de un enlace que ya enviaste.
PUT/sites/:idOrSlug
Actualiza con la propia cartera (sin clave)
La cartera que paga también es la credencial de actualización de la página — sin reclamo, sin cuenta, sin clave API. POST /wallet-auth/challenge con {"wallet":"0x…"}, personal_sign el mensaje devuelto, luego PUT /sites/:id con Authorization: Wallet challenge=…,sig=0x… y el cuerpo JSON. Misma URL, revisiones gratuitas; los desafíos son de un solo uso con un TTL de 5 minutos. Solo carteras EOA de EVM por ahora (sin carteras de contrato inteligente).
POST/wallet-auth/challenge
Todo lo que una cartera ha pagado
Una publicación pagada desde una cartera devuelve next.receipt_url, un enlace estable a una página que lista cada página que esa cartera ha pagado: título, URL, fecha, la liquidación en cadena, si el token de reclamo sigue activo, la solicitud exacta que revisa cada una, y un botón para moverlas todas a una cuenta. El enlace es la credencial y la dirección del pagador nunca se acepta en su lugar: las direcciones son públicas en cadena, por lo que una página basada en dirección haría que los títulos de páginas privadas de cada cliente x402 fueran enumerables desde un explorador de bloques. No se devuelve por POST /wallet-auth/challenge por la misma razón, y está deliberadamente ausente del desafío 402, que los índices rastrean y republican.
Dominios personalizados
Planes de pago (Solo 1 dominio, Studio 10, Firm 25), o el desbloqueo x402 custom_domain. Trae tu propio nombre de host (docs.acme.com y otros), apunta un CNAME a nuestro origen de respaldo Cloudflare para SaaS, demuestra propiedad mediante un registro TXT, y el tráfico a ese nombre de host sirve tu sitio a través de 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"}'`
La respuesta incluye un verify_token y los registros DNS que aún necesitas añadir. Dos para un nombre de host nuevo; si una reclamación de dominio padre verificada ya lo cubre, instructions es null (subdominio: el CNAME comodín hace el enrutamiento) o solo CNAME (el nombre reclamado en sí, cuya propiedad ya está demostrada):
`{
"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
Después de añadir los registros DNS, llama a verify. Hacemos una búsqueda DNS del registro TXT; si coincide, registramos el nombre de host con CF para SaaS y comienza el aprovisionamiento SSL (~60 s).
`curl -X POST https://api.stacktr.ee/custom-domains/docs.acme.com/verify \
-H "Authorization: Bearer stk_live_..."`
Advertencia — CNAME solo DNS. Si tu DNS está en Cloudflare, el CNAME debe configurarse como solo DNS (nube gris), no como Proxied (naranja). Un CNAME proxied hace que Cloudflare reclame el nombre de host para tu propia zona y el enrutamiento SaaS de Stacktree nunca ve el SNI.
Re-vincular o eliminar
`PATCH https://api.stacktr.ee/custom-domains/:hostname # { "site_id": "..." } — re-bind
DELETE https://api.stacktr.ee/custom-domains/:hostname # unregister + drop row`
Lista tus dominios con GET https://api.stacktr.ee/custom-domains. Las filas no verificadas se eliminan automáticamente después de 7 días.
OAuth (autores de conectores personalizados)
Para implementadores de hosts MCP — si usas un cliente mantenido (Claude.ai, Cursor, etc.) omite esta sección.
Descubrimiento
`GET https://api.stacktr.ee/.well-known/oauth-authorization-server
GET https://api.stacktr.ee/.well-known/oauth-protected-resource`
Ambos devuelven documentos de metadatos estándar RFC 8414 / RFC 9728.
Flujo
OAuth 2.1 con PKCE (S256 requerido) y Registro Dinámico de Clientes (RFC 7591). Endpoints:
POST/oauth/register
DCR — limitado a 10/IP/hora.
GET/oauth/authorize
Redirige a la página de consentimiento controlada por Clerk en app.stacktr.ee.
POST/oauth/token
Código → token de acceso (JWT HS256, TTL de 30 días).
POST/oauth/revoke
Revocación RFC 7009.
Callback para superficies de Claude alojadas: https://claude.ai/api/mcp/auth_callback.
Límites
Cada número a continuación se aplica en el servidor desde una sola tabla. GET /me devuelve el objeto limits del propio llamante; léelo desde allí en lugar de codificar un límite en un cliente.
LímiteAnónimoGratisSolo $19Studio $79Firm $249
Páginas—3 en total25 activasilimitadoilimitado
Vida de página24h7 días, siempresiemprepermanentepermanente
Publicaciones / 24h20 por IP501,0001,000ilimitado
Tamaño por sitio10 MB25 MB250 MB250 MB1 GB
Archivos / archivo1,0001,0001,0001,0001,000
Códigos de acceso · bloqueos de correo—solo código de accesosolo código de acceso✓✓✓
Números de visitantes——aperturas, vistas, última apertura+ compromiso completo+ compromiso completo
Slug personalizado—✓✓✓✓
Dominios personalizados——11025
Espacios de cliente——110ilimitado
Insignia de Stacktreepermanecepermaneceremovidoremovidoremovido
La fila de espacios de cliente cuenta espacios ACTIVADOS, es decir, aquellos con un nombre de host vinculado o un portal habilitado. Archivar páginas bajo un cliente es gratuito en todos los planes, incluido el Gratis: la unidad de pago es la dirección, no la etiqueta. Archivar un espacio libera el espacio, y un nombre de host de espacio no consume un espacio de dominio personalizado.
Gratis cuenta publicaciones, no páginas activas. El 3 es lifetime_publishes, un contador que solo sube: eliminar una página o dejar que caduque no devuelve el espacio. El 25 de Solo es el otro modelo: páginas activas, liberadas al eliminar. Cada página gratuita caduca 7 días después de publicarse, y pasar expires_in_hours: "never" se rechaza en lugar de aterrizar silenciosamente en el techo: un agente que recibe un 201 le dice a su usuario que el enlace es permanente, por lo que la respuesta debe ser un error que no pueda confundir con éxito. accept_clamp la publica con los 7 días.
Límite de DCR: 10 registros de cliente / IP / hora. Una página caducada deja de servirse dentro de la hora y la URL entonces dice que el enlace caducó, exactamente como antes; lo que cambió es lo que sucede después. El contenido se conserva durante 30 días en lugar de destruirse en ese momento, por lo que POST /sites/:idOrSlug/restore puede restaurarlo en la misma URL, y solo entonces se purga de R2 y D1 definitivamente.
Enterprise es personalizado y anual (autoalojamiento, DPA, SLA, residencia de datos). Pregunta en gm@stacktr.ee. Las cuentas en los planes antiguos Pro y Agent mantienen los límites con los que se registraron; ninguno se vende ya.
¿Sin plan? El desbloqueo higher_limits ($25 / 30 días mediante x402) eleva una identidad gratuita a límites de flota: 1 GB por sitio, publicaciones diarias ilimitadas, sin tope de páginas, y páginas que no caducan. make_permanent ($5, una página) cancela la caducidad en una sola página en su lugar.
Errores de plan
Cada uno lleva un código estable error, el plan del llamante, un message humano, y cuando corresponde un limit. Muéstralos como una solicitud de actualización, no como una cadena cruda:
CódigoEstadoSignificado
`plan_lifetime_limit_exceeded`402Las 3 páginas gratuitas usadas. Eliminar una no ayuda.
`plan_site_limit_exceeded`402Se alcanzó el tope de páginas activas (Solo). Elimina una, o sube de plan.
`plan_password_not_available`402Los códigos de acceso no están en este plan (solo planes desconocidos; cada plan real los tiene).
`plan_password_limit_exceeded`402Se alcanzó el tope de páginas protegidas con código de acceso.
`plan_viewer_gate_not_available`402Los bloqueos de correo no están en este plan.
`plan_viewer_gate_limit_exceeded`402Se alcanzó el tope de páginas con bloqueo de correo.
`plan_domain_not_available`402Los dominios personalizados no están en este plan.
`plan_domain_limit_exceeded`402Se alcanzó el tope de dominios personalizados.
`plan_space_not_available`402Activar un espacio de cliente (dirección o portal) no está en este plan. Archivar páginas bajo un cliente aún funciona.
`plan_space_limit_exceeded`402Se alcanzó el tope de espacios de cliente activados. Archiva o desactiva uno, o sube de plan.
`plan_upload_limit_exceeded`429Se alcanzó el tope diario de publicaciones; se reinicia en una ventana móvil de 24h.
La caducidad es media excepción. Una vida de página más larga que el techo del plan se recorta en lugar de rechazarse: vuelve acortada en expires_at, con expiry_clamped: true y sin error. Pedir una página que nunca caduca en un plan con tope se rechaza en su lugar, 409 expiry_clamped, porque ese es el único caso donde la diferencia se repite a una persona como "este enlace es permanente". accept_clamp toma el techo en un campo.
Cada respuesta que lleva una página lleva su fecha límite de seis maneras: expires_at (segundos unix, sin cambios), expires_at_iso (RFC 3339 UTC, la que se muestra a un humano), ttl_seconds (nunca negativa), expiry_clamped, expiry_ceiling_hours (24 anónimo, 168 Gratis, null en planes sin techo) y expiry_source (request, plan_ceiling, plan_default o stored).
Resumen markdown completo de la superficie de marketing de Stacktree: https://stacktr.ee/llms-full.txt