# Autenticação (https://docs.weetpay.com/docs/authentication) Client ID e client secret nos cabeçalhos de cada requisição. Toda chamada à API leva as credenciais geradas em **Desenvolvedores** no painel. Não existe token de sessão nem etapa de login: cada requisição é autenticada sozinha, sempre por HTTPS. ## Formatos aceitos [#formatos-aceitos] Use **um** dos três formatos (são equivalentes): ```http vspi: weetpay-100123 vsps: 3f1c9a52-7b0e-4d61-9a8c-2e5f4b7d1a90 ``` Mesmos nomes da API de gateway compatível: quem migra não precisa mudar código, só a URL e as chaves. ```http x-client-id: weetpay-100123 x-client-secret: 3f1c9a52-7b0e-4d61-9a8c-2e5f4b7d1a90 ``` ```http Authorization: Basic d2VldHBheS0xMDAxMjM6M2YxYzlhNTItN2IwZS00ZDYxLTlhOGMtMmU1ZjRiN2QxYTkw ``` O valor é `base64(":")`. ## Exemplos [#exemplos] ```bash curl https://api.weetpay.com/api/v1/gateway/walletBalance \ -H "vspi: $WEETPAY_CLIENT_ID" \ -H "vsps: $WEETPAY_CLIENT_SECRET" ``` ```js const res = await fetch('https://api.weetpay.com/api/v1/gateway/walletBalance', { headers: { vspi: process.env.WEETPAY_CLIENT_ID, vsps: process.env.WEETPAY_CLIENT_SECRET }, }); console.log(await res.json()); // { currentBalance: "397.70" } ``` ```php true, CURLOPT_HTTPHEADER => ['vspi: ' . getenv('WEETPAY_CLIENT_ID'), 'vsps: ' . getenv('WEETPAY_CLIENT_SECRET')], ]); var_dump(json_decode(curl_exec($ch), true)); ``` ```python import os, requests r = requests.get( "https://api.weetpay.com/api/v1/gateway/walletBalance", headers={"vspi": os.environ["WEETPAY_CLIENT_ID"], "vsps": os.environ["WEETPAY_CLIENT_SECRET"]}, timeout=15, ) print(r.json()) ``` ## Respostas de autenticação [#respostas-de-autenticação] | HTTP | `message` | `code` | O que fazer | | ----- | -------------------------------------------------------------- | ----------------- | --------------------------------------------------------------- | | `401` | Credenciais ausentes | — | envie o client ID e o client secret | | `401` | Credenciais inválidas | — | confira as chaves; o secret pode ter sido atualizado no painel | | `403` | Verificação de identidade pendente | `KYC_REQUIRED` | conclua a verificação no painel | | `403` | Conta bloqueada. Fale com o suporte. | `ACCOUNT_BLOCKED` | fale com o suporte | | `429` | Limite de requisições por minuto atingido | `RATE_LIMITED` | espere e tente de novo ([limites](/docs/limits-and-rules)) | | `429` | Muitas tentativas com credenciais inválidas. Tente mais tarde. | `RATE_LIMITED` | o IP errou credenciais demais; corrija e aguarde alguns minutos | ## Boas práticas [#boas-práticas] O client secret dá acesso ao seu saldo. **Nunca** o coloque em aplicativo, site (JavaScript no navegador) ou repositório. Chame a API só do seu servidor. * Guarde as chaves em variáveis de ambiente ou num cofre de segredos. * Se suspeitar de vazamento, use **Atualizar credenciais** em Desenvolvedores: o secret antigo para de funcionar na hora (o client ID continua o mesmo). * Deixe o **saque pela API** desligado se você só recebe pagamentos — assim, mesmo com as chaves vazadas, ninguém tira dinheiro da conta. * O client secret também assina os callbacks das suas transações: atualizá-lo muda a chave de validação ([Callbacks](/docs/webhooks)). # Erros (https://docs.weetpay.com/docs/errors) Formato único de erro, códigos HTTP e mensagens mais comuns. Todo erro da API tem o mesmo formato: ```json { "response": "ERROR", "message": "amount inválido (em reais, ex.: 10.50)" } ``` Alguns erros de autenticação trazem também `code` (`RATE_LIMITED`, `ACCOUNT_BLOCKED`, `KYC_REQUIRED`). `message` é em português e pronta para log; para decidir o que fazer no código, use o **status HTTP** (e o `code`, quando houver). ## Status HTTP [#status-http] | HTTP | Significado | Repetir? | | --------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | `200` | sucesso | — | | `400` | dados inválidos ou regra de negócio (saldo, limite, `requestNumber` repetido) | não, corrija o pedido | | `401` | credenciais ausentes ou inválidas | não | | `403` | conta bloqueada, KYC pendente ou operação não liberada | não | | `404` | transação ou endpoint não encontrado | não | | `409` | chave de idempotência reutilizada com outro pedido | não | | `429` | limite de requisições | sim, com espera | | `500` / `502` / `503` | falha temporária | sim, com espera crescente — em saques, **sempre com a mesma `Idempotency-Key`** | ## Mensagens comuns [#mensagens-comuns] ### Cobranças [#cobranças] | `message` | Causa | | ---------------------------------------------------------------- | -------------------------------------------------------- | | `requestNumber é obrigatório` | campo ausente ou vazio | | `requestNumber já utilizado` | já existe uma cobrança com esse `requestNumber` na conta | | `amount inválido (em reais, ex.: 10.50)` | zero, negativo, não numérico ou com mais de 2 casas | | `client.name é obrigatório` | nome com menos de 3 caracteres | | `client.document inválido (CPF ou CNPJ)` | dígitos verificadores não conferem | | `client.email inválido` | e-mail mal formatado | | `callbackUrl inválida` | não é http(s) ou passa de 500 caracteres | | `Split não está liberado nesta conta. Fale com o suporte.` (403) | `split` sem liberação do Compliance | | `split.account inválida para split` | conta de destino inexistente, inativa ou a própria conta | | `split.percentageSplit deve ser um inteiro entre 1 e 100` | percentual fora da faixa | Valores abaixo do mínimo ou acima do máximo de cobrança da plataforma também voltam como `400`, com o limite na mensagem. ### Saques [#saques] | `message` | Causa | | ------------------------------------------------------------------------------- | ----------------------------------------------- | | `Saque pela API não está liberado nesta conta. Ative em Desenvolvedores.` (403) | ligue o saque pela API no painel | | `typeKey inválido (use CPF, CNPJ, EMAIL, PHONE ou EVP)` | tipo de chave desconhecido | | `key inválida para o typeKey informado` | chave não corresponde ao tipo | | `document deve ser o mesmo CPF/CNPJ da chave` | chave CPF/CNPJ com `document` diferente | | `Saque só para a chave CPF/CNPJ do titular da conta…` (403) | conta sem liberação para pagar terceiros | | `insufficient balance` | saldo menor que valor + tarifa de saque | | `O valor mínimo para saque é …` / `O valor máximo por saque é …` | fora dos limites por saque | | `Limite diário de saque atingido…` | soma das últimas 24 h passaria do limite diário | | `Esta chave de idempotência já foi usada em outro saque` (409) | mesma `Idempotency-Key` com outro valor/chave | | `Pagamento de PIX copia e cola (QRCODE) ainda não está disponível` | `typeKey: "QRCODE"` não é suportado | ### Consulta [#consulta] | `message` | Causa | | -------------------------------------------------- | -------------------------------------------- | | `Informe requestNumber, idTransaction ou endToEnd` | corpo sem nenhum identificador | | `Transação não encontrada` (404) | não existe na sua conta | | `Endpoint não encontrado` (404) | caminho errado (confira `/api/v1/gateway/…`) | # Início rápido (https://docs.weetpay.com/docs/getting-started) Da criação da conta à primeira cobrança paga, em cinco passos. ### Crie e verifique sua conta [#crie-e-verifique-sua-conta] Cadastre-se em [app.weetpay.com](https://app.weetpay.com) e envie os documentos da verificação de identidade. **A API só funciona depois da aprovação** — antes disso toda chamada responde `403` com `code: "KYC_REQUIRED"`. ### Gere as credenciais [#gere-as-credenciais] No painel, abra **Desenvolvedores** e revele as chaves com o seu PIN de transação. Você recebe: * **Client ID** — `weetpay-`, fixo para sempre; * **Client secret** — um UUID. Guarde num cofre de segredos; **Atualizar credenciais** gera um novo e invalida o anterior na hora. ### Gere uma cobrança [#gere-uma-cobrança] ```bash curl -X POST https://api.weetpay.com/api/v1/gateway/request-qrcode \ -H "Content-Type: application/json" \ -H "vspi: $WEETPAY_CLIENT_ID" \ -H "vsps: $WEETPAY_CLIENT_SECRET" \ -d '{ "requestNumber": "pedido-12345", "amount": 49.90, "callbackUrl": "https://sualoja.com.br/webhooks/weetpay", "client": { "name": "Maria da Silva", "document": "12345678909", "email": "maria@email.com" } }' ``` A resposta traz o PIX copia e cola (`paymentCode`) e a imagem do QR Code (`paymentCodeBase64`): ```json { "idTransaction": "cmh1x2y3z0001ab12cd34ef56", "paymentCode": "00020101021226850014br.gov.bcb.pix…", "paymentCodeBase64": "iVBORw0KGgoAAAANSUhEUgAA…", "response": "OK", "status": "WAITING_FOR_APPROVAL" } ``` Mostre ao cliente a imagem `data:image/png;base64,{paymentCodeBase64}` e um botão "copiar" com o `paymentCode`. ### Receba o aviso de pagamento [#receba-o-aviso-de-pagamento] Quando o PIX for pago, a WeetPay faz um `POST` no `callbackUrl`: ```json { "requestNumber": "pedido-12345", "statusTransaction": "PAID_OUT", "idTransaction": "cmh1x2y3z0001ab12cd34ef56", "typeTransaction": "PIX", "value": 49.9, "debtorName": "MARIA DA SILVA", "debtorDocument": "12345678909", "date": "2026-10-30T13:03:40.000Z", "endToEnd": "E18236120202610301303s0123456789" } ``` Confira a assinatura `X-WeetPay-Signature`, libere o pedido e responda `200`. Detalhes em [Callbacks e webhooks](/docs/webhooks). ### Confira quando quiser [#confira-quando-quiser] Use [Consultar transação](/docs/transactions/get-transaction) para checar o status a qualquer momento (por exemplo, quando o cliente volta para a página do pedido) e [Consultar saldo](/docs/account/balance) para ver quanto está disponível. ## Clientes de referência [#clientes-de-referência] Prontos para copiar, sem dependências: * [weetpay-client.mjs](/examples/weetpay-client.mjs) — Node.js 18+ (`fetch` nativo), com validação de callback; * [weetpay-client.php](/examples/weetpay-client.php) — PHP 7.4+ com cURL, com validação de callback. ```js import { weetpay } from './weetpay-client.mjs'; const { status, data } = await weetpay('POST', '/api/v1/gateway/request-qrcode', { requestNumber: 'pedido-12345', amount: 49.9, client: { name: 'Maria da Silva', document: '12345678909' }, }); ``` # Idempotência (https://docs.weetpay.com/docs/idempotency) Repita requisições com segurança — uma cobrança ou um saque nunca são criados duas vezes. Falhas de rede acontecem: o pedido chega à WeetPay, mas a resposta se perde. A API foi feita para que você possa **repetir a mesma requisição sem medo**. ## Saques (`pix-payment`) [#saques-pix-payment] Envie uma chave única por saque — de preferência o ID do pagamento no seu sistema: ```http POST /api/v1/gateway/pix-payment Idempotency-Key: saque-2026-10-30-0001 ``` Também é aceito o cabeçalho `x-idempotency-key` ou, sem cabeçalho, o campo `requestNumber` do corpo. | Situação | Resultado | | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | primeira vez | saque criado, `200 { id, status: "processing" }` | | mesma chave, mesmo valor e mesma chave PIX | **o mesmo saque** — `200` com o mesmo `id` e o cabeçalho `Idempotent-Replayed: true`. Nada é debitado de novo | | mesma chave, outro valor ou outra chave PIX | `409` — "Esta chave de idempotência já foi usada em outro saque" | | sem chave nenhuma | o mesmo valor para a mesma chave PIX em menos de **1 minuto** devolve o saque anterior | A chave vale para sempre na sua conta (não expira) e tem no máximo 100 caracteres. Gere a chave **uma vez** por pagamento e guarde-a antes de chamar a API. Gerar uma chave nova a cada tentativa anula a proteção. ## Cobranças (`request-qrcode`) [#cobranças-request-qrcode] O `requestNumber` é único por conta: uma segunda cobrança com o mesmo `requestNumber` é recusada com `400 requestNumber já utilizado`. Se a resposta da criação se perder, recupere a cobrança com [Consultar transação](/docs/transactions/get-transaction) informando o `requestNumber` — o PIX copia e cola volta em `pixCopiaECola` enquanto ela estiver pendente. ## Callbacks [#callbacks] Do lado do seu sistema, os avisos também podem chegar repetidos (reenvio após timeout, por exemplo). Processe cada `idTransaction` / `id` uma única vez. Veja [Callbacks e webhooks](/docs/webhooks#entrega-e-reenvio). # Introdução (https://docs.weetpay.com/docs) Bem-vindo à documentação da API WeetPay Baixar OpenAPI (Postman/Insomnia) Guia para IAs (llms.txt) Início rápido A **WeetPay** é um gateway de pagamentos PIX. Pela API sua aplicação gera cobranças com QR Code dinâmico, recebe o aviso de pagamento em tempo real, envia PIX para qualquer chave e consulta transações e saldo — com poucas chamadas HTTP e valores em reais. ## O que dá para fazer [#o-que-dá-para-fazer] Recebimentos (**cash-in**) viram cobranças PIX copia e cola com QR Code pronto para exibir. Quando o cliente paga, o valor entra no seu saldo e a WeetPay avisa o seu sistema no `callbackUrl`. Pagamentos (**cash-out**) saem do seu saldo para uma chave PIX, com proteção contra envio duplicado e resultado também por callback. ## Por que integrar? [#por-que-integrar] quatro endpoints, JSON puro e valores em reais ( `49.90` ) mesmos caminhos, campos e respostas da API de gateway mais usada no mercado — migre trocando a URL e as chaves aviso de pagamento e de saque com HMAC-SHA256 e reenvio automático a Idempotency-Key garante que um PIX nunca saia duas vezes PIX copia e cola e imagem PNG em base64 na mesma resposta divida recebimentos com outra conta WeetPay (mediante liberação) ## Módulos [#módulos] ## URLs base [#urls-base] | Ambiente | URL | | -------------- | -------------------------------------------------------------- | | API (produção) | `https://api.weetpay.com` | | Painel | `https://app.weetpay.com` — credenciais em **Desenvolvedores** | | Documentação | `https://docs.weetpay.com` | Toda requisição leva o **client ID** e o **client secret** nos cabeçalhos `vspi` e `vsps`. Erros sempre vêm como `{ "response": "ERROR", "message": "…" }`. Veja [Autenticação](/docs/authentication) e [Erros](/docs/errors). ## Próximos passos [#próximos-passos] Siga o [Início rápido](/docs/getting-started) para gerar sua primeira cobrança em minutos. Para assistentes e agentes de código, use o [llms.txt](/llms.txt) (índice) ou o [llms-full.txt](/llms-full.txt) (conteúdo completo). # Limites e regras (https://docs.weetpay.com/docs/limits-and-rules) Limites de requisição, de valores e as regras de segurança para saques e split. ## Requisições [#requisições] | Limite | Valor | Resposta | | ---------------------------- | ------------------------------------------------- | ----------------------------- | | Por conta (client ID) | **600 requisições por minuto** | `429`, `code: "RATE_LIMITED"` | | Credenciais inválidas por IP | 30 erros em 5 minutos bloqueiam o IP por um tempo | `429`, `code: "RATE_LIMITED"` | Ao receber `429`, espere alguns segundos e repita com espera crescente. Para acompanhar pagamentos, use [callbacks](/docs/webhooks) em vez de consultas em loop. ## Valores [#valores] * Valores sempre em **reais**, com até 2 casas decimais (`49.9`, `"49.90"` ou `"49,90"`). * Cobranças e saques têm **mínimo e máximo por operação** definidos pela WeetPay; saques têm também **limite diário** (janela móvel de 24 h). Quando um limite é ultrapassado, a mensagem de erro informa o valor permitido. * A **validade do QR Code** é definida pela plataforma (padrão: 1 hora). Depois disso a cobrança fica `EXPIRED`. * Tarifas de recebimento e de saque são as do seu contrato e aparecem no painel. Recebimentos entram no saldo já líquidos; a tarifa de saque é debitada junto com o valor. ## Saques pela API [#saques-pela-api] **Liberação pelo cliente.** O saque pela API vem **desligado**. Ligue em **Desenvolvedores** no painel (exige o PIN de transação). Desligado, `pix-payment` responde `403`. **Destino.** Sem liberação da WeetPay, o saque só vai para a **chave CPF/CNPJ do titular da conta**. Para pagar terceiros (fornecedores, afiliados, clientes), peça a liberação ao suporte. **Aprovação.** Saques acima do valor de aprovação automática da plataforma passam por análise da operação antes do envio. Enquanto isso o saque continua `PROCESSING` e o valor fica reservado. **Resultado.** Pago ou não, o resultado chega no `callbackUrl`. Não pago (recusado na análise, chave inexistente, falha no banco) tem valor e tarifa **estornados** automaticamente. ## Split [#split] O campo `split` de [Gerar cobrança PIX](/docs/cash-in/create-charge) divide o valor recebido com outra conta WeetPay. Ele move dinheiro entre contas, por isso só funciona em contas **liberadas pelo Compliance**. A conta de destino precisa estar ativa e com a verificação aprovada; o percentual é um inteiro de 1 a 100. ## Verificação de identidade [#verificação-de-identidade] A API só responde para contas com a verificação de identidade (KYC) **aprovada** e não bloqueadas. Até lá, todas as chamadas retornam `403` com `code: "KYC_REQUIRED"`. # Callbacks e webhooks (https://docs.weetpay.com/docs/webhooks) Avisos assinados de pagamento e de saque — o jeito certo de conciliar sem consultar a API em loop. A WeetPay avisa o seu sistema de duas formas, que podem ser usadas juntas: | | **Callback da transação** | **Webhook do painel** | | -------------- | ---------------------------------------------------- | ------------------------------------------------------------------- | | Onde configura | campo `callbackUrl` de cada cobrança ou saque na API | **Webhooks** no painel, um endereço por evento | | Formato | o payload da API compatível (valores em **reais**) | envelope `{ id, event, createdAt, data }` (valores em **centavos**) | | Assinado com | o **client secret** da API | o segredo do webhook (`whsec_…`), visível no painel | | Eventos | pagamento da cobrança; resultado do saque | cobrança criada, paga, devolvida; saque concluído, falhou | Em ambos: `POST` com `Content-Type: application/json`, assinatura no cabeçalho `X-WeetPay-Signature` e reenvio automático em caso de falha. ## Callback de cobrança paga [#callback-de-cobrança-paga] Enviado ao `callbackUrl` de [Gerar cobrança PIX](/docs/cash-in/create-charge) quando o PIX é pago: ```json { "requestNumber": "pedido-12345", "statusTransaction": "PAID_OUT", "idTransaction": "cmh1x2y3z0001ab12cd34ef56", "typeTransaction": "PIX", "value": 49.9, "debtorName": "MARIA DA SILVA", "debtorDocument": "12345678909", "date": "2026-10-30T13:03:40.000Z", "endToEnd": "E18236120202610301303s0123456789" } ``` | Campo | Descrição | | ------------------------------ | ------------------------------------------------ | | `requestNumber` | o identificador que você enviou na criação | | `statusTransaction` | sempre `PAID_OUT` (só pagamentos geram callback) | | `idTransaction` | ID da cobrança na WeetPay | | `value` | valor pago, em reais (número) | | `debtorName`, `debtorDocument` | quem pagou, como informado pelo banco | | `date` | data/hora do pagamento (ISO 8601, UTC) | | `endToEnd` | End-to-End ID do PIX | ## Callback de saque [#callback-de-saque] Enviado ao `callbackUrl` de [Enviar PIX](/docs/cash-out/pix-payment) quando o saque termina: ```json { "id": "cmh1x9k2m0004ab12xy98zt76", "status": "sucess", "date": "2026-10-30T14:10:05.000Z", "message": "", "value": 150, "endToEnd": "E00416968202610301410abcdEFGH1234" } ``` ```json { "id": "cmh1x9k2m0004ab12xy98zt76", "status": "not paid", "date": "2026-10-30T14:10:05.000Z", "message": "Chave PIX não encontrada", "value": 150, "endToEnd": "" } ``` `status` é `"sucess"` (com essa grafia, mantida por compatibilidade com a API de gateway de origem) ou `"not paid"`. Saque não pago tem o **valor e a tarifa estornados** automaticamente ao seu saldo; o motivo vem em `message`. ## Webhooks do painel [#webhooks-do-painel] Cadastre em **Webhooks** no painel uma URL para cada evento que quiser receber. O corpo vem num envelope: ```json { "id": "cmh1xa0b10007ab12qq11ww22", "event": "TRANSACTION_PAID", "createdAt": "2026-10-30T13:03:41.000Z", "data": { "id": "cmh1x2y3z0001ab12cd34ef56", "externalId": "pedido-12345", "status": "PAID", "amount": 4990, "fee": 99, "netAmount": 4891, "description": "Camiseta básica", "pixCopiaECola": "00020101021226850014br.gov.bcb.pix…", "endToEndId": "E18236120202610301303s0123456789", "payer": { "name": "MARIA DA SILVA", "document": "12345678909" }, "expiresAt": "2026-10-30T14:02:11.000Z", "paidAt": "2026-10-30T13:03:40.000Z", "createdAt": "2026-10-30T13:02:11.000Z" } } ``` | `event` | Quando | `data` | | ---------------------- | ------------------------------------ | ------------------------------------------------ | | `TRANSACTION_CREATED` | cobrança criada | cobrança | | `TRANSACTION_PAID` | cobrança paga | cobrança | | `TRANSACTION_REFUNDED` | cobrança devolvida / contestada | cobrança + `refund { id, kind, amount, reason }` | | `WITHDRAWAL_COMPLETED` | saque pago | saque | | `WITHDRAWAL_FAILED` | saque recusado ou falhou (estornado) | saque | Na cobrança, `externalId` é o seu `requestNumber`; `amount`, `fee` e `netAmount` estão em **centavos**. O saque traz `id`, `transactionId`, `status` (`PAID`, `FAILED`, `REJECTED`), `amount`, `fee`, `pixKeyType`, `pixKey`, `endToEndId`, `reason`, `paidAt` e `createdAt`. ## Cabeçalhos [#cabeçalhos] | Cabeçalho | Valor | | --------------------- | ---------------------------------------------------------------------------- | | `X-WeetPay-Signature` | `t=,v1=` — veja abaixo | | `X-WeetPay-Event` | evento (`TRANSACTION_PAID`, `WITHDRAWAL_COMPLETED`…) | | `X-WeetPay-Delivery` | ID da entrega — o mesmo em todas as tentativas; use para descartar repetidos | | `User-Agent` | `WeetPay-Webhooks/1.0` | ## Validando a assinatura [#validando-a-assinatura] `v1` é o HMAC-SHA256, em hexadecimal, de `"."`, usando como chave o **client secret** (callbacks da transação) ou o **segredo do webhook** (webhooks do painel). Calcule sobre o corpo **exatamente como chegou**, antes de qualquer parse, compare em tempo constante e recuse avisos com `t` muito antigo (ex.: mais de 5 minutos). ```js import { createHmac, timingSafeEqual } from 'node:crypto'; export function validWeetPaySignature(rawBody, header, secret, toleranceSec = 300) { const parts = Object.fromEntries((header ?? '').split(',').map((p) => p.split('='))); const t = Number(parts.t); if (!t || !parts.v1 || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); return expected.length === parts.v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1)); } // Express: app.post('/webhooks/weetpay', express.raw({ type: 'application/json' }), (req, res) => { // if (!validWeetPaySignature(req.body.toString('utf8'), req.get('X-WeetPay-Signature'), process.env.WEETPAY_CLIENT_SECRET)) return res.sendStatus(401); // const event = JSON.parse(req.body); … ; res.sendStatus(200); // }); ``` ```php $tolerance) return false; return hash_equals(hash_hmac('sha256', $t . '.' . $rawBody, $secret), $parts['v1']); } $raw = file_get_contents('php://input'); if (!weetpay_valid_signature($raw, $_SERVER['HTTP_X_WEETPAY_SIGNATURE'] ?? null, getenv('WEETPAY_CLIENT_SECRET'))) { http_response_code(401); exit; } $event = json_decode($raw, true); http_response_code(200); ``` ```python import hmac, hashlib, time def valid_weetpay_signature(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool: parts = dict(p.split("=", 1) for p in (header or "").split(",") if "=" in p) t = int(parts.get("t", 0)) if not t or "v1" not in parts or abs(time.time() - t) > tolerance: return False expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts["v1"]) ``` ## Entrega e reenvio [#entrega-e-reenvio] * Responda com qualquer **2xx em até 10 segundos**. Outro status, timeout ou erro de conexão conta como falha. * Falhas são reenviadas após **1, 5, 15, 60, 180, 360, 720 e 1440 minutos** (até 9 tentativas, cerca de 2 dias). Depois disso a entrega fica como falha no histórico; você pode reenviar manualmente pelo painel. * O mesmo aviso pode chegar mais de uma vez: trate pelo `idTransaction` / `id` (ou `X-WeetPay-Delivery`) e torne o processamento **idempotente**. * A URL precisa ser **http(s) pública**. Redirecionamentos não são seguidos e endereços de rede interna (localhost, 10.x, 192.168.x…) são recusados. * Responda rápido e processe depois (fila): o aviso não espera o seu sistema terminar o pedido. Não confie só no corpo do aviso para liberar um pedido de valor alto: valide a assinatura ou confirme com [Consultar transação](/docs/transactions/get-transaction). # Consultar saldo (https://docs.weetpay.com/docs/account/balance) {/* */} # Conta (https://docs.weetpay.com/docs/account) Saldo disponível da carteira WeetPay. `GET /api/v1/gateway/walletBalance` devolve o saldo disponível em reais, como string com duas casas: `{ "currentBalance": "397.70" }`. * Cobranças pagas entram **líquidas** da tarifa de recebimento. * Saques reservam o valor **e** a tarifa no momento do pedido; se o saque não for pago, os dois voltam ao saldo. * Antes de um saque, confira se `currentBalance` cobre o valor mais a tarifa de saque — senão a API responde `insufficient balance`. Extratos, relatórios e repasses ficam no [painel](https://app.weetpay.com). # Gerar cobrança PIX (https://docs.weetpay.com/docs/cash-in/create-charge) {/* */} # Cash-in (https://docs.weetpay.com/docs/cash-in) Receba pagamentos com PIX copia e cola e QR Code dinâmico. `POST /api/v1/gateway/request-qrcode` gera uma cobrança PIX. A resposta traz o PIX copia e cola (`paymentCode`) e a imagem PNG do QR Code em base64 (`paymentCodeBase64`) para você mostrar ao cliente. ## Fluxo [#fluxo] 1. Seu servidor chama [Gerar cobrança PIX](/docs/cash-in/create-charge) com o `requestNumber` do pedido. 2. Você exibe o QR Code e o botão "copiar código" ao cliente. 3. O cliente paga no app do banco. 4. A WeetPay credita o valor (líquido da tarifa) no seu saldo e faz `POST` no `callbackUrl` com `statusTransaction: "PAID_OUT"`. 5. Seu sistema valida a assinatura, libera o pedido e responde `200`. ## Exibindo o QR Code [#exibindo-o-qr-code] ```html QR Code PIX ``` ## Status da cobrança [#status-da-cobrança] | `processingStatus` | Significado | | ---------------------- | ---------------------------------------- | | `WAITING_FOR_APPROVAL` | aguardando pagamento | | `PAID_OUT` | paga — valor creditado no saldo | | `EXPIRED` | QR venceu sem pagamento (padrão: 1 hora) | | `CANCELED` | cancelada pela operação | | `REFUNDED` | devolvida / contestada (MED) | ## Dicas [#dicas] * Use um `requestNumber` por tentativa de pagamento. Se o QR expirar, gere outra cobrança com um novo `requestNumber` (ex.: `pedido-12345-2`). * Informe o CPF/CNPJ real do pagador em `client.document`: ele é validado e repassado ao banco. * Envie `utm_source`, `utm_campaign`… na query string para guardar a origem da venda junto da cobrança. # Cash-out (https://docs.weetpay.com/docs/cash-out) Envie PIX do seu saldo para qualquer chave, com proteção contra envio duplicado. `POST /api/v1/gateway/pix-payment` debita o valor e a tarifa do seu saldo e envia um PIX para a chave informada. A resposta é imediata (`status: "processing"`); o resultado chega no `callbackUrl`. Antes do primeiro saque, ligue **Saque pela API** em **Desenvolvedores** no painel. Sem liberação da WeetPay, o destino precisa ser a chave CPF/CNPJ do próprio titular. Veja [Limites e regras](/docs/limits-and-rules#saques-pela-api). ## Tipos de chave [#tipos-de-chave] | `typeKey` | `key` | `document` | | --------- | -------------------------------------------------------- | ---------------------------- | | `CPF` | 11 dígitos | o mesmo CPF da chave | | `CNPJ` | 14 dígitos | o mesmo CNPJ da chave | | `EMAIL` | e-mail | CPF/CNPJ do titular da chave | | `PHONE` | celular com DDD (ex.: `11999998888` ou `+5511999998888`) | CPF/CNPJ do titular da chave | | `EVP` | chave aleatória (UUID) | CPF/CNPJ do titular da chave | ## Fluxo [#fluxo] 1. Gere e guarde uma `Idempotency-Key` para o pagamento ([Idempotência](/docs/idempotency)). 2. Chame [Enviar PIX](/docs/cash-out/pix-payment). Em erro de rede ou `5xx`, repita **com a mesma chave**. 3. O saque fica `PROCESSING` (análise da operação, quando aplicável, e envio ao banco). 4. O `callbackUrl` recebe `status: "sucess"` com o `endToEnd`, ou `status: "not paid"` com o motivo em `message` — nesse caso valor e tarifa voltam ao saldo. ## Status do saque [#status-do-saque] | `processingStatus` (consulta) | Callback `status` | Significado | | ----------------------------- | ----------------- | ------------------------------ | | `PROCESSING` | — | em análise ou enviado ao banco | | `PAID_OUT` | `sucess` | pago | | `NOT_PAID` | `not paid` | recusado ou falhou; estornado | # Enviar PIX (saque) (https://docs.weetpay.com/docs/cash-out/pix-payment) {/* */} # Consultar transação (https://docs.weetpay.com/docs/transactions/get-transaction) {/* */} # Transações (https://docs.weetpay.com/docs/transactions) Consulte cobranças e saques por qualquer identificador. `POST /api/v1/gateway/walletTransaction` devolve uma cobrança (`transactionType: "PIX_IN"`) ou um saque (`"PIX_OUT"`) da sua conta, no mesmo formato. ## Identificadores [#identificadores] | Campo | Encontra | | --------------- | -------------------------------------------- | | `requestNumber` | cobrança, pelo identificador que você enviou | | `idTransaction` | cobrança ou saque, pelo ID da WeetPay | | `endToEnd` | cobrança ou saque, pelo End-to-End ID do PIX | ## Status [#status] | `processingStatus` | Tipo | Significado | | ---------------------- | --------- | ----------------------------------------------- | | `WAITING_FOR_APPROVAL` | `PIX_IN` | aguardando pagamento | | `PAID_OUT` | ambos | pago | | `EXPIRED` | `PIX_IN` | expirou sem pagamento | | `CANCELED` | `PIX_IN` | cancelada | | `REFUNDED` | `PIX_IN` | devolvida | | `PROCESSING` | `PIX_OUT` | em análise ou em envio | | `NOT_PAID` | `PIX_OUT` | não pago (motivo em `message`), valor estornado | ## Quando consultar [#quando-consultar] * O cliente voltou à página do pedido e você ainda não recebeu o callback. * Conciliação ou contingência (o seu servidor esteve fora do ar). * Para recuperar o `pixCopiaECola` de uma cobrança pendente. Cobranças pendentes são conferidas no banco a cada consulta (no máximo uma vez a cada 10 s). Não consulte em loop: use [callbacks](/docs/webhooks).