Pular para o conteúdo

Tratamento de erros

O Cord usa códigos HTTP convencionais e uma estrutura de erro previsível para indicar sucesso ou falha.

Códigos de status HTTP

A API do Cord sempre devolve códigos de status HTTP padrão. Como regra geral:

  • 2xx indica sucesso.
  • 4xx indica um erro originado nas informações enviadas (por exemplo, parâmetros ausentes, token inválido).
  • 5xx indica um erro nos servidores do Cord (são muito raros).

Resumo dos códigos

Código Descrição
200 OK Tudo funcionou como esperado.
400 Bad Request A requisição era inaceitável. Geralmente significa invalid_request (faltam campos) ou invalid_json; também invalid_cursor ou invalid_api_version.
401 Unauthorized A sua chave de API está ausente, é incorreta ou foi revogada.
402 Payment Required A operação exige um plano superior (subscription_required), excede um limite do seu plano atual (plan_limit_reached, por exemplo, número de clientes ou produtos) ou a chave excede o número de chaves que o seu plano inclui (subscription_key_limit).
403 Forbidden Você não tem permissões suficientes (por exemplo, tentou escrever com uma chave que só tem permissão de leitura, ou uma Publishable Key tentou uma operação fora do seu escopo).
404 Not Found O recurso (orçamento, cliente, fatura) não existe.
409 Conflict Uma mudança de status inválida para o recurso (invalid_state) — por exemplo, aprovar um orçamento que ainda é rascunho, ou apagar dados de teste (/api/test-mode/reset) sem estar em uma organização do tipo Sandbox. Também quando outra requisição com a mesma Idempotency-Key ainda está em andamento (idempotency_in_progress), ou quando uma fatura timbrada precisa de uma nota de crédito em vez de ser cancelada (credit_note_required).
413 Payload Too Large O corpo passa de 1 MB (payload_too_large); em POST /api/v1/elements/ai-draft, o arquivo passa de 4 MB, e em POST /api/v1/setup/plans, o arquivo passa de 3 MB.
415 Unsupported Media Type O corpo não foi enviado como application/json (unsupported_media_type).
422 Unprocessable Entity Você reutilizou uma Idempotency-Key com uma requisição diferente (idempotency_key_reused), ou a IA não encontrou produtos no texto (no_items).
429 Too Many Requests Você ultrapassou um limite de requisições por minuto (rate_limited, veja Limites de requisições), a cota mensal de API do seu plano (api_quota_exceeded) ou a de IA (ai_quota_exceeded). Respeite o header Retry-After.
502 Bad Gateway Um provedor externo rejeitou ou não concluiu a operação: o provedor fiscal ao emitir (provider_error) ou o envio de um e-mail (send_failed).
503 Service Unavailable Um serviço do qual a operação depende não respondeu — por exemplo, não foi possível obter uma taxa de câmbio (fx_unavailable) ou o catálogo de impostos (tax_catalog_unavailable), ou não foi possível verificar a sua assinatura (subscription_verification_unavailable). O Cord nunca inventa uma taxa: se não puder comprová-la, a operação falha de forma fechada. Tente de novo mais tarde.

Estrutura do objeto de erro

Quando ocorre um erro 4xx ou 5xx, o Cord sempre responde com um objeto JSON plano (não aninhado) com dois campos: error (mensagem legível, para mostrar ou registrar) e code (string estável para a sua lógica de tratamento). Alguns erros acrescentam campos adicionais conforme o caso (veja os exemplos abaixo).

Exemplo de resposta de erro:

{
  "error": "The company name is required",
  "code": "invalid_request"
}

Exemplo com campos adicionais (limite de plano, 402):

{
  "error": "Your plan allows 50 clients. Free up space or upgrade your plan to continue.",
  "code": "plan_limit_reached",
  "resource": "clients",
  "limit": 50,
  "plan": "starter"
}

Não conte com a forma aninhada error.code / error.message para fazer o parse da resposta: error é sempre a string da mensagem e code é um campo irmão no mesmo nível, não uma propriedade de error.

Toda resposta de /api/v1 traz o header Cord-Request-Id (req_…). Em um erro, o corpo o repete como request_id e acrescenta doc_url, o link para a explicação desse código nesta página. Inclua o request_id quando escrever para o suporte: com ele, encontramos a sua requisição exata.

{
  "error": "API key inválida o revocada.",
  "code": "invalid_key",
  "request_id": "req_3f9c2a1b7d4e6f8a0b1c2d3e",
  "doc_url": "https://docs.cordhq.app/docs/desarrolladores/esenciales/errores#invalid_key"
}

Códigos de erro comuns (code)

  • invalid_json: o corpo da sua requisição POST não é um JSON válido, ou não foi enviado Content-Type: application/json.

  • invalid_request: as validações de negócio falham (falta um campo, um desconto fora do intervalo, um orçamento sem cliente válido). O campo error explica o motivo exato.

  • invalid_fiscal_data (400): os dados fiscais de cliente.fiscal não passam na validação do país. A resposta traz issues, uma lista de { field, code }. Veja Formulário fiscal.

  • missing_key / invalid_key: falta o header Authorization: Bearer, ou a chave não existe / foi revogada.

  • token_expired: a credencial de uma conexão autorizada (Zapier, Make) expirou. O app a renova sozinho com o seu refresh token.

  • insufficient_scope: a sua chave não tem o escopo necessário (uma chave somente leitura tentou escrever, ou uma Publishable Key tentou uma rota fora da sua lista permitida).

  • insufficient_permissions (403): uma chave restrita (rk_) não tem permissão para o recurso dessa rota, ou foi usada com MCP. O campo error nomeia o recurso.

  • ip_not_allowed (403): a chave tem IPs permitidos e a requisição chegou de outro. O campo error inclui o IP que o Cord viu.

  • key_expired (401): a chave expirou, ou foi rotacionada e o período de carência terminou. Use a chave nova ou gere outra.

  • not_found: o recurso solicitado não existe na sua organização.

  • subscription_required: o recurso exige um plano superior. A resposta inclui plan (o atual) e plan_required.

  • plan_limit_reached: você atingiu um limite rígido do seu plano (clientes, produtos ou orçamentos ativos). A resposta inclui resource, limit e plan.

  • integration_limit_reached (403): as suas integrações já criaram as 100 assinaturas de webhook permitidas por organização. Exclua as que você não usa mais.

  • rate_limited / api_quota_exceeded: limite de requisições por minuto ou de cota mensal da API. Tente de novo respeitando Retry-After.

  • fx_unavailable / tax_catalog_unavailable: um dado de terceiros (taxa de câmbio ou catálogo de impostos) não pôde ser obtido com certeza. A operação não foi concluída — não presuma que ela ocorreu.

  • subscription_key_limit (402): a sua organização tem mais chaves ativas do que o plano inclui (por exemplo, depois de mudar para um plano inferior) e esta chave ficou fora da cota; as mais antigas continuam funcionando. Revogue as chaves que você não usa mais ou mude para um plano superior. A cota conta as chaves secretas, restritas e publicáveis ativas, sem as conexões autorizadas por OAuth: 2 no Grátis, 5 no Starter, 20 no Profissional, 50 no Scale e 200 no Developer.

  • subscription_verification_unavailable (503): o Cord não conseguiu verificar a sua assinatura ou registrar o uso da chamada. A operação não foi executada; tente de novo.

  • invalid_api_version (400): o header Cord-Version pede uma versão que não existe. A mensagem lista as disponíveis. Veja Versões da API.

  • invalid_cursor (400): o cursor não é válido. Use exatamente o next_cursor da resposta anterior.

  • payload_too_large (413): o corpo JSON passa de 1 MB, ou o arquivo enviado para POST /api/v1/elements/ai-draft passa de 4 MB.

  • unsupported_media_type (415): o corpo não vem como application/json (ou como multipart/form-data em POST /api/v1/elements/ai-draft).

  • test_mode_only (403): os simuladores de /api/v1/test_helpers só funcionam com uma chave sk_test_ e sobre o ambiente de teste.

  • credit_note_required (409): a fatura já timbrada não pode ser cancelada diretamente. Emita uma nota de crédito com action: "credit_note".

  • provider_error (502): o provedor fiscal rejeitou ou não concluiu a emissão. O campo error explica o motivo.

  • send_failed (502): não foi possível enviar o e-mail da fatura. Tente o envio de novo.

  • ai_quota_exceeded (429) / no_items (422) / ai_unavailable (502 ou 503) / missing_text / text_too_long (400): erros das rotas com IA (POST /api/v1/cotizaciones/ia e POST /api/v1/elements/ai-draft): a cota de IA do seu plano acabou, o texto não trazia produtos, a IA não está disponível ou não conseguiu processar o pedido, ou o texto está ausente ou passa do máximo. Em ai-draft, esses códigos chegam como evento error dentro do stream.

  • invalid_state: o recurso não está em um status que permita a operação, ou mudou enquanto a processávamos. Nada foi aplicado.

  • invalid_url: a URL de um webhook não é https:// ou aponta para um host interno.

  • invalid_idempotency_key / idempotency_key_reused / idempotency_in_progress / idempotency_unavailable: veja a próxima seção.

  • secret_key_in_browser (403): uma Secret Key chegou a partir de um navegador. Ela já ficou exposta no código da página: revogue-a na aba Chaves do Cord Workbench e chame a API somente a partir do seu servidor.

  • missing_origin / unauthorized_origin / invalid_origin (403): uma Publishable Key chegou sem Origin, ou de um domínio que não está nos domínios permitidos da sua organização (Configurações › Gerador de orçamentos incorporável).

  • origin_allowlist_required (403): uma Publishable Key de produção só funciona com domínios permitidos configurados em Configurações › Gerador de orçamentos incorporável. As chaves pk_test_ funcionam a partir de qualquer origem.

Limites de requisições

O Cord aplica estes limites por janela de um minuto, salvo onde indicado. Ao ultrapassá-los, responde 429 com code: "rate_limited", em geral com o header Retry-After em segundos. Os marcados como rígidos não deixam passar requisições quando o Cord não consegue contá-las: em /api/v1/cotizaciones/{id} e /api/v1/elements/ai-draft, eles respondem então 503 com error: "access_temporarily_unavailable".

Limite Escopo Aplica-se a
120 por minuto Por IP de origem Toda requisição a /api/v1 e ao servidor MCP, com qualquer chave, antes de validar a chave.
600 por minuto Por chave secreta (sk_, rk_ ou conexão OAuth) Toda requisição a /api/v1 e ao servidor MCP.
120 por minuto Por chave publicável (pk_) As quatro rotas que uma pk_ aceita.
120 por minuto (rígido) Por organização POST e DELETE em /api/v1/cotizaciones/{id} e as ferramentas MCP que mudam o status de um orçamento.
20 por minuto Por chave POST /api/v1/webhooks.
20 por minuto Por organização POST /api/v1/cotizaciones/ia.
6 por minuto por IP, 60 por minuto e 500 por dia por organização (rígidos) IP e organização POST /api/v1/elements/ai-draft.
6 por dia (rígido) Por organização POST /api/v1/setup/plans e proponer_configuracion no MCP.

Como o limite por IP é menor que o de uma chave secreta, um servidor que envia tudo a partir de um único IP chega primeiro a 120 por minuto. Além desses limites, as chaves de produção consomem a cota mensal de API do seu plano (api_quota_exceeded).

Novas tentativas seguras com Idempotency-Key

Se uma requisição que cria ou altera algo (POST, PATCH, DELETE) for interrompida pela rede ou por timeout, você não sabe se o Cord a aplicou. Envie o header Idempotency-Key com um valor único por operação (por exemplo, um UUID gerado por você) e tente de novo com a mesma chave e o mesmo corpo:

curl -X POST "https://cordhq.app/api/v1/clientes" \
     -H "Authorization: Bearer sk_live_tU..." \
     -H "Content-Type: application/json" \
     -H "Idempotency-Key: 5d9c2b7e-6f1a-4c3d-9e8b-2a1f0c7d6e5b" \
     -d '{ "empresa": "ACME Corp" }'
  • Nova tentativa com a mesma chave e o mesmo corpo: o Cord devolve a resposta original sem executar a operação de novo nem contá-la na sua cota. A resposta repetida traz o header Idempotent-Replayed: true.
  • A mesma chave com outro corpo, método ou rota: 422 idempotency_key_reused. Use uma chave nova para cada operação diferente.
  • A primeira requisição ainda não terminou: 409 idempotency_in_progress. Aguarde e tente de novo.
  • Erros 5xx e 429: não são armazenados, então você pode tentar de novo com a mesma chave.
  • A chave vale por chave de API, aceita de 1 a 255 caracteres visíveis (invalid_idempotency_key se não) e expira em 24 horas.
  • Se o Cord não conseguir reservar a chave, responde 503 idempotency_unavailable sem executar a operação.

O header é opcional: sem ele, cada requisição é executada como chega.