Profile Server API

Erros e convenções

Códigos de status, formato de erro, paginação e cabeçalhos comuns.

Convenções gerais

  • Base path: rotas de usuário sob /api, rotas de serviço sob /service.
  • Autenticação: sempre Authorization: Bearer <jwt>.
  • Content-Type: application/json em requisições com corpo.
  • Datas: ISO 8601 em UTC (ex.: 2026-07-10T12:00:00.000Z).
  • IDs: UUID v4.

Códigos de status

StatusQuando ocorre
200Leitura/edição bem-sucedida.
201Criação bem-sucedida (POST).
204Remoção bem-sucedida (DELETE), sem corpo.
400Falha de validação (Zod) ou regra de negócio violada.
401Token ausente, inválido ou expirado.
403Autenticado, mas sem a permissão exigida (NOT_ALLOWED).
404Recurso não encontrado.
409Conflito de unicidade ou de estado (ex.: federalTaxId já existente).
500Falha interna (inclui falha de storage no upload/download).
503Dependência externa indisponível (ex.: Keycloak).

Formato de erro

Toda falha da API responde o mesmo envelope, com um code estável:

{
  "statusCode": 409,
  "code": "DOCUMENT_ALREADY_VALID",
  "message": "A valid document of this type already exists",
  "path": "/api/documents",
  "timestamp": "2026-07-17T12:00:00.000Z"
}
CampoDescrição
statusCodeStatus HTTP da resposta.
codeContrato estável — identifica a falha e nunca muda depois de publicado.
messageTexto legível em inglês, para logs e consumidores sem tradução própria.
pathRota que originou o erro.
timestampMomento da falha, ISO 8601 em UTC.
detailsSó em VALIDATION_ERROR: lista de { path, message } por campo inválido.

Trate sempre o code, nunca o message — o texto pode mudar, o código não. O painel usa o code para escolher a mensagem exibida ao usuário, com fallback para o message quando o código for desconhecido.

Erro de validação (400) traz o detalhamento por campo em details:

{
  "statusCode": 400,
  "code": "VALIDATION_ERROR",
  "message": "Validation failed",
  "path": "/api/users",
  "timestamp": "2026-07-17T12:00:00.000Z",
  "details": [
    { "path": "email", "message": "Invalid email" },
    { "path": "name", "message": "Too small: expected string to have >=1 characters" }
  ]
}

Falha inesperada responde 500 com code: "INTERNAL_ERROR" e mensagem genérica — o erro real (com stack) fica só no log do servidor.

Códigos genéricos

Não vêm de uma regra de negócio específica; são produzidos pelo filtro global.

codeStatusQuando
VALIDATION_ERROR400Corpo ou query reprovados pelo schema Zod.
BAD_REQUEST400Requisição inválida sem regra de domínio própria.
UNAUTHORIZED401Token ausente, inválido ou expirado.
FORBIDDEN403Sem permissão (UMA/scope).
NOT_ALLOWED403Sem a role de persona exigida pelo endpoint.
NOT_FOUND404Rota inexistente.
RESOURCE_NOT_FOUND404Recurso genérico não encontrado.
CONFLICT409Conflito sem regra de domínio própria.
INTERNAL_ERROR500Falha inesperada.
SERVICE_UNAVAILABLE503Dependência externa indisponível.

Códigos de domínio

O code de cada endpoint está listado na tabela Erros da respectiva página em Endpoints. Referência completa:

codeStatusSignificado
USER_NOT_FOUND404Usuário inexistente.
USER_ALREADY_EXISTS409Já existe usuário com esse email/federalTaxId.
USER_DATA_MISMATCH409federalTaxId e email pertencem a usuários diferentes.
IDENTITY_ALREADY_LINKED409Identidade do Keycloak já vinculada a outro usuário.
IDENTITY_PROVIDER_UNAVAILABLE503Keycloak indisponível.
CUSTOMER_NOT_FOUND404Customer inexistente.
CUSTOMER_ALREADY_EXISTS409Já existe customer com esses dados.
APP_NOT_FOUND404App inexistente.
APP_ALREADY_EXISTS409Já existe app com esse nome.
TENANT_NOT_FOUND404Tenant inexistente.
USER_TENANT_NOT_FOUND404Usuário não é membro ativo desse tenant.
ORGANIZATION_NOT_LINKED_TO_TENANT400Uma ou mais organizations não estão vinculadas a esse tenant.
NOT_ALLOWED_ORGANIZATION403Organização fora do escopo de cooperativas do usuário (write).
ORGANIZATION_NOT_FOUND404Organização inexistente.
ORGANIZATION_ALREADY_EXISTS409Já existe organização com esse federalTaxId.
ORGANIZATION_ADDRESS_NOT_FOUND404Endereço da organização inexistente.
ORGANIZATION_ADDRESS_NOT_CURRENT400O endereço não é o vigente da organização.
ORGANIZATION_CONTACT_NOT_FOUND404Contato da organização inexistente.
STATE_NOT_FOUND404Estado inexistente.
STATE_ALREADY_EXISTS409Estado já cadastrado.
CITY_NOT_FOUND404Cidade inexistente.
CITY_ALREADY_EXISTS409Cidade já cadastrada (código IBGE ou SIAFI).
CITY_STATE_MISMATCH400A cidade não pertence ao estado informado.
DOCUMENT_NOT_FOUND404Documento inexistente.
DOCUMENT_ALREADY_VALID409Já há documento válido desse tipo para a organização.
DOCUMENT_PENDING_REVIEW_EXISTS409Já há documento desse tipo aguardando análise.
DOCUMENT_INVALID_REVIEW_STATUS400Status de revisão diferente de APPROVED/REJECTED.
DOCUMENT_EXPIRATION_DATE_REQUIRED400O tipo exige validade e ela não foi informada.
DOCUMENT_AUTHENTICITY_CODE_REQUIRED400O tipo exige código de autenticidade e ele não foi informado.
DOCUMENT_TYPE_NOT_FOUND404Tipo de documento inexistente, ou restrito a outro tenant.
DOCUMENT_TYPE_ALREADY_EXISTS409Já existe tipo com esse nome no escopo (tenant ou global).
DOCUMENT_TYPE_TENANT_REQUIRED400Pediu tipo restrito sem tenant ativo na request.
DOCUMENT_TYPE_INACTIVE400Tipo de documento inativo.
DOCUMENT_TYPE_INVALID_EXPIRATION400defaultValidityDays preenchido com hasExpiration=false.
DOCUMENT_TYPE_IN_USE409Tipo de documento em uso por um ou mais documentos — não pode ser removido.
ATTACHMENT_NOT_FOUND404Attachment inexistente.
INVALID_ATTACHMENT_TYPE400Tipo de arquivo não permitido.
FILE_UPLOAD_FAILED500Falha ao enviar o arquivo ao storage.
FILE_DOWNLOAD_FAILED500Falha ao baixar o arquivo do storage.
FILE_REMOVE_FAILED500Falha ao remover o arquivo do storage.

Paginação

Endpoints de listagem (GET de coleção) aceitam os query params:

ParamTipoPadrãoRegras
pagenumber1inteiro, mín. 1
limitnumber20inteiro, 1 a 100

E respondem no envelope:

{
  "data": [],
  "total": 0,
  "totalPages": 0,
  "currentPage": 1
}

Filtros adicionais (ex.: name, email, type) são específicos de cada recurso e estão descritos na respectiva página de endpoints.