Eleva Payments

Documentação para desenvolvedores

API do Eleva Payments

Pix, cartão, USDT, split, saques e webhooks assinados. Tudo o que você precisa para integrar seu sistema, com exemplos prontos.

Base URL
https://app.elevapayments.live/api/v1
OpenAPI (YAML)

API REST v1

Integre a Eleva Payments ao seu sistema

Com a API você cria cobranças Pix e no cartão, recebe em reais ou em USDT, divide o valor com parceiros (split), consulta transações, faz saques via Pix e é avisado de tudo por webhook. Funciona com qualquer linguagem que faça requisições HTTPS com JSON.

Como funciona uma venda

  1. 1

    Seu sistema cria a cobrança

    POST /payments/pix com valor e dados do pagador. Guarde o transaction_uuid junto do pedido.

  2. 2

    Você mostra o Pix ao cliente

    Use qr_code_base64 (imagem pronta) e pix_code (copia e cola). A cobrança expira em expires_in_seconds.

  3. 3

    O cliente paga

    Nós recebemos a confirmação da adquirente e creditamos o valor líquido no seu saldo.

  4. 4

    Você é avisado

    Enviamos o webhook deposit.completed para a sua URL. Valide a assinatura e libere o pedido.

Base URL

https://app.elevapayments.live/api/v1

Formato

JSON (UTF-8), só HTTPS

Especificação

OpenAPI 3 (YAML)

O arquivo OpenAPI pode ser importado no Postman, Insomnia ou em geradores de SDK. Não existe ambiente de testes separado: teste em produção com valores baixos (ex.: R$ 5,00).

Em 10 minutos

Início rápido

Do zero até receber o primeiro Pix e o aviso de pagamento no seu servidor.

1. Gere as credenciais

Em Chave API crie uma credencial. Você recebe um Client ID e um Token. O token só aparece uma vez: guarde em variável de ambiente do servidor. Na mesma tela informe a URL de webhook.

2. Crie uma cobrança Pix

cURL
curl -X POST "https://app.elevapayments.live/api/v1/payments/pix" \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "X-Client-ID: SEU_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "amount": 49.90,
    "payer_name": "Maria Souza",
    "payer_email": "[email protected]",
    "payer_cpf": "52998224725",
    "description": "Pedido #1042"
  }'

3. Mostre o QR Code ao cliente

A resposta traz tudo pronto. Guarde o transaction_uuid no seu pedido.

JSON · 201
{
  "success": true,
  "data": {
    "transaction_uuid": "9d3f1c1e-6a2b-4d7e-9a51-2f0c8b7e4a10",
    "amount": 49.90,
    "fee": 1.50,
    "amount_net": 48.40,
    "status": "pending",
    "qr_code": "00020101021226870014br.gov.bcb.pix2565...6304ABCD",
    "pix_code": "00020101021226870014br.gov.bcb.pix2565...6304ABCD",
    "qr_code_base64": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...",
    "expires_at": "2026-10-01T14:35:00-03:00",
    "expires_in_seconds": 300,
    "settlement": "brl"
  }
}
HTML
<!-- QR Code pronto: use o qr_code_base64 direto na tag img -->
<img src="{qr_code_base64}" alt="QR Code Pix" width="240" height="240">

<!-- Copia e cola -->
<input value="{pix_code}" readonly>
<button onclick="navigator.clipboard.writeText('{pix_code}')">Copiar código Pix</button>

4. Receba o webhook e libere o pedido

Quando o Pix for pago, enviamos deposit.completed para a sua URL. antes de liberar. Sem webhook, consulte GET /payments/{uuid} a cada 5 a 10 segundos enquanto o cliente está na tela.

Segurança

Autenticação

Toda requisição leva o token no header Authorization e o Client ID em X-Client-ID.

Headers
Authorization: Bearer SEU_TOKEN
X-Client-ID: SEU_CLIENT_ID
Content-Type: application/json
Accept: application/json

Boas práticas

  • • Chame a API só do seu servidor. Nunca exponha o token em site, app ou repositório.
  • • Crie uma credencial por sistema/loja: fica fácil revogar uma sem afetar as outras.
  • • Cadastre o IP do servidor na credencial: chamadas de outros IPs são recusadas (403).
  • • O mesmo token é o segredo que assina os webhooks.

Quando a autenticação falha

  • 401 token ausente, inválido, revogado ou expirado.
  • 403 conta bloqueada, cadastro (KYC) não aprovado ou IP fora da lista da credencial.

Compatibilidade: o token também é aceito no header X-API-Token. Token na URL ou no corpo é recusado. O token aparece uma única vez ao criar a credencial (dá para trocar a qualquer momento no painel). Em saques, envie o header Idempotency-Key (8 a 80 caracteres): repetir o pedido com a mesma chave devolve o saque já criado, sem sacar de novo.

Antes de codar

Convenções e limites

Valores

Em reais, número decimal com ponto e até 2 casas: 49.90. Nas respostas: amount (bruto), fee (taxa) e amount_net (o que entra no seu saldo).

Datas

ISO 8601 com fuso, ex.: 2026-10-01T14:31:12-03:00. Filtros de data aceitam AAAA-MM-DD.

Identificadores

Cada cobrança tem um transaction_uuid (UUID v4). Use-o para consultar, estornar e casar com os webhooks.

Respostas

Sempre JSON com success (true/false). Em erro vem message e, na validação, errors por campo.

Limite de requisições

120 por minuto por token. Acima disso a resposta é 429 com o header Retry-After. Existe também um limite geral por IP contra abuso.

Repetição segura

Não há chave de idempotência. Se a criação der timeout, consulte a lista de transações antes de criar outra, para não cobrar duas vezes o mesmo pedido.

Paginação

page e per_page (1 a 100, padrão 20). A resposta traz pagination.total e last_page.

Tempo limite

Use 30 segundos de timeout. A criação de cobrança consulta a adquirente e pode levar alguns segundos.

Receber

Cobrança Pix

Gera um Pix com QR Code e copia e cola. O valor líquido entra no seu saldo assim que o pagamento é confirmado.

POSThttps://app.elevapayments.live/api/v1/payments/pix

Corpo da requisição

CampoTipoObrigatórioDescrição
amountdecimalSimValor da cobrança em reais (ex.: 49.90).
payer_namestringSimNome completo do pagador (até 255).
payer_emailstringSimE-mail do pagador.
payer_cpfstringSimCPF ou CNPJ do pagador (com ou sem pontuação).
descriptionstringNãoDescrição que aparece para você (até 500). Ex.: "Pedido #1042".
settlementstringNão"brl" (padrão) ou "usdt" para receber esta venda em USDT. Veja Pix em USDT.
splitsarrayNãoDivisão do valor com outros lojistas. Veja Split de pagamento.

Resposta 201

JSON
{
  "success": true,
  "data": {
    "transaction_uuid": "9d3f1c1e-6a2b-4d7e-9a51-2f0c8b7e4a10",
    "amount": 49.90,
    "fee": 1.50,
    "amount_net": 48.40,
    "status": "pending",
    "qr_code": "00020101021226870014br.gov.bcb.pix2565...6304ABCD",
    "pix_code": "00020101021226870014br.gov.bcb.pix2565...6304ABCD",
    "qr_code_base64": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...",
    "expires_at": "2026-10-01T14:35:00-03:00",
    "expires_in_seconds": 300,
    "settlement": "brl"
  }
}
CampoO que é
transaction_uuidIdentificador da cobrança. Guarde junto do pedido.
pix_code / qr_codePix copia e cola (texto EMV). Os dois campos têm o mesmo valor.
qr_code_base64Imagem do QR Code pronta (data URI SVG) para usar em <img src>.
expires_at / expires_in_secondsQuando a cobrança expira. Em geral 5 minutos (30 em USDT). Depois disso, crie outra.
fee / amount_netTaxa desta cobrança e o valor líquido que vai para o seu saldo.
A resposta da criação não confirma pagamento (o status é pending). Libere o pedido apenas com o webhook deposit.completed ou consultando o status completed.

Depósito na própria conta

Para colocar saldo na sua conta (você é o pagador), use POST /cashin/pix com amount (mínimo R$ 1,00). A resposta traz transaction.uuid e qr_code.

Receber

Cartão de crédito

Cobre no cartão em até 12x. A venda aprovada vira parcelas que entram no seu saldo nas datas de liquidação. Precisa estar liberado para a sua conta (sem liberação a resposta é 403).

Envie os dados do cartão só do seu servidor, por HTTPS. Nunca grave número completo nem CVV e não registre o corpo dessa requisição em log (regras PCI DSS). Nós também não guardamos.
POSThttps://app.elevapayments.live/api/v1/payments/credit-card

Corpo da requisição

CampoTipoObrigatórioDescrição
amountdecimalSimValor da compra (mínimo R$ 1,00).
installmentsintegerNãoParcelas, de 1 a 12 (limite da sua conta). Padrão 1.
card.numberstringSimNúmero do cartão (com ou sem espaços).
card.holderstringSimNome impresso no cartão.
card.expirationstringSimValidade MM/AAAA ou MM/AA.
card.cvvstringSimCódigo de segurança (3 ou 4 dígitos).
payer_namestringSimNome do comprador.
payer_cpfstringNãoCPF/CNPJ do comprador. Aumenta a aprovação.
payer_emailstringNãoE-mail do comprador (análise de risco).
payer_phonestringNãoTelefone do comprador.
billingobjectNãoEndereço de cobrança: zipcode, street, number, city, state (UF).
three_dsstringNão"none", "auto" ou "required". Com 3DS o risco de chargeback por fraude passa ao banco emissor.
return_urlstringNãoPara onde o cliente volta depois de autenticar no banco (use com 3DS).
descriptionstringNãoDescrição da venda.

Respostas

  • 201 approved: aprovada. Traz release_schedule com as parcelas e datas.
  • 202 requires_authentication: redirecione o cliente para authentication_url. Ele volta em return_url?transaction_uuid=...&status=approved|declined|pending. Confirme pelo webhook ou pela consulta, nunca só pela URL de volta.
  • 202 processing: a adquirente não respondeu a tempo. Consulte a transação em instantes.
  • 402 declined: recusada pelo banco. Mostre message e veja decline.retryable antes de tentar de novo.
cURL
curl -X POST "https://app.elevapayments.live/api/v1/payments/credit-card" \
  -H "Authorization: Bearer SEU_TOKEN" -H "X-Client-ID: SEU_CLIENT_ID" \
  -H "Content-Type: application/json" -H "Accept: application/json" \
  -d '{
    "amount": 250.00,
    "installments": 3,
    "card": { "number": "4111111111111111", "holder": "MARIA S SOUZA", "expiration": "12/2030", "cvv": "123" },
    "payer_name": "Maria Souza",
    "payer_cpf": "52998224725",
    "payer_email": "[email protected]",
    "three_ds": "auto",
    "return_url": "https://sualoja.com/pedido/4471"
  }'
JSON · 201
{
  "success": true,
  "data": {
    "transaction_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "status": "approved",
    "amount": 250.00, "fee": 18.50, "amount_net": 231.50,
    "installments": 3,
    "card": { "brand": "Visa", "last4": "1111" },
    "release_schedule": [
      { "installment": 1, "amount": 77.16, "date": "2026-11-01" },
      { "installment": 2, "amount": 77.16, "date": "2026-12-01" },
      { "installment": 3, "amount": 77.18, "date": "2026-12-31" }
    ]
  }
}

Estorno

POSThttps://app.elevapayments.live/api/v1/payments/{transaction_uuid}/refund

Corpo opcional { "amount": 50.00 } para estorno parcial; sem ele o estorno é total. A taxa da venda não volta. O valor sai primeiro das parcelas ainda não liberadas e depois do saldo. Resposta: refunded_amount, full e status. Também enviamos o webhook transaction.refunded.

Chargeback: se o cliente contestar a compra no banco, as parcelas futuras são canceladas, o que já foi liberado é debitado do saldo e você recebe transaction.chargeback.

Receber

Pix convertido em USDT

O cliente paga em Pix normalmente e você recebe USDT direto na sua carteira (BSC, Polygon ou Tron), assim que o Pix é confirmado.

  1. 1. Cadastre a carteira no painel em Cripto → Vendas Pix em USDT (pede PIN e 2FA). Carteira nova tem um período de segurança antes do primeiro envio.
  2. 2. Envie "settlement": "usdt" em POST /payments/pix (ou ligue o recebimento em USDT para todas as vendas no painel e use "brl" para exceções).
  3. 3. Pago o Pix, o valor líquido é convertido na cotação do momento. Valores abaixo do mínimo de envio acumulam e seguem junto com a próxima venda.
JSON · POST /payments/pix
{
  "amount": 500.00,
  "payer_name": "Joao Silva",
  "payer_email": "[email protected]",
  "payer_cpf": "52998224725",
  "settlement": "usdt"
}

Sem carteira cadastrada a resposta é 422. Na consulta GET /payments/{uuid}, o bloco settlement mostra status, amount_usdt, network e tx_hash. Webhooks: crypto_settlement.completed quando o USDT chega e crypto_settlement.failed se a conversão falhar (o valor fica em reais no seu saldo).

Receber

Split de pagamento

Divida uma cobrança Pix com outros lojistas cadastrados na Eleva Payments. Quando o Pix é pago, cada parceiro recebe o percentual dele e você fica com o restante.

JSON · POST /payments/pix
{
  "amount": 200.00,
  "payer_name": "Maria Souza",
  "payer_email": "[email protected]",
  "payer_cpf": "52998224725",
  "splits": [
    { "email": "[email protected]", "percentage": 10 },
    { "email": "[email protected]", "percentage": 5.5 }
  ]
}
  • • email precisa ser de uma conta existente na plataforma; cada e-mail só uma vez.
  • • percentage de 0,01 a 100; a soma não pode passar de 100%.
  • • Formato antigo para um único parceiro continua aceito: split_email + split_percentage.
  • • Erros de split voltam como 422 no campo splits.

Receber

Consultar e listar

Consultar uma cobrança pendente também confere o status na adquirente na hora, então serve como alternativa (ou reforço) ao webhook.

Uma cobrança

GEThttps://app.elevapayments.live/api/v1/payments/{transaction_uuid}
cURL
curl "https://app.elevapayments.live/api/v1/payments/9d3f1c1e-6a2b-4d7e-9a51-2f0c8b7e4a10" \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "X-Client-ID: SEU_CLIENT_ID" \
  -H "Accept: application/json"
JSON · 200
{
  "success": true,
  "data": {
    "uuid": "9d3f1c1e-6a2b-4d7e-9a51-2f0c8b7e4a10",
    "amount": "49.90",
    "fee": "1.50",
    "amount_net": "48.40",
    "type": "pix",
    "status": "completed",
    "created_at": "2026-10-01T17:30:00.000000Z",
    "updated_at": "2026-10-01T17:31:12.000000Z"
  }
}

Vendas no cartão trazem também card (bandeira, final, parcelas, valor estornado) e release_schedule. Vendas em USDT trazem settlement. Existe também GET /transactions/{uuid}, com os mesmos campos da listagem.

Listar transações

GEThttps://app.elevapayments.live/api/v1/transactions?status=completed&start_date=2026-10-01&per_page=50
CampoTipoObrigatórioDescrição
statusstringNãoFiltra por status (veja Status).
typestringNão"pix" ou "credit" (cartão).
start_date / end_datedateNãoPeríodo pela data de criação (AAAA-MM-DD).
pageintegerNãoPágina (padrão 1).
per_pageintegerNãoItens por página, 1 a 100 (padrão 20).
JSON · 200
{
  "success": true,
  "data": [
    {
      "uuid": "9d3f1c1e-6a2b-4d7e-9a51-2f0c8b7e4a10",
      "amount": 49.9, "amount_gross": 49.9, "amount_net": 48.4, "fee": 1.5,
      "type": "pix", "status": "completed", "payment_method": "pix", "settlement": "brl",
      "description": "Pedido #1042",
      "payer": { "name": "Maria Souza", "email": "[email protected]", "document": "52998224725" },
      "created_at": "2026-10-01T17:30:00-03:00", "paid_at": "2026-10-01T17:31:12-03:00"
    }
  ],
  "pagination": { "current_page": 1, "last_page": 4, "per_page": 20, "total": 71 }
}

Pagar

Saque via Pix

Transfere o seu saldo para uma chave Pix. Você informa quanto quer que chegue; a taxa é somada e debitada do saldo.

POSThttps://app.elevapayments.live/api/v1/cashout/pix
CampoTipoObrigatórioDescrição
amountdecimalSimValor líquido que deve chegar na chave (mínimo R$ 20,00).
pix_keystringSimChave Pix de destino: CPF, CNPJ, e-mail, telefone (+55...) ou aleatória.
cURL
curl -X POST "https://app.elevapayments.live/api/v1/cashout/pix" \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "X-Client-ID: SEU_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "amount": 150.00, "pix_key": "[email protected]" }'
JSON · 200
{
  "success": true,
  "message": "Saque criado com sucesso. Aguardando aprovação manual.",
  "withdrawal": {
    "id": 3187,
    "amount": 150.00,
    "amount_gross": 152.50,
    "fee": 2.50,
    "status": "pending",
    "pix_key": "[email protected]"
  }
}

Manual ou automático

Cada credencial tem um modo de saque. No manual o saque fica pending até a aprovação da equipe. No automático ele é enviado na hora, desde que a chamada venha de um IP cadastrado na credencial e com o header X-Client-ID.

Segurança

Chamadas de saque feitas por ferramentas de teste (Postman, Insomnia, Thunder Client) são recusadas com 403: faça do seu servidor. Saldo insuficiente volta como 400 com o valor necessário. Acompanhe o resultado pelos webhooks withdrawal.completed e withdrawal.failed.

Notificações

Webhooks

Enviamos um POST em JSON para a URL cadastrada na credencial sempre que algo acontece. Cada credencial ativa com URL recebe os eventos da conta.

Requisitos da URL

HTTPS em domínio público (porta 443 ou 8443). Redirecionamentos não são seguidos.

Resposta

Responda qualquer 2xx em até 10 segundos. Processe o evento depois (fila).

Reenvio

Se o seu servidor não responder ou devolver 5xx, tentamos de novo a cada 1 minuto, até 3 tentativas. Respostas 4xx não são reenviadas.

Requisição enviada

HTTP
POST /seu-endpoint HTTP/1.1
Content-Type: application/json
User-Agent: Eleva Payments-Webhook/1.0
X-Webhook-Id: 1b4e28ba-2fa1-4d3b-a3f5-ef19b5a7633b
X-Webhook-Event: deposit.completed
X-Webhook-Timestamp: 1790871072
X-Webhook-Signature-V2: t=1790871072,v1=5f2b0c9e...a41
X-Webhook-Signature: 8c1d2e3f...9b0

{
  "id": "1b4e28ba-2fa1-4d3b-a3f5-ef19b5a7633b",
  "event": "deposit.completed",
  "data": {
    "transaction_uuid": "9d3f1c1e-6a2b-4d7e-9a51-2f0c8b7e4a10",
    "status": "completed",
    "type": "pix",
    "payment_method": "pix",
    "amount": 49.9,
    "amount_gross": 49.9,
    "amount_net": 48.4,
    "fee": 1.5,
    "settlement": "brl",
    "description": "Pedido #1042",
    "payer": { "name": "Maria Souza", "email": "[email protected]", "document": "52998224725" },
    "created_at": "2026-10-01T14:30:00-03:00",
    "paid_at": "2026-10-01T14:31:12-03:00"
  },
  "created_at": "2026-10-01T14:31:12-03:00"
}

Headers

HeaderConteúdo
X-Webhook-IdID único do evento (o mesmo do campo "id"). Igual em todas as tentativas: use para não processar duas vezes.
X-Webhook-EventNome do evento, ex.: deposit.completed.
X-Webhook-TimestampMomento do envio (Unix, segundos).
X-Webhook-Signature-V2t={timestamp},v1={HMAC-SHA256 de "timestamp.corpo"}. Recomendado.
X-Webhook-SignatureHMAC-SHA256 do corpo (formato antigo, mantido por compatibilidade).

Eventos

EventoQuandoPrincipais campos em data
deposit.completed Cobrança paga (Pix ou cartão aprovado). É o evento para liberar o pedido. transaction_uuid, status, amount, amount_net, fee, payment_method, settlement, payer, paid_at
transaction.waiting_payment A adquirente informou que a cobrança aguarda pagamento. transaction_uuid, status, amount
transaction.failed Cobrança expirou, foi cancelada ou recusada. transaction_uuid, status, reason
transaction.refunded Venda no cartão estornada (total ou parcial). transaction_uuid, refund_amount, full_refund, refunded_amount
transaction.chargeback Pagador contestou (MED no Pix / chargeback no cartão). transaction_uuid, chargeback_amount
transaction.completed Status alterado para pago manualmente pela equipe (raro). Trate igual a deposit.completed. transaction_uuid, status, amount_net
withdrawal.pending Saque criado, aguardando processamento. withdrawal_id, amount, status
withdrawal.completed Saque pago. withdrawal_id, amount, status
withdrawal.failed Saque recusado/falhou; o valor voltou ao saldo. withdrawal_id, status, amount, refunded_to_balance
pix_payment.pending Pagamento Pix para terceiros criado (pode ir para análise). payment_id, amount, status
pix_payment.completed Pagamento Pix para terceiros confirmado. payment_id, amount, recipient_name
pix_payment.failed Pagamento Pix para terceiros falhou; valor devolvido. withdrawal_id, status, refunded_to_balance
crypto_settlement.completed USDT entregue na sua carteira. conversion_id, amount_brl, amount_crypto, network, tx_hash
crypto_settlement.failed Conversão em USDT falhou; o valor ficou em reais no saldo. withdrawal_id, status, refunded_to_balance
checkout.order_paid Pedido do checkout próprio pago (produto digital entregue). order_id, product_id, amount, method, buyer, transaction_uuid

Eventos de cobrança (deposit.*, transaction.*) trazem sempre o bloco completo da transação: transaction_uuid, status, type, payment_method, amount, amount_net, fee, settlement, description, payer, card (no cartão), created_at, paid_at. Novos campos podem ser acrescentados a qualquer momento: ignore os que não conhecer.

Boas práticas

  • • Valide a assinatura antes de qualquer coisa.
  • • Guarde o id dos eventos processados: o mesmo evento pode chegar mais de uma vez.
  • • A ordem de chegada não é garantida. Em caso de dúvida, consulte GET /payments/{uuid}: a consulta é a fonte da verdade.
  • • Confira o valor (amount) com o do seu pedido antes de liberar.

Notificações

Validar a assinatura

A assinatura prova que o webhook saiu da Eleva Payments e não foi alterado. O segredo é o token da credencial.

  1. 1. Leia o corpo cru da requisição (antes de converter o JSON; qualquer espaço diferente muda a assinatura).
  2. 2. Separe t e v1 do header X-Webhook-Signature-V2.
  3. 3. Calcule HMAC-SHA256(token, t + "." + corpo) em hexadecimal e compare com v1 em tempo constante.
  4. 4. Recuse se t tiver mais de 5 minutos de diferença do seu relógio (protege contra reenvio de mensagens antigas).
PHP
<?php
// Laravel: Route::post('/webhooks/eleva', [ElevaWebhookController::class, '__invoke']);
// PHP puro: use file_get_contents('php://input') como $body e $_SERVER['HTTP_X_WEBHOOK_SIGNATURE_V2'].

$secret = getenv('ELEVA_API_TOKEN');           // o mesmo token usado na API
$body   = file_get_contents('php://input');   // corpo CRU, antes de qualquer json_decode
$header = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE_V2'] ?? '';

parse_str(str_replace(',', '&', $header), $sig); // ['t' => '...', 'v1' => '...']
$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, $secret);

if (empty($sig['v1']) || !hash_equals($expected, $sig['v1']) || abs(time() - (int) $sig['t']) > 300) {
    http_response_code(401);
    exit('assinatura inválida');
}

$event = json_decode($body, true);

// Idempotência: o mesmo evento pode chegar mais de uma vez.
if (jaProcessado($event['id'])) { http_response_code(200); exit; }

if ($event['event'] === 'deposit.completed') {
    liberarPedido($event['data']['transaction_uuid'], $event['data']['amount']);
}

marcarProcessado($event['id']);
http_response_code(200);
Node.js
// Node.js + Express: use o corpo CRU (express.raw), não o JSON já convertido.
const crypto = require('crypto');
const express = require('express');
const app = express();

app.post('/webhooks/eleva', express.raw({ type: 'application/json' }), (req, res) => {
  const secret = process.env.ELEVA_API_TOKEN;
  const body = req.body.toString('utf8');
  const header = req.get('X-Webhook-Signature-V2') || '';
  const sig = Object.fromEntries(header.split(',').map(p => p.split('=')));

  const expected = crypto.createHmac('sha256', secret).update(`${sig.t}.${body}`).digest('hex');
  const valid = sig.v1 && sig.v1.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig.v1), Buffer.from(expected));

  if (!valid || Math.abs(Date.now() / 1000 - Number(sig.t)) > 300) {
    return res.status(401).send('assinatura inválida');
  }

  const event = JSON.parse(body);
  res.sendStatus(200); // responda rápido; processe em seguida (fila)

  if (event.event === 'deposit.completed') {
    liberarPedido(event.data.transaction_uuid, event.id);
  }
});
Python
# Python + Flask
import hmac, hashlib, json, os, time
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["ELEVA_API_TOKEN"].encode()

@app.post("/webhooks/eleva")
def eleva_webhook():
    body = request.get_data()  # bytes crus
    parts = dict(p.split("=", 1) for p in request.headers.get("X-Webhook-Signature-V2", "").split(",") if "=" in p)
    expected = hmac.new(SECRET, f"{parts.get('t', '')}.".encode() + body, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(expected, parts.get("v1", "")) or abs(time.time() - int(parts.get("t", 0))) > 300:
        abort(401)

    event = json.loads(body)
    if event["event"] == "deposit.completed":
        liberar_pedido(event["data"]["transaction_uuid"], event["id"])
    return "", 200

Integração antiga: X-Webhook-Signature = HMAC-SHA256(token, corpo). Continua sendo enviado, mas não protege contra reenvio; migre para a v2.

Referência

Status

Cobranças (Pix e cartão)

StatusSignificadoFinal?
pendingCobrança criada, aguardando o pagamento.Não
waiting_paymentAguardando pagamento (algumas adquirentes informam este estado).Não
processingCartão em conferência na adquirente (resposta sem confirmação). Consulte de novo em instantes.Não
completedPago. O valor líquido entrou (ou vai entrar, no cartão) no seu saldo.Sim
failedRecusado ou com falha na adquirente.Sim
cancelledExpirou sem pagamento ou foi cancelado.Sim
refundedEstornado integralmente.Sim
chargebackContestação do pagador (MED no Pix, chargeback no cartão).Sim
mediationEm análise de contestação.Não

Um Pix expirado (cancelled) que for pago mesmo assim é reaberto e passa para completed, com webhook deposit.completed. No cartão, a resposta usa approved/declined e a transação fica completed/failed.

Saques

StatusSignificado
pendingCriado e aguardando aprovação manual (modo manual) ou envio.
processingEnviado ao banco; aguardando confirmação.
paidPix enviado com sucesso.
rejectedRecusado (chave inválida, análise, adquirente). O valor volta ao saldo.
failedFalhou no envio. O valor volta ao saldo.
cancelledCancelado. O valor volta ao saldo.

Referência

Erros

Todo erro volta em JSON com success: false e uma message em português, que pode ser mostrada ao seu usuário.

JSON · 422 validação
{
  "success": false,
  "message": "O campo payer email deve ser um endereço de e-mail válido.",
  "errors": {
    "payer_email": ["O campo payer email deve ser um endereço de e-mail válido."]
  }
}
JSON · 401
{ "success": false, "message": "Credenciais de API inválidas ou expiradas" }
CódigoNomeO que fazer
200OKConsulta ou ação concluída.
201CreatedCobrança criada (Pix) ou cartão aprovado.
202AcceptedCartão aguardando autenticação 3DS ou em conferência. Não é aprovação.
400Bad RequestOperação não pôde ser feita (saldo insuficiente, adquirente indisponível).
401UnauthorizedToken ausente, inválido ou expirado.
402Payment RequiredCartão recusado pelo banco emissor.
403ForbiddenConta bloqueada, KYC pendente, IP fora da lista ou recurso não liberado.
404Not FoundTransação não existe ou não pertence a esta conta.
422Unprocessable EntityCampos inválidos. O corpo traz "errors" por campo.
429Too Many RequestsMais de 120 requisições por minuto neste token. Respeite o header Retry-After.
500Server ErrorErro interno ou da adquirente. Consulte a transação antes de tentar de novo.

Quando tentar de novo

Pode repetir: 429 (depois do Retry-After), 500 e erros de rede, com espera crescente (2s, 4s, 8s). Na criação de cobrança, consulte antes para não duplicar. Não repita sem corrigir: 400, 401, 403, 404, 422 e 402.

Referência

Exemplos completos

Cliente pronto para criar um Pix e consultar o status. Copie, ajuste as variáveis de ambiente e rode.

PHP
<?php
// Cliente mínimo em PHP (cURL nativo). Guarde token e client id em variáveis de ambiente.
final class ElevaClient
{
    public function __construct(
        private string $token,
        private string $clientId,
        private string $baseUrl = 'https://app.elevapayments.live/api/v1',
    ) {}

    public function request(string $method, string $path, ?array $body = null): array
    {
        $ch = curl_init($this->baseUrl . $path);
        curl_setopt_array($ch, [
            CURLOPT_CUSTOMREQUEST  => $method,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_HTTPHEADER     => [
                'Authorization: Bearer ' . $this->token,
                'X-Client-ID: ' . $this->clientId,
                'Content-Type: application/json',
                'Accept: application/json',
            ],
            CURLOPT_POSTFIELDS     => $body ? json_encode($body) : null,
        ]);
        $raw = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $json = json_decode((string) $raw, true) ?? [];
        if ($status >= 400 && $status !== 402) {
            throw new RuntimeException($json['message'] ?? "Erro HTTP $status", $status);
        }
        return $json;
    }

    public function createPix(float $amount, string $name, string $email, string $cpf, string $description = ''): array
    {
        return $this->request('POST', '/payments/pix', [
            'amount' => round($amount, 2),
            'payer_name' => $name,
            'payer_email' => $email,
            'payer_cpf' => preg_replace('/\D/', '', $cpf),
            'description' => $description,
        ])['data'];
    }

    public function payment(string $uuid): array
    {
        return $this->request('GET', '/payments/' . $uuid)['data'];
    }
}

$eleva = new ElevaClient(getenv('ELEVA_API_TOKEN'), getenv('ELEVA_CLIENT_ID'));
$pix = $eleva->createPix(49.90, 'Maria Souza', '[email protected]', '529.982.247-25', 'Pedido #1042');
// Salve $pix['transaction_uuid'] junto do pedido e mostre $pix['qr_code_base64'] / $pix['pix_code'].
Node.js
// Node.js 18+ (fetch nativo)
const BASE = 'https://app.elevapayments.live/api/v1';
const headers = {
  Authorization: `Bearer ${process.env.ELEVA_API_TOKEN}`,
  'X-Client-ID': process.env.ELEVA_CLIENT_ID,
  'Content-Type': 'application/json',
  Accept: 'application/json',
};

async function eleva(method, path, body) {
  const res = await fetch(BASE + path, { method, headers, body: body ? JSON.stringify(body) : undefined });
  const json = await res.json().catch(() => ({}));
  if (!res.ok && res.status !== 402) {
    const err = new Error(json.message || `HTTP ${res.status}`);
    err.status = res.status; err.errors = json.errors;
    throw err;
  }
  return json;
}

const { data: pix } = await eleva('POST', '/payments/pix', {
  amount: 49.90,
  payer_name: 'Maria Souza',
  payer_email: '[email protected]',
  payer_cpf: '52998224725',
  description: 'Pedido #1042',
});
console.log(pix.transaction_uuid, pix.pix_code);

const { data: status } = await eleva('GET', `/payments/${pix.transaction_uuid}`);
console.log(status.status); // pending | completed | cancelled ...
Python
# Python 3 + requests
import os, requests

BASE = "https://app.elevapayments.live/api/v1"
session = requests.Session()
session.headers.update({
    "Authorization": f"Bearer {os.environ['ELEVA_API_TOKEN']}",
    "X-Client-ID": os.environ["ELEVA_CLIENT_ID"],
    "Accept": "application/json",
})

def eleva(method, path, **kwargs):
    r = session.request(method, BASE + path, timeout=30, **kwargs)
    data = r.json() if r.content else {}
    if r.status_code >= 400 and r.status_code != 402:
        raise RuntimeError(f"{r.status_code}: {data.get('message')} {data.get('errors', '')}")
    return data

pix = eleva("POST", "/payments/pix", json={
    "amount": 49.90,
    "payer_name": "Maria Souza",
    "payer_email": "[email protected]",
    "payer_cpf": "52998224725",
    "description": "Pedido #1042",
})["data"]
print(pix["transaction_uuid"], pix["pix_code"])

print(eleva("GET", f"/payments/{pix['transaction_uuid']}")["data"]["status"])
cURL · criar Pix
curl -X POST "https://app.elevapayments.live/api/v1/payments/pix" \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "X-Client-ID: SEU_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "amount": 49.90,
    "payer_name": "Maria Souza",
    "payer_email": "[email protected]",
    "payer_cpf": "52998224725",
    "description": "Pedido #1042"
  }'
cURL · consultar
curl "https://app.elevapayments.live/api/v1/payments/9d3f1c1e-6a2b-4d7e-9a51-2f0c8b7e4a10" \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "X-Client-ID: SEU_CLIENT_ID" \
  -H "Accept: application/json"
cURL · saque
curl -X POST "https://app.elevapayments.live/api/v1/cashout/pix" \
  -H "Authorization: Bearer SEU_TOKEN" \
  -H "X-Client-ID: SEU_CLIENT_ID" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "amount": 150.00, "pix_key": "[email protected]" }'

Para receber os avisos, veja o código de . Plataformas prontas (Shopify, WooCommerce) têm integração no painel, em Integrações.

Referência

Checklist de produção

Confira antes de abrir a integração para os seus clientes.

Pronto para integrar?

Crie sua conta, aprove o cadastro e gere sua chave de API no painel.

Criar conta