Pular para o conteúdo principal

Webhook

Atualizações no status de fraude (Para RentalAgreements 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 um secret_token que será utilizado para assinar a requisição.

O cliente pode, apesar de não recomendável, 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 de RentalAgreement para proceder com o polling.

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úsculasPOST 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 é POST.
  4. A ordem da concatenação está certa? É endpoint + method + payload, nessa ordem.
  5. O digest está em hexadecimal minúsculo? Não é Base64.

Requisição

Exemplo de requisição:

{
"rental_agreement_id": "123456",
"fraud_status": "automatically_approved",
"upgrade_status": "automatically_approved",
"event_date": "2019-10-01T10:37:25-03:00"
}

A requisição possui o formato acima e notifica a mudança no status de fraude.

Retentativas

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

  • 10 segundos
  • 30 segundos
  • 60 segundos
  • 120 segundos
  • 120 segundos
  • 3600 segundos
  • 7200 segundos
  • 36000 segundos