🩺 Erros comuns e boas práticas

O que fazer em cada código de erro, como reprocessar lotes 207 sem duplicar, limites e armadilhas conhecidas da API externa.

⚠️ Conferência retroativa — gravou pela API antes de 28/09/2026 às 17:43? ✅ Novo — 29/09/2026

A correção geral da API externa de 28/09/2026 (em produção às 17:43, Brasília) acabou com rotas que respondiam sucesso sem gravar ou gravavam errado sem avisar. Confira uma vez o que foi gravado antes disso:

  • Pacientes em lote — POST /pacientes/bulk podia responder criado sem gravar: compare a planilha de origem com GET /pacientes e reenvie os que faltarem.
  • Lote de preços da tabela interna — /tabelas-preco/produtos/bulk gravava sem converter para centavos: confira os valores em GET /tabelas-preco/produtos?id=… e reenvie (é upsert).
  • Movimentações alteradas por PUT sem duplicatas — as parcelas eram apagadas.
  • Fornecedores alterados por PUT sem ativo — eram reativados.
  • UF de operadora, empresa e colaborador enviados sem UF — gravava a primeira UF da lista.
  • Saídas e transferências de estoque sem lote — baixavam de um lote qualquer.
  • Preços da tabela interna carregados em lote antes de 28/09 — os preços priceType1..3 são em reais; confira se não ficaram divididos por 100 (#652).
  • Serviços regravados por PUT /servicos/{id} antes de 01/10/2026 sem todas as listas — podiam perder o documento obrigatório (ex.: PRESCRIÇÃO MÉDICA) e o valor de produtos da composição (#634, corrigido em 01–02/10): confira por GET /servicos/{id}.

1. Erros comuns na implantação e como resolver

SintomaCausa provávelComo resolver
POST /locais → 422 "O depósito padrão de saída selecionado está inativo ou não existe"Ordem antiga: local antes do depósito (ou depósito desativado)Crie o depósito mínimo da unidade (POST /depositos) e use o id dele em depositoPadraoSaidaId. Veja a dependência nº 1.
POST /produtos → 422 "Falha ao criar produto (referência inválida)"depositoId, tipoProdutoId, fabricanteId ou unidadeDeMedidaId inexistenteCrie depósito e fabricante antes; confira os tipos em GET /auxiliares/tipos-produto e /unidades-medida.
Serviço composto criado sem os itensServiço criado antes do produto/subserviçoCrie o item que falta, faça GET /servicos/{id} (desde 26/09/2026 ele devolve servicosRelacionados e especialidadesId), e envie por PUT /servicos/{id} só a lista afetada, já completa (ex.: servicosRelacionados com o item novo) — desde 01–02/10/2026 o PUT é parcial: lista enviada substitui, campo omitido mantém.
Serviço "perdeu" a composição ou as especialidades depois de um PUT /servicos/{id}Até 25/09/2026, o GET /servicos/{id} não devolvia especialidadesId nem servicosRelacionados; regravar a partir dele apagava essas listasCorrigido em 26/09/2026: o GET agora traz as duas listas com os mesmos nomes do PUT. Receita: GET → altere → PUT completo. Serviços regravados antes disso: confira a composição e reenvie. ✅ Atualização 13/10/2026: desde 01–02/10 o PUT de serviço é parcial (lista omitida mantém).
POST /servicos → 500 "Cannot read properties of undefined (reading 'filter')"Até 28/09/2026, campo opcional omitido (ex.: especialidadesId) derrubava a rota✅ Corrigido em 28/09/2026: campo opcional omitido não derruba mais o cadastro de serviço (nem os demais cadastros e operações). Se ainda acontecer, envie especialidadesId: [] e avise o time Rabi.
Integração antiga envia as taxas do serviço em taxaServicoId/valorTaxaServicoContrato antigo: esses campos saíram do contrato em 28/09/2026 — não conte com elesEnvie as taxas em servicoTaxa: [{ "taxaId": 15, "quantidade": 1 }] (POST/PUT /servicos). produtoIds, equipamentoIds e servicosRelacionados aceitam ID puro ou objeto. Ver o Passo 8.
POST /estoque/saida ou /estoque/transferencia recusado por falta de loteDesde 28/09/2026 lote é obrigatório nessas rotasInforme o lote de onde sai o estoque ou envie "lote": null para produto sem lote (antes, sem lote, o sistema baixava de um lote qualquer — ver conferência retroativa).
POST /pacientes/bulk respondeu criado, mas o paciente não existeFalha corrigida em 28/09/2026 (transação aninhada — respondia sem gravar); o mesmo em /colaboradores/bulk✅ Corrigido em 28/09/2026. Lotes enviados antes: compare com GET /pacientes e reenvie os que faltarem (conferência retroativa).
POST/PUT /grades-equipamento → 500, mas a grade foi gravadaErro depois da gravação (até 28/09/2026)✅ Corrigido em 28/09/2026 — não está mais em aberto. Grades enviadas antes: confira por GET /grades-equipamento?equipamentoId=… antes de reenviar (evita duplicar).
/tabelas-preco/produtos respondeu antes de gravar / preço gravado com valor erradoAté 28/09/2026 a rota respondia sem esperar a gravação e o lote de preços gravava sem converter para centavos✅ Corrigido em 28/09/2026 — não está mais em aberto. Confira e reenvie os preços gravados antes (upsert).
POST /orcamentos respondeu com data: nullRetorno incompleto (até 28/09/2026)✅ Corrigido em 28/09/2026 (a resposta deixou de vir com data: null).
Chamada respondeu 401 com mensagem sobre "token", mas a chave estava válidaAté 28/09/2026, qualquer erro com a palavra "token" (ex.: token obrigatório do convênio) virava 401✅ Corrigido em 28/09/2026: só falha real de autenticação responde 401. Nos demais casos, leia a mensagem em error (ex.: token obrigatório do convênio).
Movimentação ficou sem parcelas depois de um PUTAté 28/09/2026, PUT /financeiro/movimentacoes/{id} sem duplicatas apagava todas as parcelas✅ Corrigido em 28/09/2026: o PUT externo tem as mesmas validações da tela e não apaga mais as parcelas; desde 01–02/10 é parcial (duplicatas omitidas não mudam). Movimentações alteradas antes: confira as parcelas.
Fornecedor inativo voltou a ficar ativo / UF da operadora, empresa ou colaborador ficou errada (a primeira da lista)Até 28/09/2026: PUT de fornecedor sem ativo reativava; UF omitida gravava a primeira UF✅ Corrigido em 28/09/2026. Corrija os registros gravados antes (conferência retroativa).
PUT /convenios/{id}/taxas → 207 com item ERROTaxa (ou tipoCodigoId/tabela87ANSId) inexistenteCadastre as taxas antes dos convênios; confira ids em GET /taxas e nos auxiliares. Reenvie só o item com erro.
POST /convenios → 422Empresa, operadora ou kit de documentos não encontradoConfira empresaId, unidadesIds, operadoraId (GET /empresas, GET /operadoras).
POST /operadoras → 404 "Unidade Federativa não encontrada"UF enviada como siglaOperadora (e colaborador) exigem o nome por extenso da UF, igual ao cadastro (GET /auxiliares/unidades-federativas).
Operadora sem os planos depois de um PUTPUT /operadoras/{id} sem a lista completa de planoO servidor remove o que não veio. Faça GET, altere e reenvie as listas completas.
Convênio "perdeu" operadora, datas, unidades ou políticasAté 01/10/2026 o PUT /convenios/{id} substituía o cadastro: o que não fosse enviado era limpo. Hoje: null enviado limpa; unidadesIds e politicasPorTipoProduto enviados são a lista completaDesde 01–02/10/2026 o PUT é parcial: envie só o que muda (omitido mantém). Se mandar unidadesIds ou politicasPorTipoProduto, mande a lista inteira (parta do GET /convenios/{id}). Convênios regravados antes de 01/10: confira operadora, datas, unidades e políticas.
PUT /convenios/{id}/colaboradores → item com erro em atendeatende: true para colaborador que não é credenciado nem tem conversãoEnvie credenciado: true ou colaboradorConvertidoId junto.
Especialidade do colaborador não sai do convênioListas de especialidades da aba Colaboradores são aditivasA rota nunca remove especialidade nem conversão — remova pela tela.
Farol roxo em muitos produtosProduto sem custo (nenhuma entrada de estoque/última compra)Registre entradas com valorCompra (POST /estoque/entrada) ou informe o custo pela tela; releia o Farol.
Item que deveria cobrar aparece com receita 0 no Farol0 gravado onde deveria ser vazio, ou item zerado em pacote de preço fechado, ou utiliza: falseLeia a linha em GET /convenios/{id}/farol/itens/{servicoRaizId}: conta_no_total: false + motivo_exclusao (NAO_UTILIZA_NO_CONVENIO, ZERADO_EM_PACOTE, PAI_FORA_DO_TOTAL) diz o motivo; conta_no_total: true com receita 0 = valor 0 gravado. Para "sem valor", envie null (volta a vazio e desce de nível). Revise zerarValor/pacote/utiliza. Veja a árvore de decisão.
Serviço passou a ser faturado sem uma taxa/material que antes cobrava (o item "sumiu" do farol/itens)O produto ou a taxa foi desativado (DELETE /produtos/{id}, DELETE /taxas/{id} ou pela tela) antes de 02/10/2026, quando a desativação não verificava composição: o item saía dos serviços sem avisoRecoloque o item (ou o substituto) na composição: GET /servicos/{id} → PUT /servicos/{id} só com a lista produtoIds/servicoTaxa corrigida; marque utiliza/zerarValor nas abas do convênio. ✅ Atualização 13/10/2026: desde 02/10 (#626) a desativação de item em uso responde 409 — isso só acontece com itens desativados antes.
DELETE /produtos/{id}, PUT /produtos/{id} com ativo: false ou DELETE /taxas/{id} → 409 ✅ Novo — 13/10/2026O item está na composição de serviço ativo (#626, desde 02/10/2026); a resposta traz a lista em servicosSubstitua ou retire o item nesses serviços (PUT /servicos/{id} com a lista corrigida), marque o substituto nas abas do convênio e tente de novo. Serviço inativo não bloqueia.
403 com escopoFaltante ✅ Novo — 13/10/2026Falta ao token a permissão indicada em escopoFaltante (a mensagem em error diz onde liberá-la)Token rbt_: Editar permissões em Configurações › Parâmetros › Integrações (o valor do token não muda; vale na chamada seguinte — #653). Chave rbk_: peça ao time Rabi.
EAN do produto perdeu o zero à esquerda / 400 em codigoEAN, codigoNCM ou codigoProduto ✅ Novo — 13/10/2026Desde 02/10/2026 (#635): EAN é texto com 8, 12, 13 ou 14 dígitos; NCM texto com 8 dígitos; código do produto até 10 caracteres (letras, números, ponto, hífen ou barra)Envie EAN e NCM como string ("07891234567895") — número ainda é aceito, mas perde os zeros.
Preço da tabela interna 100× menor (ou maior)Lote gravado antes de 28/09/2026 (#652)Hoje priceType1..3 são em reais nas duas rotas (ex.: 19547.56 = R$ 19.547,56). Confira e reenvie os lotes antigos (upsert).
PUT /colaboradores/{id} → 400 no vinculoRepasse ✅ Novo — 13/10/2026Mais de uma linha geral (item com servico/produto/taxa vazio ou null) no mesmo tipo (#643)Deixe no máximo uma linha geral por tipo; as demais linhas precisam do item.
POST /financeiro/pagamentos/confirmacao → 409 / 404 ✅ Novo — 13/10/2026409: a parcela já foi paga por outro pagamento, ou o valor é menor que o da parcela. Novo — out/2026 Duas confirmações ao mesmo tempo para a mesma parcela: a segunda recebe 409 "Esta parcela já está paga por outro pagamento". 404: parcela não encontrada pelo duplicataId/identificadorCobrancaConfira a parcela e o valor. Repetir a mesma confirmação é seguro: responde "já confirmado" (200 com jaConfirmado: true) — Novo — out/2026 não devolve mais 404.
Chamada responde 404 e o id existeRota inexistente (caminho ou método errado). Desde 26/09/2026, rota que não existe sob /api/v1/integrations responde 404 — antes caía em 401 "jwt malformed", parecendo problema de chaveConfira o caminho, o método e a grafia no Swagger (ex.: /convenios/{id}/farol/itens/{servicoRaizId}, não /farol/item). Se o caminho está certo, o id não existe nesta clínica/ambiente.
Valores 0.01 vindos do sistema antigoMarcador legado de "sem valor"Não migre: envie null/omita. 0.01 é cobrado como R$ 0,01.
Atendimento migrado com a data de hojePOST /atendimentos grava sempre "agora"Chame PUT /atendimentos/{id} com responsavelId e horarioInicio real (repita pacienteId/empresaId — PUT sem declaração = sobrescrita).
GET /atendimentos/historico recusa a chamadaFalta pacienteIdNesta API o filtro por paciente é obrigatório (✅ em produção desde 24/09/2026).
Digitou valorInternoConvenio no serviço e os itens continuaram somando no FarolValor combinado não é pacote (regra vigente): sem pacote: true, os itens somam por cima e o zerarValor deles nem é lidoEnvie pacote: true no serviço (PUT /convenios/{id}/servicos) e zerarValor: true em cada item incluso (abas produtos/taxas/servicos). Veja o exemplo.
Cadastro "perdeu" campos depois de um PUTEm serviço, convênio, paciente, colaborador, grades, orçamento, movimentação e guia isso não acontece mais desde 01–02/10/2026 (PUT parcial — #634 corrigido), salvo lista enviada (substitui) ou null (limpa). Nas rotas sem declaração (produto, taxa, equipamento, local, depósito, fornecedor, fabricante…) e em /empresas/{id}, o PUT ainda sobrescreveNas rotas parciais, envie só o que muda. Nas demais, GET antes e objeto completo. Ver convenções de PUT.
Totais de faturamento 100× maiores (ou soma que vira texto)A rota devolve centavos ou string — exceção sinalizada na descrição (ex.: GET /faturamento/guias/servico/{guiaFilha}, GET /faturamento/glosas/guia/{guiaMae})Leia a descrição da rota no Swagger e converta (÷ 100; string → número) antes de somar ou comparar com valores em reais.
GET /agendamentos → 400Falta data (obrigatória desde 25/09/2026)Informe data=AAAA-MM-DD; para vários dias, uma chamada por dia, paginando com page/pageSize.
Integração parou de repente com 401Token expirou (ou foi revogado)Token rbt_ (recomendado): a clínica gera ou renova em Configurações › Parâmetros › Integrações — acompanhe a validade definida na geração. Chave rbk_: peça chave nova ao time Rabi (não há renovação automática nem autoatendimento); para não ser pego de surpresa, monitore o cabeçalho X-ApiKey-Expires-At e peça a renovação antes da data.
503 que não passa com novas tentativasFalha de rede/tempo ao validar a chave (chave errada responde 401, não 503)Espera progressiva (2 s, 4 s, 8 s…); se persistir, avise o time Rabi.
POST /orcamentos → 422O Farol de rentabilidade exige aprovação e não há token/pendênciaResolva a margem (preço/custo) ou siga o fluxo de aprovação por alçada; o parâmetro desabilitarBloqueioFarol fica em /parametros/orcamento.
A tela do convênio mostra "Modo consulta. Para alterar, clique em Liberar para edição.", mas a API gravou normalmente ✅ Novo — 30/09/2026Comportamento esperado: desde 29/09/2026 (#632) as telas de convênio abrem em modo consulta e só gravam depois de Liberar para edição e Salvar (desde 01/10); a API não muda e grava direto — e aparece no Histórico do convênio (#638)Para conferir pela tela o que a API gravou, basta o modo consulta (expandir serviço, Farol, exportar). Para corrigir pela tela, clique em Liberar para edição. Pela API, siga gravando pelas abas PUT /convenios/{id}/….
Políticas de preço por tipo de produto do convênio ficaram inativas(a) PUT /convenios/{id} com politicasPorTipoProduto incompleta (a lista enviada é a completa; omitida, desde 01–02/10, não mexe — antes de 01/10, omitir também inativava); (b) até 29/09/2026, um Salvar pela tela feito antes de as políticas carregarem mandava lista vazia e inativava todas — corrigido em 29/09Leia GET /convenios/{id} (devolve politicasPorTipoProduto), corrija e reenvie a lista inteira de políticas no PUT (os demais campos podem ser omitidos).
POST /colaboradores/{id}/usuario → 400 / 409E-mail ausente ou senha com menos de 8 caracteres / colaborador já tem loginCorrija a senha; se já tem login, não crie outro. Se o e-mail já tem acesso ao Rabi (ex.: em outra clínica), o usuário é vinculado a esta clínica e continua com a senha que já usa — a senha enviada não é aplicada.
DELETE /empresas/{id} ou /operadoras/{id} → 400; DELETE /locais/{id} → 409Há vínculos ativosDesative antes os vínculos (convênios, locais, grades etc.) — ou mantenha o registro ativo.

2. Código a código

CódigoRepetir a mesma chamada resolve?Ação
400NãoCorrija o corpo/parâmetro conforme a mensagem em error.
401NãoQualquer chave rejeitada: ausente, inválida, revogada ou expirada — token rbt_ (recomendado): a clínica gera outro em Configurações › Parâmetros › Integrações; chave rbk_: peça outra ao time Rabi (evite: monitore X-ApiKey-Expires-At). (Até 25/09/2026, rota inexistente também caía aqui como "jwt malformed"; agora é 404. Até 28/09/2026, erro de negócio com a palavra "token" — ex.: token obrigatório do convênio — também virava 401; agora só autenticação real.)
403Não (até liberar a permissão)A chave não tem a permissão da rota — a resposta diz qual em escopoFaltante (e, em error, onde liberar). Com token rbt_: Editar permissões no próprio token (vale na chamada seguinte), ou ele é do tipo TalkMe (só o tipo "Implantação e manutenção" acessa a API externa). Tabela: permissões.
404NãoId inexistente nesta clínica/ambiente (ids de homologação não valem em produção) — ou rota inexistente (caminho/método errado; desde 26/09/2026 responde 404 em vez de 401 "jwt malformed"). Em GET /convenios/{id}/farol/itens/{servicoRaizId}: convênio não encontrado ou serviço raiz não utilizado neste convênio.
409NãoJá existe (CNPJ, CPF, nome, login, conflito de grade): localize pelo GET e reutilize. Desde 02/10/2026, também a desativação de produto/taxa que está na composição de serviço ativo (#626 — lista em servicos) e a confirmação de pagamento de parcela já paga/valor menor.
422NãoReferência inválida/inativa — crie ou ative o pré-requisito (ordem de implantação).
429Sim, depois de esperarOutro lote/atualização em andamento para o mesmo recurso (ou convênio). Aguarde e reenvie.
503Sim, depois de esperarSó falha real de rede/tempo ao validar a chave (chave rejeitada é 401). Espera progressiva (2 s, 4 s, 8 s…); se persistir, avise o time Rabi.

3. Reprocessar um lote 207 sem duplicar

Resposta típica de POST /…/bulk com falha parcial:

{
  "total": 3, "criados": 1, "falhas": 2,
  "resultados": [
    { "indice": 0, "status": "CRIADO", "id": 501, "identificador": "Soro fisiológico 500ml" },
    { "indice": 1, "status": "ERRO", "erro": "fabricanteId 99 não encontrado" },
    { "indice": 2, "status": "NAO_PROCESSADO" }
  ]
}
  1. Guarde os ids dos itens CRIADO (e ATUALIZADO, nas abas do convênio) — já estão gravados; cada item é gravado em transação própria, nunca pela metade.
  2. Corrija os itens ERRO pela mensagem de erro (o indice aponta a posição no array enviado, começando em 0).
  3. Reenvie só os itens ERRO (corrigidos) e NAO_PROCESSADO (interrompidos pelo limite de 45 s), num novo lote.
  4. Não dispare lotes em paralelo do mesmo recurso: o segundo recebe 429.
RotaReenviar o lote inteiro é seguro?
POST /convenios/bulkSim — os já criados são recusados por CNPJ duplicado (mas reenviar só os com erro é o recomendado).
PUT /convenios/{id}/taxas|servicos|produtos|especialidades|planos|colaboradoresSim — são upsert idempotentes (reenviar não duplica).
POST /tabelas-preco/produtos(/bulk)Sim — upsert por productId + purchasePriceSourceId.
Demais /bulk (pacientes, operadoras, serviços, colaboradores, produtos, equipamentos, taxas, fornecedores, fabricantes, depósitos, movimentações financeiras, tomadores)Não conte com isso — reenvie só os itens com ERRO/NAO_PROCESSADO. O Swagger não declara idempotência para esses lotes: reenviar tudo pode gerar erros de duplicidade (onde há chave única, como CPF ou nome de depósito/equipamento) ou registros duplicados.

4. Idempotência e reprocessamento seguro

5. Limites

LimiteValor
Itens por lote /bulk50 (tabela de preço interna: 200; tomadores NFS-e: 100)
Itens por aba do convênio (PUT)200 (colaboradores: 100)
Tempo de processamento de um lote45 s — o restante volta NAO_PROCESSADO
Lotes simultâneos1 por clínica e recurso (abas: 1 por convênio) — senão 429
pageSizepadrão 50, máximo 200 — respeitado também em GET /agendamentos (que exige data) e nas grades. ✅ Novo — 14/10/2026 Desde 14/10 o teto de 200 vale em toda a API externa (#669); pedido acima é reduzido sem erro — percorra por totalPages.
Anexos de pacienteaté 10 arquivos por requisição; JPG/PNG/PDF; 10 MB cada; URL assinada de leitura válida por 1 hora
Senha de login do colaboradormínimo 8 caracteres
Revogaçãotoken rbt_: vale na hora; chave rbk_: pode continuar aceita por até 60 s
Validadeinformada em toda resposta autenticada com sucesso, no cabeçalho X-ApiKey-Expires-At (ISO 8601, UTC; chave sem validade não o envia). Token rbt_: 30, 90, 365 dias ou sem validade, renovável na tela de Integrações; chave rbk_: renovação só pelo time Rabi
Requisições do token rbt_há limite de requisições — excedido, responde 429
Planos da clínicacriar agendamento consome agendamentos.mes; emitir NFS-e consome nfse.notas.mes
GET /faturamento/guias/pacienteslimitado a 50 por padrão

6. Armadilhas conhecidas do Swagger publicado

7. Boas práticas

  1. Ensaie em homologação o roteiro inteiro com uma amostra real da clínica; só depois rode em produção.
  2. Siga a ordem oficial — 90% dos 422 são pré-requisito faltando. Veja o roteiro.
  3. Lotes pequenos e sequenciais (50 é o teto, não a meta); registre a resposta de cada lote.
  4. PUT parcial onde a rota declara (serviços, convênios, pacientes, colaboradores, grades, orçamentos, movimentações, guias): envie só o que muda; ao trocar uma lista, mande a lista inteira (parta do GET). Nas rotas sem declaração, GET antes e objeto completo.
  5. Vazio ≠ zero: "sem valor" é null/omitido; 0 é zero; nunca 0.01.
  6. Feche pela conferência: Farol de cada convênio (farol/servicos + farol/itens/{servicoRaizId} de cada serviço composto, conferindo conta_no_total/motivo_exclusao contra o contrato) e amostras por GET de cada recurso.
  7. Antes de desativar produto ou taxa, liste os serviços que o contêm e substitua-o — senão a API recusa com 409 (#626, desde 02/10/2026).
  8. Segurança: prefira o token rbt_ da clínica (tipo "Implantação e manutenção", só com as permissões da implantação); token (rbt_) ou chave (rbk_) em cofre, permissões mínimas, revogação ao fim da implantação; o token aparece uma única vez — nunca o cole em documento, chamado, e-mail, manual ou conversa com IA salva; token de uma clínica não acessa outra; suspeita de vazamento → revogue e gere outro. Não inclua dados pessoais de pacientes em logs (LGPD).
  9. Gravou antes de 28/09/2026 17:43? Faça a conferência retroativa uma vez.
  10. Monitore a validade: registre X-ApiKey-Expires-At (rbk_ e rbt_) e crie um alerta com antecedência — rbt_: Renovar na tela de Integrações (o valor antigo deixa de valer); rbk_: pedir a chave nova ao time Rabi. Faltou permissão? Editar permissões no mesmo rbt_.
  11. Valores: reais por padrão; nas leituras de faturamento, confira na descrição da rota se o valor vem em centavos ou string.

Continue por aqui: Visão geral · Implantação pela API · Referência — Cadastros · Referência — Operação · Referência — Parâmetros