Pular para o conteúdo
Nigora Zap API

    Entrar Criar conta

    Webhooks

    Webhooks são chamadas POST que a API faz para um endereço do seu sistema quando algo acontece: chegou uma mensagem, uma mensagem foi enviada, o número conectou ou desconectou.

    Evento Quando acontece
    message.received Chegou uma mensagem
    message.sent Uma mensagem da fila foi enviada
    message.status A situação de uma mensagem mudou (inclui falhas de envio)
    presence Mudança de presença de um contato, como “digitando”. O corpo traz chatId e presence
    instance.connected O número conectou. O corpo traz phone
    instance.disconnected O número desconectou. O corpo traz reason e loggedOut
    contact.opted_out Um contato pediu para não receber mais mensagens. O corpo traz phone

    PUT /v1/instances/{instanceId}/webhooks substitui toda a configuração. Envie sempre o conjunto completo. Cada evento tem a sua própria URL e pode ser ligado ou desligado:

    Terminal window
    curl -X PUT https://api.zap.nigora.com.br/v1/instances/INSTANCIA_ID/webhooks \
    -H "Authorization: Bearer TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
    "events": {
    "message.received": { "url": "https://meusistema.com.br/hooks/recebida", "enabled": true },
    "message.status": { "url": "https://meusistema.com.br/hooks/status", "enabled": true }
    },
    "notifySentByMe": false,
    "receiveFilters": {
    "ignoreGroups": true
    }
    }'

    A resposta (200) traz a configuração salva e o secret, o segredo usado na assinatura.

    As URLs têm até 2.048 caracteres e precisam ser públicas. Endereços da rede interna e de loopback (como localhost) são recusados com 400 e url_not_allowed. Campos fora do formato acima também voltam 400 (validation_error). Eventos sem URL, ou com enabled: false, não geram chamadas.

    Em receiveFilters, cada campo é false por padrão. Ligue para não receber esse tipo de mensagem:

    ignoreGroups, ignorePrivate, ignoreText, ignoreImage, ignoreVideo, ignoreAudio, ignoreDocument.

    Com notifySentByMe ligado, você também recebe message.received para as mensagens que você mesmo enviou pelo celular.

    Para ler a configuração atual, use GET /webhooks. A resposta inclui o segredo de assinatura.

    O corpo é sempre JSON, neste formato:

    {
    "event": "message.received",
    "instanceId": "…",
    "timestamp": "2026-11-02T14:30:00.000Z",
    "data": { }
    }

    data muda conforme o evento. Em message.received:

    Campo Descrição
    waMessageId Identificador da mensagem no WhatsApp
    chatId Conversa, como 5511999999999@s.whatsapp.net (grupos terminam em @g.us)
    from Quem enviou, no mesmo formato
    fromMe true se foi enviada pelo próprio número
    isGroup true se veio de um grupo
    timestamp Horário da mensagem, em segundos desde 1970
    type text, image, video, audio, document ou other
    text Texto, ou null
    quotedMessageId Mensagem respondida, ou null
    pushName Nome de exibição de quem enviou, ou null
    media Para mídia: url, mimeType, fileName e expiresAt
    mediaSkipped true se a mídia não pôde ser baixada ou era grande demais

    Em message.sent, data traz id (o devolvido no 202 do envio), waMessageId e type. Em message.status, traz id, waMessageId e status (sent, delivered, read ou failed); quando o envio falha, vem também error (veja Enviando mensagens).

    Cabeçalho Conteúdo
    x-nigora-event Nome do evento
    x-nigora-delivery Identificador desta entrega
    x-nigora-signature Assinatura do corpo, no formato sha256=<hex>

    Antes de confiar numa chamada, confira a assinatura. Ela é o HMAC-SHA256 dos bytes exatos do corpo recebido, calculado com o segredo da instância (o secret de GET /webhooks) e escrito em hexadecimal, depois do prefixo sha256=.

    import { createHmac, timingSafeEqual } from 'node:crypto'
    // `corpoBruto` é o corpo recebido, sem passar por JSON.parse e re-serialização.
    function assinaturaValida(corpoBruto, cabecalho, segredo) {
    const esperada = 'sha256=' + createHmac('sha256', segredo).update(corpoBruto).digest('hex')
    const a = Buffer.from(esperada)
    const b = Buffer.from(cabecalho ?? '')
    return a.length === b.length && timingSafeEqual(a, b)
    }
    <?php
    $corpo = file_get_contents('php://input');
    $esperada = 'sha256=' . hash_hmac('sha256', $corpo, $segredo);
    if (!hash_equals($esperada, $_SERVER['HTTP_X_NIGORA_SIGNATURE'] ?? '')) {
    http_response_code(401);
    exit;
    }

    Para trocar o segredo, chame POST /webhooks/secret/regenerate. A resposta é { "secret": "..." } e o anterior deixa de valer. Tentativas e reenvios feitos depois da troca já saem assinados com o segredo novo.

    Responda com qualquer status 2xx para confirmar, em até 10 segundos. Qualquer outra resposta, ou falta de resposta, conta como falha e a API tenta de novo, com espera crescente entre as tentativas (a primeira espera é de 5 segundos e ela dobra a cada falha), até 8 tentativas no total. Depois disso, a entrega fica como failed.

    Faça o processamento pesado depois de responder. Confirme primeiro e trabalhe em seguida, de preferência numa fila sua.

    Como pode haver reenvios, use o cabeçalho x-nigora-delivery para ignorar uma entrega que você já processou.

    A API guarda as entregas dos últimos 7 dias.

    Operação Rota
    Listar entregas, da mais recente para a mais antiga GET /webhooks/deliveries (parâmetros limit, de 1 a 100, e before, uma data ISO 8601 com fuso, para paginar)
    Ver uma entrega: evento, situação, tentativas e conteúdo GET /webhooks/deliveries/{id}
    Reenviar uma entrega POST /webhooks/deliveries/{id}/resend

    A lista vem em { "deliveries": [...] }. Cada entrega traz id, event, url, status (pending, success ou failed), attempts, lastStatusCode, lastResponse, createdAt e updatedAt. A consulta de uma entrega acrescenta o payload.

    O reenvio responde 202 com { "id": "..." }, o identificador de uma nova entrega com o mesmo conteúdo, para a mesma URL. Um id que não existe nesta instância volta 404 com webhook_delivery_not_found.

    O histórico é útil quando o seu sistema ficou fora do ar: liste as entregas com falha e reenvie.

    Ligue o descadastro em PATCH /settings:

    Terminal window
    curl -X PATCH https://api.zap.nigora.com.br/v1/instances/INSTANCIA_ID/settings \
    -H "Authorization: Bearer TOKEN" \
    -H "Content-Type: application/json" \
    -d '{ "optOut": { "enabled": true, "keywords": ["SAIR", "PARAR"] } }'

    Quando um contato envia, numa conversa privada, uma mensagem que seja só uma dessas palavras (sem diferenciar maiúsculas, minúsculas e acentos), ele entra na lista de descadastro e você recebe o evento contact.opted_out. Novos envios para ele são recusados com 422 (contact_opted_out). A palavra padrão é SAIR.

    • GET /opt-outs lista os descadastrados (com limit e before para paginar).
    • DELETE /opt-outs/{phone} permite voltar a enviar para um telefone. Responde 204, mesmo que o telefone não estivesse na lista.