Integrações
Webhooks de saída
O Paywallo envia eventos de assinatura — compras, renovações, cancelamentos, reembolsos — pro seu servidor em tempo real, assinados com HMAC. Este documento é a referência completa do payload.
Configurar
No dashboard, vá em Configurações > Apps, selecione o app e role até a seção Webhooks de saída.
Na aba Configurações, preencha a URL do endpoint (https) e clique em Gerar novo secret.
Clique em Salvar. Guarde o secret no seu servidor — ele valida a assinatura de cada entrega.
Sem secret, a entrega não é assinada
Deixar o secret em branco envia os eventos sem o header X-Paywallo-Signature. Gerar um novo secret invalida o anterior na mesma hora — atualize os dois lados juntos.
Formato do payload
Toda entrega é um POST com um envelope único: api_version e um objeto event.
api_versionVersão do formato do payload1.0event.idID único do evento — use para dedup do seu ladopw_5f2a1c3e-...event.typeTipo do evento (ver tabela abaixo)INITIAL_PURCHASEevent.event_timestamp_msQuando o evento ocorreu, em ms desde epoch1755612345000event.app_user_idID do usuário no Paywallouser_8f3e2a1bevent.original_app_user_idMesmo valor de app_user_iduser_8f3e2a1bevent.product_idSKU do produto configurado na lojamensalevent.priceValor da transação — sempre em USD11.51event.currencySempre "USD" — mesma moeda de priceUSDevent.storeLoja de origem da compraPLAY_STOREevent.environmentAmbiente real da compraPRODUCTIONevent.period_typeTrial ou cobrança normalNORMALevent.transaction_idID da transação atual na lojaGPA.3300-...event.original_transaction_idID da transação original da assinaturaGPA.3300-...event.expiration_at_msQuando o acesso expira, em ms (0 quando não aplicável)1758290745000event.country_codePaís de faturamento, ISO 3166-1 alpha-2 (opcional)BRevent.entitlement_idsEntitlements liberados por essa assinatura["premium"]Tipos de evento
event.type é sempre um destes cinco valores:
INITIAL_PURCHASEPrimeira compra ou início de trial — inclui reassinatura de quem já tinha cancelado antes.RENEWALRenovação de assinatura — inclui recuperação automática após falha de cobrança.CANCELLATIONUsuário desativou a renovação automática. O acesso continua valendo até o fim do período já pago.EXPIRATIONO acesso terminou de fato: fim do período, falha de cobrança, fim do grace period ou reembolso.UNCANCELLATIONUm reembolso anterior foi revertido — a compra volta a ser válida.Como diferenciar reembolso de expiração natural
Reembolso também chega como EXPIRATION. Nesse caso o payload traz expiration_reason e cancel_reason com o valor 'CUSTOMER_SUPPORT'. Sem esses dois campos, a expiração é natural (fim do período, falha de cobrança ou fim do grace period) — use essa diferença antes de pagar comissão sobre a venda.
environment e currency
environment reflete o ambiente real da compra
'PRODUCTION' para compra real feita por um usuário, 'SANDBOX' para compra de teste. Valide sempre esse campo antes de liberar acesso ou registrar receita em produção.
price e currency descrevem a MESMA moeda
currency é sempre 'USD' e price é o valor da transação já convertido pra USD — nunca a moeda local em que o usuário pagou. Não assuma BRL, EUR ou qualquer outra moeda a partir de currency: ele sempre acompanha price em dólar.
Exemplo de payload
Dados fictícios — o formato é fiel ao que o Paywallo envia:
{
"api_version": "1.0",
"event": {
"id": "pw_5f2a1c3e-8b91-4a3d-9c2e-1a2b3c4d5e6f",
"type": "INITIAL_PURCHASE",
"event_timestamp_ms": 1755612345000,
"app_user_id": "user_8f3e2a1b",
"original_app_user_id": "user_8f3e2a1b",
"product_id": "mensal",
"price": 11.51,
"currency": "USD",
"store": "PLAY_STORE",
"environment": "PRODUCTION",
"period_type": "NORMAL",
"transaction_id": "GPA.3300-1234-5678-90123",
"original_transaction_id": "GPA.3300-1234-5678-90123",
"expiration_at_ms": 1758290745000,
"country_code": "BR",
"entitlement_ids": ["premium"]
}
}Assinatura (HMAC)
Cada entrega leva o header X-Paywallo-Signature com o HMAC-SHA256 do corpo bruto da requisição, usando o secret gerado na configuração.
Content-Typeapplication/jsonUser-AgentPaywallo/1.0X-Paywallo-Signaturesha256=<hmac-sha256 do corpo bruto> — só é enviado se houver secret configuradox-revenuecat-event-typemesmo valor de event.type (nome do header mantido por compatibilidade histórica)import { createHmac, timingSafeEqual } from "crypto";
function isValidSignature(rawBody: string, signatureHeader: string, secret: string): boolean {
const expected = `sha256=${createHmac("sha256", secret).update(rawBody).digest("hex")}`;
const receivedBuf = Buffer.from(signatureHeader);
const expectedBuf = Buffer.from(expected);
return receivedBuf.length === expectedBuf.length && timingSafeEqual(receivedBuf, expectedBuf);
}
// Calcule o HMAC sobre o corpo BRUTO da requisição, não sobre JSON.stringify(req.body) —
// reserializar pode mudar espaços ou ordem de chaves e invalidar a assinatura.Confiabilidade e reentrega
O Paywallo aguarda até 10s por tentativa. Se a entrega falhar (timeout, erro de rede ou status fora da faixa 2xx), tenta de novo — até 4 tentativas no total, com backoff exponencial e jitter (intervalos de aproximadamente 2s, 4s e 8s entre elas). Depois da última tentativa, a entrega fica marcada como falha.
Responda rápido
Responda 2xx assim que persistir o evento e processe o resto de forma assíncrona. Endpoint lento aumenta a chance de timeout e de reentrega — trate o event.id como idempotente para não duplicar efeitos em retries.
Autodiagnóstico
Toda entrega fica registrada em Configurações > Apps > app > Webhooks de saída > aba Entregas — com status HTTP, duração e o payload exato enviado em cada tentativa. É o primeiro lugar pra checar antes de abrir um chamado de suporte.
Essa página foi útil?
Desenvolvido e mantido por Virex