API do SeuMotor
Para CRMs e sistemas de loja lerem os contatos e manterem o estoque. O SeuMotor gera o contato; o acompanhamento da venda fica no CRM.
CRM recomendado: Fusion CRM
A API é aberta a qualquer CRM. Para lojas que ainda não têm um, o SeuMotor recomenda a Fusion CRM, feita para revendas de veículos.
Autenticação e escopos
O gerente ou o dono da loja gera a chave em Painel da loja, API e CRM. Envie a chave em todas as chamadas, no cabeçalho Authorization. Cada chave enxerga só os dados da loja que a criou.
curl https://seumotor.com.br/api/v1/leads \
-H "Authorization: Bearer sm_live_..."A chave nasce com um de dois escopos, escolhido na criação:
- Só leitura: consulta contatos, estoque e loja, e registra webhooks.
- Leitura e escrita: também cria, altera e exclui veículos e fotos.
Uma chamada de escrita com chave de leitura recebe 403, código insufficient_scope. GET /api/v1/dealer devolve o escopo da chave em key_scope.
Limites
Por chave: 120 requisições de leitura e 30 de escrita por minuto, em contadores separados. Toda resposta traz X-RateLimit-Limit e X-RateLimit-Remaining. Acima do limite a resposta é 429, com Retry-After em segundos.
Endpoints
| Método | Caminho | Escopo | O que faz |
|---|---|---|---|
GET | /api/v1/leads | leitura | Contatos recebidos nos anúncios da loja. Filtros: after, since, channel. |
GET | /api/v1/leads/{id} | leitura | Um contato. |
GET | /api/v1/vehicles | leitura | Estoque da loja. Filtro: status=active, paused, sold, removed, suspended ou all. |
GET | /api/v1/vehicles/{id} | leitura | Um veículo, com fotos e opcionais. |
POST | /api/v1/vehicles | escrita | Cria um veículo. |
PATCH | /api/v1/vehicles/{id} | escrita | Altera preço, quilometragem, descrição, opcionais ou status. |
DELETE | /api/v1/vehicles/{id} | escrita | Exclui o veículo e as fotos dele. |
POST | /api/v1/vehicles/{id}/photos | escrita | Envia fotos (multipart). |
DELETE | /api/v1/vehicles/{id}/photos/{photoId} | escrita | Remove uma foto. |
GET | /api/v1/dealer | leitura | Dados da loja dona da chave e o escopo da chave. |
GET | /api/v1/webhooks | leitura | Webhooks registrados. |
POST | /api/v1/webhooks | leitura | Registra um endereço para receber eventos. |
DELETE | /api/v1/webhooks/{id} | leitura | Remove um webhook. |
Paginação
As listas vêm em ordem crescente de id. Use limit (1 a 100, padrão 50) e after com o último id recebido. A resposta traz has_more e next_after. Para sincronizar contatos sem perder nenhum, guarde o next_after e mande-o na chamada seguinte.
Em /leads, since aceita uma data ISO 8601 e devolve só os contatos criados a partir dela, e channel filtra por canal.
O contato
{
"id": 4312,
"created_at": "2026-11-15T18:04:11.000Z",
"channel": "financiamento",
"contact": {
"name": "Ana Ribeiro",
"phone": "5511987654321",
"email": "[email protected]"
},
"message": "Quero esta simulação.",
"proposal_value": null,
"details": {
"entrada": 45000,
"parcelas": 48,
"taxa": 1.89,
"parcela": 3312.54,
"financiado": 103900
},
"vehicle": {
"id": 187,
"title": "Jeep Compass 1.3 Turbo Longitude 2022",
"brand": "Jeep",
"model": "Compass",
"version": "1.3 Turbo Longitude",
"year": 2022,
"km": 41200,
"price": 148900,
"plate_end": "7",
"url": "https://seumotor.com.br/anuncio/jeep-compass-1-3-turbo-longitude-2022-187"
}
}channel:mensagem,proposta,financiamento,whatsappoutelefone.contact.phone: só dígitos, com DDI e DDD.proposal_value: valor em reais quando o comprador fez uma proposta.details: dados extras do contato, ounull. No canalfinanciamentotraz a simulação pedida:entradaefinanciadoem reais,parcelasem meses,taxaem % ao mês eparcelaem reais.vehicle:nullse o anúncio foi excluído.
Criar e alterar veículos
Exige chave de leitura e escrita. Marca, modelo e versão precisam existir no catálogo do SeuMotor, com a mesma grafia do site. A cidade e o estado são os da loja.
curl -X POST https://seumotor.com.br/api/v1/vehicles \
-H "Authorization: Bearer sm_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: estoque-crm-8841" \
-d '{
"brand": "Fiat",
"model": "Argo",
"version": "1.3 Drive",
"year_model": 2022,
"km": 38000,
"price": 74900,
"color": "Prata",
"plate_end": "4",
"description": "Único dono, revisões em dia.",
"features": ["Ar-condicionado", "Câmera de ré"],
"flags": { "one_owner": true, "ipva_paid": true }
}'- Obrigatórios:
brand,model,version,year_model,km,priceecolor. - Opcionais:
year_made(igual ao ano do modelo ou um antes),doors,plate_end,description,features,flagsestatus(activeoupaused; padrãoactive). - Cores aceitas: Branco, Prata, Preto, Cinza, Vermelho, Azul, Marrom e Verde.
flags:one_owner,ipva_paid,licensed,service_history,accepts_tradeearmored.- A resposta é 201 com o veículo em
data. A referência de preço (reference_price) é calculada pelo SeuMotor.
Quando o veículo não pode ficar no ar (loja aguardando aprovação, loja suspensa ou limite do plano atingido), ele é criado como paused e a resposta traz warnings com o motivo:
{
"data": { "id": 512, "status": "paused", ... },
"warnings": [
{ "code": "plan_limit_reached", "message": "O plano da loja permite 10 veículos no ar e esse limite já foi atingido. O veículo foi criado como pausado." }
]
}Idempotency-Key
Mande em POST /vehicles um identificador seu no cabeçalho Idempotency-Key (até 200 caracteres). Se a mesma chave de API repetir a chamada com o mesmo valor em até 24 horas, o SeuMotor devolve a primeira resposta, com o cabeçalho Idempotent-Replayed: true, e não cria outro veículo. Use quando a rede cair antes de a resposta chegar.
Alterar
curl -X PATCH https://seumotor.com.br/api/v1/vehicles/512 \
-H "Authorization: Bearer sm_live_..." \
-H "Content-Type: application/json" \
-d '{"price": 72900, "status": "active"}'- Campos aceitos:
price,km,color,doors,plate_end,description,features,flagsestatus(active,pausedousold). - Envie só o que muda. A resposta traz o veículo atualizado e
changescom os campos que mudaram de fato. - Mudança de preço entra no histórico de preços do anúncio.
- Ativar um veículo pode devolver 409:
plan_limit_reached,dealer_not_approvedoudealer_suspended. - Veículo removido pela moderação (
removed) ou de loja suspensa (suspended) não muda de status pela API.
Fotos
curl -X POST https://seumotor.com.br/api/v1/vehicles/512/photos \
-H "Authorization: Bearer sm_live_..." \
-F "[email protected]" -F "[email protected]"- JPEG, PNG ou WebP, até 8 MB cada, no máximo 12 fotos por veículo. A primeira é a capa.
- As fotos são recortadas para 4:3 em 1280 por 960 pixels.
- A resposta traz
addedeskipped. Para remover uma foto, use oidque vem emphoto_itemsdo veículo.
Webhooks
Para receber os eventos na hora, registre um endereço HTTPS. O segredo de assinatura aparece só na resposta do registro.
curl -X POST https://seumotor.com.br/api/v1/webhooks \
-H "Authorization: Bearer sm_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://seu-crm.com/webhooks/seumotor", "events": ["lead.created", "vehicle.status_changed"]}'| Evento | Quando acontece |
|---|---|
lead.created | Um contato novo chegou em um anúncio da loja. data é o contato. |
vehicle.created | Um veículo foi cadastrado, pelo painel ou pela API. data é o veículo. |
vehicle.updated | Dados do veículo mudaram. data é o veículo depois da mudança; changes lista os campos alterados. |
vehicle.status_changed | O status mudou (active, paused, sold, removed ou suspended). previous_status traz o anterior. |
vehicle.deleted | O veículo foi excluído. data traz só id, title, brand, model, version e year_model. |
Sem events, o webhook assina só lead.created. Cada evento chega como um POST com este corpo:
{
"id": "evt_9f2c41d0a7b3e6c15d8a0b42",
"type": "vehicle.updated",
"created_at": "2026-11-15T18:04:12.310Z",
"data": { "id": 512, "status": "active", "price": 72900, ... },
"changes": ["price"]
}changes só aparece em vehicle.updated e previous_status só em vehicle.status_changed. Os cabeçalhos X-SeuMotor-Event, X-SeuMotor-Event-Id e X-SeuMotor-Delivery-Attempt repetem o tipo, o id e o número da tentativa.
Conferir a assinatura
O cabeçalho X-SeuMotor-Signature vem no formato t=<timestamp>,v1=<assinatura>. A assinatura é o HMAC-SHA256, em hexadecimal, de timestamp + "." + corpo, com o segredo do webhook. Recuse eventos com timestamp de mais de 5 minutos.
import { createHmac, timingSafeEqual } from "node:crypto";
function assinaturaValida(corpo, cabecalho, segredo) {
const partes = Object.fromEntries(cabecalho.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(partes.t)) > 300) return false;
const esperado = createHmac("sha256", segredo).update(`${partes.t}.${corpo}`).digest("hex");
return esperado.length === partes.v1.length && timingSafeEqual(Buffer.from(esperado), Buffer.from(partes.v1));
}Reenvio e duplicatas
- Responda com status 2xx em até 8 segundos. Qualquer outra resposta conta como falha.
- Depois de uma falha, o SeuMotor tenta de novo em 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas e 24 horas. Sem sucesso na última, a entrega é abandonada.
- Todas as tentativas levam o mesmo corpo e o mesmo
idde evento; só o timestamp da assinatura muda. Guarde os ids já processados e ignore os repetidos: um evento pode chegar mais de uma vez. - Os eventos podem chegar fora de ordem quando há reenvio. Use
created_atpara ordenar. - Depois de 15 falhas seguidas o webhook é pausado. A loja reativa no painel, e as entregas pendentes voltam a ser enviadas. Entregas paradas há mais de 72 horas são abandonadas.
- Para recuperar o que se perdeu, consulte
GET /api/v1/leads?after=eGET /api/v1/vehicles.
Erros
Os erros vêm em JSON, com um código estável e uma mensagem:
{ "error": { "code": "invalid_key", "message": "Chave inválida ou revogada." } }| Status | Quando |
|---|---|
| 400 | Parâmetro ou corpo inválido, marca, modelo ou versão fora do catálogo. |
| 401 | Chave ausente, inválida ou revogada. |
| 403 | Escrita com chave só de leitura. |
| 404 | Recurso inexistente ou de outra loja. |
| 409 | Webhook repetido, limite de webhooks, de fotos ou do plano, loja sem aprovação ou suspensa. |
| 429 | Limite de requisições. |
Dados pessoais
Os contatos trazem dados pessoais de compradores. Quem consome a API trata esses dados em nome da loja e responde por eles conforme a LGPD. Veja a política de privacidade.