Webhooks
Registre endpoints para receber eventos em tempo real.
Scopes: webhooks:read (listar) · webhooks:write (criar, atualizar, excluir)
Listar webhooks
GET /api/webhooks
curl "https://api.placaflow.com.br/api/webhooks" \
-H "Authorization: Bearer pk_a1b2c3d4..."
Resposta 200:
{
"webhooks": [
{
"id": "w1b2c3d4-...",
"name": "Sistema ERP",
"url": "https://api.example.com/webhook",
"secret": "a1b2c3d4e5f6...",
"enabled": true,
"events": ["recognition.created", "alert.triggered"],
"headers": { "X-Source": "placaflow" },
"failureCount": 0,
"lastDeliveryAt": "2026-03-22T14:30:00.000Z",
"lastDeliveryStatus": 200,
"createdAt": "2026-03-01T10:00:00.000Z"
}
]
}
Criar webhook
POST /api/webhooks
Content-Type: application/json
Campos:
| Campo | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
name | string | sim | — | Nome do webhook |
url | string | sim | — | URL do endpoint |
secret | string | não | auto-gerado | Secret para HMAC-SHA256 |
enabled | boolean | não | true | Webhook ativo |
events | string[] | sim | — | Eventos a receber |
headers | object | não | {} | Headers HTTP customizados |
Eventos disponíveis
| Evento | Descrição |
|---|---|
recognition.created | Nova placa reconhecida |
alert.triggered | Alerta acionado |
camera.online | Câmera conectou |
camera.offline | Câmera desconectou |
Exemplo:
curl -X POST "https://api.placaflow.com.br/api/webhooks" \
-H "Authorization: Bearer pk_a1b2c3d4..." \
-H "Content-Type: application/json" \
-d '{
"name": "Meu sistema",
"url": "https://api.example.com/placaflow",
"events": ["recognition.created", "alert.triggered"],
"headers": {"Authorization": "Bearer meu-token"}
}'
Resposta 201: retorna { "webhook": {...} } com secret gerado automaticamente se não fornecido.
Atualizar webhook
PUT /api/webhooks/:id
Content-Type: application/json
Excluir webhook
DELETE /api/webhooks/:id
Verificação de assinatura
Cada requisição inclui o header X-Signature-256 com a assinatura HMAC-SHA256 do body.
Verificação em Node.js:
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return expected === signature;
}
app.post('/webhook', (req, res) => {
const sig = req.headers['x-signature-256'];
if (!verifySignature(req.rawBody, sig, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// processar...
});
Verificação em Python:
import hmac, hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Erros
| Código | Descrição |
|---|---|
| 400 | URL ou eventos ausentes |
| 401 | Não autenticado |
| 404 | Webhook não encontrado |