Bom de Lance
Integração de estoque
Referência para gestores de estoque e integradores de anúncios.
Documentação para gestores de estoque e integradores de anúncios publicarem o estoque das lojas clientes no Bom de Lance.
Base: https://www.bomdelance.com.br/api/integracao/v1
Tudo é JSON, em UTF-8. Todas as respostas trazem sucesso (booleano) e, quando
algo não deu certo, erro com uma frase em português explicando o que fazer.
Autenticação
O lojista gera um código de acesso dentro do painel dele, em Meus anúncios → Conectar meu sistema de estoque, e cola no sistema de vocês.
Authorization: Bearer bdl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
O código identifica a loja. Não existe campo de identificação de loja em nenhuma chamada — quem manda o código já disse de qual pátio está falando.
O lojista pode gerar outro código ou desligar o recebimento a qualquer momento.
Nos dois casos, as chamadas passam a responder 401.
O modelo: remessa
Uma remessa é o estoque completo da loja naquele momento, não um delta.
1. abre a remessa POST /remessas
2. envia os veículos POST /remessas/{uuid}/veiculos (repita quantas vezes precisar)
3. fecha declarando o total POST /remessas/{uuid}/fechar
4. consulta o resultado GET /remessas/{uuid}
Veículo que estava na remessa anterior e não está nesta é considerado vendido e sai do ar. Não é preciso mandar exclusão.
Por que declarar o total no fechamento
É a única forma de sabermos que a remessa chegou inteira. Uma conexão que caiu no lote 3 de 7 é, do nosso lado, idêntica a uma loja que ficou com 400 carros a menos — e a segunda leitura apagaria os anúncios que se perderam no caminho.
Se total_declarado não bater com o número de veículos distintos recebidos,
a remessa fica inconsistente e nada é aplicado ao estoque.
1. Abrir remessa
POST /remessas
Authorization: Bearer <código>
Idempotency-Key: 2026-08-10T03:00:00Z-loja42 (opcional, recomendado)
{
"sucesso": true,
"remessa": "9f1c8f2e-...",
"situacao": "aberta",
"itens_por_lote": 500,
"veiculos_por_remessa": 5000,
"expira_em_horas": 6
}
Use o Idempotency-Key. Com ele, repetir a chamada devolve a mesma remessa
em vez de criar outra. Sem ele, um timeout na resposta faz vocês reabrirem — e a
segunda remessa, vazia porque os carros foram para a primeira, seria lida como
"a loja esvaziou o pátio".
Só existe uma remessa aberta por vez por loja. Se houver outra em aberto, a
resposta é 409 com o identificador dela. Remessas abandonadas expiram em 6
horas.
2. Enviar veículos
POST /remessas/{uuid}/veiculos
{
"veiculos": [
{
"id_externo": "12345",
"marca": "FIAT",
"modelo": "ARGO",
"versao": "1.0 FIREFLY FLEX DRIVE MANUAL",
"ano_fabricacao": 2022,
"ano_modelo": 2023,
"preco": "74.900,00",
"km": 32000,
"combustivel": "Flex",
"cambio": "Manual",
"cor": "Branco",
"portas": 4,
"tipo": "carro",
"zero_km": false,
"descricao": "Único dono, revisões na concessionária.",
"opcionais": ["Ar-condicionado", "Direção elétrica", "Câmera de ré"],
"unico_dono": true,
"ipva_pago": true,
"aceita_troca": true,
"blindado": false,
"fotos": [
"https://cdn.exemplo.com/12345-1.jpg",
"https://cdn.exemplo.com/12345-2.jpg"
]
}
]
}
Os campos
| Campo | Obrigatório | Observação |
|---|---|---|
id_externo |
sim | O identificador do veículo no sistema de vocês. É por ele que sabemos se o carro é novo, mudou ou sumiu. |
marca, modelo |
sim | Texto. |
versao |
não, mas decisivo | É o que faz o carro casar com a versão certa da tabela FIPE. Sem ela, a chance de recusa sobe muito. |
ano_modelo |
sim | Sem o ano não há como achar a versão na FIPE. |
ano_fabricacao |
não | |
preco |
sim | Aceita "74.900,00", "74900.00" e 74900. |
km |
não | Número ou texto com pontuação. |
combustivel |
não, mas ajuda | É o desempate quando duas versões da FIPE são igualmente parecidas. |
tipo |
não | carro, moto ou caminhao. Sem ele, uma moto pode casar com um carro da mesma marca. |
fotos |
não | Até 50 endereços por veículo; publicamos até 20. |
descricao |
não | Ver a regra de preço na descrição, mais abaixo. |
Não mandem placa, chassi, CPF, CNPJ nem nome de proprietário. Não usamos, e não guardamos.
Cada chamada aceita até 500 veículos. Mandem quantos lotes precisarem dentro
da mesma remessa. O mesmo id_externo repetido na mesma remessa substitui o
anterior e conta como um.
{ "sucesso": true, "recebidos_nesta_chamada": 500, "total_na_remessa": 500 }
3. Fechar
POST /remessas/{uuid}/fechar
{ "total_declarado": 500 }
{
"sucesso": true,
"remessa": "9f1c8f2e-...",
"situacao": "recebendo",
"total_declarado": 500,
"total_recebido": 500,
"explicacao": "Fechada e conferida. Os veículos estão sendo publicados."
}
A publicação acontece em segundo plano (baixamos e convertemos as fotos de cada veículo). Consultem a remessa alguns minutos depois para ver o resultado.
4. Consultar
GET /remessas/{uuid}
{
"sucesso": true,
"situacao": "aplicada",
"explicacao": "Publicada: 487 no ar, 13 recusados, 4 removidos.",
"importados": 487,
"recusados": 13,
"removidos": 4,
"recusas": [
{
"id_externo": "12876",
"veiculo": "FIAT ARGO 1.0 2023",
"motivo": "Encontrei 2 versões parecidas na FIPE e não dá para saber qual é a certa."
}
]
}
As situações
situacao |
O que significa |
|---|---|
aberta |
Aceitando veículos. |
recebendo |
Fechada e conferida, publicando. |
aplicada |
Publicada. |
inconsistente |
A contagem não bateu. Nada foi alterado. Reenviem a remessa inteira. |
bloqueada |
Os novos entraram e nenhuma remoção foi feita — ver as salvaguardas. |
expirada |
Ficou aberta mais de 6 horas. Abram outra. |
falha |
Quebrou do nosso lado. O que já entrou continua no ar; reenviem. |
As salvaguardas de remoção
Gravar é seguro, remover é perigoso. Um envio que falhou no meio e uma loja que vendeu meio pátio chegam aqui com a mesma cara. Na dúvida, gravamos o que veio e não removemos nada.
| Situação | O que acontece |
|---|---|
| Remessa vazia com estoque no ar | Bloqueia. Nem com autorização do lojista. |
| Sumiram mais de 30% dos veículos | Bloqueia até o lojista autorizar na tela dele. |
| Sumiram menos de 5 veículos | O percentual não se aplica (loja pequena vende 2 de 6). |
| Anúncio com negociação em andamento | Nunca é removido, nem com autorização. |
Quando bloqueia, os veículos novos entram normalmente — só as remoções ficam pendentes, e o lojista vê o motivo e o botão de autorizar no painel dele.
Por que um veículo é recusado
O casamento com a tabela FIPE é obrigatório. O Bom de Lance vende análise de preço; um veículo sem código FIPE ocuparia vaga do plano da loja sem fazer a única coisa pela qual ela paga.
Como o código FIPE não costuma existir no cadastro de vocês, o casamento é por texto — marca, modelo, versão e ano. E ele recusa em vez de escolher o mais parecido: um Civic publicado como City é pior que um carro que não entrou.
Os motivos mais comuns, e o que resolve cada um:
| Motivo | O que fazer |
|---|---|
| "Não encontrei este veículo na tabela FIPE de 2023" | Conferir marca, modelo e ano no cadastro. |
| "Encontrei N versões parecidas e não dá para saber qual é a certa" | Mandar a versao completa, e o combustivel. |
| "Achei no catálogo, mas ainda está sem código FIPE aqui" | É do nosso lado; o catálogo se completa sozinho. |
| "Limite de anúncios do plano atingido" | O lojista precisa subir de plano. |
| "Já existe um anúncio idêntico" | O mesmo veículo com o mesmo preço já está no ar. |
Todas as recusas aparecem em GET /remessas/{uuid} e na tela do lojista, com
o motivo escrito para ele ler.
Preço e parcela na descrição
Anúncio que estampa "R$ 890" e esconde no texto que é o valor da parcela é o
golpe mais comum do mercado de usados, e recusamos. Não coloquem preço nem
parcelamento no campo descricao — o preço vai no campo preco.
Fotos
Nós baixamos as imagens e as hospedamos. Não usamos hotlink: se a loja sair do sistema de vocês, os anúncios continuam com foto.
- Só endereços https.
- Endereços que apontem para rede interna são recusados (é defesa contra SSRF).
- Não usamos redirecionamento: mandem o endereço final da imagem.
- Até 15 MB por arquivo.
Limites
| Envio (abrir, enviar, fechar) | 60 chamadas por minuto, por código de acesso |
| Consulta | 300 por minuto, por código de acesso |
| Veículos por chamada | 500 |
| Veículos por remessa | 5.000 |
O limite é por código, não por endereço de rede: um servidor de vocês pode atender centenas de lojas sem uma atrapalhar a outra.
Sugestão de frequência
Uma remessa completa a cada 1 a 4 horas cobre com folga a operação de uma revenda. Não há ganho em sincronizar de minuto em minuto: a remessa é sempre o pátio inteiro.
Como testar
Peçam ao lojista o código de acesso dele (ou usem uma loja de teste). O fluxo
inteiro funciona com curl:
BASE=https://www.bomdelance.com.br/api/integracao/v1
TOKEN=cole_o_codigo_aqui
R=$(curl -s -X POST $BASE/remessas -H "Authorization: Bearer $TOKEN" | jq -r .remessa)
curl -s -X POST $BASE/remessas/$R/veiculos \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"veiculos":[{"id_externo":"1","marca":"FIAT","modelo":"ARGO","versao":"1.0 DRIVE","ano_modelo":2023,"preco":"74.900,00","fotos":[]}]}'
curl -s -X POST $BASE/remessas/$R/fechar \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"total_declarado":1}'
curl -s $BASE/remessas/$R -H "Authorization: Bearer $TOKEN"
Para ver a conferência agindo, declarem um total errado no fechamento: a resposta
volta inconsistente e nada é aplicado.
Falar com a gente
Dúvida técnica, ambiente de teste ou pedido de ajuste no contrato: [email protected].