API de Webhooks

Os webhooks permitem que sua aplicação receba notificações HTTP em tempo real quando eventos ocorrem na sua loja Mercozy. Em vez de consultar a API, registre uma URL e o Mercozy enviará automaticamente os dados do evento.

Início rápido

Comece em 3 passos:

Passo 1: Registre seu endpoint

Obtenha sua chave API em Configurações > Integração > Chaves API. Permissão de administrador necessária. O segredo de assinatura do webhook (whsec_xxx) é gerado automaticamente ao criar um endpoint e exibido apenas uma vez.

bash
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks" \
  -H "X-API-Key: mk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My ERP Integration",
    "url": "https://your-app.com/webhooks/mercozy",
    "events": ["order.created", "order.cancelled", "payment.received"]
  }'
Passo 2: Processe os eventos recebidos
javascript
app.post('/webhooks/mercozy', (req, res) => {
  // 1. Verify signature (see below)
  const signature = req.headers['x-webhook-signature'];
  if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // 2. Process the event
  const { type, data } = req.body;
  switch (type) {
    case 'order.created':
      syncOrderToERP(data);
      break;
    case 'payment.received':
      updateAccountingSystem(data);
      break;
  }

  // 3. Respond quickly with 200
  res.status(200).json({ received: true });
});
Passo 3: Teste seu endpoint
bash
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks/{id}/test" \
  -H "X-API-Key: mk_live_your_key_here"

Endpoints

GET

/webhooks

webhooks:read

Liste todos os endpoints de webhook registrados.

POST

/webhooks

webhooks:write

Registre um novo endpoint de webhook para receber notificacoes de eventos.

PUT

/webhooks/:id

webhooks:write

Atualize um endpoint de webhook existente (URL, eventos ou status ativo).

DELETE

/webhooks/:id

webhooks:write

Exclua um endpoint de webhook. Os eventos nao serao mais entregues.

Referencia de Campos
CampoTipoObrigatorioDescricao

id

string

Nao

Identificador unico do webhook (somente leitura)

name

string

Sim

Um nome descritivo para este endpoint

url

string

Sim

URL do endpoint HTTPS para receber eventos de webhook

events

string[]

Sim

Array de tipos de evento para assinar

secret

string

Nao

Segredo de assinatura para verificacao de payload (somente leitura, gerado na criacao)

isActive

boolean

Nao

Se o webhook esta ativo (padrao: true)

createdAt

datetime

Nao

Timestamp ISO 8601 (somente leitura)


Tipos de Evento Disponiveis

O Mercozy suporta 18 tipos de eventos de webhook em 6 categorias. Inscreva-se apenas nos eventos que você precisa.

Pedidos
  • order.created

    Disparado quando um novo pedido é realizado

  • order.updated

    Disparado quando os detalhes do pedido são modificados

  • order.cancelled

    Disparado quando um pedido é cancelado

  • order.completed

    Disparado quando um pedido é marcado como concluído

  • order.status_changed

    Disparado em qualquer mudança de status do pedido

Pagamentos
  • payment.received

    Disparado quando o pagamento é capturado ou cobrado na entrega

  • payment.refunded

    Disparado quando um pagamento é reembolsado ou cancelado

Produtos
  • product.created

    Disparado quando um novo produto é adicionado

  • product.updated

    Disparado quando os detalhes do produto mudam

  • product.deleted

    Disparado quando um produto é excluído

Estoque
  • stock.low

    Disparado quando o estoque fica abaixo do limite

  • stock.updated

    Disparado quando a quantidade em estoque muda

Clientes
  • customer.created

    Disparado quando um novo cliente é registrado

  • customer.updated

    Disparado quando as informações do cliente são atualizadas

Entregas
  • delivery.batch_started

    Disparado quando um lote de entregas é despachado

  • delivery.batch_completed

    Disparado quando todas as paradas do lote são concluídas

  • delivery.completed

    Disparado quando uma entrega individual é concluída

  • delivery.failed

    Disparado quando uma tentativa de entrega falha


Payload do Webhook

Cada entrega de webhook inclui o tipo de evento, timestamp e os dados do recurso relevante.

Dados do evento de pedido
json
{
  "id": "evt_clx1abc2def3",
  "type": "order.created",
  "timestamp": "2026-03-19T10:30:00Z",
  "data": {
    "id": "clx9order123",
    "orderNumber": "ORD-1042",
    "status": "PENDING",
    "total": 4999,
    "currency": "USD"
  }
}
Dados do evento de pagamento
json
{
  "id": "evt_clx2pay4ghi5",
  "type": "payment.received",
  "timestamp": "2026-03-19T10:35:00Z",
  "data": {
    "orderId": "clx9order123",
    "orderNumber": "ORD-1042",
    "amount": 4999,
    "currency": "USD",
    "paymentMethod": "CARD",
    "status": "CAPTURED"
  }
}
Dados do evento de produto
json
{
  "id": "evt_clx3prod6jkl",
  "type": "product.created",
  "timestamp": "2026-03-19T11:00:00Z",
  "data": {
    "id": "clx9prod789",
    "name": "Organic Coffee Beans",
    "sku": "COF-001",
    "price": 1299,
    "status": "ACTIVE"
  }
}
Dados do evento de entrega
json
{
  "id": "evt_clx4del7mno",
  "type": "delivery.completed",
  "timestamp": "2026-03-19T14:22:00Z",
  "data": {
    "orderId": "clx9order123",
    "orderNumber": "ORD-1042"
  }
}

Cabeçalhos HTTP

Cada requisição de webhook inclui os seguintes cabeçalhos:

CampoTipoObrigatorioDescricao

Content-Type

string

Sim

application/json

X-Webhook-Signature

string

Sim

Assinatura HMAC-SHA256: sha256={resumo_hexadecimal}

X-Webhook-Timestamp

string

Sim

Timestamp Unix em milissegundos

X-Webhook-ID

string

Sim

ID de evento único para deduplicação

User-Agent

string

Sim

Mercozy-Webhook/1.0 (+https://www.mercozy.com/docs/webhooks)


Verificacao de Assinatura

Cada webhook inclui um cabeçalho X-Webhook-Signature contendo uma assinatura HMAC-SHA256. Sempre verifique esta assinatura antes de processar o evento para garantir que a requisição veio do Mercozy.

Node.js
javascript
const crypto = require('crypto');

function verifyWebhook(rawBody, signature, timestamp, secret) {
  // Signature is computed over "timestamp.body"
  const message = timestamp + '.' + rawBody;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express middleware
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-webhook-signature'];
  const ts = req.headers['x-webhook-timestamp'];
  if (!verifyWebhook(req.body, sig, ts, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // Process event...
  res.status(200).json({ received: true });
});
Python
python
import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    # Signature is computed over "timestamp.body"
    message = (timestamp + '.').encode() + payload
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        message,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route('/webhooks', methods=['POST'])
def handle_webhook():
    sig = request.headers.get('X-Webhook-Signature')
    ts = request.headers.get('X-Webhook-Timestamp')
    if not verify_webhook(request.data, sig, ts, WEBHOOK_SECRET):
        return 'Invalid signature', 401
    event = request.get_json()
    # Process event...
    return {'received': True}, 200
PHP
php
<?php
function verifyWebhook(string $payload, string $signature, string $timestamp, string $secret): bool {
    // Signature is computed over "timestamp.body"
    $message = $timestamp . '.' . $payload;
    $expected = 'sha256=' . hash_hmac('sha256', $message, $secret);
    return hash_equals($expected, $signature);
}

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
if (!verifyWebhook($payload, $signature, $timestamp, $webhookSecret)) {
    http_response_code(401);
    exit('Invalid signature');
}
$event = json_decode($payload, true);
// Process event...
http_response_code(200);
echo json_encode(['received' => true]);

Política de retentativas

Se seu endpoint retornar um código de status diferente de 2xx ou expirar (10 segundos), o Mercozy retentará a entrega com backoff exponencial:

CampoTipoObrigatorioDescricao

Tentativa 1

Nao

Imediato

Tentativa 2

Nao

Após ~1s

Tentativa 3

Nao

Após ~4s

Após 3 tentativas com falha, a entrega é marcada como falha. Você pode retentar manualmente pelo painel ou pela API.


Melhores práticas

  • Responda em menos de 5 segundosRetorne status 200 imediatamente e processe o evento de forma assíncrona. O timeout do Mercozy é de 10 segundos.

  • Sempre verifique assinaturasVerifique o cabeçalho X-Webhook-Signature antes de processar qualquer evento para evitar requisições falsificadas.

  • Trate duplicatas (idempotência)Use o cabeçalho X-Webhook-ID para deduplicar eventos. Armazene os IDs processados e pule os que já foram tratados.

  • Use endpoints HTTPSO Mercozy exige URLs HTTPS em produção para proteger os dados do webhook em trânsito.

  • Registre e monitoreRegistre todos os webhooks recebidos e monitore falhas. Use a API de logs de entrega para verificar o status.