{
  "version": 1,
  "hosts": {
    "rest": "https://valorbrain-api.valor.digital",
    "mcp": "https://mcpbrain.valor.digital/mcp",
    "app": "https://valorbrain.valor.digital",
    "connect": "https://valorbrain.com.br/connect.md",
    "mcpTokensSettings": "https://valorbrain.valor.digital/settings/mcp-tokens"
  },
  "client_env": [
    {
      "name": "VALORBRAIN_MCP_TOKEN",
      "holds": {
        "pt": "Token `vbm_`",
        "en": "`vbm_` token"
      }
    },
    {
      "name": "VALORBRAIN_API_KEY",
      "holds": {
        "pt": "Chave REST (`vb_agent_`)",
        "en": "REST key (`vb_agent_`)"
      }
    },
    {
      "name": "VALORBRAIN_API_URL",
      "holds": {
        "pt": "Base do REST (padrão https://valorbrain-api.valor.digital)",
        "en": "REST base (default https://valorbrain-api.valor.digital)"
      }
    },
    {
      "name": "VALORBRAIN_MCP_URL",
      "holds": {
        "pt": "URL do MCP (padrão https://mcpbrain.valor.digital/mcp)",
        "en": "MCP URL (default https://mcpbrain.valor.digital/mcp)"
      }
    }
  ],
  "surfaces": [
    {
      "id": "mcp",
      "label": {
        "pt": "MCP (Streamable HTTP)",
        "en": "MCP (Streamable HTTP)"
      },
      "endpoint": "https://mcpbrain.valor.digital/mcp"
    },
    {
      "id": "rest",
      "label": {
        "pt": "REST do engine",
        "en": "Engine REST"
      },
      "endpoint": "https://valorbrain-api.valor.digital/api/v1/*"
    },
    {
      "id": "saas_ingest",
      "label": {
        "pt": "Ingest do SaaS",
        "en": "SaaS ingest"
      },
      "endpoint": "POST https://valorbrain.valor.digital/api/v1/ingest"
    },
    {
      "id": "oauth_consent",
      "label": {
        "pt": "Consentimento OAuth (token colado)",
        "en": "OAuth consent (pasted token)"
      },
      "endpoint": "https://valorbrain-api.valor.digital/oauth/authorize"
    },
    {
      "id": "oauth_revoke",
      "label": {
        "pt": "Revogação OAuth (RFC 7009)",
        "en": "OAuth revocation (RFC 7009)"
      },
      "endpoint": "POST https://valorbrain-api.valor.digital/oauth/revoke"
    },
    {
      "id": "oauth_introspect",
      "label": {
        "pt": "Introspecção OAuth (RFC 7662)",
        "en": "OAuth introspection (RFC 7662)"
      },
      "endpoint": "POST https://valorbrain-api.valor.digital/oauth/introspect"
    },
    {
      "id": "admin",
      "label": {
        "pt": "Rotas de administração",
        "en": "Admin routes"
      },
      "endpoint": "https://valorbrain-api.valor.digital/api/v1/admin/*"
    },
    {
      "id": "money_admin",
      "label": {
        "pt": "Rotas de crédito e assinatura",
        "en": "Credit and subscription routes"
      },
      "endpoint": "https://valorbrain-api.valor.digital/api/v1/credits/grant, /api/v1/subscription*, /api/v1/billing/events*"
    },
    {
      "id": "metrics",
      "label": {
        "pt": "Métricas Prometheus",
        "en": "Prometheus metrics"
      },
      "endpoint": "https://valorbrain-api.valor.digital/metrics"
    },
    {
      "id": "saas_dashboard",
      "label": {
        "pt": "Painel do SaaS",
        "en": "SaaS dashboard"
      },
      "endpoint": "https://valorbrain.valor.digital"
    }
  ],
  "credentials": [
    {
      "kind": "mcp_token",
      "label": {
        "pt": "Token MCP",
        "en": "MCP token"
      },
      "prefix": "vbm_",
      "format": "vbm_<65 base62 chars> (69 chars)",
      "audience": "client",
      "issuers": [
        {
          "id": "agent_signup",
          "label": {
            "pt": "Signup agent-native (`mcp_token` da resposta)",
            "en": "Agent-native signup (`mcp_token` in the response)"
          },
          "via": "npx -y @valorbrain/cli@latest init --agent --agent-caller <id> --json (POST /api/v1/agents/signup)"
        },
        {
          "id": "agent_reissue",
          "label": {
            "pt": "Reemissão pela chave `vb_agent_` (mesmo teto do signup; revoga o anterior)",
            "en": "Reissue with the `vb_agent_` key (same ceiling as the signup; revokes the previous one)"
          },
          "via": "POST /api/v1/agents/mcp-token (Authorization: Bearer vb_agent_…)"
        },
        {
          "id": "settings",
          "label": {
            "pt": "App → Configurações → Tokens MCP",
            "en": "App → Settings → MCP Tokens"
          },
          "via": "https://valorbrain.valor.digital/settings/mcp-tokens (POST /api/v1/mcp/tokens)"
        },
        {
          "id": "connect_device_flow",
          "label": {
            "pt": "Device flow do connect (um token por harness)",
            "en": "Connect device flow (one token per harness)"
          },
          "via": "npx -y @valorbrain/connect (POST /api/v1/cli/device/code no app)"
        },
        {
          "id": "oauth",
          "label": {
            "pt": "OAuth 2.1 (consentimento, código + PKCE)",
            "en": "OAuth 2.1 (consent, code + PKCE)"
          },
          "via": "POST /oauth/token grant_type=authorization_code"
        },
        {
          "id": "ema",
          "label": {
            "pt": "EMA: asserção do IdP da empresa",
            "en": "EMA: company IdP assertion"
          },
          "via": "POST /oauth/token grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer"
        }
      ],
      "storage": "mcp_tokens.token_hash (sha256)",
      "accepted": [
        "mcp",
        "rest",
        "saas_ingest",
        "oauth_consent",
        "oauth_revoke"
      ],
      "refused": [
        {
          "surface": "admin",
          "status": 401,
          "error": "Unauthorized: admin secret required"
        },
        {
          "surface": "money_admin",
          "status": 403,
          "error": "Forbidden: admin credential required for money routes"
        },
        {
          "surface": "metrics",
          "status": 403,
          "error": "Forbidden: /metrics is served only to local scrapers"
        }
      ],
      "identity": {
        "tenant": {
          "pt": "`mcp_tokens.tenant_id` (header nunca troca o tenant)",
          "en": "`mcp_tokens.tenant_id` (a header never switches the tenant)"
        },
        "user": {
          "pt": "`mcp_tokens.user_id`; agente/persona por `X-Source-Agent`, senão a persona do token (`intended_agent_platform` que não é nome de harness), senão `X-ValorBrain-Harness`, senão a plataforma de harness do token, senão `clientInfo` (só sem plataforma no token), senão o nome do token",
          "en": "`mcp_tokens.user_id`; agent/persona from `X-Source-Agent`, else the token's persona (an `intended_agent_platform` that is not a harness name), else `X-ValorBrain-Harness`, else the token's harness platform, else `clientInfo` (only when the token has no platform), else the token name"
        },
        "scopes": {
          "pt": "Escopos do token (`read`, `write`, `admin`, granulares de src/mcp-scopes.ts; `[]` não concede nada), toolsets aditivos (`agent,graph`), coleções permitidas e audience (RFC 8707). Token OAuth pedido para o MCP ou para o app vale nos dois (audience irmã, ADR-085); o ingest exige `write`",
          "en": "Token scopes (`read`, `write`, `admin`, granular ones from src/mcp-scopes.ts; `[]` grants nothing), additive toolsets (`agent,graph`), allowed collections and audience (RFC 8707). An OAuth token asked for MCP or for the app is valid at both (sibling audience, ADR-085); ingest requires `write`"
        }
      },
      "lifecycle": {
        "validity": {
          "pt": "Sem expiração quando criado no app. Signup: 30 dias até o claim, que remove a expiração. OAuth: até a validade de quem consentiu ou `VALORBRAIN_OAUTH_TOKEN_MAX_TTL_DAYS`. EMA: `token_ttl_seconds` do emissor (padrão 900 s).",
          "en": "No expiry when created in the app. Signup: 30 days until the claim, which removes the expiry. OAuth: up to the consenter's validity or `VALORBRAIN_OAUTH_TOKEN_MAX_TTL_DAYS`. EMA: the issuer's `token_ttl_seconds` (default 900 s)."
        },
        "revocation": {
          "pt": "`DELETE /api/v1/mcp/tokens/:id`, botão Revogar no app ou `POST /oauth/revoke`; revogar o pai derruba os tokens OAuth filhos.",
          "en": "`DELETE /api/v1/mcp/tokens/:id`, the Revoke button in the app or `POST /oauth/revoke`; revoking the parent drops its OAuth children."
        },
        "rotation": {
          "pt": "Crie um token novo, troque no cliente e revogue o antigo. OAuth não emite refresh token: o cliente refaz o consentimento.",
          "en": "Create a new token, swap it in the client and revoke the old one. OAuth issues no refresh token: the client runs the consent again."
        }
      },
      "clientEnv": "VALORBRAIN_MCP_TOKEN",
      "deprecatedEnv": [
        "VALORBRAIN_TOKEN"
      ],
      "rateLimit": {
        "pt": "`authenticated` e `search`, por sha256 do token",
        "en": "`authenticated` and `search`, per sha256 of the token"
      }
    },
    {
      "kind": "agent_key",
      "label": {
        "pt": "Chave de conta de agente",
        "en": "Agent account key"
      },
      "prefix": "vb_agent_",
      "format": "vb_agent_<random>",
      "audience": "legacy_client",
      "issuers": [
        {
          "id": "agent_signup",
          "label": {
            "pt": "Signup agent-native (`api_key` da resposta)",
            "en": "Agent-native signup (`api_key` in the response)"
          },
          "via": "POST /api/v1/agents/signup"
        }
      ],
      "storage": "shadow_tenants.api_key_hash (sha256)",
      "accepted": [
        "rest",
        "oauth_consent"
      ],
      "refused": [
        {
          "surface": "mcp",
          "status": 401,
          "error": "wrong_credential_type"
        },
        {
          "surface": "saas_ingest",
          "status": 401,
          "error": "invalid_token"
        },
        {
          "surface": "admin",
          "status": 401,
          "error": "Unauthorized: admin secret required"
        },
        {
          "surface": "money_admin",
          "status": 403,
          "error": "Forbidden: admin credential required for money routes"
        },
        {
          "surface": "metrics",
          "status": 403,
          "error": "Forbidden: /metrics is served only to local scrapers"
        }
      ],
      "identity": {
        "tenant": {
          "pt": "`shadow_tenants.tenant_id`, só com `tenants.billing_status = 'active'`",
          "en": "`shadow_tenants.tenant_id`, only while `tenants.billing_status = 'active'`"
        },
        "user": {
          "pt": "`shadow_tenants.default_user_id` (`agent-default`)",
          "en": "`shadow_tenants.default_user_id` (`agent-default`)"
        },
        "scopes": {
          "pt": "Escopos implícitos `read write mcp read_log:read secrets` no guard REST (sem billing, preço, admin nem credenciais de conector); teto `read write` no consentimento OAuth",
          "en": "Implicit scopes `read write mcp read_log:read secrets` at the REST guard (no billing, pricing, admin or connector credentials); capped at `read write` on the OAuth consent"
        }
      },
      "lifecycle": {
        "validity": {
          "pt": "30 dias a partir do signup se ninguém fizer o claim; depois do claim não expira.",
          "en": "30 days from signup unless someone claims the workspace; after the claim it does not expire."
        },
        "revocation": {
          "pt": "Cai junto com o workspace (exclusão do tenant ou `billing_status` diferente de `active`), levando os tokens OAuth aprovados com ela.",
          "en": "Goes with the workspace (tenant deletion or a `billing_status` other than `active`), taking the OAuth tokens approved with it."
        },
        "rotation": {
          "pt": "A chave não roda; ela reemite o `vbm_` do signup (`POST /api/v1/agents/mcp-token`: `read write`, toolset `agent`, mesma validade, o anterior revogado). No dia a dia use o `vbm_`; depois do claim, o token pessoal de quem fez o claim serve a todos os agentes dessa pessoa, que se identificam pelos cabeçalhos do contrato.",
          "en": "The key does not rotate; it reissues the signup `vbm_` (`POST /api/v1/agents/mcp-token`: `read write`, toolset `agent`, same validity, the previous one revoked). Use the `vbm_` day to day; after the claim, the claimer's personal token serves every agent of that person, each naming itself through the contract headers."
        }
      },
      "clientEnv": "VALORBRAIN_API_KEY",
      "deprecatedEnv": [
        "VALORBRAIN_API_TOKEN",
        "VALORBRAIN_TOKEN"
      ],
      "rateLimit": {
        "pt": "`authenticated` e `search`, por sha256 da chave",
        "en": "`authenticated` and `search`, per sha256 of the key"
      }
    },
    {
      "kind": "service_key",
      "label": {
        "pt": "Chave de serviço",
        "en": "Service key"
      },
      "prefix": "vb_",
      "format": "vb_<tenant-slug>_<random>",
      "audience": "service",
      "issuers": [
        {
          "id": "tenant_provisioning",
          "label": {
            "pt": "Provisionamento do tenant (`saas-service`)",
            "en": "Tenant provisioning (`saas-service`)"
          },
          "via": "POST /api/v1/admin/tenants/:id/api-tokens (rota de administração da plataforma)"
        },
        {
          "id": "cli_device_flow",
          "label": {
            "pt": "Device flow da CLI/valorcode no app",
            "en": "CLI/valorcode device flow in the app"
          },
          "via": "POST /api/v1/cli/device/token no app"
        }
      ],
      "storage": "api_tokens.token_hash (sha256)",
      "accepted": [
        "rest",
        "oauth_consent"
      ],
      "refused": [
        {
          "surface": "mcp",
          "status": 401,
          "error": "wrong_credential_type"
        },
        {
          "surface": "saas_ingest",
          "status": 401,
          "error": "invalid_token"
        },
        {
          "surface": "admin",
          "status": 401,
          "error": "Unauthorized: admin secret required"
        },
        {
          "surface": "money_admin",
          "status": 403,
          "error": "Forbidden: admin credential required for money routes"
        },
        {
          "surface": "metrics",
          "status": 403,
          "error": "Forbidden: /metrics is served only to local scrapers"
        }
      ],
      "identity": {
        "tenant": {
          "pt": "`api_tokens.tenant_id`, só com `tenants.billing_status = 'active'`",
          "en": "`api_tokens.tenant_id`, only while `tenants.billing_status = 'active'`"
        },
        "user": {
          "pt": "`api_tokens.user_id`",
          "en": "`api_tokens.user_id`"
        },
        "scopes": {
          "pt": "Escopos implícitos `read write mcp read_log:read secrets` no guard REST (sem billing, preço, admin nem credenciais de conector); teto `read write` no consentimento OAuth",
          "en": "Implicit scopes `read write mcp read_log:read secrets` at the REST guard (no billing, pricing, admin or connector credentials); capped at `read write` on the OAuth consent"
        }
      },
      "lifecycle": {
        "validity": {
          "pt": "`api_tokens.expires_at` quando definido; sem expiração caso contrário.",
          "en": "`api_tokens.expires_at` when set; no expiry otherwise."
        },
        "revocation": {
          "pt": "`api_tokens.is_active = false` (painel de tokens de CLI ou offboarding do membro); os tokens OAuth aprovados com ela caem junto.",
          "en": "`api_tokens.is_active = false` (CLI tokens panel or member offboarding); the OAuth tokens approved with it go too."
        },
        "rotation": {
          "pt": "Emita uma chave nova pelo mesmo emissor e desative a antiga.",
          "en": "Issue a new key through the same issuer and deactivate the old one."
        }
      },
      "clientEnv": null,
      "deprecatedEnv": [],
      "rateLimit": {
        "pt": "`authenticated` e `search`, por sha256 da chave",
        "en": "`authenticated` and `search`, per sha256 of the key"
      }
    },
    {
      "kind": "ingest_key",
      "label": {
        "pt": "Chave de ingest do workspace",
        "en": "Workspace ingest key"
      },
      "prefix": "fk_",
      "format": "fk_<key-id>.sk_<secret>",
      "audience": "service",
      "issuers": [
        {
          "id": "settings_api_keys",
          "label": {
            "pt": "App → Configurações → Chaves de API",
            "en": "App → Settings → API keys"
          },
          "via": "https://valorbrain.valor.digital/settings/api-keys"
        }
      ],
      "storage": "SaaS api_keys (hash do segredo)",
      "accepted": [
        "saas_ingest"
      ],
      "refused": [
        {
          "surface": "mcp",
          "status": 401,
          "error": "wrong_credential_type"
        },
        {
          "surface": "rest",
          "status": 401,
          "error": "Unauthorized"
        },
        {
          "surface": "admin",
          "status": 401,
          "error": "Unauthorized: admin secret required"
        },
        {
          "surface": "money_admin",
          "status": 401,
          "error": "Unauthorized"
        },
        {
          "surface": "metrics",
          "status": 403,
          "error": "Forbidden: /metrics is served only to local scrapers"
        }
      ],
      "identity": {
        "tenant": {
          "pt": "Workspace dono da chave no SaaS",
          "en": "The workspace that owns the key in the SaaS"
        },
        "user": {
          "pt": "Não carrega usuário; a escrita é atribuída ao workspace",
          "en": "Carries no user; writes are attributed to the workspace"
        },
        "scopes": {
          "pt": "Só ingest",
          "en": "Ingest only"
        }
      },
      "lifecycle": {
        "validity": {
          "pt": "Expiração da chave quando definida; sem expiração caso contrário.",
          "en": "The key's expiry when set; no expiry otherwise."
        },
        "revocation": {
          "pt": "Excluir a chave em Configurações → Chaves de API.",
          "en": "Delete the key in Settings → API keys."
        },
        "rotation": {
          "pt": "Crie uma chave nova, troque no sistema externo e exclua a antiga.",
          "en": "Create a new key, swap it in the external system and delete the old one."
        }
      },
      "clientEnv": null,
      "deprecatedEnv": [],
      "rateLimit": {
        "pt": "`saas_ingest`, por credencial",
        "en": "`saas_ingest`, per credential"
      }
    },
    {
      "kind": "saas_session",
      "label": {
        "pt": "Sessão do painel",
        "en": "Dashboard session"
      },
      "prefix": null,
      "format": "cookie HttpOnly",
      "audience": "human",
      "issuers": [
        {
          "id": "saas_login",
          "label": {
            "pt": "Login no app",
            "en": "App login"
          },
          "via": "https://valorbrain.valor.digital/login"
        }
      ],
      "storage": "cookie HttpOnly no navegador",
      "accepted": [
        "saas_dashboard"
      ],
      "refused": [],
      "identity": {
        "tenant": {
          "pt": "Workspace ativo da sessão",
          "en": "The session's active workspace"
        },
        "user": {
          "pt": "Usuário logado",
          "en": "The signed-in user"
        },
        "scopes": {
          "pt": "Papel do membro no workspace",
          "en": "The member's role in the workspace"
        }
      },
      "lifecycle": {
        "validity": {
          "pt": "Validade da sessão do app; não é contrato de integração.",
          "en": "The app session's validity; not an integration contract."
        },
        "revocation": {
          "pt": "Logout ou remoção do membro.",
          "en": "Logout or member removal."
        },
        "rotation": {
          "pt": "Novo login.",
          "en": "Sign in again."
        }
      },
      "clientEnv": null,
      "deprecatedEnv": [],
      "rateLimit": {
        "pt": "Limites do app",
        "en": "App limits"
      }
    }
  ],
  "transients": [
    {
      "id": "claim_otp",
      "label": {
        "pt": "Código do claim (OTP)",
        "en": "Claim code (OTP)"
      },
      "issuedBy": "POST /api/v1/agents/claim",
      "validity": {
        "pt": "10 minutos, até 5 tentativas",
        "en": "10 minutes, up to 5 attempts"
      },
      "usage": {
        "pt": "`POST /api/v1/agents/claim/verify` com a `vb_agent_` do workspace",
        "en": "`POST /api/v1/agents/claim/verify` with the workspace's `vb_agent_`"
      }
    },
    {
      "id": "oauth_code",
      "label": {
        "pt": "Código de autorização OAuth",
        "en": "OAuth authorization code"
      },
      "issuedBy": "GET /oauth/authorize → consentimento",
      "validity": {
        "pt": "Uso único, minutos",
        "en": "Single use, minutes"
      },
      "usage": {
        "pt": "`POST /oauth/token` com o `code_verifier` PKCE",
        "en": "`POST /oauth/token` with the PKCE `code_verifier`"
      }
    },
    {
      "id": "oauth_client",
      "label": {
        "pt": "Cliente OAuth (DCR)",
        "en": "OAuth client (DCR)"
      },
      "issuedBy": "POST /oauth/register",
      "validity": {
        "pt": "Até ser removido; cliente público, sem segredo",
        "en": "Until removed; public client, no secret"
      },
      "usage": {
        "pt": "`client_id` em `/oauth/authorize` e `/oauth/token`",
        "en": "`client_id` on `/oauth/authorize` and `/oauth/token`"
      }
    },
    {
      "id": "device_code",
      "label": {
        "pt": "Código de dispositivo",
        "en": "Device code"
      },
      "issuedBy": "POST https://valorbrain.valor.digital/api/v1/cli/device/code",
      "validity": {
        "pt": "Minutos, até a aprovação humana",
        "en": "Minutes, until a person approves it"
      },
      "usage": {
        "pt": "Polling em `POST /api/v1/cli/device/token`; entrega o token uma vez",
        "en": "Polled at `POST /api/v1/cli/device/token`; delivers the token once"
      }
    }
  ],
  "rate_limits": [
    {
      "id": "public",
      "label": {
        "pt": "Rotas públicas e sem bearer",
        "en": "Public routes and requests without a bearer"
      },
      "routes": "*",
      "key": {
        "pt": "IP real do cliente (`CF-Connecting-IP`)",
        "en": "Real client IP (`CF-Connecting-IP`)"
      },
      "limit": 60,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_RATE_LIMIT_MAX",
      "onExceed": {
        "pt": "429 com `retry_after_ms`",
        "en": "429 with `retry_after_ms`"
      }
    },
    {
      "id": "authenticated",
      "label": {
        "pt": "Rotas autenticadas",
        "en": "Authenticated routes"
      },
      "routes": "*",
      "key": {
        "pt": "sha256 do bearer inteiro (dois tokens nunca dividem balde); a credencial de plataforma, por tenant de destino. Isenção só para `api_tokens.is_admin` com `VALORBRAIN_RATE_LIMIT_EXEMPT=true`",
        "en": "sha256 of the whole bearer (two tokens never share a bucket); the platform credential, per target tenant. Exempt only for `api_tokens.is_admin` with `VALORBRAIN_RATE_LIMIT_EXEMPT=true`"
      },
      "limit": 300,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_RATE_LIMIT_AUTH_MAX",
      "onExceed": {
        "pt": "429 com `retry_after_ms`",
        "en": "429 with `retry_after_ms`"
      }
    },
    {
      "id": "auth_failure",
      "label": {
        "pt": "Bearer do engine que não resolve",
        "en": "Engine bearer that does not resolve"
      },
      "routes": "*",
      "key": {
        "pt": "IP real do cliente (`CF-Connecting-IP`); estourado, responde 429 sem consultar o banco",
        "en": "Real client IP (`CF-Connecting-IP`); once spent, 429 without a database lookup"
      },
      "limit": 60,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_RATE_LIMIT_AUTH_FAILURE_MAX",
      "onExceed": {
        "pt": "429 com `retry_after_ms`",
        "en": "429 with `retry_after_ms`"
      }
    },
    {
      "id": "agent_reissue",
      "label": {
        "pt": "Reemissão do token MCP do signup",
        "en": "Signup MCP token reissue"
      },
      "routes": "POST /api/v1/agents/mcp-token",
      "key": {
        "pt": "Tenant da chave `vb_agent_`",
        "en": "Tenant of the `vb_agent_` key"
      },
      "limit": 3,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_RATE_LIMIT_AGENT_REISSUE_MAX",
      "onExceed": {
        "pt": "429 com `retry_after_ms`",
        "en": "429 with `retry_after_ms`"
      }
    },
    {
      "id": "search",
      "label": {
        "pt": "Busca",
        "en": "Search"
      },
      "routes": "/search, /api/v1/search, /retrieve",
      "key": {
        "pt": "sha256 do bearer",
        "en": "sha256 of the bearer"
      },
      "limit": 120,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_RATE_LIMIT_SEARCH_MAX",
      "onExceed": {
        "pt": "429 com `retry_after_ms`",
        "en": "429 with `retry_after_ms`"
      }
    },
    {
      "id": "signup",
      "label": {
        "pt": "Signup de agente",
        "en": "Agent signup"
      },
      "routes": "POST /api/v1/agents/signup",
      "key": {
        "pt": "IP real do cliente; também 5 signups por IP por dia",
        "en": "Real client IP; also 5 signups per IP per day"
      },
      "limit": 10,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_RATE_LIMIT_SIGNUP_MAX",
      "onExceed": {
        "pt": "429 com `retry_after_ms`",
        "en": "429 with `retry_after_ms`"
      }
    },
    {
      "id": "oauth_register",
      "label": {
        "pt": "Registro dinâmico OAuth",
        "en": "OAuth dynamic registration"
      },
      "routes": "POST /oauth/register",
      "key": {
        "pt": "IP real do cliente",
        "en": "Real client IP"
      },
      "limit": 10,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_RATE_LIMIT_OAUTH_MAX",
      "onExceed": {
        "pt": "429 `rate_limited` com `Retry-After`",
        "en": "429 `rate_limited` with `Retry-After`"
      }
    },
    {
      "id": "saas_ingest",
      "label": {
        "pt": "Ingest do SaaS",
        "en": "SaaS ingest"
      },
      "routes": "POST https://valorbrain.valor.digital/api/v1/ingest",
      "key": {
        "pt": "Credencial (token `vbm_` ou chave `fk_`)",
        "en": "Credential (`vbm_` token or `fk_` key)"
      },
      "limit": 200,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": null,
      "onExceed": {
        "pt": "429 `Rate limit exceeded (200 req/min)`",
        "en": "429 `Rate limit exceeded (200 req/min)`"
      }
    },
    {
      "id": "answers",
      "label": {
        "pt": "Respostas (`/ask`)",
        "en": "Answers (`/ask`)"
      },
      "routes": "POST /ask",
      "key": {
        "pt": "Tenant (padrão do plano em `burst_answers_per_min`); teto mensal opcional do cliente",
        "en": "Tenant (plan default in `burst_answers_per_min`); optional customer monthly cap"
      },
      "limit": 60,
      "window": {
        "pt": "60 s",
        "en": "60 s"
      },
      "env": "VALORBRAIN_TENANT_BURST_DEFAULT",
      "onExceed": {
        "pt": "429 `answer_burst_exceeded` com `Retry-After`; 429 `answer_cap_reached` no teto mensal",
        "en": "429 `answer_burst_exceeded` with `Retry-After`; 429 `answer_cap_reached` at the monthly cap"
      }
    }
  ],
  "errors": [
    {
      "code": "missing_bearer",
      "kind": "code",
      "status": [
        401
      ],
      "surfaces": [
        "mcp"
      ],
      "cause": {
        "pt": "Requisição ao MCP sem `Authorization: Bearer`.",
        "en": "MCP request without `Authorization: Bearer`."
      },
      "action": {
        "pt": "Envie um token `vbm_` ou siga o `WWW-Authenticate` para a descoberta OAuth.",
        "en": "Send a `vbm_` token or follow `WWW-Authenticate` into OAuth discovery."
      }
    },
    {
      "code": "invalid_token",
      "kind": "code",
      "status": [
        401
      ],
      "surfaces": [
        "mcp",
        "rest",
        "saas_ingest",
        "oauth"
      ],
      "cause": {
        "pt": "Token desconhecido, revogado ou vencido (ou, no MCP, um segredo sem prefixo).",
        "en": "Unknown, revoked or expired token (or, on MCP, a secret with no prefix)."
      },
      "action": {
        "pt": "Crie um token novo em Configurações → Tokens MCP ou refaça o signup/consentimento.",
        "en": "Create a new token in Settings → MCP Tokens or redo the signup/consent."
      }
    },
    {
      "code": "wrong_credential_type",
      "kind": "code",
      "status": [
        401
      ],
      "surfaces": [
        "mcp"
      ],
      "cause": {
        "pt": "Chave REST (`vb_`, `vb_agent_`) ou de ingest (`fk_`) enviada ao MCP.",
        "en": "REST key (`vb_`, `vb_agent_`) or ingest key (`fk_`) sent to MCP."
      },
      "action": {
        "pt": "Use o `mcp_token` (`vbm_…`) no MCP e guarde a `api_key` para o REST.",
        "en": "Use the `mcp_token` (`vbm_…`) on MCP and keep the `api_key` for REST."
      }
    },
    {
      "code": "agent_key_required",
      "kind": "code",
      "status": [
        401
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "A reemissão do token MCP do signup (`POST /api/v1/agents/mcp-token`) recebeu outra credencial que não a `vb_agent_` do workspace.",
        "en": "The signup MCP token reissue (`POST /api/v1/agents/mcp-token`) got a credential other than the workspace's `vb_agent_` key."
      },
      "action": {
        "pt": "Chame a rota com a `api_key` (`vb_agent_…`) que o signup devolveu.",
        "en": "Call the route with the `api_key` (`vb_agent_…`) the signup returned."
      }
    },
    {
      "code": "insufficient_scope",
      "kind": "code",
      "status": [
        403
      ],
      "surfaces": [
        "rest",
        "saas_ingest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "O token é válido mas não tem o escopo exigido pela rota ou ferramenta.",
        "en": "The token is valid but lacks the scope the route or tool requires."
      },
      "action": {
        "pt": "Emita um token com o escopo indicado em `required_scope` (ou `write` no ingest).",
        "en": "Issue a token with the scope named in `required_scope` (or `write` for ingest)."
      }
    },
    {
      "code": "credential_required",
      "kind": "code",
      "status": [
        403
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Purga de documentos sem credencial bearer.",
        "en": "Document purge without a bearer credential."
      },
      "action": {
        "pt": "Envie o token do tenant; `dry_run=true` funciona sem credencial.",
        "en": "Send the tenant token; `dry_run=true` works without one."
      }
    },
    {
      "code": "admin_required",
      "kind": "code",
      "status": [
        403
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Operação que exige papel ADMIN do tenant.",
        "en": "Operation that requires the tenant ADMIN role."
      },
      "action": {
        "pt": "Repita com o token de um administrador do workspace.",
        "en": "Repeat with a workspace administrator's token."
      }
    },
    {
      "code": "attestation_required",
      "kind": "code",
      "status": [
        403
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Ato de autoridade Classe A sem `X-VB-Attestation`.",
        "en": "Class-A authority act without `X-VB-Attestation`."
      },
      "action": {
        "pt": "Envie um envelope de atestação interativo e válido para esta requisição.",
        "en": "Send a live interactive attestation envelope for this request."
      }
    },
    {
      "code": "cap_human_forbidden",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Mandato com `cap=human`: aprovação humana não se delega.",
        "en": "Mandate with `cap=human`: human approval cannot be delegated."
      },
      "action": {
        "pt": "Use um teto abaixo de `human`.",
        "en": "Use a cap below `human`."
      }
    },
    {
      "code": "identity_denied",
      "kind": "code",
      "status": [
        200
      ],
      "surfaces": [
        "mcp_tool"
      ],
      "cause": {
        "pt": "O token tem `scoped_access` e a ferramenta pediu uma coleção fora da lista permitida.",
        "en": "The token has `scoped_access` and the tool asked for a collection outside its allow-list."
      },
      "action": {
        "pt": "Peça ao dono do workspace para incluir a coleção no token.",
        "en": "Ask the workspace owner to add the collection to the token."
      }
    },
    {
      "code": "scope_denied",
      "kind": "code",
      "status": [
        200
      ],
      "surfaces": [
        "mcp_tool"
      ],
      "cause": {
        "pt": "A ferramenta exige um escopo que o token MCP não tem.",
        "en": "The tool requires a scope the MCP token lacks."
      },
      "action": {
        "pt": "Emita um token com o escopo da ferramenta (Configurações → Tokens MCP).",
        "en": "Issue a token with the tool's scope (Settings → MCP Tokens)."
      }
    },
    {
      "code": "outside_keyspace",
      "kind": "code",
      "status": [
        200,
        403
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "Credencial de integração tentou gravar fora do seu keyspace: um fato com chave fora dele, ou qualquer escrita que não seja fato (documento, mensagem, estado). Nada foi gravado.",
        "en": "An integration credential tried to write outside its keyspace: a fact key outside it, or any write that is not a keyed fact (document, message, state). Nothing was written."
      },
      "action": {
        "pt": "Grave só fatos (`POST /api/v1/keyed-facts` ou `upsert_keyed_fact`) com chaves do keyspace; para outro keyspace, peça ao admin para ampliar a integração.",
        "en": "Write only keyed facts (`POST /api/v1/keyed-facts` or `upsert_keyed_fact`) with keys in the keyspace; for another keyspace, ask the admin to widen the integration."
      }
    },
    {
      "code": "profile_identity_unavailable",
      "kind": "code",
      "status": [
        200
      ],
      "surfaces": [
        "mcp_tool"
      ],
      "cause": {
        "pt": "Perfil de plugin sem identidade de usuário resolvida.",
        "en": "Plugin profile without a resolved user identity."
      },
      "action": {
        "pt": "Conecte com um token ligado a um usuário do workspace.",
        "en": "Connect with a token bound to a workspace user."
      }
    },
    {
      "code": "mcp_init_failed",
      "kind": "code",
      "status": [
        403,
        500
      ],
      "surfaces": [
        "mcp"
      ],
      "cause": {
        "pt": "O token pertence a outro destino (audience) ou o transporte MCP não subiu.",
        "en": "The token belongs to another target (audience) or the MCP transport failed to start."
      },
      "action": {
        "pt": "Use o token da instância certa; em 500, tente de novo.",
        "en": "Use the token for the right instance; on 500, retry."
      }
    },
    {
      "code": "internal_error",
      "kind": "code",
      "status": [
        500
      ],
      "surfaces": [
        "mcp"
      ],
      "cause": {
        "pt": "Falha inesperada ao atender a requisição MCP.",
        "en": "Unexpected failure while serving the MCP request."
      },
      "action": {
        "pt": "Tente de novo em instantes; se persistir, abra um chamado com o horário da requisição.",
        "en": "Retry shortly; if it persists, open a ticket with the request time."
      }
    },
    {
      "code": "invalid_tenant_header",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`X-Tenant-ID` não é um UUID de tenant.",
        "en": "`X-Tenant-ID` is not a tenant UUID."
      },
      "action": {
        "pt": "Remova o header (o tenant vem da credencial) ou envie um UUID válido.",
        "en": "Drop the header (the tenant comes from the credential) or send a valid UUID."
      }
    },
    {
      "code": "invalid_user_header",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`X-User-ID` não é um UUID de usuário.",
        "en": "`X-User-ID` is not a user UUID."
      },
      "action": {
        "pt": "Remova o header ou envie o UUID do usuário.",
        "en": "Drop the header or send the user's UUID."
      }
    },
    {
      "code": "invalid_member_id",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`member_id` não é um UUID de membro.",
        "en": "`member_id` is not a member UUID."
      },
      "action": {
        "pt": "Envie o UUID do membro do time.",
        "en": "Send the team member's UUID."
      }
    },
    {
      "code": "not_document_owner",
      "kind": "code",
      "status": [
        403
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`POST /documents` sobre documento privado de outro usuário, ou mudando a sensibilidade de documento com dono, sem ser o dono com a própria credencial, admin do tenant ou a plataforma; também `PUT`/`DELETE` de foundation em documento privado alheio. Nada foi gravado.",
        "en": "`POST /documents` over another user's private document, or changing an owned document's sensitivity, without being the owner on their own credential, a tenant admin or the platform; also a foundation `PUT`/`DELETE` on another user's private document. Nothing was written."
      },
      "action": {
        "pt": "Grave com a credencial do dono, de um admin do tenant ou da plataforma, ou use outro caminho.",
        "en": "Write with the owner's, a tenant admin's or the platform credential, or use another path."
      }
    },
    {
      "code": "sensitivity_change_requires_admin",
      "kind": "code",
      "status": [
        403
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`POST /documents` mudando a sensibilidade de um documento sem dono: rebaixar o abre a tokens restritos, elevar tranca o time fora. Nada foi gravado.",
        "en": "`POST /documents` changing the sensitivity of a document with no owner: lowering it opens it to restricted tokens, raising it locks the team out. Nothing was written."
      },
      "action": {
        "pt": "Peça a um admin do tenant, ou grave sem mudar a sensibilidade.",
        "en": "Ask a tenant admin, or write without changing the sensitivity."
      }
    },
    {
      "code": "integration_not_minted_here",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`POST /api/v1/mcp/tokens` com `credential_kind: integration`: a credencial de integração nasce com o mandato dela, em outra rota. Nada foi criado.",
        "en": "`POST /api/v1/mcp/tokens` with `credential_kind: integration`: an integration credential is created with its mandate, on another route. Nothing was created."
      },
      "action": {
        "pt": "Crie a integração em `POST /api/v1/authority/integrations`, ou peça `personal` ou `gateway` aqui.",
        "en": "Create the integration at `POST /api/v1/authority/integrations`, or ask for `personal` or `gateway` here."
      }
    },
    {
      "code": "user_not_in_tenant",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest",
        "oauth"
      ],
      "cause": {
        "pt": "Token MCP (ou consentimento OAuth pelo app) pedido para um `user_id` que não é membro do tenant.",
        "en": "MCP token (or app OAuth consent) requested for a `user_id` that is not a tenant member."
      },
      "action": {
        "pt": "Provisione o usuário antes de emitir o token ou aprovar o consentimento.",
        "en": "Provision the user before issuing the token or approving the consent."
      }
    },
    {
      "code": "email_already_registered",
      "kind": "code",
      "status": [
        409
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "O e-mail do administrador já existe em outro tenant.",
        "en": "The admin e-mail already exists in another tenant."
      },
      "action": {
        "pt": "Entre com a conta existente.",
        "en": "Sign in with the existing account."
      }
    },
    {
      "code": "user_id_conflict",
      "kind": "code",
      "status": [
        409
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "O e-mail já está ligado a outro id de usuário no tenant.",
        "en": "The e-mail is already bound to another user id in the tenant."
      },
      "action": {
        "pt": "Use o `engine_user_id` devolvido.",
        "en": "Use the returned `engine_user_id`."
      }
    },
    {
      "code": "rate_limited",
      "kind": "code",
      "status": [
        429
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Registro dinâmico OAuth acima do limite por IP.",
        "en": "OAuth dynamic registration above the per-IP limit."
      },
      "action": {
        "pt": "Aguarde o `Retry-After` e reutilize o `client_id` já registrado.",
        "en": "Wait for `Retry-After` and reuse the `client_id` you already registered."
      }
    },
    {
      "code": "answer_burst_exceeded",
      "kind": "code",
      "status": [
        429
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Respostas demais do tenant numa janela curta.",
        "en": "Too many answers for the tenant in a short window."
      },
      "action": {
        "pt": "Aguarde o `Retry-After`.",
        "en": "Wait for `Retry-After`."
      }
    },
    {
      "code": "answer_cap_reached",
      "kind": "code",
      "status": [
        429
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Teto mensal de respostas definido pelo cliente foi atingido.",
        "en": "The customer's monthly answer cap was reached."
      },
      "action": {
        "pt": "Aumente ou remova o teto nas configurações.",
        "en": "Raise or remove the cap in settings."
      }
    },
    {
      "code": "not_found",
      "kind": "code",
      "status": [
        404,
        200
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "Documento, arquivo ou lacuna não existe neste tenant.",
        "en": "Document, file or gap does not exist in this tenant."
      },
      "action": {
        "pt": "Confira o docid/caminho; `similarFiles` sugere nomes próximos.",
        "en": "Check the docid/path; `similarFiles` suggests close names."
      }
    },
    {
      "code": "ambiguous",
      "kind": "code",
      "status": [
        409
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "O nome casa com mais de uma entidade.",
        "en": "The name matches more than one entity."
      },
      "action": {
        "pt": "Escolha um dos `candidates` e repita com o id.",
        "en": "Pick one of the `candidates` and repeat with its id."
      }
    },
    {
      "code": "ambiguous_docid",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "O prefixo de docid casa com mais de um documento.",
        "en": "The docid prefix matches more than one document."
      },
      "action": {
        "pt": "Use um prefixo mais longo.",
        "en": "Use a longer prefix."
      }
    },
    {
      "code": "confirmation_required",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Purga de coleção inteira sem `confirm` igual ao alvo.",
        "en": "Whole-collection purge without `confirm` equal to the target."
      },
      "action": {
        "pt": "Rode `dry_run=true`, depois repita com `confirm` e credencial de admin.",
        "en": "Run `dry_run=true`, then repeat with `confirm` and an admin credential."
      }
    },
    {
      "code": "superseded_document",
      "kind": "code",
      "status": [
        404
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "O docid é uma versão substituída.",
        "en": "The docid is a replaced version."
      },
      "action": {
        "pt": "Leia `read_at` ou o documento vivo em `superseded_by`.",
        "en": "Read `read_at` or the live document in `superseded_by`."
      }
    },
    {
      "code": "supersedes_self",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "`supersedes` aponta para o próprio documento sendo escrito.",
        "en": "`supersedes` points at the document being written."
      },
      "action": {
        "pt": "Remova o alvo: reescrever o mesmo caminho já é uma revisão.",
        "en": "Drop the target: rewriting the same path is already a revision."
      }
    },
    {
      "code": "supersedes_invalid",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "Lista `supersedes` grande demais ou com alvo malformado.",
        "en": "`supersedes` list too long or with a malformed target."
      },
      "action": {
        "pt": "Envie até o máximo de alvos, cada um docid ou caminho.",
        "en": "Send up to the maximum targets, each a docid or a path."
      }
    },
    {
      "code": "supersedes_not_found",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "Um alvo de `supersedes` não existe.",
        "en": "A `supersedes` target does not exist."
      },
      "action": {
        "pt": "Confira o docid ou caminho do documento substituído.",
        "en": "Check the replaced document's docid or path."
      }
    },
    {
      "code": "supersedes_ambiguous",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "Um alvo de `supersedes` casa com mais de um documento.",
        "en": "A `supersedes` target matches more than one document."
      },
      "action": {
        "pt": "Use o docid completo ou o caminho.",
        "en": "Use the full docid or the path."
      }
    },
    {
      "code": "revision_conflict",
      "kind": "code",
      "status": [
        409
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`expected_revision` não é a revisão atual.",
        "en": "`expected_revision` is not the current revision."
      },
      "action": {
        "pt": "Releia o documento (`current_revision`) e reaplique a mudança.",
        "en": "Reread the document (`current_revision`) and reapply the change."
      }
    },
    {
      "code": "update_failed",
      "kind": "code",
      "status": [
        200
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Um item do lote não pôde ser atualizado.",
        "en": "One batch item could not be updated."
      },
      "action": {
        "pt": "Repita só os itens com `ok: false`.",
        "en": "Retry only the items with `ok: false`."
      }
    },
    {
      "code": "resolve_failed",
      "kind": "code",
      "status": [
        200
      ],
      "surfaces": [
        "mcp_tool"
      ],
      "cause": {
        "pt": "A lacuna de conhecimento não pôde ser marcada como resolvida.",
        "en": "The knowledge gap could not be marked resolved."
      },
      "action": {
        "pt": "Tente de novo em instantes; se persistir, abra um chamado com o horário da requisição.",
        "en": "Retry shortly; if it persists, open a ticket with the request time."
      }
    },
    {
      "code": "approval_required",
      "kind": "code",
      "status": [
        403,
        200
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "Escrita de autoridade mais fraca que o valor vencedor; vira proposta.",
        "en": "Write with weaker authority than the winning value; it becomes a proposal."
      },
      "action": {
        "pt": "Peça aprovação humana ou corrija com `assert_authority_correction`.",
        "en": "Ask for human approval or correct with `assert_authority_correction`."
      }
    },
    {
      "code": "pii_defense_block",
      "kind": "code",
      "status": [
        422
      ],
      "surfaces": [
        "rest",
        "mcp_tool"
      ],
      "cause": {
        "pt": "Escrita recusada: PII de alto risco que não pôde ir para o cofre.",
        "en": "Write refused: high-risk PII that could not be vaulted."
      },
      "action": {
        "pt": "Remova o dado sensível ou guarde-o com `secrets`.",
        "en": "Remove the sensitive data or store it with `secrets`."
      }
    },
    {
      "code": "invalid_request",
      "kind": "code",
      "status": [
        400,
        405
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Parâmetro ausente ou inválido (PKCE S256, `redirect_uri`, corpo do formulário).",
        "en": "Missing or invalid parameter (PKCE S256, `redirect_uri`, form body)."
      },
      "action": {
        "pt": "Corrija a requisição conforme `error_description`.",
        "en": "Fix the request per `error_description`."
      }
    },
    {
      "code": "invalid_client",
      "kind": "code",
      "status": [
        401,
        400
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "`client_id` desconhecido.",
        "en": "Unknown `client_id`."
      },
      "action": {
        "pt": "Registre o cliente de novo em `/oauth/register`.",
        "en": "Register the client again at `/oauth/register`."
      }
    },
    {
      "code": "invalid_client_metadata",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Metadados do registro dinâmico inválidos.",
        "en": "Invalid dynamic registration metadata."
      },
      "action": {
        "pt": "Corrija o corpo do `/oauth/register`.",
        "en": "Fix the `/oauth/register` body."
      }
    },
    {
      "code": "invalid_redirect_uri",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "`redirect_uri` fora do permitido (http só em loopback; esquemas perigosos recusados).",
        "en": "`redirect_uri` not allowed (http only on loopback; dangerous schemes refused)."
      },
      "action": {
        "pt": "Use https, loopback ou um esquema próprio do app.",
        "en": "Use https, loopback or an app-specific scheme."
      }
    },
    {
      "code": "invalid_grant",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Código expirado, já usado, de outro cliente, PKCE errado ou asserção EMA inválida.",
        "en": "Code expired, reused, from another client, wrong PKCE or invalid EMA assertion."
      },
      "action": {
        "pt": "Recomece o fluxo de autorização.",
        "en": "Restart the authorization flow."
      }
    },
    {
      "code": "invalid_scope",
      "kind": "code",
      "status": [
        400,
        302
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Escopo pedido fora de `read write`.",
        "en": "Requested scope outside `read write`."
      },
      "action": {
        "pt": "Peça `read`, `write` ou ambos.",
        "en": "Ask for `read`, `write` or both."
      }
    },
    {
      "code": "invalid_target",
      "kind": "code",
      "status": [
        400,
        302
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "`resource` (RFC 8707) não é um recurso deste emissor.",
        "en": "`resource` (RFC 8707) is not a resource of this issuer."
      },
      "action": {
        "pt": "Use a URL do MCP ou omita `resource`.",
        "en": "Use the MCP URL or omit `resource`."
      }
    },
    {
      "code": "access_denied",
      "kind": "code",
      "status": [
        302
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "A pessoa recusou o consentimento.",
        "en": "The person denied the consent."
      },
      "action": {
        "pt": "Nada a fazer; ofereça tentar de novo.",
        "en": "Nothing to do; offer to try again."
      }
    },
    {
      "code": "unsupported_grant_type",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "`grant_type` diferente de `authorization_code` ou jwt-bearer.",
        "en": "`grant_type` other than `authorization_code` or jwt-bearer."
      },
      "action": {
        "pt": "Use `authorization_code` com PKCE (ou jwt-bearer no EMA).",
        "en": "Use `authorization_code` with PKCE (or jwt-bearer for EMA)."
      }
    },
    {
      "code": "unsupported_response_type",
      "kind": "code",
      "status": [
        302
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "`response_type` diferente de `code`.",
        "en": "`response_type` other than `code`."
      },
      "action": {
        "pt": "Use `response_type=code`.",
        "en": "Use `response_type=code`."
      }
    },
    {
      "code": "method_not_allowed",
      "kind": "code",
      "status": [
        405
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Endpoint OAuth chamado sem POST.",
        "en": "OAuth endpoint called without POST."
      },
      "action": {
        "pt": "Use POST.",
        "en": "Use POST."
      }
    },
    {
      "code": "server_error",
      "kind": "code",
      "status": [
        500
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Falha interna no servidor de autorização.",
        "en": "Internal failure in the authorization server."
      },
      "action": {
        "pt": "Tente de novo em instantes; se persistir, abra um chamado com o horário da requisição.",
        "en": "Retry shortly; if it persists, open a ticket with the request time."
      }
    },
    {
      "code": "invalid_consent_session",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "`consent_session` adulterada, assinada por outra chave ou malformada.",
        "en": "`consent_session` tampered with, signed by another key or malformed."
      },
      "action": {
        "pt": "Comece a conexão de novo pelo app (novo `/oauth/authorize`).",
        "en": "Start the connection again from the app (new `/oauth/authorize`)."
      }
    },
    {
      "code": "consent_session_expired",
      "kind": "code",
      "status": [
        400
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "A `consent_session` passou dos 15 minutos.",
        "en": "The `consent_session` is past its 15 minutes."
      },
      "action": {
        "pt": "Comece a conexão de novo pelo app.",
        "en": "Start the connection again from the app."
      }
    },
    {
      "code": "consent_session_used",
      "kind": "code",
      "status": [
        409
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Este consentimento já foi decidido (aprovação ou negação é de uso único).",
        "en": "This consent was already decided (approval or denial is single use)."
      },
      "action": {
        "pt": "Comece a conexão de novo pelo app.",
        "en": "Start the connection again from the app."
      }
    },
    {
      "code": "tenant_inactive",
      "kind": "code",
      "status": [
        403
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "O workspace da sessão não está com `billing_status` ativo.",
        "en": "The session's workspace is not billing-active."
      },
      "action": {
        "pt": "Regularize a assinatura do workspace e aprove de novo.",
        "en": "Restore the workspace subscription and approve again."
      }
    },
    {
      "code": "unauthorized",
      "kind": "code",
      "status": [
        401
      ],
      "surfaces": [
        "oauth"
      ],
      "cause": {
        "pt": "Endpoint interno de consentimento chamado sem a credencial de plataforma (só o SaaS chama).",
        "en": "Internal consent endpoint called without the platform credential (only the SaaS calls it)."
      },
      "action": {
        "pt": "Clientes não chamam este endpoint: use `/oauth/authorize`.",
        "en": "Clients do not call this endpoint: use `/oauth/authorize`."
      }
    },
    {
      "code": "Unauthorized",
      "kind": "message",
      "status": [
        401
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "REST sem bearer, ou com uma credencial que não é do REST (`fk_`, segredo de administração).",
        "en": "REST without a bearer, or with a credential that is not for REST (`fk_`, admin secret)."
      },
      "action": {
        "pt": "Envie `Authorization: Bearer vbm_…` (ou a `vb_agent_` da conta).",
        "en": "Send `Authorization: Bearer vbm_…` (or the account's `vb_agent_`)."
      }
    },
    {
      "code": "Unauthorized: admin secret required",
      "kind": "message",
      "status": [
        401
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Rota de administração da plataforma.",
        "en": "Platform administration route."
      },
      "action": {
        "pt": "Não é rota de cliente; use as rotas públicas do REST.",
        "en": "Not a client route; use the public REST routes."
      }
    },
    {
      "code": "Forbidden: admin credential required for money routes",
      "kind": "message",
      "status": [
        403
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Rota de crédito ou assinatura chamada com token de tenant.",
        "en": "Credit or subscription route called with a tenant token."
      },
      "action": {
        "pt": "Não é rota de cliente; planos se mudam pelo app.",
        "en": "Not a client route; change plans in the app."
      }
    },
    {
      "code": "Forbidden: /metrics is served only to local scrapers",
      "kind": "message",
      "status": [
        403
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "`/metrics` fora da rede local e sem o token de métricas.",
        "en": "`/metrics` from outside the local network without the metrics token."
      },
      "action": {
        "pt": "Não é rota de cliente.",
        "en": "Not a client route."
      }
    },
    {
      "code": "Rate limit exceeded — please slow down",
      "kind": "message",
      "status": [
        429
      ],
      "surfaces": [
        "rest"
      ],
      "cause": {
        "pt": "Limite por credencial (ou por IP, em rota pública) estourado.",
        "en": "Per-credential (or per-IP, on a public route) limit exceeded."
      },
      "action": {
        "pt": "Aguarde `retry_after_ms` e reduza a cadência.",
        "en": "Wait `retry_after_ms` and slow down."
      }
    }
  ],
  "sha256": "9d2b630103a5dc6a8f519b109b444ea18d39d5e971c42e0b744cc890e3e2d818"
}
