Pular para o conteúdo

Limites e erros

Toda rota /v1 e todo pedido ao MCP passam por dois baldes, os dois na mesma conta:

  • o da empresa, que soma todos os tokens dela;
  • o do token, para um script não esgotar a empresa sozinho.

Os baldes são por classe de operação. A classe de cada rota e de cada ferramenta está na Referência da API (x-nexo-operation.rateClass) e na Referência do MCP.

Classe O que conta Empresa Token Rajada empresa / token
read Leituras, listas, prévias, consultas de exportação; cada mensagem ao MCP 300/min 120/min 60 / 30
content Conteúdo de conversa: leitura, trechos, transcrição, sessão de WhatsApp 120/min 60/min 30 / 15
export Pedir uma exportação (POST /v1/exports) 10/hora 5/hora 3 / 2
file Arquivo de uma conversa, downloads e envio, confirmação e download de materiais 60/min 30/min 15 / 10
write Mudanças na Calibração e na Base de conhecimento 60/min 30/min 20 / 10
crm_write Escrita no CRM (próximo passo de um negócio) 30/min 15/min 10 / 5

Os números são iguais para todas as empresas, e GET /v1/me devolve os que valem para o seu token em rateLimits. O limite é contado no esquema de balde de tokens (GCRA): a rajada é quantas chamadas seguidas cabem antes de o ritmo valer. Um 429 pela empresa não gasta o balde do token, e vice-versa.

No MCP, cada mensagem JSON-RPC do pedido gasta uma unidade de read antes de qualquer coisa (num lote, uma por mensagem), e um tools/call gasta também a classe da ferramenta.

Toda resposta traz o estado dos dois baldes da classe, no formato do rascunho da IETF:

RateLimit-Policy: "read";q=300;w=60, "read-credential";q=120;w=60
RateLimit: "read";r=59;t=1, "read-credential";r=29;t=1

q é a cota, w a janela em segundos, r o que resta e t os segundos até o balde se recompor.

429 com Retry-After (segundos) e o motivo em meta:

{
"type": "public_api.rate_limited",
"title": "PublicRateLimitedError",
"status": 429,
"detail": "Muitas chamadas em pouco tempo. Tente de novo em 12 segundos.",
"requestId": "019fcae7-…",
"meta": {
"class": "read",
"limitedBy": "credential",
"limit": 120,
"windowSeconds": 60,
"retryAfterSeconds": 12
}
}

limitedBy diz qual balde recusou: company (a empresa inteira) ou credential (só este token). Espere Retry-After e tente de novo. No MCP, um tools/call recusado volta como resultado com isError e esse mesmo corpo, para o modelo ler e esperar.

  • Downloads: além da classe file, os downloads (PDFs de transcrição e link do áudio) gastam a mesma cota do app, 60 por pessoa e 600 por empresa a cada 10 minutos; o pedido de ZIP, 10 por pessoa e 60 por empresa por hora. Passou: 429 core.too_many_attempts.
  • Exportações: no máximo duas em andamento por empresa; a terceira recebe 429 exports.too_many_running.
  • Token inválido: 20 falhas a cada 5 minutos por endereço; depois, 429 public_api.auth_failures_limited.
  • Tokens: no máximo 20 válidos por pessoa (Autenticação).

Todo erro é application/problem+json:

{
"type": "public_api.insufficient_scope",
"title": "InsufficientScopeError",
"status": 403,
"detail": "Este token não tem o escopo conversations:read, exigido por esta operação. Gere um token com esse escopo.",
"requestId": "019fcae7-…",
"meta": { "operation": "conversations.reading", "scope": "conversations:read" }
}
Campo Significado
type Código estável, em inglês (<contexto>.<motivo>). É nele que o seu código deve decidir
title Nome do erro, para log
status O mesmo status HTTP
detail Mensagem em português para uma pessoa ler; pode mudar de texto
requestId Id da requisição. Mande ao suporte junto com o horário
meta Dados do erro, quando existem (o escopo que faltou, o limite, o id não encontrado…)

Os erros comuns a toda rota:

Status type Quando
400 validation_failed Parâmetro ou corpo inválido; os detalhes da validação vêm em meta
401 public_api.invalid_credential Token ausente, inválido, expirado ou revogado
403 public_api.insufficient_scope O token não tem o escopo da operação (meta.scope)
403 public_api.role_not_allowed O seu papel não permite a operação
403 public_api.product_not_contracted O plano da empresa não inclui a operação
404 <contexto>.not_found e afins O recurso não existe ou está fora da sua visibilidade (ex.: deals.not_found)
429 public_api.rate_limited Passou do limite da classe (acima)
500 internal_error Erro inesperado do nosso lado; tente de novo e, se persistir, mande o requestId

Os erros específicos de cada rota (por exemplo, conversations.deal_unavailable ou exports.too_many_running) estão nas respostas de cada operação na Referência da API.

Um recurso fora da sua visibilidade responde 404, como se não existisse: o vendedor não descobre que o negócio de outra pessoa existe.

As listas usam um de dois formatos:

  • Por página: page (começa em 1) e pageSize (até 100), com total na resposta. Os negócios (GET /v1/deals) usam page e size (até 200, padrão 50).
  • Por cursor: GET /v1/conversations e GET /v1/activity recebem limit (até 200) e cursor, e devolvem nextCursor. Para a página seguinte, mande o nextCursor como cursor; quando ele vier nulo, acabou. O cursor de conversas é estável: conversa nova entrando no meio não faz a página seguinte pular nem repetir item.

Os limites e o padrão de cada lista estão nos parâmetros da operação na Referência da API.

Nenhum arquivo passa pela API: exportações, o arquivo de uma conversa, downloads e materiais da Base de conhecimento saem como link assinado do S3, com expiresAt na resposta. O link já baixa com o nome certo e não precisa do token.

O quê Validade do link
Arquivos de uma exportação (GET /v1/exports/{id} quando ready) 15 minutos
Arquivo de uma conversa (POST /v1/conversations/{channel}/{id}/file, em PDF, TXT ou JSON) 15 minutos
Downloads (/v1/downloads/...: transcrição em PDF, áudio da reunião, ZIP) 15 minutos
Material da Base de conhecimento (POST /v1/knowledge/materials/{id}/download-url) 5 minutos

O link expirou? Peça de novo: consultar a exportação gera links novos. As exportações ficam guardadas por 7 dias e podem ser apagadas antes (DELETE /v1/exports/{id}); depois disso aparecem como expired, sem links.

Cada exportação traz um manifest.json com, para cada arquivo, o tamanho, o sha256 e o número de linhas, para você conferir se o download veio inteiro.