# WinnerPay — Documentação Completa da API (Markdown para IAs) > Este arquivo contém toda a documentação da API WinnerPay em Markdown puro para leitura por agentes de IA e LLMs. > Documentação interativa: https://documentacao.winnerpayments.com.br/ > Última atualização: 2025 --- ## Visão geral WinnerPay é um gateway de pagamentos PIX (subadquirente) que atua como camada intermediária entre o sistema do cliente e as adquirentes de pagamento. **Versão da API:** 2.0.0 ### Como funciona a integração 1. O sistema busca a adquirente ativa configurada no WinnerPay 2. Cria a transação internamente 3. Chama a API da adquirente ativa 4. Retorna os dados do QR Code para o checkout 5. Recebe notificações via webhook da adquirente 6. **Normaliza** os webhooks para um formato único e padronizado 7. Envia o webhook normalizado para o endpoint configurado pelo cliente 8. Atualiza o status da transação automaticamente > O cliente pode trocar de adquirente a qualquer momento **sem alterar seu código**. Todos os webhooks seguem o mesmo formato independente da adquirente. --- ## URL base ``` https://api.winnerpayments.com.br/api ``` **Ambiente:** produção e sandbox compartilham a mesma URL base. O ambiente é distinguido pela credencial (sandbox: `client_id` contém "test"; produção: aprovação KYC concluída, `is_sandbox: false`). --- ## Autenticação A integração via API usa **Client Credentials** (`client_id` e `client_secret`), gerados no painel WinnerPay em **API → Credenciais**. > ⚠️ Nunca exponha credenciais no client-side. Todas as chamadas devem partir do backend. ### Opção 1 — Authorization Basic (recomendado) ``` Authorization: Basic {base64(client_id:client_secret)} ``` ### Opção 2 — Headers separados ``` X-Client-Id: seu_client_id X-Client-Secret: seu_client_secret ``` ### Bearer Token (apenas endpoints do painel/dashboard) ``` Authorization: Bearer seu_jwt_token ``` --- ## Formato dos valores monetários | Endpoint | Formato | Exemplo | |----------|---------|---------| | `POST /financial/receber-pix` | Reais (float) | `150.00` | | `POST /financial/transferencia-pix` | Reais (float) | `100.50` | | `POST /transactions/split` | Centavos (integer) | `10000` (= R$ 100,00) | | Respostas de saldo (`GET /financial/balance`) | Reais (decimal) | `1250.75` | --- ## Sandbox Contas novas entram automaticamente em modo Sandbox até aprovação KYC. No sandbox nenhuma transação real é processada e webhooks são simulados localmente. ```json GET /api/auth/me { "kyc_status": "pending", "is_sandbox": true } ``` `kyc_status`: `pending` | `approved` | `rejected` `is_sandbox`: `true` até aprovação KYC; `false` em produção --- ## Endpoints ### POST /financial/receber-pix — Gerar QR Code PIX (Cash In) Gera um QR Code PIX para receber pagamentos. **Campos obrigatórios:** | Campo | Tipo | Descrição | |-------|------|-----------| | `amount` | float | Valor em reais (ex.: `150.00`). Mínimo: R$ 0,01 | | `description` | string | Descrição da cobrança | | `postbackUrl` | string (URI) | URL HTTPS do servidor para receber webhooks | **Campos opcionais:** | Campo | Tipo | Descrição | |-------|------|-----------| | `include_qr_image` | boolean | Se `true`, retorna `qr_code_image` (PNG Base64 puro) e `qr_code_image_mime` | | `metadata.order_id` | string | ID do pedido interno | | `metadata.product.name` | string | Nome do produto (aparece na coluna "Produto" do painel) | | `product_name` | string | Atalho para nome do produto | | `product` | string ou object | Atalho alternativo | | `customer.name` | string | Nome do pagador | | `customer.email` | string | E-mail do pagador | | `customer.document` | object | `{ "type": "CPF", "number": "12345678900" }` | **Exemplo de request:** ```json { "amount": 150.00, "description": "Pagamento do Plano Premium", "postbackUrl": "https://meu-servidor.com/webhook/winnerpay", "include_qr_image": true, "metadata": { "order_id": "ORD-12345", "product": { "name": "Plano Premium" } }, "customer": { "name": "João Silva", "email": "joao@email.com", "document": { "type": "CPF", "number": "12345678900" } } } ``` **Response 200:** ```json { "success": true, "message": "QR Code PIX gerado com sucesso", "transaction": { "id": 1, "transaction_id": "TXN_1697123456_XYZ98765", "type": "receber_pix", "status": "pending", "amount": 150.00, "fee": 0.00, "pix_key": "contato@winnerpay.com.br" }, "qr_code_data": "00020101021226820014br.gov.bcb.pix...", "pix_copia_e_cola": "00020101021226820014br.gov.bcb.pix...", "qr_code_image": "iVBORw0KGgoAAAANSUhEUgAA...", "qr_code_image_mime": "image/png", "acquirer": "PIX UP" } ``` > `qr_code_image` é PNG Base64 puro (sem prefixo `data:`). Para exibir: `` > QR Code expira em 30 minutos. Gere cobrança e imagem **somente no backend**. --- ### GET /financial/transactions — Listar transações Consulta histórico paginado de todas as transações da conta. **Query params:** `page` (default 1), `per_page` (default 15) **Response 200:** ```json { "success": true, "transactions": { "current_page": 1, "data": [ { "id": 1, "transaction_id": "TXN_...", "type": "receber_pix", "status": "pending", "amount": 150.00, "product_name": "Plano Premium" } ], "total": 50, "per_page": 15, "last_page": 4 } } ``` --- ### GET /dashboard/transactions/{transactionId} — Consultar transação Retorna detalhes de uma transação pelo `transaction_id` (ex.: `TXN_...`) ou pelo `id` numérico interno. A transação retornada é **sempre da conta autenticada**. Se pertencer a outro lojista: 403. **Response 200:** ```json { "success": true, "transaction": { "transactionId": "TXN_1697123456_XYZ98765", "type": "receber_pix", "status": "paid", "amount": 150.00, "fee": 4.50 } } ``` **Response 403:** `{ "success": false, "message": "Acesso negado" }` **Response 404:** `{ "success": false, "message": "Transação não encontrada" }` --- ### POST /financial/estornar/{transactionId} — Estornar transação Apenas transações com status `paid` ou `completed` podem ser estornadas. Transferências PIX **não** podem ser estornadas. **Response 200:** ```json { "success": true, "message": "Transação estornada com sucesso", "transaction": { "transaction_id": "TXN_1697123456_ABC12345", "status": "refunded", "amount": 100.50 } } ``` **Response 400:** ```json { "success": false, "message": "Apenas transações pagas/completas podem ser estornadas" } ``` --- ### GET /seller — Dados do Seller Retorna dados cadastrais da empresa vinculada às credenciais. **Response 200:** ```json { "success": true, "seller": { "id": 123, "company_name": "ACME LTDA", "document": { "type": "CNPJ", "number": "12345678000190" }, "email": "contato@acme.com.br", "status": "approved" } } ``` --- ### GET /financial/balance — Consultar saldo Retorna o saldo **somente da conta autenticada**. Não é possível consultar saldo de outro lojista. Valores em **reais** (decimal). **Response 200:** ```json { "success": true, "balance": { "availableBalance": 1250.75, "cautionaryBlock": 103.52, "receivedToday": 480.30 } } ``` | Campo | Descrição | |-------|-----------| | `availableBalance` | Saldo disponível para saque e operações | | `cautionaryBlock` | Valor reservado (ex.: saques pendentes) | | `receivedToday` | Total líquido recebido no dia (referência) | **Response 401:** `{ "statusCode": 401, "message": "Credenciais inválidas ou inexistentes" }` **Response 403:** `{ "statusCode": 403, "message": "Credencial não aprovada" }` --- ### POST /financial/transferencia-pix — Transferência PIX (Cash Out / Saque) Envia PIX para qualquer chave diretamente via API. **Campos obrigatórios:** | Campo | Tipo | Descrição | |-------|------|-----------| | `amount` | float | Valor em reais (ex.: `100.50`). Mínimo: R$ 0,01 | | `recipient_key` | string | Chave PIX do destinatário | **Campos opcionais:** | Campo | Tipo | Descrição | |-------|------|-----------| | `recipient_document` | string | CPF/CNPJ do destinatário | | `description` | string | Descrição | | `pix_key_type` | string | `email`, `cpf`, `cnpj`, `phone`, `random` | | `postbackUrl` | string (URI) | URL HTTPS para webhook `saque.processado` | **Exemplo:** ```json { "amount": 100.50, "recipient_key": "destino@email.com", "recipient_document": "12345678900", "description": "Pagamento de serviços", "pix_key_type": "email", "postbackUrl": "https://meu-servidor.com/webhook" } ``` **Response 200:** ```json { "success": true, "message": "Transferência PIX criada com sucesso", "transaction": { "transaction_id": "TXN_1697123456_ABC12345", "type": "transferencia_pix", "status": "pending", "amount": 100.50, "fee": 3.02, "total_amount": 103.52 } } ``` **Response 400 (saldo insuficiente):** ```json { "success": false, "message": "Saldo insuficiente para realizar o saque." } ``` > Taxa: **3%** sobre o valor enviado. Saldo deve cobrir valor + taxa. Transferências PIX são **irreversíveis**. > Chaves aceitas: CPF, CNPJ, Email, Telefone, Chave Aleatória. --- ### POST /transactions/split — Split Payment Cria cobrança PIX com divisão entre múltiplos recebedores. > Valor em **centavos** (integer). Mínimo: R$ 3,00 (300 centavos). A soma dos splits deve ser exatamente igual ao `amount`. **Exemplo:** ```json { "amount": 10000, "description": "Pedido Marketplace #123", "postbackUrl": "https://plataforma.com/webhooks/winnerpay", "splits": [ { "recipient": "chave_pix_vendedor", "amount": 9000 }, { "recipient": "chave_pix_plataforma", "amount": 1000 } ] } ``` **Response 200:** ```json { "success": true, "message": "QR Code PIX gerado com sucesso", "transaction": { "transaction_id": "TXN_1697123456_SPLIT01", "type": "receber_pix", "status": "pending", "amount": 100.00 } } ``` **Erros 400:** ```json { "statusCode": 400, "message": "A soma dos splits deve ser exatamente igual ao valor total da transação" } { "statusCode": 400, "message": "O valor mínimo para split payment é de R$ 3,00" } ``` --- ### GET /sales/my — Listar vendas **Query params:** `status` (all | paid | pending | refunded), `page`, `per_page` (default 10) **Response 200:** ```json { "success": true, "data": { "current_page": 1, "data": [ { "transaction_id": "TXN_...", "payer_name": "João Silva", "amount": 250.00, "status": "paid" } ], "total": 50 } } ``` --- ### GET /sales/stats — Estatísticas de vendas **Response 200:** ```json { "success": true, "data": { "total_transactions": 150, "total_processed": 37500.50, "total_fees": 1312.52, "average_ticket": 250.00 } } ``` --- ### GET /sales/entries-stats — Estatísticas de entradas **Response 200:** ```json { "success": true, "data": { "confirmed_payments": 145, "pending_payments": 5, "total_billing": 37500.50, "average_ticket": 258.62 } } ``` --- ## Status de transações ### Cash In (Receber PIX) | Status | Descrição | |--------|-----------| | `pending` | Aguardando pagamento | | `processing` | Em processamento | | `paid` | Pago (status em webhooks cash_in) | | `completed` | Completado (status em consultas via API) | | `refused` | Recusado / Negado | | `failed` | Falhou / Rejeitado | | `cancelled` | Cancelado | | `refunded` | Reembolsado | | `refund_pending` | Estorno em processo | > Em webhooks de pagamento recebido, o status será `paid`. Em consultas via API, pode aparecer como `completed`. Ambos representam pagamento confirmado. ### Cash Out (Transferência PIX / Saque) | Status | Descrição | Saldo do usuário | |--------|-----------|------------------| | `pending` | Saque criado, aguardando processamento | Valor + taxa **debitados** (reservados) | | `processing` | Em processamento na adquirente | Debitados | | `completed` | PIX enviado com sucesso | Debitados (finalizado) | | `failed` | Falhou na adquirente | **Estornado automaticamente** | | `cancelled` | Cancelado | **Estornado automaticamente** | | `refused` | Recusado | **Estornado automaticamente** | --- ## Webhooks Existem **duas formas** de receber notificações: 1. **`postbackUrl` na API** — informada ao criar uma transação. Válida apenas para aquela transação. 2. **Webhooks no painel** — configure em **API → Webhooks** no dashboard. URLs fixas que recebem todos os eventos selecionados. ### Configurar webhook no painel (passo a passo) 1. Acesse app.winnerpayments.com.br → API → Webhooks 2. Preencha a **URL de destino** (deve começar com `https://`) 3. Selecione os eventos desejados 4. Clique em **Criar Webhook** 5. Gere um **segredo de assinatura** na seção "Segurança — segredo de assinatura" 6. Copie o segredo imediatamente (exibido uma única vez) e salve em variável de ambiente ### Eventos — Webhooks configurados no painel | Evento | Quando dispara | |--------|----------------| | `payment.pending` | Cobrança criada / aguardando PIX | | `payment.approved` | PIX confirmado | | `payment.refused` | Falha ou recusa | | `payment.refunded` | Estorno aplicado | | `payment.chargeback` | Chargeback | | `saque.processado` | Transferência PIX/USDT concluída ou falha | ### Eventos — Via postbackUrl (por transação) | Evento | Quando dispara | |--------|----------------| | `transaction.created` | Transação criada | | `transaction.status.updated` | Status atualizado | | `transaction.completed` | Completada com sucesso | | `transaction.processing` | Em processamento | | `transaction.refused` | Recusada | | `transaction.failed` | Falhou | | `transaction.refunded` | Estornada | | `transaction.cancelled` | Cancelada | ### Payload — Pagamento recebido (cash_in) ```json { "event": "transaction.status.updated", "transaction_id": "TXN_1697123456_ABC12345", "external_id": "TXN_1697123456_ABC12345", "acquirer_transaction_id": "PIXUP123456789", "status": "paid", "previous_status": "pending", "amount": 150.00, "fee": 4.50, "total_amount": 154.50, "type": "cash_in", "payment_method": "PIX", "payer": { "name": "João Silva", "email": "joao@email.com", "document": "12345678900" }, "created_at": "2025-03-28T12:00:00.000Z", "updated_at": "2025-03-28T12:05:23.000Z" } ``` ### Payload — Saque concluído ```json { "event": "saque.processado", "transaction_id": "TXN_1697123456_XYZ98765", "status": "completed", "previous_status": "pending", "amount": 100.00, "fee": 3.00, "total_debited": 103.00, "type": "transferencia_pix", "recipient_key": "destinatario@email.com", "currency": "BRL", "timestamp": "2025-03-28T12:15:30.000Z" } ``` ### Payload — Saque falho (saldo estornado) ```json { "event": "saque.processado", "transaction_id": "TXN_1697123456_XYZ98765", "status": "failed", "previous_status": "pending", "amount": 100.00, "fee": 3.00, "total_debited": 103.00, "type": "transferencia_pix", "recipient_key": "destinatario@email.com", "failure_reason": "Saque falhou.", "currency": "BRL", "timestamp": "2025-03-28T12:20:00.000Z" } ``` ### Assinatura HMAC-SHA256 Todo webhook inclui o header **`X-WinnerPay-Signature`** com valor `sha256={hash}`. | Header | Exemplo | Descrição | |--------|---------|-----------| | `X-WinnerPay-Signature` | `sha256=a1b2c3...` | HMAC-SHA256 do body JSON | | `X-WinnerPay-Event` | `payment.approved` | Tipo do evento | A assinatura é calculada sobre o **body JSON exatamente como enviado**. **Validar em Node.js (Express):** ```javascript const crypto = require('crypto'); app.post('/webhook/winnerpay', express.json(), (req, res) => { const signature = req.headers['x-winnerpay-signature']; const secret = process.env.WINNERPAY_WEBHOOK_SECRET; const expected = 'sha256=' + crypto .createHmac('sha256', secret) .update(JSON.stringify(req.body)) .digest('hex'); if (expected !== signature) return res.status(401).send('Assinatura inválida'); // Processar evento console.log('Evento:', req.headers['x-winnerpay-event'], req.body); return res.status(200).send('OK'); }); ``` **Validar em PHP:** ```php function verifyWebhook(array $body, string $signature, string $secret): bool { $expected = 'sha256=' . hash_hmac('sha256', json_encode($body), $secret); return hash_equals($expected, $signature); } ``` ### Requisitos do endpoint de webhook - Método: **POST** - Content-Type: **application/json** - Resposta esperada: **HTTP 200–299** em alguns segundos - URL deve começar com **`https://`** (TLS obrigatório) - Rejeite requisições sem `X-WinnerPay-Signature` em produção ### Idempotência - O WinnerPay pode reenviar o mesmo webhook. Antes de processar, verifique se o `transaction_id` já foi processado no banco. - **Nunca confie apenas no webhook** — confirme o status consultando `GET /dashboard/transactions/{transactionId}` antes de liberar o produto/serviço. ### Gerenciar segredos de assinatura - Gere em: painel → API → Webhooks → "Segurança — segredo de assinatura" - O segredo é exibido **uma única vez** — copie imediatamente - Se houver mais de um segredo ativo, o WinnerPay usa o **mais recentemente atualizado** - Após "Renovar" o segredo, atualize a variável de ambiente no servidor antes de descartar o valor antigo - Nunca exponha o segredo no frontend, repositório público ou logs --- ## Códigos HTTP | Código | Status | Descrição | |--------|--------|-----------| | 200 | OK | Requisição bem-sucedida | | 201 | Created | Recurso criado com sucesso | | 400 | Bad Request | Parâmetro obrigatório ausente ou inválido | | 401 | Unauthorized | Token inválido ou não fornecido | | 403 | Forbidden | Sem permissão ou credencial bloqueada | | 404 | Not Found | Recurso não encontrado | | 422 | Unprocessable | Dados inválidos na validação | | 500 | Server Error | Erro interno no servidor | --- ## Taxas e limites | Operação | Taxa | Observação | |----------|------|------------| | Transferência PIX (cash-out) | **3%** | Sobre o valor enviado | | Receber PIX (cash-in) | Conforme contrato | Definido na aprovação KYC | ### Regras Cash In - Valor mínimo: **R$ 0,01** - Valor máximo: conforme limite da adquirente ativa - QR Code expira em **30 minutos** (padrão) - Liquidação: instantânea após confirmação - Cada `transaction_id` é único (idempotência) ### Regras Cash Out - Valor mínimo: **R$ 0,01** - Saldo deve cobrir valor + taxa (3%) - Transferências PIX são **irreversíveis** - Processamento: instantâneo após aprovação - Chaves aceitas: CPF, CNPJ, Email, Telefone, Chave Aleatória --- ## Segurança - `client_id` e `client_secret` SOMENTE no backend, em variável de ambiente - Nunca exponha credenciais no frontend, Git, logs ou repositório público - Use HTTPS em todas as chamadas e na URL do webhook - Valide HMAC-SHA256 em todo webhook antes de processar - Implemente idempotência com base no `transaction_id` - Logs: nunca registre `client_secret`, `X-WinnerPay-Signature` nem dados pessoais sensíveis - Implemente timeout (recomendado: 30s) e retry com backoff exponencial --- ## Variáveis de ambiente sugeridas ```env WINNERPAY_CLIENT_ID=seu_client_id_aqui WINNERPAY_CLIENT_SECRET=seu_client_secret_aqui WINNERPAY_WEBHOOK_SECRET=seu_segredo_hmac_aqui WINNERPAY_API_URL=https://api.winnerpayments.com.br/api ``` --- ## Links - Dashboard: https://app.winnerpayments.com.br/ - Documentação interativa: https://documentacao.winnerpayments.com.br/ - Esta documentação (Markdown): https://app.winnerpayments.com.br/llms.txt - OpenAPI YAML: https://documentacao.winnerpayments.com.br/openapi.yaml