<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Verissimo Ribeiro</title>
    <description>The latest articles on DEV Community by Verissimo Ribeiro (@verissimo_ribeiro_0154185).</description>
    <link>https://dev.to/verissimo_ribeiro_0154185</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3893177%2F8275d9b6-4196-405d-b071-3008a7739b32.png</url>
      <title>DEV Community: Verissimo Ribeiro</title>
      <link>https://dev.to/verissimo_ribeiro_0154185</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/verissimo_ribeiro_0154185"/>
    <language>en</language>
    <item>
      <title>O que aprendi rodando consultas de CNPJ em produção por 8 meses</title>
      <dc:creator>Verissimo Ribeiro</dc:creator>
      <pubDate>Wed, 22 Apr 2026 23:42:43 +0000</pubDate>
      <link>https://dev.to/verissimo_ribeiro_0154185/o-que-aprendi-rodando-consultas-de-cnpj-em-producao-por-8-meses-152g</link>
      <guid>https://dev.to/verissimo_ribeiro_0154185/o-que-aprendi-rodando-consultas-de-cnpj-em-producao-por-8-meses-152g</guid>
      <description>&lt;p&gt;Faz 8 meses que coloquei consulta de CNPJ no caminho crítico de um produto. Escrevo isso pra passar pra frente o que ninguém te conta antes de subir pra produção.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contexto rápido
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uso: fluxo de onboarding B2B, consulta no cadastro e em re-validações periódicas&lt;/li&gt;
&lt;li&gt;Volume: cerca de 150 mil consultas/mês, com picos de 3x nas segundas&lt;/li&gt;
&lt;li&gt;Latência: parte da experiência depende disso, então acima de 2s começa a machucar conversão&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  O que eu achei que ia funcionar
&lt;/h2&gt;

&lt;p&gt;Comecei do jeito óbvio: bati direto numa API pública gratuita. Funciona muito bem até não funcionar. O que vi, na ordem em que fui descobrindo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rate limit é o menor dos problemas.&lt;/strong&gt; Dá pra contornar com fila e cache. O problema de verdade é o provider ficar instável por 20 minutos no meio do dia útil, sem status page, sem aviso.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dados "completos" não são iguais entre providers.&lt;/strong&gt; QSA (sócios) vem em um, Simples vem em outro, CNAE secundário vem só em metade deles. Acabei precisando compor resposta de mais de uma fonte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frescor dos dados varia MUITO.&lt;/strong&gt; Uma mesma consulta retorna situações cadastrais diferentes dependendo de quando o provider atualizou a base da Receita. Isso vira bug silencioso.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  O que eu implementaria de novo desde o dia 1
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Cache com TTL por tipo de dado
&lt;/h3&gt;

&lt;p&gt;Nome e endereço mudam raramente. Situação cadastral muda sem avisar. Tratei tudo com o mesmo TTL no começo e paguei o preço. Hoje uso 30 dias pra dados "estáveis" e 24h pra situação cadastral.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fallback entre providers, não failover
&lt;/h3&gt;

&lt;p&gt;Failover (troca quando cai) chega atrasado. Fallback (race entre dois providers, fica com o primeiro que responde ok) deu latência muito melhor no p95. Custo extra foi pequeno perto da dor que evitou.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Normalização na camada de integração
&lt;/h3&gt;

&lt;p&gt;Cada provider tem schema próprio. Construí um tipo interno único, com todos os campos opcionais, e um adapter por provider. Isso isolou o resto do código de qualquer troca posterior.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Logar o provider que atendeu cada consulta
&lt;/h3&gt;

&lt;p&gt;Sem isso, você não consegue debugar "por que esse cadastro ficou com razão social diferente semana passada?".&lt;/p&gt;

&lt;h2&gt;
  
  
  Erros que custaram caro
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Assumir que CNPJ inválido é erro 4xx uniforme.&lt;/strong&gt; Não é. Cada provider trata de um jeito. Teve provider devolvendo 200 com body vazio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confiar na situação cadastral sem timestamp.&lt;/strong&gt; Hoje eu guardo &lt;code&gt;consultado_em&lt;/code&gt; junto com o registro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Não ter rate limit do meu lado.&lt;/strong&gt; Um bug de retry em loop torrou cota em 15 minutos.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Observações sobre as opções que testei
&lt;/h2&gt;

&lt;p&gt;Sem ranquear, só o que senti:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gratuitas públicas&lt;/strong&gt;: ótimas pra começar, ruins pra volume. Se o produto depende de CNPJ, você vai sair delas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pagas&lt;/strong&gt;: pagou, funcionou na maioria dos casos. Olha contrato, SLA real (não o anunciado) e suporte técnico antes de fechar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base local da Receita&lt;/strong&gt;: é uma opção legítima se você aceita o custo operacional de manter ETL mensal. Não era o meu caso.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Se eu pudesse voltar no tempo
&lt;/h2&gt;

&lt;p&gt;Colocaria cache + fallback desde a primeira linha. Todo o resto foi consequência de não ter feito isso no dia 1.&lt;/p&gt;

&lt;p&gt;Se você tá começando agora, escolhe dois providers diferentes, põe cache na frente, e começa a logar o que cada um devolve. O resto você aprende na dor, ou pula essa parte usando algo como &lt;a href="https://cnpj-api.com" rel="noopener noreferrer"&gt;cnpj-api.com&lt;/a&gt;, que foi o que acabei construindo depois dessa jornada.&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>devjournal</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
