K
Kodama Vault
knowledge hub
Vault
HomeBoardMap of ContentChatConversasAuditoria
Agentes
AgentsIssuesTerminalPreviews
Sistema
MCPSetup MCPSettings
Brain
Global agent instructions
Análise custos migração — evitar senha no payloadLevantamento fluxo registro + duplicados StripeRelatório segurança + pentes finos (Cláudio)Revisão security concerns e race conditionsMagic link / esqueceu senha via SupabaseCorrigir erros pós-upgrade TypeScriptTestar PRs do agente Vault para mergeAnálise de 3 issues para iniciarErro no terminal do VSCodePR #173 — aguardando aprovação do LeoTestar fluxo ponta a ponta — criação de clients no StripePR #172 — testar e subir correção de funções deprecatedPitch de vendas SaaS — agendar call de conversãoOrganizar issues e bugs rápidos para a semanaMerge PR cadastro-novo — funcionalidades e correçõesCorrigir bugs PR #173 e #172 — image domainsPR mesosóico — página de acesso mobile + segurança OTPRefatoração de códigos — PR #202Ajustes em PRs abertos de ontemEstudo de jornada de compra e técnicas de fechamentoDefinir preço e entregável do produtoProspecção de reuniões para esta semanaAgente anti AI slop — centralização de conhecimento ConnfitPR #179 — resolver conflitos e erros de teste CLIAlinhamento de preços e usos da ConffitFix adicional para PR #183 — perfil do usuárioCorrigir estilização da Connfit para identidade visualSubir modificações no copy da ConnfitCriação de 4 campanhas no Meta AdsRevisão de PRs do GilinesExploração do Roblox EditorRelatório João — devolutiva TikTok ShopReunião presencial Zassi Uniformes — diagnóstico automaçõesCriar repositório de diagnósticos e relatórios de entrevistasDiagnóstico da ZassiGeração de relatórios para reuniões de fechamentoProposta Zassi — apresentação amanhãProspecção — Clínica Odontológica Dr. But
VPS Hermes — acesso e estrutura
Always Commit Push DeployHermes Voice GeminiHermes VPSKodama Prospects TrackerMEMORYObsidian VaultRoblox Mining Sim
OpenSpec -- Spec-Driven Development no VaultPlano de Teste — OpenSpec Vault Persistence
CaumzitoNyxzZanini
vek1-api — arquiteturavek1-api — contextovek1-api — decisões técnicasvek1-api — catálogo de endpointsvek1-api — gotchasvek1-api — integrações externasvek1-api — atividade recente
Claude Code — Setup MCP VaultClaude Desktop — Setup MCP Vault (remote)VS Code + Copilot — Setup MCP Vault
Skill — Carousel Designer (Paper Style)
Standup 2026-05-14Standup 2026-05-15Standup 2026-05-16Standup 2026-05-17Standup 2026-05-18Standup 2026-05-19Standup 2026-05-20Standup 2026-05-21Standup 2026-05-22Standup 2026-05-25Standup 2026-05-26Standup 2026-05-27Standup 2026-05-28Standup 2026-05-29Standup 2026-06-01Standup 2026-06-02Standup 2026-06-03Standup 2026-06-05Standup 2026-06-11Standup 2026-06-15Standup 2026-06-16Standup 2026-06-17Standups
MOCWelcome
v0.3
K
Kodama Vault
brain / projects / vek1-api

vek1-api — catálogo de endpoints

Catálogo de endpoints

Todos os endpoints /internal/* exigem token + (na maioria) X-Actor-User-Id pra ownership check. Endpoints públicos (/chat, /embed, /health, /billing/plans-public, /webhooks/stripe, etc.) ficam atrás do firewall do VPS mas sem token.

Auth scope (X-Auth-Token) — routers/auth.py

Better Auth HTTP backing store. Endpoints purpose-built (não CRUD genérico):

Users

Path Adapter call
POST /internal/auth/users createUser
GET /internal/auth/users/by-id/{id} findUserById
GET /internal/auth/users/by-email/{email} findUserByEmail (cached TTL curto)
PATCH /internal/auth/users/{id} patchUser
DELETE /internal/auth/users/{id} deleteUser (204)

Sessions

Path Adapter call
POST /internal/auth/sessions createSession
GET /internal/auth/sessions/by-token/{token} findSessionByToken (cached)
GET /internal/auth/sessions/by-id/{id} findSessionById
PATCH /internal/auth/sessions/{id} patchSession
DELETE /internal/auth/sessions/{id} deleteSession (204)
DELETE /internal/auth/sessions/by-user/{user_id} bulk delete (logout all)

Accounts

Path Adapter call
POST /internal/auth/accounts createAccount
GET /internal/auth/accounts/by-user/{user_id} findAccountsByUser (inclui password hash — fix PR #23)
GET /internal/auth/accounts/by-provider?provider_id&account_id findAccountByProvider
GET /internal/auth/accounts/password-by-user/{user_id} hash lookup pro login
PATCH /internal/auth/accounts/{id} patchAccount
DELETE /internal/auth/accounts/{id} deleteAccount (204)

Verifications (PKCE, reset password, email verify)

Path Adapter call
POST /internal/auth/verifications createVerification
GET /internal/auth/verifications/by-value/{value} findVerificationByValue (PR #22)
GET /internal/auth/verifications/by-identifier/{identifier} findVerificationByIdentifier (PR #22)
POST /internal/auth/verifications/consume consumeOne — DELETE..RETURNING atomic (anti-race)
DELETE /internal/auth/verifications/by-identifier/{identifier} bulk delete

Misc

Path Função
GET /internal/auth/_cache-stats métrica interna (dev)

App scope (X-Internal-Token + X-Actor-User-Id)

Billing — routers/billing.py (NEW PR #24)

Path O que faz
GET /internal/billing/plans Lista planos ativos pra UI signup/upgrade (com stripe_price_id)
GET /internal/billing/summary Sub + settings + usage agregado pra /billing UI
POST /internal/billing/subscriptions Create/update Stripe sub com 2 prices (recurring + metered), proration on switch
DELETE /internal/billing/subscriptions cancel_at_period_end
POST /internal/billing/setup-intent client_secret pro Stripe Elements montar form de cartão
POST /internal/billing/topup PaymentIntent BRL R$30-5000 (off-session se cartão, Elements se sem)
GET /internal/billing/settings Lê company_billing_settings
PATCH /internal/billing/settings Update cap, auto_overage, alert_pct
GET /internal/billing/usage-this-month used + topup_remaining + period
GET /internal/billing/invoices Proxy Stripe.Invoice.list com hosted_invoice_url
POST /internal/billing/_trigger-usage-report Debug: dispara worker manualmente
POST /internal/billing/_trigger-overage-charge Debug: dispara try_charge_overage

Orders — routers/orders.py

Path O que faz
POST /internal/orders Cria order (validate items vs products, dropa fake product_ids)
GET /internal/orders?store_ids&status&limit&offset Lista com filtros
GET /internal/orders/{id} Detalhe + items + events + payment_attempts
POST /internal/orders/{id}/transition State machine transition (valida from → to)
POST /internal/orders/{id}/attach-proof Anexa comprovante (foto/PDF do PIX manual via webhook Evolution)
GET /internal/orders/stats/{store_id} Stats agregadas
GET /internal/orders/store/{store_id}/payment-settings Lê store_payment_settings
PUT /internal/orders/store/{store_id}/payment-settings Patch settings (AbacatePay key, PIX expires, COD, manual PIX)
POST /internal/orders/{id}/checkout-state Salva BR Code + payment_link_url após criar charge no AbacatePay
POST /internal/orders/{id}/payment-attempt Log de tentativa de pagamento
GET /internal/orders/awaiting-proof-by-lead/{lead_id} Busca order awaiting_proof do lead (chamado pelo webhook Evolution pra anexar mídia)
GET /internal/orders/by-payment-external-id/{charge_id} Lookup pelo external_id (chamado pelo AbacatePay webhook)

Leads — routers/leads.py

Path O que faz
POST /internal/leads/ensure Idempotente: cria ou retorna lead por (store_id, channel, external_id)
GET /internal/leads/{id} Detalhe
GET /internal/leads?store_ids&status&channel&limit&offset Lista filtrada (valida ownership por store_ids)
PATCH /internal/leads/{id} Atualiza campos (name, phone, address, custom_attributes, interests, profile_summary, profile_embedding)
POST /internal/leads/{lead_id}/event Adiciona lead_event

Agents — routers/agents.py

Path O que faz
GET /internal/agents?store_id Lista
GET /internal/agents/{id}/full Detalhe + KB + conversations count
POST /internal/agents Cria (com evolution_instance_id gerado backend)
PATCH /internal/agents/{id} Update persona, channels, KB, rate limits
POST /internal/agents/{id}/toggle-active Toggle com regra "1 ativo por store" centralizada
PUT /internal/agents/{id}/knowledge-base Replace KB links (agent_knowledge_base rows)
GET /internal/agents/{id}/conversations?limit&offset Lista conversas do agente
Webhook GET /webhooks/agents/by-evolution-instance/{instance_id} Lookup agent pelo evolution_instance_id (PR #17 inclui company_id no retorno)

Products + documents + product_files — routers/products.py

Path O que faz
GET /internal/products?store_id&q&limit&offset Lista
GET /internal/products/{id} Detalhe
POST /internal/products/batch-upsert Bulk insert/update (wizard CSV)
GET /internal/products/stats/{store_id} Stats
POST /internal/products/{product_id}/files Cria product_file row (após upload MinIO no vek1)
GET /internal/product-files/{file_id} Detalhe
PATCH /internal/product-files/{file_id}/status Update status (processing → completed → error)
DELETE /internal/product-files/{file_id} Delete
GET /internal/products/{product_id}/files Lista files do produto
POST /internal/documents/upsert-by-product Upsert document pelo product_id (caminho wizard)
GET /internal/documents?store_id&... Lista
GET /internal/documents/{id} Detalhe
POST /internal/documents Cria
PATCH /internal/documents/{id} Update
DELETE /internal/documents/{id} Delete (204)
PUT /internal/documents/{id}/agents Replace agent_knowledge_base links pra esse doc

Stores + company — routers/stores.py

Path O que faz
GET /internal/stores?company_id Lista
GET /internal/stores/{id} Detalhe
POST /internal/stores Cria
PATCH /internal/stores/{id} Update
GET /internal/stores/slug-available/{slug} Check
GET /internal/company Lê company do actor
POST /internal/company/ensure Cria se não existir (pós-signup)
PATCH /internal/company Update name/logo/slug

Dashboard — routers/dashboard.py

Path O que faz
GET /internal/dashboard/{store_id} Stats agregadas (orders/leads/products/conversations recentes)

Messages + audit — routers/messages.py

Path O que faz
POST /internal/messages Insert em messages_history
GET /internal/messages?lead_id|agent_id&limit Lista filtrada
GET /internal/audit?actor_user_id|target_type|target_id&limit Lê audit_log (read-only — writes via audit_service em background)

Token usage — routers/token_usage.py (PR #20)

Path O que faz
POST /internal/token-usage Insert (chamado pelo /chat quando registra uso real)
GET /internal/token-usage?company_id&period_start&period_end Lista
GET /internal/token-usage/summary?company_id&period Aggregação por modelo/operation_type

Stock — routers/stock.py

Path O que faz
POST /internal/stock/decrement-for-order Decrement produtos da order (chamado em transition para confirmed)
POST /internal/stock/restore-for-order Restore (chamado em cancellation)
Webhook POST /webhooks/stock-sync/{store_id} Inbound ERP → vek1 (HMAC com inbound_secret da store)
GET /internal/stock-sync-settings/{store_id} Lê settings
PUT /internal/stock-sync-settings/{store_id} Update outbound URL/secret + enabled flags
POST /internal/stock-sync/test-outbound/{store_id} Testa conexão ERP

Webhook scope (X-Webhook-Token)

Path Origem
POST /webhooks/abacate-pay AbacatePay pinga vek1 → vek1 relay com X-Webhook-Token pro vek1-api confirmar PIX
POST /internal/email/send-reset-password Better Auth sendResetPassword → Resend via vek1-api
POST /webhooks/stock-sync/{store_id} ERP customer-owned → vek1-api (HMAC validação inbound_secret)

Endpoints públicos (sem token)

Conversação + RAG

Path O que faz
POST /chat Function calling loop (até 5 iterações). Body {type, message, user_id?, lead_id?, agent_id?, store_id?, conversation_history?, dry_run?}. Suporta knowledgeBase filter por document_ids
POST /embed Ollama bge-m3 (1024 dim). Body {text} ou {texts[]} → {model, dimension, embeddings[][]}
POST /extract-lead DeepSeek JSON mode extraction. Body {messages, existing_profile?, store_context?} → schema completo de campos delta com confidence
POST /process-file Upload PDF/CSV/XLSX → texto extraído + chunks. Resposta inclui performance_metrics
GET /supported-formats Lista formatos aceitos

Agents config

Path O que faz
GET /agents Lista tipos disponíveis com config + preço (do agents_config.yaml)
GET /agents/{type} Detalhe + validation
POST /agents/reload Reload YAML sem restart container

Billing público (NEW PR #26)

Path O que faz
GET /billing/plans-public Lista planos ativos sem auth. Retorna só campos não-sensíveis: id, slug, name, monthly_cents, included_tokens, max_*, overage_per_million_cents. SEM stripe_*_id, SEM timestamps. Usado pela landing /pricing pra evitar TCP direto Postgres.

Stripe webhook público (NEW PR #24)

Path O que faz
POST /webhooks/stripe Signature HMAC validation com STRIPE_WEBHOOK_SECRET. Handlers pros 6 events: customer.subscription.{created,updated,deleted}, invoice.paid, invoice.payment_failed, payment_intent.succeeded

Health

Path O que faz
GET / Info
GET /health Status llm + postgres + ollama + agents configurados. Status degraded se algum down

Tools registradas no Function Calling (/chat)

  1. search_products(query, limit) — busca semântica via Ollama embedding + pgvector cosine
  2. get_product_details(product_id) — SELECT por id (+ filtro store_id)
  3. filter_products_by_price(min_price, max_price, category?, limit) — busca semântica + parse regex preço
  4. create_order(items, payment_method, customer_info) (PR #3) — cria order via HTTP interno (/internal/orders), valida items vs products, dropa fake product_ids (PR #4); retorna BR Code PIX ou instrução COD pra agente devolver ao cliente
  5. confirm_shipping(order_id) — marca shipped (opcional, prompt usa pouco)

check_quota_or_block(company_id) injetado no início de process_query_with_functions (PR #25). BLOCK retorna mensagem genérica "temporariamente indisponível, posso te conectar com atendente". Skip backend persistence em messages_history se lead_id present (vek1 já grava — dd2ac9f).

Pydantic strict (extra='forbid')

Todos modelos de body herdam:

class Strict(BaseModel):
    model_config = ConfigDict(extra="forbid")

422 explícito se cliente manda campo desconhecido. Anti-typo + anti-version-drift entre vek1 e vek1-api.

Idempotência

  • POST /internal/leads/ensure — natural (lookup por (store_id, channel, external_id))
  • POST /internal/company/ensure — natural (1:1 user.id)
  • POST /webhooks/stripe (topup) — stripe_payment_intent_id unique em token_topups; INSERT ON CONFLICT DO NOTHING
  • POST /internal/billing/topup — Stripe PaymentIntent idempotência via Stripe-Idempotency-Key
  • report_usage_to_stripe (worker) — identifier = f"{company_id}:{batch_min_id}:{batch_max_id}" no MeterEvent
  • Outras POSTs criam novo recurso a cada call — frontend é responsável por dedup
notas relacionadas
carregando…