Carregando...

Primeiros passos

  1. Crie a conta e, no painel, abra Chaves de API para criar uma chave com os escopos de que precisa.
  2. Mande a chave no cabeçalho Authorization: Bearer xqp_… em toda requisição.
  3. Use o endereço base https://app.xeqplaca.com/api/public/v1.

Campos e eventos em inglês; mensagens de erro em português. Datas sempre em ISO 8601 UTC, com Z (2026-11-07T12:00:00Z): converta para o seu fuso na hora de exibir.

curl "https://app.xeqplaca.com/api/public/v1/recognitions?plate=ABC1D23&limit=20" \
  -H "Authorization: Bearer xqp_SUA_CHAVE"

Autenticação e escopos

A chave (xqp_ seguido de 40 caracteres) é mostrada uma vez, quando é criada; guarde-a num cofre ou variável de ambiente, nunca no código do navegador. Perdeu? Revogue no painel e crie outra. Cada chave só faz o que os escopos dela permitem:

EscopoRotas
recognitions:readGET /recognitions, GET /recognitions/{id}
recognitions:writePOST /recognize (gasta 1 crédito por foto)
cameras:readGET /cameras, GET /cameras/{id}
alerts:readGET /alerts
alerts:writePOST /alerts, PUT /alerts/{id}, DELETE /alerts/{id}
webhooks:readGET /webhooks
webhooks:writePOST /webhooks, DELETE /webhooks/{id}, POST /webhooks/{id}/test
qualquer chave válidaGET /credits

Toda chave enxerga só os dados da própria conta.

Erros

Erros voltam com o código HTTP abaixo e a mensagem em português no corpo.

CódigoQuando
400Pedido inválido: parâmetro fora do formato, foto que não é JPEG/PNG ou acima de 10 MB. Não gasta crédito.
401Chave ausente, inválida ou revogada.
402Sem créditos para reconhecer a foto. Compre um pacote ou uma recarga no painel.
403A chave não tem o escopo que a rota pede.
404O recurso não existe ou é de outra conta (as duas situações respondem igual).
409Conflito com o estado atual (por exemplo, cadastro repetido).
429Limite por minuto atingido. Espere os segundos do cabeçalho Retry-After e tente de novo.
503Serviço de leitura indisponível no momento. Não gasta crédito; tente de novo em instantes.

Em 429 e 503, repita depois da espera:

import time
import requests

def pedir(metodo, url, tentativas=5, **kwargs):
    """Repete a requisição em 429 e 503, esperando o Retry-After."""
    for _ in range(tentativas):
        resposta = requests.request(metodo, url, timeout=30, **kwargs)
        if resposta.status_code not in (429, 503):
            return resposta
        time.sleep(int(resposta.headers.get("Retry-After", "5")))
    return resposta

Paginação

As listas usam cursor: peça com limit (até 100) e, enquanto a resposta trouxer next_cursor, mande-o em cursor para a próxima página. Em GET /recognitions os filtros são plate (aceita *, como ABC*), from, to, camera_id e origin.

import requests

BASE = "https://app.xeqplaca.com/api/public/v1"
CABECALHOS = {"Authorization": "Bearer xqp_SUA_CHAVE"}

params = {"from": "2026-11-01T00:00:00Z", "to": "2026-11-02T00:00:00Z", "limit": 100}
while True:
    resposta = requests.get(f"{BASE}/recognitions", params=params, headers=CABECALHOS, timeout=30)
    resposta.raise_for_status()
    pagina = resposta.json()
    for item in pagina["data"]:
        print(item)
    if not pagina.get("next_cursor"):
        break
    params["cursor"] = pagina["next_cursor"]

Reconhecer foto

POST /recognize (escopo recognitions:write) recebe uma foto JPEG ou PNG de até 10 MB, em multipart/form-data no campo image ou como corpo binário (application/octet-stream), e devolve até 8 placas, cada uma com a confiança, a confiança por caractere, os 4 cantos em pixels, o padrão (Mercosul ou antigo) e o veículo. Gasta 1 crédito por foto processada; foto recusada não gasta.

O parâmetro mode diz que tipo de foto é:

  • scene: quadro de câmera, com a placa pequena na imagem.
  • closeup: foto de perto, como a do celular na traseira do carro.
  • auto (padrão): tenta scene e, sem placa com boa confiança, closeup. Continua sendo 1 crédito.

A foto não é guardada, a menos que a conta ligue "guardar fotos do Snapshot por 48 h" nas configurações. Sem placa, plates vem vazio e diagnostic diz em que etapa a leitura parou.

curl -X POST "https://app.xeqplaca.com/api/public/v1/recognize?mode=auto" \
  -H "Authorization: Bearer xqp_SUA_CHAVE" \
  -F "[email protected]"
Resposta (exemplo)
{
  "plates": [
    {
      "plate": "ABC1D23",
      "confidence": 0.97,
      "char_confidences": [0.99, 0.98, 0.99, 0.97, 0.95, 0.98, 0.99],
      "corners": [[412, 388], [548, 390], [547, 431], [411, 429]],
      "pattern": "mercosul",
      "vehicle": { "type": "carro", "year": 2021 }
    }
  ],
  "processing_time_ms": 85,
  "credits_remaining": 41,
  "diagnostic": null
}

Webhooks

Cadastre uma URL https no painel (Webhooks) ou pela API e escolha os eventos. Cada evento chega num POST JSON:

EventoQuando
recognition.createdUma placa foi lida por uma câmera ou por foto.
alert.triggeredUma passagem bateu numa regra de alerta.
camera.offlineA câmera parou de enviar imagens.
camera.onlineA câmera voltou a enviar imagens.
Corpo do evento (exemplo)
POST https://seu-sistema.com.br/webhook
Content-Type: application/json
X-XeqPlaca-Assinatura: t=1762516800,v1=5f2b…(64 caracteres hexadecimais)

{
  "id": "…",
  "event": "recognition.created",
  "created_at": "2026-11-07T12:00:00Z",
  "data": { … }
}

Responda com um código 2xx em até 5 segundos. Sem resposta ou com erro, o envio é tentado de novo depois de 1, 5 e 30 segundos; use o id do evento para não processar o mesmo duas vezes.

Verificar a assinatura

Confira que o evento veio daqui antes de usá-lo. O cabeçalho X-XeqPlaca-Assinatura traz t=<epoch>,v1=<assinatura>, em que a assinatura é o HMAC-SHA256, em hexadecimal, de <t>.<corpo> com o segredo do webhook (mostrado uma vez, quando ele é criado). Calcule sobre o corpo cru, como chegou, compare em tempo constante e recuse t muito antigo:

import hashlib
import hmac
import time

TOLERANCIA_S = 300  # recusa envio com mais de 5 minutos (reaproveitamento de um envio antigo)

def assinatura_valida(segredo: str, cabecalho: str, corpo: bytes) -> bool:
    """corpo = os bytes da requisição como chegaram, ANTES de interpretar o JSON."""
    partes = dict(p.strip().split("=", 1) for p in (cabecalho or "").split(",") if "=" in p)
    t, v1 = partes.get("t", ""), partes.get("v1", "")
    if not t.isdigit() or abs(time.time() - int(t)) > TOLERANCIA_S:
        return False
    esperado = hmac.new(segredo.encode(), t.encode() + b"." + corpo, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperado, v1)  # comparação em tempo constante


# Exemplo com Flask:
# @app.post("/webhook")
# def receber():
#     if not assinatura_valida(SEGREDO, request.headers.get("X-XeqPlaca-Assinatura"), request.get_data()):
#         return "", 401
#     evento = request.get_json()
#     ...
#     return "", 200

Limites e prazos

  • 60 requisições por minuto por chave; 30 fotos por minuto em POST /recognize. Acima disso, 429 com Retry-After.
  • Foto: JPEG ou PNG de até 10 MB; até 8 placas por foto.
  • Endereços de imagem (image_url, plate_image_url no detalhe do reconhecimento) valem 1 hora; peça o detalhe de novo para ter um endereço novo.
  • Imagens das câmeras ficam 48 horas; os registros das passagens, 90 dias (ou o prazo do seu plano). Veja a política de privacidade.

MCP: conectar à sua IA

O servidor MCP em https://app.xeqplaca.com/mcp deixa o seu assistente de IA (Claude, Cursor ou um agente próprio) consultar a conta em linguagem natural, como "onde a placa ABC1D23 passou ontem?". Ele usa a mesma chave de API, com os mesmos escopos e limites: a IA só vê as ferramentas que os escopos da chave permitem. No painel, Conectar à sua IA gera a chave e mostra a configuração pronta para colar.

FerramentaEscopoO que faz
buscar_passagensrecognitions:readPassagens por placa (aceita curinga), período, câmera e veículo.
ultima_passagemrecognitions:readOnde e quando uma placa foi vista por último.
contar_passagensrecognitions:readTotais por câmera, por hora ou por tipo de veículo num período.
listar_camerascameras:readCâmeras com situação, última captura e saúde.
listar_alertasalerts:readRegras de alerta da conta.
criar_alertaalerts:writeCria uma regra de alerta por placa.
reconhecer_imagemrecognitions:writeLê as placas de uma imagem (URL ou base64); gasta 1 crédito.

Horários saem em UTC com o fuso da conta ao lado, para a IA responder na hora local.

Claude Code
claude mcp add --transport http xeqplaca https://app.xeqplaca.com/mcp --header "Authorization: Bearer xqp_SUA_CHAVE"