Pular para o conteúdo principal

Webhook

Atualizações no status de fraude (Para eventos que sejam derivados para análise manual ou que sejam respondidos como Pendente), são notificados por meio de Webhook. Para tanto, é necessário, por meio da equipe do suporte, configurar um endereço do endpoint por onde vamos notificar as atualizações e também uma signature_key que será utilizada para assinar a requisição.

O cliente pode também utilizar a técnica de polling. Neste caso, basta não configurar o endpoint de webhook e utilizar os endpoints de recuperação para proceder com o polling.

Atenção

Por questões de segurança, todas as requisições de Webhook serão somente realizadas em endpoints servidos por HTTPS.

Assinatura do Webhook

Para garantir que a requisição recebida no seu endpoint partiu dos nossos servidores, enviamos uma assinatura HMAC no header Signature. Você recalcula essa assinatura do seu lado e compara com a recebida — se forem iguais, a requisição é confiável.

Como a assinatura é calculada

Signature = HMAC-SHA1(signature_key, endpoint + method + payload) → hexadecimal

Os três componentes são concatenados nesta ordem, sem separador:

ComponenteO que é
endpointA URL completa do seu webhook, exatamente como foi configurada com o suporte (incluindo https:// e eventual query string).
methodO verbo HTTP em letras maiúsculasPUT nestas notificações.
payloadO corpo da requisição exatamente como recebido, byte a byte.
signature_keyO segredo que você combinou com o suporte (também chamado de secret_token). É a chave do HMAC, não parte da mensagem.
Use o corpo bruto, nunca o JSON reserializado

A assinatura é calculada sobre os bytes exatos do corpo. Se você desserializar o JSON e serializar de novo antes de validar, a ordem das chaves e o espaçamento mudam, e a assinatura nunca vai bater.

Leia o corpo como string/bytes brutos primeiro, valide a assinatura, e só depois faça o parse. Nos exemplos abaixo isso aparece como request.get_data(), file_get_contents('php://input'), express.raw() etc.

Acentuação no payload

O corpo é serializado com ensure_ascii=False, ou seja, caracteres acentuados vão como UTF-8 literal ("João"), e não escapados ("João"). Trate o corpo como UTF-8 ao calcular o HMAC — é o comportamento padrão em todas as linguagens abaixo, mas é a causa mais comum de assinatura divergente quando algum campo tem acento.

Exemplos de validação

import hashlib
import hmac

SIGNATURE_KEY = "YOUR_SECRET_TOKEN"
WEBHOOK_URL = "https://seu-dominio.com/webhooks/qitech"
HTTP_METHOD = "HTTP_VERB" # veja a tabela acima


def calculate_signature(endpoint: str, method: str, payload: str) -> str:
hmac_obj = hmac.new(
SIGNATURE_KEY.encode("utf-8"),
(endpoint + method + payload).encode("utf-8"),
hashlib.sha1,
)
return hmac_obj.hexdigest()


def is_valid(received_signature: str, raw_body: str) -> bool:
expected = calculate_signature(WEBHOOK_URL, HTTP_METHOD, raw_body)
# compare_digest evita ataques de temporização
return hmac.compare_digest(expected, received_signature)


# Exemplo com Flask
from flask import Flask, request

app = Flask(__name__)


@app.route("/webhooks/qitech", methods=[HTTP_METHOD])
def receive_webhook():
raw_body = request.get_data(as_text=True) # corpo bruto, sem parse
received = request.headers.get("Signature", "")

if not is_valid(received, raw_body):
return "", 401

event = request.get_json() # parse só depois de validar
print(event)
return "", 200
Assinatura não bate? Verifique nesta ordem
  1. O corpo foi reserializado? É a causa mais frequente. Use o corpo bruto.
  2. A URL está idêntica? Uma barra final a mais ou a menos muda a assinatura. Use exatamente a URL configurada com o suporte.
  3. O método está correto e em maiúsculas? Nestas notificações é PUT.
  4. A ordem da concatenação está certa? É endpoint + method + payload, nessa ordem.
  5. O digest está em hexadecimal minúsculo? Não é Base64.

Webhook de Atualização de Evento

Request Body
{
"id": "123456",
"analysis_status": "automatically_approved",
"event_date": "2019-10-01T10:37:25-03:00"
}

A requisição de atualização do status de análise de um evento possui o formato acima e notifica a mudança no status de fraude. O método utilizado é um PUT e o endereço do endpoint pode conter também o id do evento, de acordo com a necessidade do cliente. É importante ressaltar que o corpo da requisição é enviado como texto codificado em UTF-8.

Exemplos de endpoints para atualização de evento:

O campo {evento}, localizado na URL da requisição, pode assumir os seguintes valores, a depender do evento sendo notificado:

  • bill_payment
  • bankslip
  • wire_transfer
  • withdrawal
  • pix

O campo event_date indica a data e hora em que a notificação foi criada e pode estar no passado caso envios de notificação anteriores tenham falhado.

Retentativas

A notificação é considerada realizada quando recebe como resposta um HTTP Status 200. Caso as notificações falhem, serão feitas 7 retentativas, com os seguintes intervalos, até que um 200 seja retornado ou as tentativas terminem:

  • 10 segundos
  • 40 segundos
  • 160 segundos
  • 640 segundos
  • 2560 segundos
  • 10240 segundos
  • 40960 segundos