CRM API — Referência de endpoints

Arc OS — The Orchestration System for AI Teams

Informações gerais

Parâmetro Valor
Base URL https://arc-os.co/api/crm
Autorização Authorization: Bearer <JWT> ou ?token=<JWT> (para SSE/WebSocket)
Content-Type application/json
Algoritmo JWT HMAC-SHA256
TTL do JWT 24 horas

Autenticação

Todos os endpoints (exceto /docs/*) exigem token JWT no header Authorization: Bearer <token>.

Para conexões SSE e WebSocket, o token é passado via query param ?token=<JWT>.

Erros de autorização

Código Descrição
401 Token ausente ou inválido
403 Sem acesso ao projeto (multi-tenancy)

Endpoints por categoria

Conta e configurações

Método Caminho Descrição
GET /account/settings Obter configurações da conta
PUT /account/settings Atualizar configurações da conta

Onboarding + Trial Credits (Phase 50.1)

Método Caminho Descrição
POST /onboarding/setup Crie o primeiro projeto. Body multipart: config (JSON) + files. O campo anthropicKey agora é opcional — se vazio + usuário com email_verified + sem período gratuito anterior, o projeto é criado com trial_mode=1 e 100K tokens gratuitos. Response: { ok, project, trial_activated }. Phase 51: retorna 402 com {error:"plan_limit_reached", reason, current, limit, plan} quando o usuário excede o limite de projetos do plano.
GET /account/trial-status Status do período gratuito para banner no UI. Response: { email, email_verified, trial_granted, has_trial_active, total_remaining, total_granted, projects: [...] }

Onboarding Checklist (Phase 54.1, issue #56)

Checklist de engajamento pós-wizard com 5 etapas. Cada etapa (workers, cli, skill, bot, issue) aceita os status completed ou skipped. As mutações são idempotentes: um POST idêntico repetido retorna o mesmo state sem gravar duplicata no activity_log. O replay não zera o state, apenas limpa dismissed_at — o UI exibe o painel novamente com o mesmo progresso.

Método Caminho Descrição
GET /onboarding/progress Estado atual do usuário 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 }. Usuário sem interações → zeros/null sem criação de linha.
POST /onboarding/event Registrar transição de etapa. Body: { step: "workers"|"cli"|"skill"|"bot"|"issue", status: "completed"|"skipped", source?: "web"|"cli" }. Validação por whitelist → 400 para step/status desconhecido. Response: mesmo shape do GET. Emite onboarding_step_completed/onboarding_step_skipped no activity_log apenas quando houve changed; ao atingir 5/5 emite adicionalmente onboarding_completed com duration_ms.
POST /onboarding/dismiss Fechar o painel (dismissed_at = now). Idempotente. Emite onboarding_dismissed na primeira chamada com payload {completed_count}.
POST /onboarding/replay Reabrir painel fechado (dismissed_at = NULL). O state das etapas não é afetado. Emite onboarding_replayed no clear-event.
POST /projects/:name/active-issue Issue #115. Vincular a sessão web atual a um issue. Body: { issue_id: number, title?: string }. Grava evento session_active_issue no activity_log (source=web).
GET /projects/:name/active-issue Issue #115. Último issue vinculado por este owner nos últimos 7d. Response: { active_issue_id, title, ts }.
GET /onboarding/cli-status Phase 54.3 (issue #58). O usuário fez login via arc login nos últimos 30 dias? Response: { installed: boolean, last_cli_at: string|null }. SSOT — linhas em activity_log com event_type='cli_invocation' e actor=chatId. O checklist de onboarding no frontend faz polling neste endpoint a cada 10s enquanto a etapa CLI estiver pendente; quando installed=true — marca a etapa cli como completed automaticamente.
GET /analytics/onboarding-funnel Phase 54.6 (issue #61). Estatísticas agregadas do funil em janela contínua. Query: hours=168 (1-720, padrão 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 onboarding_step_* + onboarding_completed + cli_invocation no activity_log. TTFC = time-to-first-arc (delta julianday da primeira etapa de onboarding até o primeiro cli_invocation por actor).

O SSOT para métricas de funil (Phase 54.6 / issue #61) são os eventos em activity_log (event_type LIKE 'onboarding_%'). A tabela onboarding_progress é um cache derivado: o UI renderiza com uma única query em vez de agregar por eventos.

Beta Feedback (Phase 53.3)

Método Caminho Descrição
POST /feedback Enviar feedback beta. Body: {type: "bug"|"feature"|"other", title, description, project?, browser?}. Registra em activity_log (event_type=feedback_report) e notifica o CEO no Telegram.
GET /admin/feedback Lista dos últimos envios (somente admin). Query: limit=50 (máx 500). Response: {items: [...], count}.

POST /feedback — validação do body: type ∈ {bug,feature,other}, title ≤ 200 chars, description ≤ 5000 chars. Sucesso → {ok: true, type, title}. O ping no Telegram é formatado como 🐞/💡/📝 New <type> feedback ... From: <user> Title: <title> + primeiros 400 caracteres da descrição.

O widget flutuante em FeedbackWidget.jsx (dashboard do CRM) passa automaticamente browser (UA + viewport + locale) e project (technical_name do projeto ativo).

Beta Invites (Phase 52.1, somente admin)

Método Caminho Descrição
GET /admin/invites Lista todos os códigos de convite + contagens (total_active, total_used). Somente admin.
POST /admin/invites Gerar N códigos. Body: {count: N, note?: string}. Somente admin. Response: {ok, codes, count}.
DELETE /admin/invites/:code Revogar código de convite não utilizado.

Atualização do fluxo de auth: POST /api/auth/register agora exige o campo invite_code (Phase 52.1 closed beta). Sem código → 403 {error: "invite_required"}. Código inválido/usado → 403 {error: "invalid_invite"}.

Billing (Phase 51)

Método Caminho Descrição
GET /account/usage Histórico de uso de tokens para o usuário autorizado (Phase 63, #148). Response: { rows: [ { project_name, worker_id, input_tokens, output_tokens, cache_tokens, total_tokens, created_at } × até 200 ], totals: { total, input, output } }. Lê token_usage_log por owner_id. Exibido no UserDropdown (UsageCard) e BillingPage (seção Token Usage).
GET /billing/status Plano atual, limites, uso e features. Cria linha Free automaticamente na primeira chamada. Response: { plan, status, current_period_end, limits, usage, features, pricing, can_upgrade, stripe_ready }
POST /billing/checkout-session Stripe Checkout (Stage 2 — retorna 501 até o Stripe SDK ser integrado)

Limites por plano (semântica OR):

Resposta 402 em POST /onboarding/setup ou POST /projects/:name/workers quando o limite é excedido: { error: "plan_limit_reached", reason: "projects_limit"|"workers_limit", current, limit, plan, message }

Usuários admin (role=admin) ignoram completamente a verificação de limites do plano — são operadores, não tenants pagantes.

Beta testers (subscriptions.plan='beta', Phase 52 F&F) também ignoram — projetos e workers ilimitados mais todas as features do plano Max. Atribuído manualmente: UPDATE subscriptions SET plan='beta' WHERE user_id=?.

Bugfix (issue #25): POST /projects/create (Quick Start, Phase 50.2) anteriormente falhava com ownerChatId is not defined por typo — corrigido; o actor de auditoria agora é registrado corretamente.

Bugfix (issue #26): allocatePort() para novos projetos agora verifica bindings TCP reais (ss -tln), não apenas o registry. Anteriormente podia retornar uma porta ocupada por serviço externo ao registry (NotebookLM bridge :19213, internal bridges) → workspace bot falhava com EADDRINUSE.

Fluxo de auth (Phase 50.1): /api/auth/register e /api/auth/login agora retornam JWT mesmo para email não verificado + flag needs_verification: true. Ações sensíveis (trial grant, billing, invites) verificam email_verified separadamente. Rate limit no signup: 3 / IP / 24h.


Projetos (9 endpoints)

Método Caminho Descrição
GET /projects Listar projetos do usuário
POST /projects/create Crie um projeto
GET /projects/:name Detalhes do projeto
GET /projects/:name/config Configuração do projeto
PUT /projects/:name/config Atualizar configuração
GET /projects/:name/protocol Protocolo do projeto
PUT /projects/:name/protocol Atualizar protocolo
GET /projects/:name/logs Logs do projeto
GET /projects/:name/metrics Métricas do projeto

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 Caminho Descrição
GET /projects/:name/workers Listar workers
POST /projects/:name/workers Crie um worker
POST /projects/:name/workers/reorder Phase 53.8 — reordenar workers. Body: {order: [id1, id2, ...]}. Reescreve atomicamente o workers_registry.json. Workers ausentes em order são adicionados ao final (proteção contra perda). Response: {ok, count, order}.
PUT /projects/:name/workers/:id Atualizar worker
DELETE /projects/:name/workers/:id Excluir worker
POST /projects/:name/workers/generate-prompt Gerar prompt de sistema
GET /projects/:name/workers/:id/telegram-token Obter token do Telegram
POST /projects/:name/workers/:id/telegram-token Phase 53.4 — valida o token via Telegram getMe, salva bot_username no vault, rejeita se o mesmo bot já estiver vinculado a outro worker (409). Response: {ok, started, bot_username}.
DELETE /projects/:name/workers/:id/telegram-token Excluir token do Telegram
POST /projects/:name/workers/:id/notify Phase 53.2 — enviar ping de evento TG ({event?, text, buttons?}). No-op silencioso se o token não estiver vinculado ou CRM_DISABLE_TG_NOTIFY=1.
POST /projects/:name/workers/:id/suggest-bot-username 53.11.1 (issue #48) — retorna 5 candidatos de username TG para o wizard de criação de bot no formato <project>_<worker>_bot + fallbacks numerados. Slugify remove hífens, trunca em 32 chars (a parte do worker é truncada primeiro). Response: {candidates: string[]}.
POST /metrics/wizard 53.11.1 (issue #48) — sink de telemetria para o wizard de criação de bot. Body: {action, duration_ms?, attempts?, success?, project?, worker_id?}. Grava em activity_log (event_type=wizard_metric), best-effort.
GET /analytics/wizard-metrics?hours=168 53.11.1 (issue #48) — resumo do funil: {starts, completions, abandons, success_rate, avg_duration_ms_completed, avg_attempts_completed, by_action}. Padrão 7 dias, clamp 1-720h.
POST /projects/:name/restart Reiniciar worker
GET /projects/:name/active-role Papel ativo atual
POST /projects/:name/active-role Alterar papel ativo

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 tem padrão 20 (anteriormente era 5, causando erro "Reached max turns" em diálogos com múltiplas etapas e tool calls).

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


Arquivos e armazenamento (8 endpoints)

Método Caminho Descrição
GET /projects/:name/files Árvore de arquivos
POST /projects/:name/files/upload Fazer upload de arquivo (multipart, máx 100MB)
POST /projects/:name/files/mkdir Criar diretório
POST /projects/:name/files/create Criar arquivo
GET /projects/:name/files/read Ler arquivo
PUT /projects/:name/files/save Salve arquivo
DELETE /projects/:name/files/delete Excluir arquivo
POST /projects/:name/files/clone Git clone de repositório

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

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


Skills (18 endpoints)

Skills do projeto

Método Caminho Descrição
GET /projects/:name/skills Listar skills do projeto
POST /projects/:name/skills Crie uma skill
PUT /projects/:name/skills/:id Atualizar skill
DELETE /projects/:name/skills/:id Excluir skill

Marketplace global

Método Caminho Descrição
GET /skills Listar skills globais
POST /skills Publicar skill
GET /skills/:id Detalhes da skill
PUT /skills/:id Atualizar skill
DELETE /skills/:id Excluir skill

Evolução e atualizações

Método Caminho Descrição
GET /skills/:id/evolution Histórico de evolução da skill
GET /skill-updates Lista de atualizações disponíveis
POST /skill-updates/:id/approve Aprovar atualização
POST /skill-updates/:id/reject Rejeitar atualização

Forks de skills

Método Caminho Descrição
GET /projects/:name/skill-forks Listar forks
POST /projects/:name/skill-forks Criar fork
PUT /projects/:name/skill-forks/:id Atualizar fork
DELETE /projects/:name/skill-forks/:id Excluir fork

Chat e mensagens

Método Caminho Descrição
POST /projects/:name/chat Enviar mensagem no chat
GET /projects/:name/chat/history Histórico do chat
POST /projects/:name/message Enviar mensagem ao worker (Phase 48.6: acorda automaticamente worker idle-killed, ~2-4s cold start; Phase 48.6.1: o wake-up também funciona em projetos single-mode, não apenas parallel)
GET /projects/:name/pins Listar notas (pins)
POST /projects/:name/pins Criar nota
DELETE /projects/:name/pins/:id Excluir nota

Wiki (4 endpoints)

Método Caminho Descrição
GET /projects/:name/wiki/tree Árvore de páginas da wiki
GET /projects/:name/wiki/file Ler página da wiki
PUT /projects/:name/wiki/save Salve página da wiki
GET /projects/:name/wiki/download Baixar wiki como arquivo ZIP

Analytics (4 endpoints)

Método Caminho Descrição
GET /analytics/activity Feed de atividade
GET /analytics/sidebar Dados para o painel lateral
GET /analytics/phases Lista de fases do projeto
POST /analytics/phases Atualizar fases do projeto

Marketplace e Sage (8 endpoints)

Método Caminho Descrição
GET /sage/scout/categories Categorias do marketplace
POST /sage/scout Buscar skills
POST /sage/scout/quick-scan Varredura rápida
POST /sage/scout/analyze Análise aprofundada de skill
POST /sage/scout/install Instalar skill
POST /sage/analyze Análise pelo Sage
GET /sage/status Status do serviço Sage
POST /sage/benchmark Executar benchmark

Memória e Knowledge

Método Caminho Descrição
POST /projects/:name/memory/refresh Atualizar memória neural
POST /projects/:name/memory/fetch-artifact Baixar artefato
GET /projects/:name/learnings Listar learnings
POST /projects/:name/learnings Adicionar learning
GET /projects/:name/knowledge-graph Grafo de conhecimento do projeto

Documentação (global, sem auth)

Método Caminho Descrição
GET /docs/tree?lang=<lang> Árvore de documentação; lang opcional (en/uk), padrão en
GET /docs/file?path=<p>&lang=<lang> Ler arquivo de documentação com language fallback

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

GET /docs/file — query: path (obrigatório), lang (opcional)


Sistema

Método Caminho Descrição
GET /system/configs Obter configurações do sistema
PUT /system/configs Atualizar configurações do sistema

Códigos de erro

Código Significado
200 Sucesso
201 Criado
400 Requisição inválida
401 Não autorizado
403 Proibido (multi-tenancy)
404 Não encontrado
409 Conflito (duplicata)
429 Muitas requisições
500 Erro no servidor

GitHub Integration (Phase 49.3)

Endpoint Método Descrição
/api/crm/projects/:name/github GET Listar repositórios GitHub vinculados ao projeto
/api/crm/projects/:name/github POST Vincular repositório (body: {owner, repo}) — retorna webhook URL + secret + instruções de configuração
/api/crm/projects/:name/github/:id DELETE Desvincular repositório
/api/crm/projects/:name/github/events GET Listar eventos GitHub recentes (Phase 49.3.1, query: ?limit=50)
/api/webhooks/github POST Receptor público de webhooks (validado por HMAC-SHA256, rate-limit 100/min)

Eventos suportados: push, pull_request, workflow_run, issues. Notificações roteadas para o Telegram do owner do projeto.

Account Security (Phase 45.4)

Endpoint Método Descrição
/api/crm/account/recovery GET Listar chaves de recuperação ativas
/api/crm/account/recovery POST Criar chave de recuperação (body: encryptedKey, keyHint)
/api/crm/account/recovery DELETE Revogar chave(s) de recuperação (body: { id } ou {} para todas)
/api/crm/account/recovery/restore GET Obter master key criptografada para recuperação

Segurança


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

Sem alteração no comportamento dos endpoints — apenas tipos internos. tsc --noEmit agora bloqueia push/CI:


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

Mudanças de comportamento em endpoints de auth + admin (correções P0 do audit Sentinel):


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

Phase 53.18 — correção de vazamento de segredos no tmux (2026-05-11)

Sem alteração no comportamento dos endpoints — apenas refactor de caminhos internos de spawn.

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

Mudanças de comportamento dos endpoints após hardening de 13 × P1:

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

Novos endpoints para sign-in via magic-link:

O union EphemeralTokenType foi ampliado: agora inclui "magic_link" junto aos tipos existentes oauth_state / password_reset / email_verification / tfa_challenge.

O frontend (CosmicCard.jsx) gerencia o state magic (contagem regressiva de 60s para reenvio) e o parâmetro de URL ?magic_token= (auto-consume → login → animação de sucesso).

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

Exportação owner-only de snapshot sanitizado do projeto como .md para compartilhar com AI externo (Gemini / ChatGPT / Perplexity / Claude.ai).

Alerta: quando o owner excede 3 exportações em 24h E prefs.notify_on_export = true (padrão OFF) — logActivity("export_alert", ...) passa pelo pipeline de notificação TG existente da Phase 53.10 (alertFired: true no body da resposta).

Scanner multi-tier (shared/secret-scanner.ts) — Tier 1 regex (PATTERN_REGISTRY do sanitizador de PII), Tier 2 entropia de Shannon ≥ 4.5 bits/char em sequências ≥ 20 chars, Tier 3 heurísticas de contexto (key=/token:/secret=/password=). Whitelist: UUID / git SHA / SHA-256 / chars repetidos / hex curto / base58 de baixa entropia. Tiers de severidade (critical/high/medium/low). Performance: < 500 ms / 1 MB.

DB migration 024 — tabelas export_audit_log + export_preferences.


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

Gerenciamento de segredos super-admin via UI do CRM em vez de ssh/editar-.env/colar-no-chat. Backend MVP (Stage 1 de 4 stages). Todos os endpoints são protegidos por requireAdmin (Phase 53.15) — retornam 403 Forbidden — admin only para não-admin e 401 Unauthorized sem JWT.

Lista de exclusão rígida NEVER_EXPOSE: CRM_SECRET (assinatura JWT) + SECRET_ENCRYPTION_KEY (meta-chave do vault) — mesmo requisição admin com token válido retorna 400 "not managed". Log de auditoria append-only (sem handler de UPDATE/DELETE); cada ação (incluindo falhas) grava uma linha com IP + UA + email.

DB migration 026 — tabela platform_audit_log. Stage 2 (frontend PlatformSettings.jsx) — publicado em 2026-05-15 (cbc8bac): grade de cards somente admin + modal de rotação (<input type="password"> + confirmação de redigitação) + drawer de auditoria; entrada na sidebar filtrada por userRole === "admin" obtido de /api/auth/me.

Polish (2026-05-15, commit 56191b0) — Reestruturação da UI de Platform Settings. Itens da resposta de GET /api/crm/platform/settings ganham 5 novos campos: category (anthropic|oauth|telegram|email), usedIn (string[] — arquivos/fluxos que consomem a chave), getFromUrl (onde obter um valor atualizado), effectAfterRotate, riskIfLeaked. Usados pelo frontend para renderizar 4 grupos de cards por seção + painel de ajuda expansível por card com contexto estruturado (Used in / Get from / Effect / Risk). Sem mudança comportamental nos endpoints mutadores (PUT/POST/restart/test).

Refactor (2026-05-16) — limpeza interna em shared/routes/platform.ts. 39 linhas removidas (16 adicionadas), sem mudança na superfície pública da API. Assinaturas e respostas dos endpoints PUT/POST/restart/test/audit inalteradas. Documentado aqui apenas porque o gate do pre-push hook de cobertura de docs dispara em qualquer diff em shared/routes/*.ts.

Atividade backdated (#117, 2026-05-16)POST /api/mcp/issues/:project/:id/log agora aceita campo opcional ts (string ISO-8601). Usado por arc retro para que entradas históricas reconstruídas sejam gravadas com seus timestamps originais. Valores com data futura são silenciosamente limitados ao momento atual dentro de addActivity() (defesa contra erros de digitação). ISO inválido → 400.

Stage 3 (2026-05-15) — hot-reload de segredos OAuth + Resend sem restart. shared/auth.ts loadOAuthConfig() agora lê getSecret("GITHUB_CLIENT_ID/SECRET" | "GOOGLE_CLIENT_ID/SECRET") a cada chamada em vez de process.env. Os callsites em master-bot/routes/auth.ts já invocavam getOAuthConfig() por requisição → 0 mudanças em callsites. RESEND_API_KEY já fazia hot-reload via shared/email.ts:47. Mudança comportamental: PUT /api/crm/platform/settings/{GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GOOGLE_CLIENT_ID|GOOGLE_CLIENT_SECRET|RESEND_API_KEY} agora entra em vigor na próxima requisição, sem exigir restart. restartTargets para essas 5 chaves está vazio → botão Restart fica oculto no UI. Caso extremo: fluxo OAuth com state-token emitido antes da rotação pode receber 400 no callback durante code-exchange — um retry do usuário resolve. ANTHROPIC_API_KEY, PLATFORM_ANTHROPIC_KEY, MASTER_BOT_TOKEN, CITADEL_BOT_TOKEN continuam exigindo restart (lidos no spawn do child-bot / init do TG long-poll).

Limpeza Phase 57.3.5 (2026-05-16) — allowlist MANAGED_KEYS reduzida de 9 para 6. Removidos: ANTHROPIC_API_KEY (operadores agora usam apenas PLATFORM_ANTHROPIC_KEY tanto para trial-credits quanto para inferência da plataforma; fallback via .env ainda funciona para caminhos de código legados até Sage/Karpathy migrarem), CITADEL_BOT_TOKEN (bot por projeto pertence às entradas de vault child:<name>:token, gerenciado pelo fluxo de onboarding de workers — não ao Platform Settings). MASTER_BOT_TOKEN teve o label atualizado para "Telegram — System Monitor Bot" e a descrição para "Server health alerts + on-demand status probes (admin-only, not a chat bot)". A Phase 58 adicionará o loop de monitoramento (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 — Consolidação UI/UX + Rastreamento de Uso de Tokens (2026-05-21, #148)

Novo endpoint:

Mudanças em claude-runner.ts:

Mudanças de UI (não API):