https://n7pay.com/api/v1
Documentação da API N7 Pay
O N7 Pay é uma plataforma global de orquestração de pagamentos. Esta API REST permite criar links de pagamento, gerenciar clientes, consultar transações e receber notificações em tempo real via webhooks.
Todos os endpoints retornam JSON. Datas seguem ISO 8601 (UTC). Valores monetários são strings decimais (ex: "299.90") para evitar erros de ponto flutuante.
Gateways suportados: Asaas (PIX, boleto, cartão — BRL) e Stripe (cartão internacional — USD/EUR/BRL). O roteamento é automático via Smart Routing.
Autenticação
Toda requisição deve incluir o header Authorization com sua chave de API:
Authorization: Bearer n7_sk_sand_SuaChaveAqui
| Prefixo | Ambiente | Uso |
|---|---|---|
| n7_sk_sand_… | Sandbox | Testes — nenhuma cobrança real |
| n7_sk_live_… | Live | Produção — cobranças reais |
Token JWT temporário
Troque sua API Key por um JWT de curta duração (útil para clientes públicos):
curl -X POST https://n7pay.com/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"api_key": "n7_sk_sand_SuaChaveAqui"}'
Ambiente Sandbox
O ambiente sandbox usa a infraestrutura de testes dos gateways. Nenhuma cobrança real é processada.
n7_sk_sand_ no seu dashboard. Todas as chamadas com essa chave são roteadas automaticamente para o sandbox dos gateways configurados.
| Comportamento | Sandbox | Live |
|---|---|---|
| Cobranças reais | Não | Sim |
| Webhooks disparados | Sim (simulado) | Sim (real) |
| Rate limit | 1000 req/min | 300 req/min |
| Dados isolados | Sim — por conta | Produção |
Erros
Erros retornam JSON com campo error (código) e message (descrição legível):
{
"error": "unauthorized",
"message": "API key inválida ou revogada."
}
| HTTP | Código | Descrição |
|---|---|---|
| 400 | invalid_params | Parâmetros ausentes ou inválidos |
| 401 | unauthorized | API key ausente, inválida ou revogada |
| 403 | forbidden | Chave sem permissão para o recurso |
| 404 | not_found | Recurso não encontrado |
| 409 | conflict | Conflito — ex: documento duplicado |
| 422 | unprocessable | Dados inválidos (validação) |
| 429 | rate_limit_exceeded | Limite de requisições atingido |
| 500 | internal_error | Erro interno — entre em contato |
Rate Limit
Limites aplicados por chave de API. Headers de resposta indicam o estado atual:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
X-RateLimit-Reset: 1717852800
Links de Pagamento
Links são URLs que permitem cobranças sem integração de checkout customizado. Suportam PIX, boleto, cartão (BRL/USD). Podem ter URL personalizada com o slug da empresa: https://n7pay.com/c/sua-empresa/pay/:slug.
page, per_page. Filtros: status, currency.Parâmetros — POST /payment-links
| Campo | Tipo | Descrição | |
|---|---|---|---|
| title | string | obrigatório | Título na página de pagamento |
| amount | decimal | obrigatório | Valor — ex: "299.90" |
| currency | string | opcional | BRL (padrão), USD ou EUR |
| methods | array | opcional | ["pix"], ["card_1x"], ["boleto"] etc. (padrão: pix) |
| fee_strategy | string | opcional | "absorb" — merchant paga · "pass_on" — cliente paga |
| expires_in | string | opcional | "1h", "24h", "3d", "7d" — omitir = sem expiração. Alternativa: expires_at com timestamp ISO 8601. |
| customer_id | uuid | opcional | ID de cliente N7 para pré-preencher dados |
| description | string | opcional | Texto auxiliar exibido abaixo do título |
| settlement_type | string | opcional | "d0", "d1" (padrão) ou "d30" |
| max_installments | integer | opcional | Teto de parcelas. Omitido, é deduzido do método: card_7_12x → 12, card_2_6x → 6, senão 1. |
POST /charges só aceita PIX; para cartão, crie um link com methods: ["card_1x"] (ou card_2_6x / card_7_12x) e envie o pagador para a pay_url. O ambiente do link (sandbox ou live) é herdado da chave de API usada.
curl -X POST https://n7pay.com/api/v1/payment-links \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui" \
-H "Content-Type: application/json" \
-d '{
"title": "Plano Pro · Mensal",
"amount": "99.90",
"currency": "BRL",
"methods": ["pix", "card_1x"],
"fee_strategy": "absorb"
}'
# Resposta 201
{
"data": {
"id": "9f1c2d3e-4b5a-6789-abcd-ef0123456789",
"slug": "abc123def",
"pay_url": "https://n7pay.com/pay/abc123def",
"title": "Plano Pro · Mensal",
"description": null,
"amount": "99.90",
"currency": "BRL",
"status": "active",
"methods": ["pix", "card_1x"],
"fee_strategy": "absorb",
"settlement_type": "d1",
"max_installments": 1,
"expires_at": null,
"environment": "sandbox",
"inserted_at": "2026-06-08T12:00:00"
}
}
Transações
Transações são criadas automaticamente quando um pagador conclui o fluxo em um link de pagamento ou via API de cobrança direta.
status, method, from, to (ISO 8601), gateway.Status de transação
| Status | Descrição |
|---|---|
| pending | Aguardando pagamento (PIX/boleto gerado) |
| processing | Pagamento detectado, aguardando confirmação |
| paid | Confirmado pelo gateway |
| failed | Recusado pelo gateway |
| expired | Expirou sem pagamento |
| refunded | Estornado |
| chargeback | Disputa aberta pelo titular do cartão |
Cobranças Diretas — PIX e Cartão inline
Use cobranças diretas quando você quer cobrar dentro da sua própria UI, sem redirecionar o pagador para o checkout hospedado. O mesmo endpoint atende PIX e cartão — muda apenas o method.
https://n7pay.com/pay/:slug. Cobranças diretas devolvem tudo na resposta: PIX retorna pix_qr_code (copia e cola) e pix_qr_image (PNG base64); cartão retorna o status final já processado.
card_token). Resposta síncrona.Métodos aceitos e parcelamento
O número de parcelas está codificado no nome do método. Não existe card_12x — a faixa é que define o teto:
method | Tipo | Parcelas |
|---|---|---|
| pix | PIX | à vista — retorna QR code |
| card_1x | Cartão de crédito | 1× (à vista) |
| card_2_6x | Cartão de crédito | 2 a 6× — padrão 6 se installments for omitido |
| card_7_12x | Cartão de crédito | 7 a 12× — padrão 12 se installments for omitido |
| boleto | Boleto | à vista |
installments explicitamente para parcelar. O método define só o teto da faixa. Com method: "card_7_12x" e installments: 10, cobra em 10×. Omitindo installments, o teto da faixa é usado (12×). Os mesmos nomes valem no campo methods de payment links, onde o campo equivalente é max_installments.
Parâmetros — POST /charges
| Campo | Tipo | Descrição | |
|---|---|---|---|
| amount | decimal | obrigatório | Valor em BRL — ex: "49.90". Mínimo R$ 5,00 (limite do Asaas); abaixo disso a resposta é 422 imediato. |
| method | string | opcional | "pix" (padrão), "card_1x", "card_2_6x", "card_7_12x" ou "boleto" — ver tabela acima |
| installments | integer | opcional | Número de parcelas. Só vale para métodos de cartão; deve caber na faixa do método. |
| card_token | string | cartão* | Token gerado em POST /tokens. *Alternativa: enviar o objeto card abaixo. |
| card | object | cartão* | Cartão inline: holder_name, number, exp_month, exp_year, cvv. Use quando não houver card_token. |
| holder | object | com card | Dados do portador exigidos pelo antifraude: document, postal_code, address_number, phone. Herdados do objeto customer quando presentes lá. |
| currency | string | opcional | "BRL" (padrão) |
| description | string | opcional | Descrição exibida no comprovante |
| external_reference | string | opcional | Seu ID interno para reconciliação |
| ip | string | recomendado | IP do pagador. Usado pelo antifraude no cartão — sem ele a taxa de recusa sobe. |
| customer.name | string | obrigatório | Nome do pagador |
| customer.document | string | obrigatório | CPF (11 dígitos) ou CNPJ (14 dígitos) — exigido pelo Banco Central para PIX |
| customer.email | string | opcional | E-mail para notificações |
curl -X POST https://n7pay.com/api/v1/charges \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui" \
-H "Content-Type: application/json" \
-d '{
"amount": "49.90",
"method": "pix",
"description": "Pedido #1042",
"external_reference": "order_1042",
"customer": {
"name": "João da Silva",
"email": "joao@exemplo.com",
"document": "123.456.789-00"
}
}'
# Resposta 201
{
"data": {
"id": 87,
"status": "pending",
"amount": "49.90",
"currency": "BRL",
"method": "pix",
"external_id": "pay_8fHtX3kZq",
"pix_qr_code": "00020126580014br.gov.bcb.pix0136...",
"pix_qr_image": "data:image/png;base64,iVBORw0KGgo...",
"expires_at": "2026-06-08T16:30:00",
"inserted_at": "2026-06-08T16:00:00Z"
}
}
Campos da resposta
| Campo | Tipo | Descrição |
|---|---|---|
| id | integer | ID da transação no N7 Pay — use para consultar status via GET /transactions/:id |
| status | string | pending — aguardando pagamento do PIX |
| pix_qr_code | string | Payload EMV (copia e cola) — exiba em um campo copiável |
| pix_qr_image | string | PNG em base64 — use diretamente em <img src="{pix_qr_image}"> para renderizar o QR scanável |
| expires_at | datetime | O QR expira 30 minutos após a criação |
| external_id | string | ID da cobrança no gateway (Asaas) |
pending não significa que o PIX foi pago. Configure o webhook de saída no seu dashboard para receber o evento payment.paid quando o pagamento for confirmado pelo Banco Central.
Consultando o status da cobrança
Use o id retornado na criação para consultar o status em qualquer momento. A resposta de GET /transactions/:id inclui os mesmos campos de QR enquanto o PIX estiver pendente.
curl https://n7pay.com/api/v1/transactions/87 \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui"
Cartão — Tokenização
Cobrança com cartão nunca recebe o número do cartão: ele é trocado antes por um card_token em POST /tokens. Você escolhe onde essa troca acontece, e a escolha tem consequência de compliance.
Dois caminhos
| Do navegador | Do seu servidor | |
|---|---|---|
| Chave | n7_pk_… (publicável) | n7_sk_… (secreta, a que você já tem) |
| Quem vê o cartão | Só o navegador do pagador e a N7 | Também os seus servidores |
| Escopo PCI-DSS | SAQ A-EP (reduzido) | SAQ D (completo — auditoria anual, pentest) |
| Variável de ambiente | Precisa de uma nova | Nenhuma — reusa a que existe |
Caminho A — do navegador (recomendado)
- Seu servidor cria (ou busca) o cliente em POST /customers e devolve o
customer_idpara a sua página. - O navegador do pagador chama
POST /tokenscom a chave publicável e os dados do cartão, e recebecard_token. - Sua página envia apenas o
card_tokenao seu servidor. - Seu servidor chama POST /charges com a chave secreta, o
card_token, omethode asinstallments.
A chave publicável é gerada no dashboard em Chaves API → Tipo → Publicável. Ela pode ficar visível no código da sua página: só tokeniza cartão, não cria cobrança nem lê dados. O endpoint responde com CORS, então o fetch cross-origin funciona.
Caminho B — do seu servidor
Se o formulário de cartão já é processado no seu backend, chame POST /tokens de lá com a mesma chave secreta que você usa em /charges — não é preciso criar chave nem variável nova. O corpo é idêntico ao do caminho A.
Caminho C — cartão inline, sem tokenizar
A tokenização é um recurso liberado à parte pelo gateway. Enquanto ela não estiver habilitada na sua conta, envie o cartão direto no POST /charges, no objeto card, e omita o card_token:
curl -X POST https://n7pay.com/api/v1/charges \
-H "Authorization: Bearer n7_sk_live_SuaChaveAqui" \
-H "Content-Type: application/json" \
-d '{
"amount": "297.00",
"method": "card_7_12x",
"installments": 12,
"ip": "189.10.20.30",
"customer": {
"name": "Maria Souza",
"email": "maria@example.com",
"document": "982.671.040-70",
"phone": "61992746281",
"postal_code": "71735103",
"address_number": "17"
},
"card": {
"holder_name": "MARIA S SOUZA",
"number": "5162306219378829",
"exp_month": "05",
"exp_year": "2031",
"cvv": "318"
}
}'
Os dados do portador saem do objeto customer; se o titular do cartão for outra pessoa, mande um objeto holder separado. Campos faltando voltam como 422 listando exatamente quais, antes de qualquer chamada ao gateway.
O efeito em compliance é o mesmo do caminho B — o cartão passa pelo seu servidor.
fetch em JS direto para a N7, e só o token pode ser enviado ao seu backend.
Parâmetros — POST /tokens
| Campo | Tipo | Descrição | |
|---|---|---|---|
| customer_id | uuid | obrigatório | Cliente N7 dono do cartão |
| card.holder_name | string | obrigatório | Nome impresso no cartão |
| card.number | string | obrigatório | Número do cartão (com ou sem espaços) |
| card.exp_month | string | obrigatório | "05" ou "5" |
| card.exp_year | string | obrigatório | "2031" ou "31" — aceitamos os dois |
| card.cvv | string | obrigatório | Código de segurança |
| holder.document | string | obrigatório* | CPF/CNPJ do portador. *Herdado do cliente se já estiver cadastrado. |
| holder.postal_code | string | obrigatório* | CEP do portador — exigido pelo antifraude |
| holder.address_number | string | obrigatório* | Número do endereço |
| holder.phone | string | obrigatório* | Telefone com DDD |
| ip | string | opcional | IP do pagador. Detectado automaticamente se omitido. |
// Caminho A — no navegador do pagador, com a chave publicável.
// No caminho B, a mesma chamada sai do seu servidor com a chave n7_sk_.
const res = await fetch("https://n7pay.com/api/v1/tokens", {
method: "POST",
headers: {
"Authorization": "Bearer n7_pk_sand_SuaChavePublicavel",
"Content-Type": "application/json"
},
body: JSON.stringify({
customer_id: "44dcf7a7-ebc3-4ad7-b122-01f404cda545",
card: {
holder_name: "MARIA S SOUZA",
number: "5162306219378829",
exp_month: "05",
exp_year: "2031",
cvv: "318"
},
holder: {
document: "982.671.040-70",
postal_code: "71735103",
address_number: "17",
phone: "61992746281"
}
})
});
// Resposta 201
{
"data": {
"card_token": "8a1b2c3d-...",
"brand": "MASTERCARD",
"last4": "8829",
"customer_id": "44dcf7a7-ebc3-4ad7-b122-01f404cda545"
}
}
Cobrando o cartão tokenizado
# No seu servidor — chave secreta
curl -X POST https://n7pay.com/api/v1/charges \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui" \
-H "Content-Type: application/json" \
-d '{
"amount": "297.00",
"method": "card_7_12x",
"installments": 12,
"card_token": "8a1b2c3d-...",
"external_reference": "payment_123",
"ip": "189.10.20.30",
"customer": {
"name": "Maria Souza",
"email": "maria@example.com",
"document": "982.671.040-70"
}
}'
# Resposta 201 — cartão é síncrono, o status já é final
{
"data": {
"id": "uuid",
"status": "paid",
"method": "card_7_12x",
"installments": 12,
"amount": "297.00",
"external_id": "pay_yxvvt5xg2tlzaong",
"gateway_status": "CONFIRMED",
"card_brand": "MASTERCARD",
"card_last4": "8829",
"authorization_url": null,
"environment": "sandbox"
}
}
Aprovação e recusa
status: "paid" — não existe tela de "processando". Diferente do PIX, que nasce pending e só vira pago pelo webhook, o cartão traz o veredito do emissor na própria resposta. Se a sua UI mostra "aguardando confirmação" depois de um 201 de cartão, ela está esperando um evento que já aconteceu.
Recusa não é 201. Quando o emissor nega, a resposta é 422 com o motivo dele — não um 201 com status negado. Trate os dois caminhos separadamente:
# 422 — recusado
{
"error": "charge_declined",
"details": [
{ "code": "invalid_credit_card", "message": "Cartão recusado pelo emissor." }
]
}
Os status possíveis num 201:
status | Significado |
|---|---|
| paid | Aprovado e capturado — pode liberar o produto |
| pending | Em análise de risco pelo Asaas, ou aguardando 3DS — veja authorization_url. O desfecho chega por webhook. |
Quando authorization_url vier preenchido, o emissor exigiu autenticação 3DS: redirecione o pagador para essa URL e aguarde o webhook payment.paid.
charge_declined acima no seu próprio cliente HTTP.
Clientes
Clientes representam os pagadores da sua empresa. Ao criar um cliente, o N7 Pay sincroniza automaticamente com os gateways configurados (Asaas, Stripe), armazenando os IDs remotos para acelerar cobranças futuras e habilitar split de receita.
document (CPF/CNPJ) para PIX. Stripe exige email + endereço de cobrança para cartões internacionais. Sempre capture o máximo de dados para cobrir ambos os casos.
Isolamento entre empresas
Seus pagadores são seus. Mesmo com várias empresas usando a plataforma, o cadastro de um CPF que compra de você é separado do cadastro do mesmo CPF comprando de outra empresa — não há reuso de cliente entre contas, nem no N7 nem no gateway.
O identificador remoto fica em gateway_customer_ids e é reaproveitado nas cobranças seguintes, o que deixa a segunda compra do mesmo pagador mais rápida. Você não precisa gerenciar esse campo: ele é preenchido sozinho.
document, email, country.gateway_customer_ids mapeados.Parâmetros — POST /customers
| Campo | Tipo | Descrição | |
|---|---|---|---|
| name | string | obrigatório | Nome completo ou razão social |
| string | opcional* | *Obrigatório para Stripe | |
| phone | string | opcional | Com DDI, ex: +5511999999999 |
| document_type | string | opcional | "cpf", "cnpj", "vat", "ssn", "passport" |
| document | string | opcional* | *Obrigatório para PIX (CPF/CNPJ) |
| country | string | opcional | ISO 3166 — ex: "BR", "US", "PT" (padrão: "BR") |
| address_line1 | string | opcional | Logradouro. Obrigatório para Stripe. |
| city | string | opcional | Cidade |
| state | string | opcional | Estado / UF |
| zip_code | string | opcional | CEP ou postal code |
| timezone | string | opcional | IANA — ex: "America/Sao_Paulo" (padrão) |
# Criar cliente (PIX + cartão internacional)
curl -X POST https://n7pay.com/api/v1/customers \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui" \
-H "Content-Type: application/json" \
-d '{
"name": "João da Silva",
"email": "joao@exemplo.com",
"phone": "+5511999999999",
"document_type": "cpf",
"document": "123.456.789-00",
"country": "BR",
"address_line1": "Rua das Flores, 100",
"city": "São Paulo",
"state": "SP",
"zip_code": "01310-100"
}'
# Resposta 201
{
"id": 7,
"name": "João da Silva",
"email": "joao@exemplo.com",
"country": "BR",
"gateway_customer_ids": {
"asaas": "cus_000123abc",
"stripe": "cus_Nxxx1234"
},
"created_at": "2026-06-08T15:00:00Z"
}
Webhooks — Saída (N7 → seu servidor)
Configure endpoints HTTPS no seu dashboard para receber notificações em tempo real. O N7 Pay assina cada payload com HMAC-SHA256.
Formato do payload
{
"event": "payment_link.paid",
"occurred_at": "2026-06-08T15:42:00Z",
"data": {
"transaction_id": 142,
"payment_link_id": 42,
"amount": "99.90",
"currency": "BRL",
"method": "pix",
"gateway": "asaas",
"status": "paid"
}
}
A assinatura é enviada no header X-N7-Signature:
# Verificação em Elixir
def valid_signature?(raw_body, signature, secret) do
expected = :crypto.mac(:hmac, :sha256, secret, raw_body)
|> Base.encode16(case: :lower)
Plug.Crypto.secure_compare(expected, signature)
end
# Verificação em Node.js
const crypto = require("crypto");
const expected = crypto.createHmac("sha256", secret)
.update(rawBody).digest("hex");
const valid = crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signature)
);
Eventos disponíveis
| Evento | Disparado quando |
|---|---|
| payment_link.paid | Pagamento confirmado pelo gateway |
| payment_link.expired | Link expirou sem pagamento |
| transaction.failed | Transação recusada pelo gateway |
| transaction.refunded | Estorno processado |
| transaction.chargeback | Disputa aberta pelo titular do cartão |
| customer.created | Novo cliente criado e sincronizado |
Gateways — o que você não precisa fazer
Você não abre conta, não configura webhook e não guarda credencial em gateway nenhum. A N7 Pay opera as contas de adquirência e cuida de toda essa camada; a sua integração termina na API do N7.
| Responsabilidade | De quem é |
|---|---|
| Conta no gateway | N7 Pay |
| Webhook do gateway | N7 Pay |
| Credenciais de adquirência | N7 Pay |
| Conciliação de eventos | N7 Pay |
| Receber webhooks de saída do N7 | Você |
Quando o pagamento é confirmado na ponta, o N7 normaliza o evento e entrega para você num formato único — o mesmo payload independente de qual gateway processou. É o que está descrito em Webhooks de saída, e é o único que você precisa consumir.
Smart Routing
O Smart Routing seleciona automaticamente o melhor gateway para cada transação com base em:
- Menor custo — taxa percentual + fixa combinada (peso 45%)
- Taxa de aprovação 24h — histórico recente de cada gateway (peso 35%)
- Latência p50 — tempo de resposta mediano (peso 15%)
- Failover automático — se um gateway falhar, tenta o próximo (peso 5%)
Critérios de roteamento por método
| Método | Gateway principal | Fallback |
|---|---|---|
| pix | Asaas (melhor custo BRL) | Outro gateway com suporte PIX |
| boleto | Asaas | — |
| card_1x · card_2_6x · card_7_12x | Asaas (BRL) / Stripe (USD, EUR) | Gateway com maior aprovação 24h |
| usd / wire | Stripe | — |
Split de Receita
Com o split ativo, o valor líquido de cada cobrança — o total menos a taxa N7, conforme o seu plano de tarifas — cai direto na sua carteira, e só a taxa fica retida pela N7. Não há repasse manual nem espera por transferência.
Nada muda na sua integração: você não envia parâmetro nenhum a mais. O net_amount devolvido em cada cobrança é exatamente o que vai para você.
O provisionamento da sua carteira é feito pela N7 durante o onboarding, a partir dos dados cadastrais da sua empresa. Se o split ainda não estiver ativo na sua conta, fale com o time N7 — não há nada a configurar por API.
Suporte Internacional
O N7 Pay suporta clientes e cobranças globais. Cada gateway tem requisitos diferentes:
| Campo do cliente | Asaas (PIX/Boleto) | Stripe (Cartão) |
|---|---|---|
| name | obrigatório | obrigatório |
| document (CPF/CNPJ) | obrigatório | não usado |
| recomendado | obrigatório | |
| address_line1 | opcional | obrigatório |
| country | BR implícito | obrigatório |
| zip_code | opcional | obrigatório |
Exemplos cURL
Listar links
curl https://n7pay.com/api/v1/payment-links \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui"
Criar link USD (Stripe)
curl -X POST https://n7pay.com/api/v1/payment-links \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui" \
-H "Content-Type: application/json" \
-d '{
"title": "International Plan",
"amount": "29.00",
"currency": "USD",
"methods": ["card_1x"]
}'
Consultar transação
curl https://n7pay.com/api/v1/transactions/142 \
-H "Authorization: Bearer n7_sk_sand_SuaChaveAqui"
Exemplos JavaScript / TypeScript
Criar link de pagamento
const res = await fetch("https://n7pay.com/api/v1/payment-links", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.N7_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Plano Mensal",
amount: "99.90",
currency: "BRL",
methods: ["pix"],
}),
});
const link = await res.json();
console.log(link.url); // https://n7pay.com/pay/abc123
Verificar assinatura de webhook
import crypto from "node:crypto";
function verifyWebhook(rawBody: Buffer, signature: string, secret: string): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(signature, "hex")
);
}