Saltar para o conteúdo principal
A Vendaze API usa códigos de status HTTP padrão e retorna um formato de erro consistente em toda falha.

Formato do erro

{
  "error": {
    "code": "not_found",
    "message": "Person not found.",
    "request_id": "550e8400-e29b-41d4-a716-446655440000"
  }
}
CampoDescrição
codeCódigo de erro legível por máquina. Use em lógica de tratamento.
messageDescrição para desenvolvedores. Não exiba ao usuário final.
request_idID único da requisição. Inclua ao contatar o suporte.
Uma resposta com status 2xx nunca contém error. Uma resposta com status não-2xx sempre contém error. O request_id também é retornado no header X-Request-ID em toda resposta, incluindo as bem-sucedidas.

Códigos de status HTTP

StatusSignificado
200Sucesso. Recurso lido ou atualizado.
201Criado com sucesso.
204Sem conteúdo. Recurso deletado. Body vazio.
400Requisição malformada ou parâmetro obrigatório ausente.
401Não autenticado. Token ausente, inválido ou expirado.
403Sem permissão. Token válido mas escopo insuficiente ou operação negada.
404Não encontrado. Recurso não existe, foi deletado, ou pertence a outro workspace.
409Conflito. A requisição não pode ser concluída por conflito com dados existentes.
422Validação falhou. Veja o objeto fields.
429Limite de taxa excedido.
500Erro interno. Algo deu errado no servidor.

Referência de códigos de erro

Retornado em três situações:
  • Header ausente ou inválido: "Missing or invalid Authorization header." o header Authorization: Bearer <token> está ausente ou malformado.
  • Token inválido: "Invalid or malformed token." a assinatura do token falhou na verificação ou o token não é um JWT válido.
  • Claims ausentes: "Token is missing required claims." o token é estruturalmente válido mas está faltando claims internos obrigatórios (workspace_id, client_id ou vendaze_scopes). Isso não deve ocorrer com tokens emitidos pelo fluxo OAuth da Vendaze.
"Access token expired. Refresh using the refresh token."O access token expirou. Access tokens são válidos por 1 hora. Use o refresh_token para obter um novo via POST /oauth/token com grant_type=refresh_token. Se o refresh token também expirou, o usuário precisa re-autorizar.
"This endpoint requires the '{scope}' scope."O token não tem o escopo necessário para este endpoint. O {scope} na mensagem é o escopo exato que está faltando (por exemplo, "This endpoint requires the 'people:write' scope."). O usuário autorizou seu app com um conjunto de escopos que não inclui o que esta operação requer. Você precisa solicitar uma nova autorização com os escopos corretos.
O token é válido e tem o escopo correto, mas a operação foi negada por uma verificação de permissão no banco de dados. A mensagem varia conforme o contexto:
  • Criação: "You do not have permission to create this {entity}. Check that all fields are within your access level."
  • Atualização: "You do not have permission to update this {entity} or one of the provided values is not allowed for your access level."
  • Deleção: "You do not have permission to delete this {entity}."
Causa comum: definir owner_user_id como outro usuário quando seu papel não permite.
"{Entity} not found." por exemplo, "Person not found." ou "Deal not found."O recurso solicitado não existe, foi soft-deletado ou pertence a um workspace diferente. A API não distingue entre esses casos para evitar vazar informações sobre outros workspaces.
"A record with this value already exists."A requisição conflita com dados existentes. A resposta também inclui o objeto fields identificando o campo em conflito. Causa comum: tentar registrar um app com um e-mail que já está em uso.
"Validation failed."O input falhou na validação. A resposta inclui o objeto fields mapeando cada campo inválido a uma descrição do problema. Corrija os campos listados e tente novamente. Veja Erros de validação para o formato completo da resposta.
Retornado em duas situações:
  • Body malformado: "Request body must be valid JSON." o body da requisição não pôde ser interpretado como JSON.
  • Atualização vazia: "No fields provided for update." uma requisição PATCH foi enviada sem nenhum campo para modificar.
"Rate limit exceeded. Try again in {N} seconds."Muitas requisições. O {N} na mensagem é o número exato de segundos a aguardar. O mesmo valor também está no header Retry-After. Veja Limites de taxa para os limites completos por método e tipo de endpoint.
Retornado em duas situações:
  • Erro inesperado no servidor: "An unexpected error occurred." algo falhou no servidor. Tente novamente com backoff exponencial. Se o erro persistir, entre em contato com o suporte incluindo o request_id.
  • Atualização parcial: "{Entity} updated but associations failed. Retry the associations." o registro principal foi salvo mas a atualização de associações (tags, listas, negócios ou campos adicionais) falhou. O registro em si está consistente. Retente apenas os campos de associação.

Códigos de erro OAuth

Estes códigos são retornados exclusivamente pelos endpoints OAuth (/oauth/authorize, /oauth/token, /oauth/revoke, /v1/auth/register-app, /v1/auth/rotate-app).
"Invalid client credentials." o client_id ou client_secret está incorreto. Verifique suas credenciais. Se suspeitar que o client_secret foi comprometido, rotacione via POST /v1/auth/rotate-app.Também retornado como 401 pelo /oauth/authorize quando o client_id não existe ou o app não está ativo, e pelo /v1/auth/rotate-app quando o e-mail enviado não corresponde ao cadastrado no aplicativo.
"The provided authorization grant is invalid, expired, or does not match."O código de autorização é inválido, expirou ou já foi utilizado. Códigos expiram em 10 minutos e são de uso único. Também retornado quando um refresh_token é inválido ou expirado. Em ambos os casos, o usuário precisa passar pelo fluxo completo de autorização novamente.
Um parâmetro OAuth obrigatório está ausente ou inválido. A mensagem identifica o parâmetro específico. Exemplos:
  • "Missing required parameter: client_id."
  • "Missing required parameter: redirect_uri."
  • "redirect_uri does not match any registered URI."
  • "Missing required parameter: token." (revoke)
  • "token must be a valid access_token. refresh_tokens are not accepted." (revoke)
"grant_type must be \"authorization_code\" or \"refresh_token\"."O campo grant_type enviado para /oauth/token não é um dos dois valores suportados.
"response_type must be \"code\"."O parâmetro response_type enviado para /oauth/authorize não é "code".

Erros de validação

Quando a validação falha, a resposta inclui o objeto fields mapeando cada campo ao problema:
{
  "error": {
    "code": "validation_error",
    "message": "Validation failed.",
    "fields": {
      "full_name": "String must contain at most 70 character(s).",
      "forecast_date": "Invalid ISO 8601 date format."
    },
    "request_id": "uuid"
  }
}

O campo request_id

Toda requisição, bem-sucedida ou não, recebe um request_id único. Ele aparece em:
  • O campo error.request_id nas respostas de erro
  • O header X-Request-ID em todas as respostas
Ao contatar o suporte sobre um problema, sempre inclua o request_id. Ele permite que o time localize a requisição exata nos logs e diagnostique o que aconteceu.

Tratamento de erros em produção

Erros recuperáveis vs não-recuperáveis

Nem todos os erros devem ser retentados. Retentar um erro não-recuperável desperdiça recursos e atrasa a identificação do problema real. Erros recuperáveis são transitórios. Retente com backoff:
StatusCódigoEstratégia
429rate_limit_exceededAguarde os segundos indicados em Retry-After e retente.
500internal_errorRetente com backoff exponencial (1s, 2s, 4s). Desista após 3 tentativas.
Erros não-recuperáveis indicam problema na requisição ou nas credenciais. Não retente automaticamente:
StatusCódigoO que fazer
400bad_requestCorrija a requisição. O body está malformado ou o PATCH não tem campos.
400invalid_grantCode ou refresh token inválido. Redirecione o usuário pelo fluxo OAuth.
400invalid_requestUm parâmetro OAuth obrigatório está ausente ou inválido. Corrija a requisição.
400unsupported_grant_typeUse authorization_code ou refresh_token.
401token_expiredRenove o access token e retente a requisição original.
401unauthorizedVerifique se o token está presente e formatado corretamente.
401invalid_clientVerifique client_id e client_secret. Não retente automaticamente.
403insufficient_scopeSolicite nova autorização com os escopos necessários.
403forbiddenCorrija a requisição. A operação ou os valores dos campos não são permitidos para seu nível de acesso.
404not_foundO recurso não existe. Não retente.
409conflictResolva o conflito antes de retentar.
422validation_errorCorrija os campos listados em fields. Não retente com o mesmo payload.

Padrão recomendado de tratamento de erros

async function apiCall(url, options) {
  const res = await fetch(url, options);

  if (!res.ok) {
    const { error } = await res.json();

    switch (error.code) {
      case 'token_expired':
        await refreshAccessToken();
        return apiCall(url, options);

      case 'invalid_grant':
        throw new Error('Autorização expirada. Usuário precisa re-autorizar.');

      case 'invalid_client':
        throw new Error('Credenciais inválidas. Verifique client_id e client_secret.');

      case 'rate_limit_exceeded': {
        const retryAfter = parseInt(res.headers.get('Retry-After') ?? '60');
        await new Promise((r) => setTimeout(r, retryAfter * 1000));
        return apiCall(url, options);
      }

      case 'not_found':
        return null;

      case 'internal_error':
        console.error(`Erro no servidor. request_id: ${error.request_id}`);
        throw new Error(`Erro no servidor (request_id: ${error.request_id})`);

      default:
        throw new Error(`${error.code}: ${error.message} (request_id: ${error.request_id})`);
    }
  }

  return res.json();
}