Referência pública dos endpoints REST de pagamento, integração e carteira pessoal do OrionPay. Base URL: https://payapi.orion.moe
Um índice legível por LLM fica em /llms.txt e a especificação completa em /llms-full.txt. A especificação OpenAPI 3.1 fica em payapi.orion.moe/openapi.json. As notas de versão do produto e da API ficam em /changelog.
Um servidor MCP Streamable HTTP com 19 ferramentas está no ar em payapi.orion.moe/mcp
claude mcp add orionpay --transport http https://payapi.orion.moe/mcp --header "X-API-Key: $ORIONPAY_API_KEY"Gere uma API Key em Dashboard > API & Webhooks > MCP / LLM.
Todo endpoint público exige uma API Key enviada no header X-API-Key (ou Authorization: Bearer). Existem dois tipos:
productId = null. Controla a carteira do próprio usuário (saldo, saques, swap) e cadastra produtos novos via POST /api/v1/personal/products, que devolve a API Key do produto. Não gera cobranças de venda.
Endpoints: /api/v1/personal/*.
Vinculada a um produto. Necessária para vender via API: gera cobranças e dispara os webhooks de venda. Gerada no dashboard ou devolvida por POST /api/v1/personal/products ao cadastrar o produto.
Endpoints: /api/v1/pix/generate, /integration/*.
X-API-Key: opay_abc123def456...// Gerar PIX via API
const response = await fetch('https://payapi.orion.moe/api/v1/pix/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'opay_sua_chave_aqui'
},
body: JSON.stringify({
amount: 199.90,
name: 'João da Silva',
email: '[email protected]'
})
})
const { data } = await response.json()
console.log(data.purchaseId) // ID interno da compra
console.log(data.pixCode) // PIX copia-e-cola
console.log(data.qrCode) // QR Code = pixCode
console.log(data.expiresAt) // ISO 8601Para vender via API
Cobranças de checkout (/api/v1/pix/generate) e webhooks de venda (purchase.created, payment.success) exigem uma API Key de Produto — crie o produto no dashboard e gere a chave dele, ou cadastre um produto novo com a API Key Pessoal em POST /api/v1/personal/products, que já devolve a chave e o webhook. A API Key Pessoal (/api/v1/personal/*) opera a sua carteira e cadastra produtos novos, mas não gera cobranças. Editar ou excluir produtos, subir imagens e conteúdo e gerir chaves e webhooks já existentes continua no dashboard. Depósitos na sua própria conta são feitos pelo dashboard, não pela API.
/api/v1/personal/productsAPI Key Pessoal10 req/hCria um produto NOVO já com a API Key de Produto e, se enviado, o webhook — numa chamada só; se uma etapa falhar, as anteriores são desfeitas. Responde 201 (200 no replay). Exige a API Key Pessoal e o plano Business ativo e em dia (senão 403 BUSINESS_NOT_ACTIVATED ou BUSINESS_EXPIRED). productType: CURSO_ONLINE, FOTOS, ARQUIVOS, AREA_MEMBROS, TELEGRAM_CHANNEL, CONSULTORIA ou MENTORIA. publish (padrão true) publica e cria o link de checkout; hideFromMarketplace é true por padrão. Sem price (ou com 0), cada cobrança leva o amount enviado ao pix/generate e paymentLink vem null; price pago abaixo do mínimo do PIX → 400 MIN_PIX_ORDER_AMOUNT. delivery só em AREA_MEMBROS ({accessUrl, accessInstructions}) e TELEGRAM_CHANNEL ({channelLink, joinInstructions}). webhook.events padrão: purchase.created, access.granted, payment.success; sem webhook.secret, um é gerado. Campo desconhecido → 400 INVALID_FIELD (com field). Repetir o externalReference devolve replayed: true com o mesmo produto e completa o que faltou (apiKey vem null se a chave do produto foi desativada ou venceu no dashboard — gerencie-a lá); outro productType ou outra webhook.url → 409 PRODUCT_REFERENCE_EXISTS. O teto de produtos criados em 24h (padrão 20 → 429 API_PRODUCT_DAILY_LIMIT) conta todo produto da conta, criado por qualquer canal, dashboard incluído; replay não conta. Compare os erros pelo code. apiKey.key e webhook.secret são segredos: guarde-os. O dono da conta recebe um e-mail a cada cadastro, e revogar a chave Pessoal não revoga as chaves de produto criadas com ela. Imagens e conteúdo (aulas, arquivos — CURSO_ONLINE, FOTOS e ARQUIVOS ficam vazios até lá), edição e exclusão continuam no dashboard. Na venda via pix/generate a OrionPay não envia nada ao comprador: a entrega é sua (ex.: /acesso/<accessToken>). Ferramenta MCP: personal_create_product.
Corpo da requisição
{
"title": "Curso X",
"productType": "CURSO_ONLINE",
"description": "Curso completo de exemplo",
"price": 49.9,
"hideFromMarketplace": true,
"publish": true,
"externalReference": "sku-123",
"webhook": {
"url": "https://example.com/webhooks/orionpay",
"events": ["purchase.created", "access.granted", "payment.success"],
"name": "Default"
}
}Resposta (201)
{
"success": true,
"replayed": false,
"product": {
"id": 123,
"title": "Curso X",
"description": "Curso completo de exemplo",
"productType": "CURSO_ONLINE",
"price": 49.9,
"status": "PUBLISHED",
"hideFromMarketplace": true,
"externalReference": "sku-123",
"createdAt": "2026-09-15T12:00:00.000Z"
},
"paymentLink": {
"slug": "3f9c2a7b1d4e5f60718293a4b5c6d7e8",
"url": "https://pay.orion.moe/p/3f9c2a7b1d4e5f60718293a4b5c6d7e8"
},
"apiKey": {
"id": 456,
"key": "opay_6b1e0f3a9c2d4e5f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f",
"name": "Curso X",
"createdAt": "2026-09-15T12:00:00.000Z"
},
"webhook": {
"id": 789,
"name": "Default",
"url": "https://example.com/webhooks/orionpay",
"events": ["purchase.created", "access.granted", "payment.success"],
"isActive": true,
"secret": "9d4c2b7e1a0f3e5d6c8b9a7f2e1d0c3b4a5f6e7d8c9b0a1f2e3d4c5b6a7f8e9d"
}
}/api/v1/pix/generateAPI Key de ProdutoGera um QR Code PIX vinculado a um produto. Usa o preço do produto ou o valor informado. O CPF/CNPJ do pagador (campo cpf) é obrigatório desde 30/06/2026 — alternativa: euid (identificação do pagador no DePix).
Corpo da requisição
{
"amount": 199.90,
"description": "Venda de produto",
"name": "João da Silva",
"email": "[email protected]",
"cpf": "52998224725",
"phone": "+5511999999999"
}Resposta (200)
{
"success": true,
"data": {
"purchaseId": 12345,
"productId": 8,
"productTitle": "Exemplo Produto",
"id": "550e8400-e29b-41d4-a716-446655440000",
"pixCode": "00020126580014br.gov.bcb.pix...",
"qrCode": "00020126580014br.gov.bcb.pix...",
"amount": 199.90,
"description": "Venda de produto: Exemplo Produto",
"expiresAt": "2026-04-24T14:30:00.000Z",
"status": "PENDING",
"coProducers": [
{ "userId": 5, "name": "Co-produtor Name", "percentage": 15.50 }
]
}
}/api/v1/pix/status/:idQualquer API Key60 req/minAceita purchaseId (numérico), transactionId (numérico) ou eulenDepositId (UUID).
Resposta (200)
{
"success": true,
"type": "product_purchase",
"id": 12345,
"eulenDepositId": "550e8400-e29b-41d4-a716-446655440000",
"status": "PAID",
"paidAt": "2026-04-24T12:00:00.000Z",
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"productId": 8,
"productTitle": "Exemplo Produto",
"amount": 199.90,
"buyerEmail": "[email protected]",
"buyerName": "João Silva",
"createdAt": "2026-04-24T10:00:00.000Z"
}/integration/verify-accessAPI Key de Produto60 req/minQuery: email ou accessToken (ao menos um obrigatório).
Resposta (200)
{
"hasAccess": true,
"purchaseId": 12345,
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"buyerEmail": "[email protected]",
"buyerName": "João Silva",
"productTitle": "Exemplo Produto",
"purchaseDate": "2026-04-20T10:00:00.000Z",
"expiresAt": "2026-05-20T10:00:00.000Z"
}/integration/grant-accessAPI Key de ProdutoCria uma compra já paga para o email informado. Útil para cortesias e suporte.
Corpo da requisição
{
"buyerEmail": "[email protected]",
"buyerName": "Maria Santos",
"price": 199.90,
"expiresAt": "2026-05-24T00:00:00.000Z"
}Resposta (200)
{
"success": true,
"message": "Acesso concedido com sucesso",
"purchaseId": 12347,
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"buyerEmail": "[email protected]",
"buyerName": "Maria Santos",
"expiresAt": "2026-05-24T00:00:00.000Z"
}/integration/buyersAPI Key de Produto60 req/minQuery opcional: status (PENDING, PAID, EXPIRED).
Resposta (200)
{
"total": 2,
"buyers": [
{
"purchaseId": 12345,
"buyerEmail": "[email protected]",
"buyerName": "João Silva",
"price": 199.90,
"paymentStatus": "PAID",
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"purchaseDate": "2026-04-20T10:00:00.000Z",
"paidAt": "2026-04-20T10:05:00.000Z",
"expiresAt": "2026-05-20T10:00:00.000Z",
"paymentLink": "Link de Pagamento Exemplo"
}
]
}/integration/buyers/:purchaseIdAPI Key de ProdutoRetorna dados completos de uma compra pelo ID.
Resposta (200)
{
"purchaseId": 12345,
"buyerEmail": "[email protected]",
"buyerName": "João Silva",
"price": 199.90,
"paymentStatus": "PAID",
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"purchaseDate": "2026-04-20T10:00:00.000Z",
"paidAt": "2026-04-20T10:05:00.000Z",
"expiresAt": "2026-05-20T10:00:00.000Z",
"product": { "id": 8, "title": "Exemplo Produto", "productType": "COURSE" },
"paymentLink": { "id": 1, "title": "Link de Pagamento Exemplo" }
}/integration/contentAPI Key de Produto60 req/minQuery: accessToken (obrigatório). Valida o token e retorna os conteúdos liberados.
Resposta (200)
{
"productId": 8,
"buyerEmail": "[email protected]",
"buyerName": "João Silva",
"contents": [
{
"id": 1,
"type": "video",
"title": "Aula 1 - Introdução",
"url": "https://storage.example.com/video1.mp4",
"fileSize": 524288000,
"mimeType": "video/mp4",
"order": 1,
"metadata": "{\"duration\": 3600}"
}
]
}/integration/revoke-access/:purchaseIdAPI Key de ProdutoInvalida o accessToken da compra informada.
Resposta (200)
{
"success": true,
"message": "Acesso revogado com sucesso",
"purchaseId": 12345
}/api/v1/integration/deposit/pixAPI Key de Produto10 req/minCria QR Code PIX para o produto. O CPF/CNPJ do pagador (campo cpf, apenas dígitos) é obrigatório desde 30/06/2026 — alternativa: euid (identificação do pagador no DePix). A identificação do lojista (merchantId) é automática (resolvida pela sua API key); não precisa ser enviada.
Corpo da requisição
{
"cpf": "52998224725",
"amount": 199.90,
"buyerEmail": "[email protected]",
"buyerName": "João da Silva"
}Resposta (200)
{
"purchaseId": 12348,
"productId": 8,
"productTitle": "Exemplo Produto",
"id": "550e8400-e29b-41d4-a716-446655440000",
"pixCode": "00020126580014br.gov.bcb.pix...",
"qrCode": "00020126580014br.gov.bcb.pix...",
"amount": 199.90,
"expiresAt": "2026-04-24T14:30:00.000Z",
"status": "created"
}/api/v1/personal/balanceAPI Key Pessoal60 req/hRetorna saldo por moeda, incluindo bloqueado e pendente.
Resposta (200)
{
"success": true,
"wallets": [
{
"currency": "BRL",
"balance": 5000.00,
"blockedBalance": 500.00,
"pendingBalance": 0.00,
"availableBalance": 4500.00
},
{
"currency": "L-BTC",
"balance": 0.02,
"blockedBalance": 0.00,
"pendingBalance": 0.00,
"availableBalance": 0.02
}
]
}/api/v1/personal/limitsAPI Key Pessoal30 req/hRetorna limites diários/mensais e o consumo atual.
Resposta (200)
{
"success": true,
"limits": {
"dailyWithdrawBRL": 10000.00,
"monthlyWithdrawBRL": 100000.00,
"dailyWithdrawCrypto": 2.00,
"monthlyWithdrawCrypto": 10.00,
"dailyUsed": 2000.00,
"monthlyUsed": 15000.00
}
}/api/v1/personal/transactionsAPI Key Pessoal60 req/hQuery: limit, offset, type (DEPOSIT, WITHDRAWAL, SWAP).
Resposta (200)
{
"success": true,
"transactions": [
{
"id": 789,
"type": "DEPOSIT",
"status": "COMPLETED",
"amount": 500.00,
"description": "Depósito PIX",
"blockchainTxId": null,
"createdAt": "2026-04-24T10:00:00.000Z"
}
],
"pagination": { "total": 50, "limit": 10, "offset": 0, "hasMore": true }
}/api/v1/personal/withdraw/quoteAPI Key Pessoal120 req/hSimula um saque com a mesma matemática do débito real. Envie exatamente um: ?amount= (bruto a debitar) OU ?netAmount= (líquido desejado na conta destino). grossAmount − totalFee = netAmount fecha exato.
Resposta (200)
{
"success": true,
"quote": { "grossAmount": 78.31, "totalFee": 3.31, "netAmount": 75.00, "requestedNetAmount": 75.00 },
"limits": { "minAmount": 4.00, "maxAmount": 50000.00 },
"validation": { "withinLimits": true }
}/api/v1/personal/withdraw/pixAPI Key Pessoal10 req/hEnvie exatamente um: amount (1–100.000, bruto a debitar) OU netAmount (líquido que deve chegar na conta — o débito é calculado automaticamente). fee é a taxa TOTAL e amount − fee = netAmount. pixKeyType é detectado automaticamente (EMAIL, CPF, CNPJ, PHONE, RANDOM).
Corpo da requisição
{
"netAmount": 75.00,
"pixKey": "12345678000123",
"pixKeyType": "CPF",
"description": "Saque via API",
"taxNumber": "52998224725"
}Resposta (200)
{
"success": true,
"message": "Saque PIX em processamento",
"queueId": 88,
"transactionId": 791,
"status": "PENDING",
"requiresApproval": false,
"amount": 78.31,
"fee": 3.31,
"total": 78.31,
"netAmount": 75.00,
"requestedNetAmount": 75.00,
"estimatedProcessingTime": "1-2 minutos"
}/api/v1/personal/withdraw/cryptoAPI Key Pessoal10 req/hSuporta L-BTC, BTC-PEGOUT, DePix, USDt, USDC. memo obrigatório para TON.
Corpo da requisição
{
"amount": 0.01,
"toAddress": "bc1q6y3kz2c8s4n9p1m0l2k3j4h5g6f7e8d9c0b1a",
"assetTicker": "BTC-PEGOUT",
"network": "bitcoin"
}Resposta (200)
{
"success": true,
"transactionId": 792,
"status": "PENDING",
"amount": 0.01,
"assetTicker": "BTC-PEGOUT",
"toAddress": "bc1q6y3kz2c8s4n9p1m0l2k3j4h5g6f7e8d9c0b1a",
"blockchainTxId": null,
"createdAt": "2026-04-24T14:00:00.000Z"
}/api/v1/personal/withdraw/status/:idAPI Key Pessoal120 req/hRetorna estado atual, taxa total e valor líquido. netAmount vira o payout confirmado pelo provedor assim que disponível (payoutConfirmed: true). Para saques cripto, toAddress/asset são preenchidos no lugar de pixKey.
Resposta (200)
{
"success": true,
"transaction": {
"id": 791,
"status": "COMPLETED",
"amount": 78.31,
"fee": 3.31,
"netAmount": 75.00,
"payoutConfirmed": true,
"requestedNetAmount": 75.00,
"pixKey": "12345678000123",
"description": "P-API: Saque PIX",
"blockchainTxId": null,
"errorCode": null,
"errorMessage": null,
"createdAt": "2026-04-24T14:00:00.000Z",
"updatedAt": "2026-04-24T14:05:00.000Z"
}
}/api/v1/personal/swap/quoteAPI Key Pessoal120 req/hMoedas suportadas: DePix, L-BTC, USDt, EURx. Cotação válida por 5 minutos.
Corpo da requisição
{
"fromCurrency": "BRL",
"toCurrency": "BTC",
"amount": 1000.00
}Resposta (200)
{
"success": true,
"fromCurrency": "BRL",
"toCurrency": "BTC",
"fromAmount": 1000.00,
"toAmount": 0.0195,
"rate": 0.0000195,
"fee": 5.00,
"feeCurrency": "BRL",
"expiresAt": "2026-04-24T14:15:00.000Z"
}/api/v1/personal/swap/executeAPI Key Pessoal20 req/hDebita fromCurrency e credita toCurrency ao preço vigente no momento da execução.
Corpo da requisição
{
"fromCurrency": "BRL",
"toCurrency": "BTC",
"amount": 1000.00
}Resposta (200)
{
"success": true,
"transactionId": 793,
"fromCurrency": "BRL",
"toCurrency": "BTC",
"fromAmount": 1000.00,
"toAmount": 0.0195,
"status": "COMPLETED",
"executedAt": "2026-04-24T14:05:00.000Z"
}/payment-links/purchase/:purchaseId/statusPúblico (sem auth)60 req/minÚnico endpoint sem auth. Aceita ID numérico (compra) ou UUID (eulenDepositId). Pensado para polling no checkout.
Resposta (200)
{
"purchaseId": 12345,
"paymentStatus": "PAID",
"paidAt": "2026-04-24T12:00:00.000Z",
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"productTitle": "Exemplo Produto",
"price": 199.90
}Ao exceder o limite, o backend responde com HTTP 429. Os limites são por API Key + rota e resetam na janela indicada.
Valores possíveis do campo status no recurso Transaction (GET /transactions/:id)
PIX gerado, aguardando pagamento. Saldo ainda não foi movimentado.
Eulen processando. Pode estar em under_review (anti-fraude), delayed (Eulen segurando o DePix antes do approved — sem efeito financeiro ainda) ou em delay-depix HOLD após o approved (PIX confirmado e blockedBalance já incrementado; sub-fase identificada por metadata.holdSource = "delay-depix" + metadata.approvedAt + availableAt). Webhook desta sub-fase: deposit.approved_delay.
DePix entregue na reserva. Saldo creditado em balance (ou em pendingBalance se isOnHold=true). Webhook emitido: deposit.success ou deposit.on_hold.
PIX falhou (não pago, expirado, recusado pela Eulen ou banco). Nenhum saldo movimentado.
Transação cancelada manualmente (admin) ou por TTL (PIX não pago dentro da janela).
Estorno: MED (PIX chargeback) detectado durante carência ou estorno manual feito por admin. Saldo retirado de blockedBalance ou pendingBalance conforme metadata.holdSource.
Transação em análise manual pelo time. Aguardando aprovação ou rejeição.
Receba notificações automáticas quando eventos importantes acontecem
Todo webhook traz assinatura HMAC-SHA256 no header X-Webhook-Signature: hex minúsculo, sem prefixo, calculado sobre o corpo bruto (raw body) com o segredo do webhook — o do dashboard ou o webhook.secret devolvido por POST /api/v1/personal/products. Valide sempre antes de processar.
X-Webhook-Signature: a1b2c3d4e5f6...payment.successPagamento confirmado e creditado.
{
"event": "payment.success",
"productId": 8,
"productTitle": "Exemplo Produto",
"webhookName": "notificar_sistema",
"timestamp": "2026-04-24T12:00:00.000Z",
"data": {
"purchaseId": 12345,
"transactionId": "txn_abc123",
"productId": 8,
"buyerEmail": "[email protected]",
"buyerName": "João Silva",
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"price": 199.90,
"netAmount": 179.91,
"platformFee": 19.99,
"timestamp": "2026-04-24T12:00:00.000Z"
}
}purchase.createdCompra criada, aguardando pagamento.
{
"event": "purchase.created",
"productId": 8,
"timestamp": "2026-04-24T10:00:00.000Z",
"data": {
"purchaseId": 12345,
"transactionId": "txn_abc123",
"amount": 199.90,
"status": "pending",
"createdAt": "2026-04-24T10:00:00.000Z",
"buyerEmail": "[email protected]",
"buyerName": "João Silva"
}
}access.grantedAcesso liberado ao comprador após confirmação de pagamento.
{
"event": "access.granted",
"productId": 8,
"timestamp": "2026-04-24T12:00:05.000Z",
"data": {
"purchaseId": 12345,
"buyerEmail": "[email protected]",
"accessToken": "abcd1234efgh5678ijkl9012mnop3456",
"expiresAt": "2026-05-24T12:00:05.000Z",
"grantedAt": "2026-04-24T12:00:05.000Z"
}
}payment.refunded_medPagamento reembolsado por MED (chargeback) durante o hold antifraude.
{
"event": "payment.refunded_med",
"productId": 8,
"timestamp": "2026-04-24T15:00:00.000Z",
"data": {
"transactionId": 789,
"amount": 199.90,
"reference": "550e8400-e29b-41d4-a716-446655440000",
"status": "refunded",
"type": "DEPOSIT",
"currency": "BRL",
"reason": "med_during_antifraud_hold",
"medDetectedAt": "2026-04-24T14:50:00.000Z",
"refundedAt": "2026-04-24T15:00:00.000Z"
}
}payment.refundedDepósito reembolsado pela Eulen ao pagador (PIX devolvido); o valor retido é estornado. Estorno MED de valor já creditado sai como payment.refunded_med. O campo opcional refundReasonDetail traz o motivo inferido (med_chargeback, cpf_mismatch, cnpj_mismatch, spam_like, user_blocked, payer_refused, indeterminate_payer). Exceto em indeterminate_payer, o payload inclui payerEuid — id pseudônimo e estável da conta pagadora, para correlacionar reincidentes sem expor identidade. Nos motivos mismatch vão também payerName e payerTaxNumber, com o CPF sempre mascarado.
{
"event": "payment.refunded",
"productId": 8,
"timestamp": "2026-04-24T15:00:00.000Z",
"data": {
"transactionId": 789,
"amount": 199.90,
"reference": "550e8400-e29b-41d4-a716-446655440000",
"status": "refunded",
"type": "DEPOSIT",
"currency": "BRL",
"reason": "eulen_refund",
"refundReasonDetail": "cpf_mismatch",
"payerEuid": "EU015562310201680",
"payerName": "João da Silva",
"payerTaxNumber": "***.456.789-**",
"eulenStatus": "refunded",
"refundedAt": "2026-04-24T15:00:00.000Z",
"credited": false
}
}payment.refund_pendingAviso PRÉVIO: a Eulen anunciou que vai devolver um PIX já recebido (risco/compliance). Não é o evento terminal — o payment.refunded vem depois, em média ~2h e até 3 dias quando o provedor retém o valor antes (informado em expectedRefundAt). Trate como irreversível. O campo opcional rejectionReasons traz o código cru do provedor (PAYER_MISMATCH, BLOCKED_USER); o vocabulário é dele e pode crescer — trate código desconhecido como recusa genérica de risco. Se o comprador já tinha acesso, a OrionPay revoga e envia accessRevoked: true; reverta a entrega do seu lado também.
{
"event": "payment.refund_pending",
"productId": 8,
"timestamp": "2026-04-24T15:00:00.000Z",
"data": {
"transactionId": 789,
"amount": 199.90,
"reference": "550e8400-e29b-41d4-a716-446655440000",
"status": "refund_pending",
"type": "DEPOSIT",
"currency": "BRL",
"reason": "eulen_will_refund",
"rejectionReasons": ["PAYER_MISMATCH"],
"expectedRefundAt": "2026-04-27T15:00:00.000Z",
"payerEuid": "EU015562310201680",
"eulenStatus": "will_refund",
"credited": false,
"accessRevoked": true,
"purchaseId": 12345,
"productId": 8,
"productTitle": "Exemplo Produto",
"buyerEmail": "[email protected]",
"buyerName": "Cliente Exemplo"
}
}med.createdMED (chargeback) detectado em depósito Eulen.
{
"event": "med.created",
"timestamp": "2026-04-24T14:50:00.000Z",
"data": {
"qrId": "550e8400-e29b-41d4-a716-446655440000",
"bankTxId": "E00000000202604241450",
"amount": 199.90,
"currency": "BRL",
"medDetectedAt": "2026-04-24T14:50:00.000Z",
"depositStatus": "depix_sent",
"payerTaxNumber": "52998224725",
"transactionId": 789,
"purchaseId": 12345,
"productId": 8,
"productTitle": "Exemplo Produto"
}
}withdrawal.completedSaque transmitido à blockchain ou ao banco.
{
"event": "withdrawal.completed",
"timestamp": "2026-04-24T14:05:00.000Z",
"data": {
"withdrawalId": 792,
"amount": 0.01,
"fee": 0.00001,
"totalDeducted": 0.01001,
"asset": "L-BTC",
"toAddress": "lq1qqw...",
"txHash": "abc123...",
"network": "liquid",
"isSideShift": false,
"completedAt": "2026-04-24T14:05:00.000Z"
}
}withdrawal.settledSaque totalmente confirmado na rede de destino (inclui Peg-Out BTC).
{
"event": "withdrawal.settled",
"timestamp": "2026-04-24T14:30:00.000Z",
"data": {
"withdrawalId": 792,
"amount": 0.01,
"asset": "BTC-PEGOUT",
"toAddress": "bc1q...",
"liquidTxHash": "abc123...",
"settleTxHash": "def456...",
"settleNetwork": "bitcoin",
"completedAt": "2026-04-24T14:30:00.000Z"
}
}withdrawal.failedSaque falhou (saldo insuficiente, endereço inválido, etc). Valores já devolvidos ao saldo.
{
"event": "withdrawal.failed",
"timestamp": "2026-04-24T14:05:00.000Z",
"data": {
"withdrawalId": 792,
"amount": 0.01,
"asset": "L-BTC",
"toAddress": "lq1qqw...",
"network": "liquid",
"error": "Insufficient hotwallet balance",
"failedAt": "2026-04-24T14:05:00.000Z"
}
}swap.completedSwap atômico executado com sucesso.
{
"event": "swap.completed",
"timestamp": "2026-04-24T14:05:00.000Z",
"data": {
"txid": "abc123...",
"fromCurrency": "L-BTC",
"toCurrency": "DePix",
"fromAmount": 0.01,
"toAmountGross": 3500.00,
"toAmountNet": 3482.50,
"feePercent": 0.5,
"feeAmount": 17.50,
"completedAt": "2026-04-24T14:05:00.000Z"
}
}swap.failedSwap falhou ou foi reembolsado.
{
"event": "swap.failed",
"timestamp": "2026-04-24T14:05:00.000Z",
"data": {
"transactionId": 793,
"fromCurrency": "L-BTC",
"toCurrency": "DePix",
"fromAmount": 0.01,
"step": "REFUNDED",
"reason": "Manual refund by admin",
"refundedAt": "2026-04-24T14:05:00.000Z"
}
}webhook.testEvento disparado manualmente pela dashboard para testar a URL.
{
"event": "webhook.test",
"timestamp": "2026-04-24T14:05:00.000Z",
"data": {
"message": "Webhook de teste",
"testId": "test_abc123"
}
}// Validar assinatura de webhook (Node.js)
const crypto = require('crypto')
// X-Webhook-Signature = hex(HMAC-SHA256(secret, raw body)), no prefix
function validateWebhook(rawBody, signature, secret) {
// timingSafeEqual throws on length mismatch: reject a missing/malformed header first
if (typeof signature !== 'string' || !/^[0-9a-f]{64}$/i.test(signature)) return false
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex')
)
}
app.post('/webhooks/orionpay', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-webhook-signature']
const rawBody = req.body // Buffer: the exact bytes that were signed
if (!validateWebhook(rawBody, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' })
}
const { event, data } = JSON.parse(rawBody.toString('utf8'))
switch (event) {
case 'payment.success':
grantAccess(data.buyerEmail, data.accessToken)
break
case 'payment.refunded_med':
case 'payment.refunded':
case 'payment.refund_pending':
revokeAccess(data.transactionId)
break
case 'withdrawal.settled':
markWithdrawalSettled(data.withdrawalId)
break
}
res.status(200).json({ received: true })
})