Voltar pro blog
integracoes

Como receber webhooks do LimãoPay

O LimãoPay envia um POST HTTPS assinado com HMAC SHA256 pra cada evento (pagamento confirmado, assinatura ativada, reembolso). Você cria o endpoint no dashboard…

Equipe LimãoPay20 de outubro de 20185 min de leitura

Resposta curta

O LimãoPay envia um POST HTTPS assinado com HMAC SHA-256 pra cada evento (pagamento confirmado, assinatura ativada, reembolso). Você cria o endpoint no dashboard, recebe um signing secret, valida a assinatura no seu servidor.

Pra que serve

Imagina que você tem um SaaS com plano Free e Pro, e usa o LimãoPay pra cobrar o Pro. Quando alguém paga, você precisa liberar o Pro pro usuário automaticamente. É exatamente pra isso que webhooks existem:

  1. Cliente paga no LimãoPay
  2. LimãoPay envia POST order.paid pro seu servidor
  3. Seu servidor recebe, valida a assinatura, libera o Pro

Sem polling, sem latência, sem precisar consultar a API toda hora.

Passo 1 — Criar o endpoint

  1. Vai em Dashboard → Developers → Webhooks
  2. Clica em Novo endpoint
  3. Escolhe o modo:
    • Test: pra desenvolvimento. Não recebe eventos reais — só os que você dispara manualmente pelo botão "Sandbox"
    • Live: pra produção. Recebe eventos de pagamentos reais
  4. Cola a URL HTTPS pública do seu servidor (ex: https://api.seusaas.com/webhooks/limaopay)
  5. Marca os eventos que quer receber (pelo menos order.paid)
  6. Clica em Criar webhook

O LimãoPay mostra o signing secret (whsec_...). Copie agora — não dá pra ver de novo. Se perder, tem que rotacionar.

Passo 2 — Validar a assinatura

Cada POST chega com esse header:

LimaoPay-Signature: t=1737686400,v1=<hmac_sha256_hex>

A assinatura é o HMAC SHA-256 da string <timestamp>.<rawBody> usando seu signing secret.

Exemplo em Node.js

import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.LIMAOPAY_WEBHOOK_SECRET!;

// IMPORTANTE: usar raw body — JSON.parse antes invalida a assinatura
app.post(
  "/webhooks/limaopay",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const rawBody = req.body.toString("utf8");
    const sig = req.headers["limaopay-signature"] as string;

    if (!verify(rawBody, sig)) return res.status(401).send("invalid");

    const event = JSON.parse(rawBody);
    if (event.type === "order.paid") {
      // Liberar acesso pro buyer_email ou external_customer_id
      console.log("Pago:", event.data.object.buyer_email);
    }
    res.status(200).send("ok");
  },
);

function verify(body: string, sigHeader: string): boolean {
  const parts = Object.fromEntries(
    sigHeader.split(",").map((p) => p.split("=")),
  );
  const t = Number(parts.t);
  const v1 = parts.v1;
  if (!t || !v1) return false;

  // Anti-replay: rejeita timestamps fora de 5min
  if (Math.abs(Date.now() / 1000 - t) > 300) return false;

  const expected = createHmac("sha256", SECRET)
    .update(`${t}.${body}`)
    .digest("hex");

  if (v1.length !== expected.length) return false;
  return timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(expected, "hex"));
}

Por que validar assim?

  • HMAC: garante que o POST veio do LimãoPay (só quem tem o secret consegue gerar a assinatura)
  • Timing-safe compare: impede que um atacante descubra o secret medindo o tempo de comparação
  • Timestamp tolerance: impede ataque de replay (alguém pegar um POST antigo e reenviar)

Passo 3 — Idempotência

O LimãoPay pode enviar o mesmo evento duas vezes (em caso de retry). Use o header LimaoPay-Event-Id pra dedupe:

const eventId = req.headers["limaopay-event-id"] as string;
if (await alreadyProcessed(eventId)) {
  return res.status(200).send("ok (duplicate)");
}
// ... processa
await markProcessed(eventId);

Passo 4 — Testar antes de ir pra produção

No dashboard, dentro do endpoint test mode, tem o botão Sandbox:

  1. Escolhe o tipo de evento (ex: order.paid)
  2. Clica em Disparar evento mock
  3. O LimãoPay envia um POST com payload realista pro seu servidor
  4. Você vê o resultado em "Últimas entregas" — incluindo response status e tempo

Use isso pra validar a integração ponta-a-ponta antes de criar o endpoint live.

Passo 5 — Casar o pagamento com o usuário do seu SaaS

Quando o cliente do seu SaaS for pagar, gere o link da página LimãoPay anexando o ID dele:

https://limaopay.com.br/sualoja/produto?external_customer_id=user_42&metadata[plan]=pro

Estrutura da URL:

ParteSignificado
limaopay.com.brDomínio fixo (ou limaopay.app em en-US)
sualojaSlug da loja do vendedor (escolhido no cadastro)
produtoSlug da página de produto
?external_customer_id=user_42ID do usuário no SEU sistema (volta em data.object.external_customer_id)
&metadata[chave]=valorMetadata livre — múltiplas keys aceitas (volta em data.object.external_metadata)

Como funciona internamente: a página guarda esses valores em sessionStorage e envia ao backend quando o cliente clica em pagar. O backend persiste em Order.externalCustomerId + Order.externalMetadata. O webhook entrega ambos no payload.

Limites (alinhados com Stripe Metadata):

  • Máx 50 chaves de metadata
  • Chave: até 40 chars, valor: até 500 chars
  • external_customer_id: até 255 chars

Funciona em todos os métodos de pagamento — Stripe, PIX (V1 e V2 inline) e Mercado Pago.

Política de retry

Se seu servidor responde algo diferente de 2xx, o LimãoPay tenta de novo:

TentativaDelay
1imediata
21 minuto
35 minutos
430 minutos
52 horas
68 horas
724 horas
848 horas

Depois disso, o evento é marcado como exhausted (esgotou). Após 30 falhas consecutivas, o endpoint é auto-pausado e você recebe e-mail.

Rotacionar o secret

Se suspeitar de vazamento, rotacione no dashboard. O secret antigo continua válido por 24h (janela pra atualizar seu receptor). Durante a janela, o LimãoPay envia 2 assinaturas: v1 (novo) e v1_prev (antigo).

Checklist

  • Endpoint criado com URL HTTPS pública
  • Signing secret copiado e salvo em variável de ambiente
  • Validação HMAC com timing-safe compare
  • Validação de timestamp (anti-replay, tolerância 5min)
  • Idempotência usando LimaoPay-Event-Id
  • Testado no modo Sandbox antes de criar endpoint live
  • Endpoint responde 2xx em até 10 segundos
  • Não segue redirects (responda 2xx final, não 3xx)

Comece a vender hoje

Crie sua página de vendas com IA, configure o pagamento e comece a faturar. Zero pra começar.