Falcon Data Hub
← Blog

Consultar FIPE a partir da placa de veículo em Node.js

Receita prática: receba uma placa, descubra marca/modelo/ano via API de placas, depois busque o preço FIPE oficial. Uma chamada do usuário, duas APIs por trás.

Caso de uso comum: usuário digita a placa do carro e você precisa mostrar o preço FIPE atualizado. Parece uma chamada só, mas são duas APIs distintas por trás — uma para descobrir marca/modelo/ano a partir da placa, outra para buscar o preço FIPE com esses dados.

Este guia mostra como encadear as duas em Node.js com TypeScript, tratamento de erro e cache local para evitar request duplicado.

Por que duas APIs

A tabela FIPE é organizada por código de marca + código de modelo + código de ano. Esses códigos são padrão FIPE, não estão na placa. Então o fluxo é:

  1. Receber placa → descobrir marca, modelo e ano modelo.
  2. Mapear esses textos para os códigos FIPE correspondentes.
  3. Buscar o preço usando os códigos.

A boa notícia é que ambas as APIs estão no mesmo provedor (Falcon Data Hub), no mesmo token. Sem login extra, sem conta separada.

Setup

npm install @falcon/datahub

Token no .env:

FALCON_TOKEN=seu_token_aqui

Implementação básica

import { FalconDataHub } from '@falcon/datahub';

const client = new FalconDataHub({ token: process.env.FALCON_TOKEN! });

interface FipeFromPlate {
  placa: string;
  marca: string;
  modelo: string;
  ano_modelo: number;
  valor: string;
  codigo_fipe: string;
  mes_referencia: string;
}

async function fipeFromPlate(placa: string): Promise<FipeFromPlate> {
  // 1. Consulta dados da placa
  const veiculo = await client.placa(placa);

  // 2. Lista marcas FIPE de carros e encontra a do veículo
  const brands = await client.fipe.brands('cars');
  const brand = brands.find(
    (b) => b.nome.toUpperCase() === veiculo.marca.toUpperCase()
  );
  if (!brand) {
    throw new Error(`Marca ${veiculo.marca} não encontrada na tabela FIPE`);
  }

  // 3. Lista modelos da marca e encontra o do veículo
  const models = await client.fipe.models('cars', brand.codigo);
  const model = models.find((m) =>
    m.nome.toUpperCase().includes(veiculo.modelo.toUpperCase())
  );
  if (!model) {
    throw new Error(`Modelo ${veiculo.modelo} não encontrado para ${brand.nome}`);
  }

  // 4. Lista anos do modelo e encontra o ano modelo do veículo
  const years = await client.fipe.years('cars', brand.codigo, model.codigo);
  const year = years.find((y) => y.nome.startsWith(String(veiculo.ano_modelo)));
  if (!year) {
    throw new Error(`Ano ${veiculo.ano_modelo} não encontrado`);
  }

  // 5. Consulta o preço FIPE final
  const fipe = await client.fipe.price(
    'cars',
    brand.codigo,
    model.codigo,
    year.codigo
  );

  return {
    placa: veiculo.placa,
    marca: fipe.Marca,
    modelo: fipe.Modelo,
    ano_modelo: fipe.AnoModelo,
    valor: fipe.Valor,
    codigo_fipe: fipe.CodigoFipe,
    mes_referencia: fipe.MesReferencia,
  };
}

// Uso
fipeFromPlate('ABC1D23')
  .then((result) => console.log(result))
  .catch((err) => console.error(err.message));

Saída esperada

{
  "placa": "ABC1D23",
  "marca": "VW - VolksWagen",
  "modelo": "Gol 1.0 Flex 12V 5p",
  "ano_modelo": 2021,
  "valor": "R$ 64.523,00",
  "codigo_fipe": "005340-6",
  "mes_referencia": "maio de 2026"
}

Cache local para evitar request duplicado

Se o mesmo usuário consultar a mesma placa duas vezes em 1 hora, não faz sentido bater na API de novo. Um cache em memória resolve:

const cache = new Map<string, { data: FipeFromPlate; expiresAt: number }>();
const TTL_MS = 60 * 60 * 1000; // 1 hora

async function fipeFromPlateWithCache(placa: string): Promise<FipeFromPlate> {
  const key = placa.toUpperCase().replace(/[^A-Z0-9]/g, '');
  const cached = cache.get(key);

  if (cached && cached.expiresAt > Date.now()) {
    return cached.data;
  }

  const data = await fipeFromPlate(placa);
  cache.set(key, { data, expiresAt: Date.now() + TTL_MS });
  return data;
}

Para produção com múltiplas instâncias, troque o Map por Redis. O padrão é o mesmo.

Tratamento de "modelo não encontrado"

O ponto mais frágil é o matching de modelo. A placa pode retornar GOL 1.0 MI e a FIPE listar Gol 1.0 Flex 12V 5p. O includes resolve muitos casos, mas vale ter fallback:

// Estratégia em 3 níveis
let model = models.find((m) =>
  m.nome.toUpperCase() === veiculo.modelo.toUpperCase()
);

if (!model) {
  // Tenta substring exata
  model = models.find((m) =>
    m.nome.toUpperCase().includes(veiculo.modelo.toUpperCase())
  );
}

if (!model) {
  // Tenta só a primeira palavra (ex: "GOL")
  const firstWord = veiculo.modelo.split(' ')[0].toUpperCase();
  const candidates = models.filter((m) =>
    m.nome.toUpperCase().startsWith(firstWord)
  );
  // Se sobrar mais de um, devolve o mais recente
  model = candidates.sort((a, b) => b.codigo - a.codigo)[0];
}

Limites a considerar

  • Plano grátis: 10 requisições por hora. Como cada fipeFromPlate faz 5 chamadas (placa + marcas + modelos + anos + preço), você gasta 50% da cota numa única consulta.
  • Plano Premium: 1000/hora. Suficiente para um SaaS de revenda ou seguradora pequena.
  • Cache: se você atender o mesmo usuário várias vezes, cache local resolve. Se atende usuários diferentes consultando o mesmo carro popular (Gol, HB20, Onix), Redis compartilhado vale muito.

Conclusão

O encadeamento placa → FIPE é o "hello world" das integrações automotivas no Brasil. Com SDK pronto, três blocos de código, cache simples e fallback de matching você cobre os casos reais. Para escalar, troque Map por Redis e considere processar em lote quando a UX permitir.

Gostou do artigo?

Comece a usar a API do Falcon Data Hub agora. Plano grátis, sem cartão.

Criar conta grátis
FIPE pela placa em Node.js — guia passo a passo | Falcon Data Hub