CRM API — Referencia de endpoints

Arc OS — The Orchestration System for AI Teams

Información general

Parámetro Valor
Base URL https://arc-os.co/api/crm
Autorización Authorization: Bearer <JWT> o ?token=<JWT> (para SSE/WebSocket)
Content-Type application/json
Algoritmo JWT HMAC-SHA256
TTL JWT 24 horas

Autenticación

Todos los endpoints (excepto /docs/*) requieren un token JWT en el header Authorization: Bearer <token>.

Para conexiones SSE y WebSocket el token se pasa mediante el query parameter ?token=<JWT>.

Errores de autorización

Código Descripción
401 Token ausente o inválido
403 Sin acceso al proyecto (multi-tenancy)

Endpoints por categoría

Cuenta y ajustes

Método Ruta Descripción
GET /account/settings Obtener ajustes de cuenta
PUT /account/settings Actualizar ajustes de cuenta
GET /account/usage Historial de uso de tokens para el usuario autorizado (Phase 63, #148). Response: { rows: [ { project_name, worker_id, input_tokens, output_tokens, cache_tokens, total_tokens, created_at } × hasta 200 ], totals: { total, input, output } }. Lee token_usage_log por owner_id. Mostrado en UserDropdown (UsageCard) y BillingPage (sección Token Usage).

Onboarding + Trial Credits (Phase 50.1)

Método Ruta Descripción
POST /onboarding/setup Crear el primer proyecto. Body multipart: config (JSON) + files. El campo anthropicKey ahora es opcional — si está vacío + el usuario tiene email verificado + no ha recibido prueba gratuita antes, el proyecto se crea en trial_mode=1 con 100K free tokens. Response: { ok, project, trial_activated }. Phase 51: devuelve 402 con {error:"plan_limit_reached", reason, current, limit, plan} cuando el usuario supera el límite de proyectos del plan.
GET /account/trial-status Estado de prueba gratuita para el banner de UI. Response: { email, email_verified, trial_granted, has_trial_active, total_remaining, total_granted, projects: [...] }

Onboarding Checklist (Phase 54.1, issue #56)

Checklist de engagement post-wizard con 5 pasos. Cada paso (workers, cli, skill, bot, issue) acepta el estado completed o skipped. Las mutaciones son idempotentes: un POST idéntico repetido devuelve el mismo estado sin escribir un duplicado en activity_log. El replay no reinicia el estado, solo elimina dismissed_at — la UI vuelve a mostrar el panel con el mismo progreso.

Método Ruta Descripción
GET /onboarding/progress Estado actual para el usuario autenticado. Response: { steps:["workers","cli","skill","bot","issue"], state:{<step>:<status>}, completed_count, total_steps:5, completed_at, dismissed_at, source, started_at, updated_at }. Usuario sin actividad → ceros/null sin crear fila.
POST /onboarding/event Registrar transición de paso. Body: { step: "workers"|"cli"|"skill"|"bot"|"issue", status: "completed"|"skipped", source?: "web"|"cli" }. Validación por whitelist → 400 para step/status desconocido. Response: mismo shape que GET. Emite onboarding_step_completed/onboarding_step_skipped en activity_log solo al changed; al llegar a 5/5 emite adicionalmente onboarding_completed con duration_ms.
POST /onboarding/dismiss Cerrar el panel (dismissed_at = now). Idempotente. Emite onboarding_dismissed en la primera llamada con payload {completed_count}.
POST /onboarding/replay Volver a abrir el panel cerrado (dismissed_at = NULL). El estado de los pasos no se modifica. Emite onboarding_replayed al limpiar el evento.
POST /projects/:name/active-issue Issue #115. Vincular la sesión web actual a un issue. Body: { issue_id: number, title?: string }. Escribe evento session_active_issue en activity_log (source=web).
GET /projects/:name/active-issue Issue #115. Último issue vinculado de este owner en los últimos 7 días. Response: { active_issue_id, title, ts }.
GET /onboarding/cli-status Phase 54.3 (issue #58). ¿El usuario inició sesión con arc login en los últimos 30 días? Response: { installed: boolean, last_cli_at: string|null }. SSOT — filas en activity_log con event_type='cli_invocation' y actor=chatId. El checklist de onboarding del frontend hace polling a este endpoint cada 10s mientras el paso CLI esté pendiente; cuando installed=true — marca automáticamente el paso cli como completado.
GET /analytics/onboarding-funnel Phase 54.6 (issue #61). Estadísticas agregadas del funnel en ventana deslizante. Query: hours=168 (1-720, default 7d). Response: { hours, total_steps:5, started_users, completed_users, completion_rate, per_step: [{step, completed, skipped}…], duration_p50_ms, duration_p90_ms, ttfc_p50_ms, ttfc_sample_size }. SSOT — eventos de activity_log onboarding_step_* + onboarding_completed + cli_invocation. TTFC = time-to-first-arc (delta julianday desde el primer onboarding-step hasta el primer cli_invocation por actor).

El SSOT para las métricas del funnel (Phase 54.6 / issue #61) son los eventos en activity_log (event_type LIKE 'onboarding_%'). La tabla onboarding_progress es un caché derivado: la UI se renderiza con una sola consulta en lugar de agregar eventos.

Beta Feedback (Phase 53.3)

Método Ruta Descripción
POST /feedback Enviar feedback beta. Body: {type: "bug"|"feature"|"other", title, description, project?, browser?}. Escribe en activity_log (event_type=feedback_report) y hace ping al CEO en Telegram.
GET /admin/feedback Lista de submissions recientes (solo admin). Query: limit=50 (máx 500). Response: {items: [...], count}.

POST /feedback — validación del body: type ∈ {bug,feature,other}, title ≤200 chars, description ≤5000 chars. Éxito → {ok: true, type, title}. El ping de Telegram tiene el formato 🐞/💡/📝 New <type> feedback ... From: <user> Title: <title> + primeros 400 caracteres de la descripción.

El widget flotante en FeedbackWidget.jsx (CRM dashboard) envía automáticamente browser (UA + viewport + locale) y project (technical_name del proyecto activo).

Beta Invites (Phase 52.1, solo admin)

Método Ruta Descripción
GET /admin/invites Lista de todos los códigos de invitación + conteos (total_active, total_used). Solo admin.
POST /admin/invites Generar N códigos. Body: {count: N, note?: string}. Solo admin. Response: {ok, codes, count}.
DELETE /admin/invites/:code Revocar código de invitación no utilizado.

Actualización del flujo de auth: POST /api/auth/register ahora requiere el campo invite_code (closed beta Phase 52.1). Sin código → 403 {error: "invite_required"}. Código inválido/usado → 403 {error: "invalid_invite"}.

Billing (Phase 51)

Método Ruta Descripción
GET /billing/status Plan actual, límites, usage, features. Crea automáticamente la fila Free en la primera llamada. Response: { plan, status, current_period_end, limits, usage, features, pricing, can_upgrade, stripe_ready }
POST /billing/checkout-session Stripe Checkout (Stage 2 — devuelve 501 hasta que el SDK de Stripe esté integrado)

Límites del plan (semántica OR):

Respuesta 402 en POST /onboarding/setup o POST /projects/:name/workers cuando se supera el límite: { error: "plan_limit_reached", reason: "projects_limit"|"workers_limit", current, limit, plan, message }

Los usuarios admin (role=admin) omiten completamente la verificación de límites del plan — son operadores, no tenants de pago.

Los beta-testers (subscriptions.plan='beta', Phase 52 F&F) también la omiten — proyectos y workers ilimitados más todas las features Max. Se asigna manualmente: UPDATE subscriptions SET plan='beta' WHERE user_id=?.

Bugfix (issue #25): POST /projects/create (Quick Start, Phase 50.2) antes fallaba con ownerChatId is not defined por un typo — corregido, el actor del audit ahora se registra correctamente.

Bugfix (issue #26): allocatePort() para nuevos proyectos ahora prueba los bindings TCP reales (ss -tln), no solo el registry. Antes podía devolver un puerto ocupado por un servicio fuera del registry (NotebookLM bridge :19213, internal bridges) → el workspace bot fallaba con EADDRINUSE.

Flujo de auth (Phase 50.1): /api/auth/register y /api/auth/login ahora devuelven JWT incluso para email no verificado + flag needs_verification: true. Las acciones sensibles (trial grant, billing, invites) verifican email_verified por separado. Rate limit en signup: 3 / IP / 24h.


Proyectos (9 endpoints)

Método Ruta Descripción
GET /projects Lista de proyectos del usuario
POST /projects/create Crear proyecto
GET /projects/:name Detalles del proyecto
GET /projects/:name/config Configuración del proyecto
PUT /projects/:name/config Actualizar configuración
GET /projects/:name/protocol Protocolo del proyecto
PUT /projects/:name/protocol Actualizar protocolo
GET /projects/:name/logs Logs del proyecto
GET /projects/:name/metrics Métricas del proyecto

POST /projects/create — body:

{
  "technical_name": "string",
  "displayName": "string",
  "description": "string",
  "icon": "string",
  "color": "string"
}

GET /projects/:name/logs — query: category, lines

GET /projects/:name/metrics — query: since, until


Workers (11 endpoints)

Método Ruta Descripción
GET /projects/:name/workers Lista de workers
POST /projects/:name/workers Crear worker
POST /projects/:name/workers/reorder Phase 53.8 — reordenar workers. Body: {order: [id1, id2, ...]}. Reescribe workers_registry.json de forma atómica. Los workers ausentes en order se añaden al final (protección contra pérdida de datos). Response: {ok, count, order}.
PUT /projects/:name/workers/:id Actualizar worker
DELETE /projects/:name/workers/:id Eliminar worker
POST /projects/:name/workers/generate-prompt Generar prompt de sistema
GET /projects/:name/workers/:id/telegram-token Obtener token de Telegram
POST /projects/:name/workers/:id/telegram-token Phase 53.4 — valida el token con Telegram getMe, guarda bot_username en el vault, rechaza si el mismo bot ya está vinculado a otro worker (409). Response: {ok, started, bot_username}.
DELETE /projects/:name/workers/:id/telegram-token Eliminar token de Telegram
POST /projects/:name/workers/:id/notify Phase 53.2 — enviar ping de evento TG ({event?, text, buttons?}). No-op silencioso si no hay token vinculado o CRM_DISABLE_TG_NOTIFY=1.
POST /projects/:name/workers/:id/suggest-bot-username 53.11.1 (issue #48) — devuelve 5 candidatos de username TG para el wizard de creación de bot con formato <project>_<worker>_bot + fallbacks numerados. Slugify elimina guiones, trunca a 32 chars (la parte del worker se trunca primero). Response: {candidates: string[]}.
POST /metrics/wizard 53.11.1 (issue #48) — sink de telemetría para el wizard de creación de bot. Body: {action, duration_ms?, attempts?, success?, project?, worker_id?}. Escribe en activity_log (event_type=wizard_metric), best-effort.
GET /analytics/wizard-metrics?hours=168 53.11.1 (issue #48) — resumen del funnel: {starts, completions, abandons, success_rate, avg_duration_ms_completed, avg_attempts_completed, by_action}. Default 7 días, clamp 1-720h.
POST /projects/:name/restart Reiniciar worker
GET /projects/:name/active-role Rol activo actual
POST /projects/:name/active-role Cambiar rol activo

POST /projects/:name/workers — body:

{
  "label": "string",
  "icon": "string",
  "type": "terminal | telegram",
  "model": "string",
  "max_turns": 20,
  "tools": ["Read", "Write", "Bash"],
  "system_prompt": "string",
  "focus_dirs": ["src/", "docs/"]
}

max_turns por defecto es 20 (antes era 5, lo que causaba el error "Reached max turns" en diálogos multi-paso con tool calls).

POST /projects/:name/restart — query: worker_id


Archivos y almacenamiento (8 endpoints)

Método Ruta Descripción
GET /projects/:name/files Árbol de archivos
POST /projects/:name/files/upload Subir archivo (multipart, máx 100MB)
POST /projects/:name/files/mkdir Crear directorio
POST /projects/:name/files/create Crear archivo
GET /projects/:name/files/read Leer archivo
PUT /projects/:name/files/save Guardar archivo
DELETE /projects/:name/files/delete Eliminar archivo
POST /projects/:name/files/clone Git clone de repositorio

GET /projects/:name/files — query: path

GET /projects/:name/files/read — query: path, raw


Skills (18 endpoints)

Skills del proyecto

Método Ruta Descripción
GET /projects/:name/skills Lista de skills del proyecto
POST /projects/:name/skills Crear skill
PUT /projects/:name/skills/:id Actualizar skill
DELETE /projects/:name/skills/:id Eliminar skill

Marketplace global

Método Ruta Descripción
GET /skills Lista de skills globales
POST /skills Publicar skill
GET /skills/:id Detalles de skill
PUT /skills/:id Actualizar skill
DELETE /skills/:id Eliminar skill

Evolución y actualizaciones

Método Ruta Descripción
GET /skills/:id/evolution Historial de evolución de la skill
GET /skill-updates Lista de actualizaciones disponibles
POST /skill-updates/:id/approve Aceptar actualización
POST /skill-updates/:id/reject Rechazar actualización

Forks de skills

Método Ruta Descripción
GET /projects/:name/skill-forks Lista de forks
POST /projects/:name/skill-forks Crear fork
PUT /projects/:name/skill-forks/:id Actualizar fork
DELETE /projects/:name/skill-forks/:id Eliminar fork

Chat y mensajes

Método Ruta Descripción
POST /projects/:name/chat Enviar mensaje al chat
GET /projects/:name/chat/history Historial de chat
POST /projects/:name/message Enviar mensaje al worker (Phase 48.6: wake-up automático del worker inactivo, ~2-4s cold start; Phase 48.6.1: el wake-up ahora funciona también en proyectos single-mode, no solo parallel)
GET /projects/:name/pins Lista de notas (pins)
POST /projects/:name/pins Crear nota
DELETE /projects/:name/pins/:id Eliminar nota

Wiki (4 endpoints)

Método Ruta Descripción
GET /projects/:name/wiki/tree Árbol de páginas wiki
GET /projects/:name/wiki/file Leer página wiki
PUT /projects/:name/wiki/save Guardar página wiki
GET /projects/:name/wiki/download Descargar wiki como archivo ZIP

Analytics (4 endpoints)

Método Ruta Descripción
GET /analytics/activity Feed de actividad
GET /analytics/sidebar Datos para el panel lateral
GET /analytics/phases Lista de fases del proyecto
POST /analytics/phases Actualizar fases del proyecto

Marketplace y Sage (8 endpoints)

Método Ruta Descripción
GET /sage/scout/categories Categorías del marketplace
POST /sage/scout Buscar skills
POST /sage/scout/quick-scan Escaneo rápido
POST /sage/scout/analyze Análisis profundo de skill
POST /sage/scout/install Instalar skill
POST /sage/analyze Análisis de Sage
GET /sage/status Estado del servicio Sage
POST /sage/benchmark Ejecutar benchmark

Memoria y Knowledge

Método Ruta Descripción
POST /projects/:name/memory/refresh Actualizar memoria neural
POST /projects/:name/memory/fetch-artifact Descargar artefacto
GET /projects/:name/learnings Lista de learnings
POST /projects/:name/learnings Añadir learning
GET /projects/:name/knowledge-graph Grafo de conocimiento del proyecto

Documentación (global, sin auth)

Método Ruta Descripción
GET /docs/tree?lang=<lang> Árbol de documentación; lang opcional (en/uk), default en
GET /docs/file?path=<p>&lang=<lang> Leer archivo de documentación con language fallback

GET /docs/tree — query: lang (opcional)

GET /docs/file — query: path (obligatorio), lang (opcional)


Sistema

Método Ruta Descripción
GET /system/configs Obtener configuraciones del sistema
PUT /system/configs Actualizar configuraciones del sistema

Códigos de error

Código Significado
200 Éxito
201 Creado
400 Solicitud inválida
401 No autorizado
403 Prohibido (multi-tenancy)
404 No encontrado
409 Conflicto (duplicado)
429 Demasiadas solicitudes
500 Error del servidor

GitHub Integration (Phase 49.3)

Endpoint Method Descripción
/api/crm/projects/:name/github GET Lista de repos de GitHub vinculados al proyecto
/api/crm/projects/:name/github POST Vincular repo (body: {owner, repo}) — devuelve webhook URL + secret + instrucciones de configuración
/api/crm/projects/:name/github/:id DELETE Desvincular repo
/api/crm/projects/:name/github/events GET Lista de GitHub events recientes (Phase 49.3.1, query: ?limit=50)
/api/webhooks/github POST Receptor público de webhooks (validado con HMAC-SHA256, rate-limit 100/min)

Eventos soportados: push, pull_request, workflow_run, issues. Las notificaciones se enrutan al Telegram del propietario del proyecto.

Account Security (Phase 45.4)

Endpoint Method Descripción
/api/crm/account/recovery GET Lista de recovery keys activas
/api/crm/account/recovery POST Crear recovery key (body: encryptedKey, keyHint)
/api/crm/account/recovery DELETE Revocar recovery key(s) (body: { id } o {} para todas)
/api/crm/account/recovery/restore GET Obtener encrypted master key para recuperación

Seguridad


Phase 53.13 — baseline de type-safety (2026-05-10)

Sin cambios de comportamiento en endpoints — solo tipos internos. tsc --noEmit ahora bloquea push/CI:


Phase 53.15 — Sentinel Sprint 1 (2026-05-10)

Cambios de comportamiento en endpoints de auth + admin (correcciones P0 del audit de Sentinel):


Phase 53.21 — Sentinel P2 batch 2 (2026-05-12)

Phase 53.18 — corrección de filtración de secretos en tmux (2026-05-11)

Sin cambios de comportamiento en endpoints — solo refactor de rutas internas de spawn.

Phase 53.16 — Sentinel Sprint 2 (2026-05-10)

Cambios de comportamiento en endpoints tras el hardening de 13 × P1:

Phase 55 — Cosmic Editorial login (2026-05-13)

Nuevos endpoints para inicio de sesión por magic-link:

El union EphemeralTokenType se extendió: ahora incluye "magic_link" junto a los existentes oauth_state / password_reset / email_verification / tfa_challenge.

El frontend (CosmicCard.jsx) gestiona el estado magic (cuenta regresiva de reenvío de 60s) y el parámetro URL ?magic_token= (auto-consume → login → animación de éxito).

Phase 56 — AI Interop / Project Context Export (2026-05-13)

Exportación exclusiva para owners de un snapshot saneado del proyecto como .md para transferirlo a una IA externa (Gemini / ChatGPT / Perplexity / Claude.ai).

Alerta: cuando el owner supera 3 exportaciones en 24h Y prefs.notify_on_export = true (por defecto OFF) — logActivity("export_alert", ...) pasa por el pipeline de notificación TG de Phase 53.10 (alertFired: true en el body de la respuesta).

El scanner multi-nivel (shared/secret-scanner.ts) — Tier 1 regex (PATTERN_REGISTRY del sanitizador PII), Tier 2 entropía Shannon ≥4.5 bits/char en cadenas de ≥20 chars, Tier 3 heurísticas de contexto (key=/token:/secret=/password=). Whitelist: UUID / git SHA / SHA-256 / chars repetidos / hex corto / base58 de baja entropía. Niveles de severidad (critical/high/medium/low). Rendimiento: <500 ms / 1 MB.

Migración DB 024 — tablas export_audit_log + export_preferences.


Phase 57 — Platform Settings (seguimiento Sentinel #103, 2026-05-15)

Gestión de secretos super-admin desde la UI de CRM en lugar de ssh/editar-.env/pegar-en-chat. Backend MVP (Stage 1 de 4 stages). Todos los endpoints requieren requireAdmin (Phase 53.15) — devuelven 403 Forbidden — admin only para no-admin, 401 Unauthorized sin JWT.

Lista de exclusión fija NEVER_EXPOSE: CRM_SECRET (firma JWT) + SECRET_ENCRYPTION_KEY (meta-clave del vault) — incluso una solicitud admin con token válido devuelve 400 "not managed". El log de auditoría es append-only (sin handler UPDATE/DELETE), cada acción (incluidas las fallidas) escribe una fila con IP + UA + email.

Migración DB 026 — tabla platform_audit_log. Stage 2 (frontend PlatformSettings.jsx) — publicado el 2026-05-15 (cbc8bac): grid de tarjetas solo para admin + modal de rotación (<input type="password"> + confirmación de reescritura) + drawer de auditoría; entrada en sidebar filtrada por userRole === "admin" obtenido de /api/auth/me.

Polish (2026-05-15, commit 56191b0) — Restructura de la UI de Platform Settings. Los items de la respuesta de GET /api/crm/platform/settings ganan 5 nuevos campos: category (anthropic|oauth|telegram|email), usedIn (string[] — archivos/flujos que consumen la clave), getFromUrl (dónde obtener un valor nuevo), effectAfterRotate, riskIfLeaked. El frontend los utiliza para renderizar 4 grupos de tarjetas por sección + panel de ayuda colapsable por tarjeta con contexto estructurado (Used in / Get from / Effect / Risk). Sin cambios de comportamiento en los endpoints mutadores (PUT/POST/restart/test).

Refactor (2026-05-16) — cleanup interno de shared/routes/platform.ts. Se eliminaron 39 líneas (16 añadidas), sin cambios en la superficie pública de la API. Las firmas y respuestas de los endpoints PUT/POST/restart/test/audit no cambian. Documentado aquí solo porque el gate pre-push de cobertura de documentación se activa ante cualquier diff en shared/routes/*.ts.

Actividad backdated (#117, 2026-05-16)POST /api/mcp/issues/:project/:id/log ahora acepta el campo opcional ts (string ISO-8601). Lo usa arc retro en la reconstrucción para que las entradas históricas queden en sus timestamps originales. Los valores con fecha futura se recortan silenciosamente a now dentro de addActivity() (defensa contra errores de tipeo). ISO inválido → 400.

Stage 3 (2026-05-15) — recarga en caliente de secretos OAuth + Resend sin reinicio. shared/auth.ts loadOAuthConfig() ahora lee getSecret("GITHUB_CLIENT_ID/SECRET" | "GOOGLE_CLIENT_ID/SECRET") por llamada en lugar de process.env. Los callsites en master-bot/routes/auth.ts ya invocaban getOAuthConfig() por request → 0 cambios en callsites. RESEND_API_KEY ya tiene hot-reload mediante shared/email.ts:47. Cambio de comportamiento: PUT /api/crm/platform/settings/{GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GOOGLE_CLIENT_ID|GOOGLE_CLIENT_SECRET|RESEND_API_KEY} ahora surte efecto en la siguiente solicitud, sin necesidad de reinicio. restartTargets para estas 5 claves está vacío → el botón Restart en la UI está oculto. Caso límite: un flujo OAuth con state-token emitido antes de la rotación puede recibir un 400 en el callback durante el code-exchange — el usuario puede resolver reintentando. ANTHROPIC_API_KEY, PLATFORM_ANTHROPIC_KEY, MASTER_BOT_TOKEN, CITADEL_BOT_TOKEN siguen requiriendo reinicio (se leen al hacer spawn del child-bot / inicio del long-poll TG).

Cleanup Phase 57.3.5 (2026-05-16) — allowlist MANAGED_KEYS reducida de 9 a 6. Eliminadas: ANTHROPIC_API_KEY (los operadores ahora usan PLATFORM_ANTHROPIC_KEY tanto para trial-credits como para inferencia de plataforma; el fallback a .env sigue funcionando para rutas de código legado hasta que Sage/Karpathy migren), CITADEL_BOT_TOKEN (el bot por proyecto pertenece a las entradas child:<name>:token del vault, gestionadas por el flujo de onboarding de workers — no en Platform Settings). MASTER_BOT_TOKEN reutilizado: label → "Telegram — System Monitor Bot", descripción → "Server health alerts + on-demand status probes (admin-only, not a chat bot)". La Phase 58 añadirá el loop de monitoreo (alertas push para crash de worker / disco / RAM / brute-force SSH / bypass CF + comandos /status, /health, /errors, /restart). Conjunto final: PLATFORM_ANTHROPIC_KEY + GITHUB×2 + GOOGLE×2 + MASTER_BOT_TOKEN + RESEND_API_KEY (refs #103).

Phase 63 — Consolidación UI/UX + Seguimiento de Uso de Tokens (2026-05-21, #148)

Nuevo endpoint:

Cambios en claude-runner.ts:

Cambios de UI (no API):