Guia de Webhooks

Integração prática de webhooks com tipos de evento, validação de assinatura e exemplos de payload para cobrança, transferência e devolução.

Este guia mostra como implementar webhooks da Qesh com segurança e idempotência, cobrindo os principais casos de uso de Pix Avulso.


Fluxo de integração

  1. Criar endpoint de webhook com url, secret e event_types;
  2. Receber requisição POST da Qesh;
  3. Validar X-Webhook-Signature com HMAC-SHA256;
  4. Persistir evento bruto e responder HTTP 200 rapidamente;
  5. Processar lógica de negócio de forma assíncrona.

Pré-requisitos

  • Token JWT válido (veja Guia de Autenticação);
  • Endpoint HTTPS público;
  • Secret exclusivo por ambiente (sandbox/produção).

Passo 1 - Criar endpoint

Referência: Criar um endpoint para tipos de eventos

POST /v1/webhook/endpoints HTTP/1.1
Host: api.qesh.ai
Authorization: Bearer <token>
Content-Type: application/json

{
  "url": "https://seu-sistema.com/webhooks/qesh",
  "secret": "seu-secret-super-seguro",
  "event_types": [
    "qrcode.approved",
    "transfer.in.processing",
    "refund.in.processing"
  ]
}

Campos obrigatórios:

  • url
  • secret
  • event_types

Passo 2 - Validar assinatura

Header enviado em cada evento:

X-Webhook-Signature: <hash_hmac_sha256>

Exemplo em Node.js:

const crypto = require('crypto');

function verifyWebhook(secret, signature, rawBody) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return expected === signature;
}
⚠️

Sempre valide com o corpo bruto (raw body).


Catálogo de eventos (exemplos)

Tipo de eventoQuando usarOrigem
qrcode.pendingAcompanhar QR Codes aguardando pagamentoCobrança
qrcode.approvedConfirmar pedido pago por QR CodeCobrança
qrcode.expiredChecar se uma cobrança com QR Code expirouCobrança
transfer.in.processingAcompanhar novo pagamento de entrada no fluxo de transferênciaTransferência
transfer.in.confirmedConfirmar pagamento de entrada no fluxo de transferênciaTransferência
transfer.in.errorTratar falha de pagamento no fluxo de transferênciaTransferência
transfer.out.processingAcompanhar nova transferência de saída iniciadaTransferência
transfer.out.confirmedConfirmar transferência de saída concluídaTransferência
transfer.out.errorTratar falha de transferência de saídaTransferência
refund.in.processingAcompanhar restituição de um pagamento iniciadoDevolução
refund.in.returnedConfirmar restituição de um pagamento concluídaDevolução
refund.in.errorTratar falha na restituição de um pagamentoDevolução
refund.out.processingAcompanhar restituição de um pagamento recebido iniciadaDevolução
refund.out.returnedConfirmar restituição de um pagamento recebido concluídaDevolução
refund.out.errorTratar falha na restituição de um pagamento recebidoDevolução

Payloads por caso de uso

Cobrança paga

{
  "id": 12345678,
  "name": "qrcode.approved",
  "payload": {
    "id": 12345678,
    "transaction_identification": "tx123",
    "external_id": "qrcode_12345678",
    "status": "APPROVED",
    "create_timestamp": "2024-06-01T12:00:00Z"
  },
  "create_timestamp": "2024-06-01T12:00:00Z"
}

Transferência em processamento

{
  "id": 12345678,
  "name": "transfer.in.processing",
  "payload": {
    "id": 12345678,
    "external_id": "transfer_12345678",
    "end_to_end_id": "E318188732025073114206r8iSU2Swrt",
    "correlation_id": "correlation_12345678",
    "amount": 1000,
    "impact_type": "IN",
    "initiation_type": "KEY",
    "status": "PROCESSING",
    "create_timestamp": "2024-06-01T12:00:00Z"
  },
  "create_timestamp": "2024-06-01T12:00:00Z"
}

Devolução em processamento

{
  "id": 12345678,
  "name": "refund.in.processing",
  "payload": {
    "id": 12345678,
    "external_id": "refund_12345678",
    "return_identification": "D318188732025073114206r8iSU2Swrt",
    "original_end_to_end_id": "E318188732025073114206r8iSU2Swrt",
    "correlation_id": "correlation_12345678",
    "amount": 1000,
    "status": "PROCESSING",
    "flow": "IN",
    "create_timestamp": "2024-06-01T12:00:00Z"
  },
  "create_timestamp": "2024-06-01T12:00:00Z"
}

Processamento recomendado

  1. Validar assinatura;
  2. Salvar evento bruto com id e name;
  3. Retornar HTTP 200 imediatamente;
  4. Enfileirar processamento;
  5. Garantir idempotência por id do evento e por identificadores de negócio (external_id, end_to_end_id, return_identification).

Gestão e observabilidade

Status operacionais do endpoint:

  • active
  • disabled
  • inactive

Próximos passos