API y MCP.
Gestiona productos, certificaciones, páginas públicas, plantillas de pasos y expedientes de alquiler desde tu propio código o desde un agente de IA. Usa la API REST o conecta cualquier cliente MCP.
- API REST
- https://app.watch-tower.dev/api/v1
- Servidor MCP
- https://app.watch-tower.dev/mcp
- Autenticación
- Authorization: Bearer wt_live_…
Inicio rápido
1. Crea un token
En el dashboard, ve a Tokens de la API → Nuevo token → Generar token (solo gestores). Copia el secreto: solo se muestra una vez.
export WATCHTOWER_TOKEN=wt_live_…
2. Conecta
claude mcp add --transport http watchtower https://app.watch-tower.dev/mcp \
--header "Authorization: Bearer $WATCHTOWER_TOKEN"
codex mcp add watchtower --url https://app.watch-tower.dev/mcp \
--bearer-token-env-var WATCHTOWER_TOKEN
Codex lee WATCHTOWER_TOKEN del entorno cada vez que arranca.
{
"mcpServers": {
"watchtower": {
"type": "http",
"url": "https://app.watch-tower.dev/mcp",
"headers": { "Authorization": "Bearer ${WATCHTOWER_TOKEN}" }
}
}
}
Cualquier cliente MCP que acepte una URL HTTP y cabeceras usa la misma URL y la misma cabecera Authorization.
curl -s "https://app.watch-tower.dev/api/v1/products?per_page=20" \
-H "Authorization: Bearer $WATCHTOWER_TOKEN"
3. Pruébalo
Pídele a tu agente:
Lista mis productos cuya última certificación fue denegada.
O llama directamente a la API:
curl -s "https://app.watch-tower.dev/api/v1/products?last_certification_status=denied" \
-H "Authorization: Bearer $WATCHTOWER_TOKEN"
Autenticación
Manda tu token en la cabecera Authorization: Bearer wt_live_…. El mismo token sirve para la API y para el servidor MCP.
Los tokens los crea y los revoca un gestor, solo en el dashboard. Revocar un token surte efecto al momento, también en los enlaces de descarga que hubiera pedido.
Peticiones, paginación, límites y errores
Todas las rutas cuelgan de https://app.watch-tower.dev/api/v1. Peticiones y respuestas van en JSON; las fechas, en ISO 8601 y UTC, con microsegundos.
Pagina las listas con ?page=1&per_page=50 (50 por defecto, 100 como máximo). Toda lista devuelve:
{
"data": [ … ],
"page": 1, "per_page": 50,
"next_page": 2, // null en la última página
"total": 137, // todas las filas, en todas las páginas
"total_pages": 3 // al menos 1
}
El contrato completo, con cada esquema y cada código de error, está en /api/v1/openapi.yaml.
Límites
120 peticiones por minuto y por token, compartidas entre la API y el MCP. Cada respuesta trae X-RateLimit-Limit y X-RateLimit-Remaining. Por encima del límite: 429 con Retry-After en segundos.
Errores
Los errores tienen una sola forma, con su estado HTTP:
{ "error": { "code": "not_found", "message": "…" } }
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | invalid_json | El cuerpo no es JSON válido. |
| 401 | unauthorized | Falta el token, no existe o está revocado. |
| 403 | forbidden | La operación pide el token de un gestor. |
| 404 | not_found | El id no existe o no es tuyo. |
| 409 | not_publishable, external_ref_taken… | La petición choca con el estado actual. |
| 422 | invalid_parameter… | Falta un parámetro o no es válido. |
| 429 | rate_limited… | Por encima del límite de peticiones o de la cuota de correos al comprador o a las partes de un expediente. |
Operaciones
Cada fila es una ruta de la API y una herramienta MCP con el mismo nombre. Las rutas son relativas a /api/v1.
| Operación y herramienta | Ruta | Qué hace |
|---|---|---|
| list_products | GET/products | Lista los productos, del más nuevo al más antiguo. Filtra por external_ref o por el estado de su última certificación (last_certification_status). Busca con q: principio de la referencia o #id. |
| create_product | POST/products | Crea un producto. Idempotente por external_ref. |
| get_product | GET/products/{id} | Devuelve un producto con su última certificación. |
| update_product | PATCH/products/{id} | Cambia o borra su external_ref. Cambia su tipo de objeto (challenge_medium: un móvil, con guía por 3 de sus zonas, o cualquier otro objeto) o qué es (asset_kind: un piso o cualquier otra cosa) mientras no tenga certificaciones; la pareja tiene que estar permitida en tu sector. |
| add_product_identifier | POST/products/{id}/identifiers | Añade un identificador: la dirección de un piso, su referencia catastral o un código tuyo. |
| replace_product_identifier | POST/products/{id}/identifiers/{identifier_id}/replace | Corrige un identificador y guarda el anterior en su historial. |
| retire_product_identifier | POST/products/{id}/identifiers/{identifier_id}/retire | Retira un identificador que era erróneo o que ya no lo identifica. |
| get_product_history | GET/products/{id}/history | Devuelve su historial de identidad y sus certificaciones, de la más antigua a la más reciente. |
| Operación y herramienta | Ruta | Qué hace |
|---|---|---|
| request_certification | POST/products/{product_id}/certifications | Pide una certificación, la grabe el vendedor o el comprador. Si es del comprador, Watchtower le avisa por correo y tiene record_days (de 1 a 365, 7 por defecto) para grabarla. Admite una plantilla de pasos (step_template_id) o los pasos de una certificación anterior (steps_from_certification_id), y un expediente con su fase (dossier_id, phase). |
| list_certifications | GET/certifications | Lista las certificaciones. Filtra por status y product_id, ordena con sort. Busca con q: principio del código WT- o del email del comprador. Devuelve el recuento de cada estado. |
| get_certification | GET/certifications/{id} | Devuelve su estado, tomas, página /v/ y lo que es público. |
| retry_certification | POST/certifications/{id}/retry | Reintenta una certificación denegada: abre el siguiente intento, hasta 3 por cadena. |
| resend_buyer_notice | POST/certifications/{id}/buyer_notice | Vuelve a enviar el correo al comprador, a la misma dirección. |
| set_buyer_email | PUT/certifications/{id}/buyer | Pasa la certificación a otro email de comprador. |
| Operación y herramienta | Ruta | Qué hace |
|---|---|---|
| get_publication | GET/certifications/{certification_id}/publication | Devuelve lo que es público y los fotogramas candidatos. |
| set_publication | PUT/certifications/{certification_id}/publication | Fija el conjunto público entero: video, candidate_ids, frame_ids. |
| get_candidate_image | GET/frame_candidates/{token} | Devuelve el JPEG de un fotograma candidato. |
| set_public_mode | PUT/certifications/{id}/public_view | Activa o desactiva el modo público de la página. |
| Operación y herramienta | Ruta | Qué hace |
|---|---|---|
| download_video | GET/certifications/{id}/video | El vídeo original. |
| download_manifest | GET/certifications/{id}/manifest | Su manifiesto C2PA. |
| download_frame | GET/certifications/{id}/frames/{frame_id} | Un fotograma sellado: JPEG con su manifiesto C2PA dentro. |
| list_downloads | GET/certifications/{id}/downloads | Lista quién descargó el vídeo, el manifiesto o un fotograma, por cualquier canal. |
| Operación y herramienta | Ruta | Qué hace |
|---|---|---|
| list_step_templates | GET/step_templates | Lista tus plantillas por nombre, con sus pasos. Busca con q: parte del nombre. |
| create_step_template | POST/step_templates | Crea una plantilla: un name único y de 1 a 40 steps, o una copia de la plantilla de un vertical (from_vertical). |
| get_step_template | GET/step_templates/{id} | Devuelve una plantilla con sus pasos en orden. |
| update_step_template | PATCH/step_templates/{id} | Le cambia el nombre, o sustituye sus pasos, sus reglas, su perfil de captura o su vertical. Las certificaciones ya pedidas guardan su copia. |
| delete_step_template | DELETE/step_templates/{id} | La archiva. Las certificaciones ya pedidas con ella conservan sus pasos. |
| list_verticals | GET/verticals | Lista los verticales de tu sector, cada uno con su plantilla ya hecha (hoy, vivienda: un piso en alquiler, entrada y salida). |
| Operación y herramienta | Ruta | Qué hace |
|---|---|---|
| list_dossiers | GET/dossiers | Lista tus expedientes (EX-…), del más reciente al más antiguo. Filtra por product_id y status. |
| create_dossier | POST/dossiers | Abre un expediente sobre un producto, uno abierto por producto. response_days: de 1 a 60, 10 por defecto. |
| get_dossier | GET/dossiers/{id} | Devuelve un expediente con sus partes. |
| update_dossier | PATCH/dossiers/{id} | Cambia el external_ref o los response_days de un expediente abierto. |
| cancel_dossier | POST/dossiers/{id}/cancel | Cancela un expediente abierto. |
| add_dossier_party | POST/dossiers/{id}/parties | Añade una parte por su email (inquilino, propietario u observador); Watchtower le avisa por correo. |
| revoke_dossier_party | DELETE/dossiers/{id}/parties/{party_id} | Revoca una parte. |
| resend_party_notice | POST/dossiers/{id}/parties/{party_id}/notice | Vuelve a avisar por correo a una parte de un expediente abierto. |
| Operación y herramienta | Ruta | Qué hace |
|---|---|---|
| get_account | GET/account | Devuelve la empresa con su sector y las opciones que permite, el usuario del token, el propio token (sin el secreto) y el equipo. |
| update_account_field_settings | PATCH/account/field_settings | Elige cómo se suben las tomas: solo por wifi (wifi_only, por defecto) o también con datos móviles (cellular_allowed). Solo con el token de un gestor. |
| list_api_tokens | GET/api_tokens | Lista los tokens de la empresa, sin su secreto. Solo con el token de un gestor. |
No disponible por API ni MCP: la grabación (solo en la app); los tokens, el inicio de sesión, el equipo y sus invitaciones, crear una empresa y la página de la cuenta (solo en el dashboard).
Para autores de clientes MCP
El servidor de /mcp usa Streamable HTTP, sin estado: cada llamada es un POST JSON-RPC que se responde con application/json. Los errores de negocio devuelven un resultado de herramienta con isError: true. download_video, download_manifest y download_frame devuelven un enlace firmado; pídelo con un GET, sin cabecera Authorization.
Llamar a una herramienta a mano
curl -s https://app.watch-tower.dev/mcp \
-H "Authorization: Bearer $WATCHTOWER_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_products","arguments":{}}}'