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 é:
- Receber placa → descobrir marca, modelo e ano modelo.
- Mapear esses textos para os códigos FIPE correspondentes.
- 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
fipeFromPlatefaz 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