# Autenticação e permissões (/api/autenticacao) Toda chamada leva a sua chave de API, de um destes dois jeitos: ```bash # No header x-api-key curl https://api.wysepay.com.br/api/v1/balance \ -H "x-api-key: wyp_test_sua_chave" # Ou como Bearer curl https://api.wysepay.com.br/api/v1/balance \ -H "Authorization: Bearer wyp_test_sua_chave" ``` Sem a chave, ou com uma chave revogada, a resposta é `401`. ## Teste e produção [#teste-e-produção] O modo é definido pela chave, não pelo endereço: as duas usam `https://api.wysepay.com.br`. | | Chave de teste | Chave de produção | | --------------------------- | ---------------------------- | ----------------------------- | | Começa com | `wyp_test_` | `wyp_` | | Dinheiro real | Nunca | Sim | | Precisa de conta verificada | Não | Sim | | Pagamentos e saques | [Simulados](/api/modo-teste) | Reais | | Webhooks | Só para endpoints de teste | Só para endpoints de produção | | `livemode` nas respostas | `false` | `true` | Os dados de teste ficam separados dos reais: uma chave de teste não enxerga cobranças, clientes ou saques de produção, e o contrário também vale. ## Criar uma chave [#criar-uma-chave] 1. No [painel](https://app.wysepay.com.br), vá em **Desenvolvedores → Chaves de API**. 2. Para uma chave de teste, ligue antes o **Modo teste** no topo da tela. 3. Dê um nome que diga onde ela será usada (ex.: "Servidor da loja"), escolha as permissões e, se quiser, os IPs. 4. Clique em **Criar chave** e copie na hora: ela aparece uma única vez. Chaves de produção só podem ser criadas depois que a conta é verificada. Veja [Criar conta e liberar produção](/painel/criar-conta). ## Permissões [#permissões] Cada chave tem permissões por recurso. Dê a cada sistema só o que ele usa: um painel de BI, por exemplo, só precisa ler. | Recurso | Ler | Criar e alterar | | ------------------ | -------------------- | --------------------- | | Cobranças Pix | | `charges:write` | | Transações | `transactions:read` | | | Links de pagamento | `payment_links:read` | `payment_links:write` | | Clientes | `customers:read` | `customers:write` | | Saldo | `balance:read` | | | Saques | `withdrawals:read` | `withdrawals:write` | * **Chaves novas** vêm com tudo, **menos `withdrawals:write`** (sacar). * **Chaves criadas antes das permissões** ficaram com tudo, menos sacar: as integrações continuam funcionando. * **Mudar as permissões** vale na hora: em **Chaves de API**, clique no ícone de ajustes da chave. Sem a permissão da rota, a resposta é `403` com `code: "API_KEY_PERMISSION"`, dizendo qual falta. A permissão de cada rota aparece na [referência](/api/referencia/gerar-pix). ## IPs permitidos [#ips-permitidos] Você pode limitar a chave aos IPs do seu servidor. Com a lista preenchida, uma chamada de outro IP responde `403` com `code: "API_KEY_IP"`, mesmo com a chave certa. * Um IP por linha, IPv4 ou IPv6. * Faixas em CIDR: `203.0.113.0/24` libera de `203.0.113.0` a `203.0.113.255`. * Lista vazia: qualquer IP. Uma chave com `withdrawals:write` tira dinheiro da conta. Libere só o IP do servidor que a usa e defina um limite diário. Veja [Saques](/api/saques). ## Guarde a chave no servidor [#guarde-a-chave-no-servidor] Quem tem a chave age em nome da sua conta, dentro das permissões dela. A chave deve ficar só no seu servidor, numa variável de ambiente, nunca no código do site, do aplicativo ou num repositório. Se uma chave vazar, revogue em **Chaves de API** e crie outra. A chave revogada para de funcionar na hora. # Clientes (/api/clientes) Cada cliente é identificado pelo CPF ou CNPJ: há um por documento, em cada modo (teste e produção). Ele é criado sozinho quando alguém paga ou preenche o checkout, e você também pode cadastrar e consultar pela API. ## Cadastrar [#cadastrar] [`POST /api/v1/customers`](/api/referencia/cadastrar-cliente) (permissão `customers:write`): ```bash curl -X POST https://api.wysepay.com.br/api/v1/customers \ -H "x-api-key: wyp_test_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "name": "Ana Souza", "document": "123.456.789-09", "email": "ana@exemplo.com.br", "phone": "11912345678", "address": { "zipCode": "01310-100", "number": "1000" } }' ``` Se já existe um cliente com esse CPF ou CNPJ, ele é **atualizado** em vez de duplicado. Campos que você não envia ficam como estavam. Um documento inválido responde `400`. ## Achar pelo CPF ou CNPJ [#achar-pelo-cpf-ou-cnpj] ```bash curl "https://api.wysepay.com.br/api/v1/customers?document=12345678909" \ -H "x-api-key: wyp_test_sua_chave" ``` A resposta é uma [lista](/api/paginacao) com no máximo um cliente. ## Atualizar [#atualizar] [`PATCH /api/v1/customers/{id}`](/api/referencia/atualizar-cliente) muda só os campos enviados. O CPF ou CNPJ não muda. ## O que fica de fora [#o-que-fica-de-fora] As notas internas e as tags que você escreve no painel não aparecem na API. # Cobranças Pix (/api/cobrancas-pix) Uma cobrança Pix é o que o cliente paga: um QR Code e um código copia e cola com o valor certo. Você cria pela API e mostra na sua tela. ## Criar [#criar] [`POST /api/v1/charges/pix`](/api/referencia/gerar-pix) com: | Campo | Obrigatório | O que é | | ------------------ | ----------- | --------------------------------------------------------------------------------------------- | | `amountCents` | Sim | Valor em centavos. Mínimo `500` (R$ 5,00). | | `description` | Sim | O que está sendo cobrado (3 a 180 caracteres). Aparece para o pagador. | | `customer` | Sim | Quem paga: `name`, `email`, `phone` (com DDD), `documentType` (`CPF` ou `CNPJ`) e `document`. | | `customer.address` | Não | Endereço, salvo no cadastro do cliente. | | `expiresAt` | Não | Até quando o Pix aceita pagamento (ISO 8601). | | `metadata` | Não | Dados seus, como o id do pedido. Voltam iguais na consulta e nos webhooks. | O CPF ou CNPJ é validado pelos dígitos. Um documento inválido responde `400` e a cobrança não é criada. Use sempre o header `idempotency-key` (ex.: o id do pedido). Se a chamada for repetida por uma falha de rede, a mesma cobrança volta, sem duplicar. Veja [Idempotência](/api/limites-e-idempotencia#idempotência). ## Mostrar ao cliente [#mostrar-ao-cliente] A resposta traz em `pix`: * `copyPaste`: o código copia e cola. Mostre com um botão de copiar. * `qrCode`: o mesmo código, para você gerar a imagem do QR Code com qualquer biblioteca de QR. Mostre também o prazo: `expiresAt` diz até quando o Pix pode ser pago. ## Saber que foi pago [#saber-que-foi-pago] Use o webhook [`transaction.paid`](/api/webhooks): ele chega em segundos, com a cobrança inteira, incluindo o seu `metadata`. Libere o pedido quando ele chegar. Se precisar conferir, consulte [`GET /api/v1/transactions/{id}`](/api/referencia/consultar-transacao). Evite consultar em loop: o webhook é mais rápido e não gasta o seu [limite de requisições](/api/limites-e-idempotencia). ## Situações (`status`) [#situações-status] | Status | Quer dizer | | --------------------- | -------------------------------------------------------------------------------------------- | | `WAITING_PAYMENT` | Pix gerado, aguardando o pagamento. | | `PAID` | Pago e confirmado. Pode liberar o pedido. | | `EXPIRED` | Passou do `expiresAt` sem pagamento. Gere uma cobrança nova se o cliente ainda quiser pagar. | | `CANCELLED`, `FAILED` | Não pode mais ser paga. | Outros status aparecem em situações raras (como `PENDING` ou `PROCESSING`, enquanto o Pix é gerado). Trate tudo que não é `PAID` como "não pago". ## Valores [#valores] * `amountCents`: o que o cliente paga. * `feeCents`: a taxa da WysePay, definida pelo seu plano no momento em que a cobrança é criada. * `netAmountCents`: o que entra no seu saldo (`amountCents − feeCents`). Se depois de pago o cliente contestar pelo banco (MED), a cobrança ganha o campo `dispute`. Veja [MED](/painel/med). # Começo rápido (/api/comeco-rapido) Em 5 minutos você faz o caminho completo de um pagamento no modo teste. Nada aqui movimenta dinheiro, e o modo teste não precisa de verificação da conta. ### Crie uma chave de teste [#crie-uma-chave-de-teste] 1. Entre no [painel](https://app.wysepay.com.br) e ligue **Modo teste**, no topo da tela. 2. Vá em **Desenvolvedores → Chaves de API** e clique em **Criar chave**. 3. Copie a chave. Ela começa com `wyp_test_` e só aparece uma vez. ### Gere um Pix [#gere-um-pix] Troque `wyp_test_sua_chave` pela chave que você copiou. ```bash curl -X POST https://api.wysepay.com.br/api/v1/charges/pix \ -H "x-api-key: wyp_test_sua_chave" \ -H "Content-Type: application/json" \ -H "idempotency-key: pedido-1042" \ -d '{ "amountCents": 8990, "description": "Pedido #1042", "customer": { "name": "Ana Souza", "email": "ana@exemplo.com.br", "phone": "11912345678", "documentType": "CPF", "document": "12345678909" }, "metadata": { "orderId": "1042" } }' ``` ```js const response = await fetch("https://api.wysepay.com.br/api/v1/charges/pix", { method: "POST", headers: { "x-api-key": process.env.WYSEPAY_API_KEY, "Content-Type": "application/json", "idempotency-key": "pedido-1042", }, body: JSON.stringify({ amountCents: 8990, description: "Pedido #1042", customer: { name: "Ana Souza", email: "ana@exemplo.com.br", phone: "11912345678", documentType: "CPF", document: "12345678909", }, metadata: { orderId: "1042" }, }), }); const charge = await response.json(); console.log(charge.pix.copyPaste); ``` ```python import os import requests response = requests.post( "https://api.wysepay.com.br/api/v1/charges/pix", headers={ "x-api-key": os.environ["WYSEPAY_API_KEY"], "idempotency-key": "pedido-1042", }, json={ "amountCents": 8990, "description": "Pedido #1042", "customer": { "name": "Ana Souza", "email": "ana@exemplo.com.br", "phone": "11912345678", "documentType": "CPF", "document": "12345678909", }, "metadata": {"orderId": "1042"}, }, ) charge = response.json() print(charge["pix"]["copyPaste"]) ``` ```php true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'x-api-key: ' . getenv('WYSEPAY_API_KEY'), 'Content-Type: application/json', 'idempotency-key: pedido-1042', ], CURLOPT_POSTFIELDS => json_encode([ 'amountCents' => 8990, 'description' => 'Pedido #1042', 'customer' => [ 'name' => 'Ana Souza', 'email' => 'ana@exemplo.com.br', 'phone' => '11912345678', 'documentType' => 'CPF', 'document' => '12345678909', ], 'metadata' => ['orderId' => '1042'], ]), ]); $charge = json_decode(curl_exec($ch), true); curl_close($ch); echo $charge['pix']['copyPaste']; ``` ```go package main import ( "bytes" "encoding/json" "fmt" "net/http" "os" ) func main() { body, _ := json.Marshal(map[string]any{ "amountCents": 8990, "description": "Pedido #1042", "customer": map[string]any{ "name": "Ana Souza", "email": "ana@exemplo.com.br", "phone": "11912345678", "documentType": "CPF", "document": "12345678909", }, "metadata": map[string]any{"orderId": "1042"}, }) req, _ := http.NewRequest("POST", "https://api.wysepay.com.br/api/v1/charges/pix", bytes.NewReader(body)) req.Header.Set("x-api-key", os.Getenv("WYSEPAY_API_KEY")) req.Header.Set("Content-Type", "application/json") req.Header.Set("idempotency-key", "pedido-1042") res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() var charge struct { Pix struct { CopyPaste string `json:"copyPaste"` } `json:"pix"` } json.NewDecoder(res.Body).Decode(&charge) fmt.Println(charge.Pix.CopyPaste) } ``` ```java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class GerarPix { public static void main(String[] args) throws Exception { String body = """ { "amountCents": 8990, "description": "Pedido #1042", "customer": { "name": "Ana Souza", "email": "ana@exemplo.com.br", "phone": "11912345678", "documentType": "CPF", "document": "12345678909" }, "metadata": { "orderId": "1042" } } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.wysepay.com.br/api/v1/charges/pix")) .header("x-api-key", System.getenv("WYSEPAY_API_KEY")) .header("Content-Type", "application/json") .header("idempotency-key", "pedido-1042") .POST(HttpRequest.BodyPublishers.ofString(body)) .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); // A cobrança em JSON: o código está em pix.copyPaste. System.out.println(response.body()); } } ``` ```ruby require 'json' require 'net/http' uri = URI('https://api.wysepay.com.br/api/v1/charges/pix') request = Net::HTTP::Post.new(uri) request['x-api-key'] = ENV.fetch('WYSEPAY_API_KEY') request['Content-Type'] = 'application/json' request['idempotency-key'] = 'pedido-1042' request.body = { amountCents: 8990, description: 'Pedido #1042', customer: { name: 'Ana Souza', email: 'ana@exemplo.com.br', phone: '11912345678', documentType: 'CPF', document: '12345678909' }, metadata: { orderId: '1042' } }.to_json response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| http.request(request) end charge = JSON.parse(response.body) puts charge['pix']['copyPaste'] ``` A resposta é a cobrança criada, com o código Pix para mostrar ao cliente: ```json { "id": "txn_01k6g8m2v4x7z9b3c5d7f9h0j2", "status": "WAITING_PAYMENT", "amountCents": 8990, "feeCents": 90, "netAmountCents": 8900, "description": "Pedido #1042", "pix": { "copyPaste": "…", "qrCode": "…" }, "customer": { "id": "cus_…", "name": "Ana Souza", "documentType": "CPF", "document": "12345678909", "…": "…" }, "metadata": { "orderId": "1042" }, "livemode": false, "expiresAt": "2026-10-04T16:00:00.000Z", "paidAt": null, "…": "…" } ``` A API confere os dígitos do CPF ou CNPJ, inclusive no modo teste. Use um CPF válido, como o `123.456.789-09` dos exemplos. ### Cadastre um webhook [#cadastre-um-webhook] No painel, ainda no modo teste, vá em **Desenvolvedores → Webhooks**, cadastre a URL do seu servidor e marque o evento `transaction.paid`. Ainda não tem um servidor no ar? Use um serviço como o [webhook.site](https://webhook.site) para ver os eventos chegando. ### Simule o pagamento [#simule-o-pagamento] No modo teste ninguém paga de verdade: você simula. Use o `id` da cobrança: ```bash curl -X POST https://api.wysepay.com.br/api/v1/sandbox/transactions/txn_01k6g8m2v4x7z9b3c5d7f9h0j2/pay \ -H "x-api-key: wyp_test_sua_chave" ``` A cobrança passa para `PAID` e o webhook `transaction.paid` chega na sua URL, igual a um pagamento real. ### Vá para produção [#vá-para-produção] 1. Complete o perfil e a verificação da conta no painel (veja [Criar conta e liberar produção](/painel/criar-conta)). 2. Desligue o modo teste e crie uma chave de produção. Ela começa com `wyp_`. 3. Cadastre o webhook de produção. Endpoints de teste e de produção são separados. 4. Troque a chave no seu servidor. O código é o mesmo. ## Próximos passos [#próximos-passos] * [Validar a assinatura dos webhooks](/api/webhooks#validar-a-assinatura), antes de confiar num evento. * [Evitar cobranças duplicadas](/api/limites-e-idempotencia) com a `idempotency-key`. * [Links de pagamento](/api/links-de-pagamento), se você não quer montar a tela de pagamento. # Erros (/api/erros) Toda resposta de erro tem o mesmo formato: ```json { "ok": false, "code": "VALIDATION_ERROR", "message": "Revise os campos informados.", "errors": [ { "path": "customer.email", "message": "E-mail inválido." } ], "path": "/api/v1/charges/pix", "timestamp": "2026-10-04T15:30:00.000Z" } ``` * `code`: para o seu código decidir o que fazer. * `message`: em português, pode ser mostrada a quem opera o seu sistema. * `errors`: só em `VALIDATION_ERROR`, com cada campo e o motivo. ## Códigos [#códigos] | `code` | Quando | | ---------------------- | ------------------------------------------------------------------------------------------------------------------ | | `VALIDATION_ERROR` | Algum campo do corpo está faltando ou inválido. Veja `errors`. | | `REQUEST_ERROR` | O pedido não pôde ser atendido. A `message` diz o motivo (ex.: "CPF ou CNPJ do pagador inválido."). | | `API_KEY_PERMISSION` | A chave não tem a permissão da rota. Ajuste em **Chaves de API**. Veja [Permissões](/api/autenticacao#permissões). | | `API_KEY_IP` | A chamada veio de um IP que a chave não libera. Veja [IPs permitidos](/api/autenticacao#ips-permitidos). | | `WITHDRAW_DAILY_LIMIT` | O saque passaria do limite diário da chave. A `message` diz quanto ainda resta hoje. | | `INTERNAL_ERROR` | Falha do nosso lado. Tente de novo em instantes. | ## Status HTTP [#status-http] | Status | Quer dizer | O que fazer | | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | | `400` | Dados inválidos. | Corrija o pedido; repetir igual dá o mesmo erro. | | `401` | Chave ausente, inválida ou revogada. | Confira o header `x-api-key`. | | `403` | A chave não pode fazer isso: falta permissão, o IP não está liberado, o limite diário de saque acabou, a conta ainda não opera em produção ou a simulação foi feita com chave de produção. | Veja o `code` e a `message`. | | `404` | Não encontrado nesta conta e neste modo. | Confira o id e se a chave é do mesmo modo (teste ou produção). | | `429` | Muitas requisições. | Espere o tempo do header `Retry-After`. Veja [Limites](/api/limites-e-idempotencia). | | `5xx` | Falha nossa ou da adquirente. | Tente de novo com a mesma `idempotency-key`. | # Visão geral da API (/api) Com a API você cobra por Pix a partir do seu sistema: gera o QR Code e o código copia e cola para o cliente, cria links de pagamento e é avisado por webhook quando o dinheiro cai. ## O que dá para fazer [#o-que-dá-para-fazer] | Você quer… | Use | | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------- | | Mostrar um Pix no seu site ou app | [`POST /api/v1/charges/pix`](/api/referencia/gerar-pix) | | Mandar um link para o cliente pagar | [`POST /api/v1/payment-links`](/api/referencia/criar-link) | | Saber se uma cobrança foi paga | [Webhook `transaction.paid`](/api/webhooks) ou [`GET /api/v1/transactions/{id}`](/api/referencia/consultar-transacao) | | Conciliar vendas | [`GET /api/v1/transactions`](/api/referencia/listar-transacoes), com [paginação](/api/paginacao) | | Manter os seus clientes | [`/api/v1/customers`](/api/clientes) | | Ver o saldo e sacar | [`/api/v1/balance` e `/api/v1/withdrawals`](/api/saques) | | Testar sem dinheiro real | [Modo teste](/api/modo-teste) | ## Como a API funciona [#como-a-api-funciona] * **Endereço:** `https://api.wysepay.com.br`. Todas as rotas começam com `/api/v1`. * **Autenticação:** a sua chave de API no header `x-api-key` (ou `Authorization: Bearer`), com as permissões que você der a ela. Veja [Autenticação e permissões](/api/autenticacao). * **Formato:** JSON no corpo e nas respostas, com `Content-Type: application/json`. * **Valores em centavos:** `8990` é R$ 89,90. O mínimo de uma cobrança é `500` (R$ 5,00). * **Datas em ISO 8601, UTC:** por exemplo, `2026-10-04T15:30:00.000Z`. * **Teste e produção com o mesmo endereço:** o que define o modo é a chave. Uma chave `wyp_test_` nunca movimenta dinheiro. ## O caminho de um pagamento [#o-caminho-de-um-pagamento] **Você cria a cobrança.** Pela API, com o valor, a descrição e os dados de quem paga. A resposta traz o código Pix. **O cliente paga** pelo app do banco, lendo o QR Code ou colando o código. **A WysePay avisa o seu sistema.** O webhook `transaction.paid` chega na sua URL em segundos. É nele que você libera o pedido. **O dinheiro entra no seu saldo**, já descontada a taxa, e fica disponível para saque conforme o prazo de liberação da sua conta. Pronto para tentar? Vá ao [Começo rápido](/api/comeco-rapido). # Limites e idempotência (/api/limites-e-idempotencia) ## Limites de requisições [#limites-de-requisições] Os limites contam por endereço IP, a cada minuto: | Rotas | Limite | | --------------------------------- | -------------- | | Consultas e listas (`GET`) | 120 por minuto | | Criar e alterar (`POST`, `PATCH`) | 60 por minuto | | `POST /api/v1/withdrawals` | 20 por minuto | Acima do limite a resposta é `429`, com o header `Retry-After` dizendo quantos segundos esperar. Para saber se algo foi pago, prefira os [webhooks](/api/webhooks) a consultar a API em loop. Precisa de mais? Fale com o comercial pelo e-mail [comercial@wysepay.com.br](mailto:comercial@wysepay.com.br). ## Idempotência [#idempotência] Uma falha de rede pode deixar você sem saber se a cobrança (ou o saque) foi criada. Para repetir sem risco de duplicar, envie o header `idempotency-key` ao criar um Pix ou um saque: ```bash curl -X POST https://api.wysepay.com.br/api/v1/charges/pix \ -H "x-api-key: wyp_test_sua_chave" \ -H "idempotency-key: pedido-1042" \ -H "Content-Type: application/json" \ -d '{ … }' ``` * Use um valor único por cobrança, como o id do pedido no seu sistema. * Repetindo com a mesma chave em até **24 horas**, a WysePay devolve a mesma cobrança (ou o mesmo saque), sem criar outro. * A chave vale por conta e por modo: a mesma `idempotency-key` em teste e em produção são cobranças diferentes. * Para cobrar de novo o mesmo pedido (ex.: o Pix venceu), use uma chave nova, como `pedido-1042-2`. # Links de pagamento (/api/links-de-pagamento) Com um link de pagamento você não monta tela nenhuma: cria o link, envia a `url` ao cliente, e ele preenche os dados, paga com Pix e vê o comprovante num checkout com a sua marca. ## Criar [#criar] [`POST /api/v1/payment-links`](/api/referencia/criar-link): ```bash curl -X POST https://api.wysepay.com.br/api/v1/payment-links \ -H "x-api-key: wyp_test_sua_chave" \ -H "Content-Type: application/json" \ -d '{ "amountCents": 15900, "description": "Caneca WysePay", "maxPayments": 1, "askAddress": true, "returnUrl": "https://loja.com.br/obrigado?pedido=1042", "metadata": { "orderId": "1042" } }' ``` A resposta traz a `url` do checkout, como `https://app.wysepay.com.br/checkout/pay_…`. Envie por WhatsApp, e-mail ou redirecione o cliente para ela. ## Opções [#opções] | Campo | O que faz | | ------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `maxPayments` | Quantos pagamentos o link aceita. `1` = uso único; omitido ou `null` = ilimitado. Depois do limite, o link mostra "esgotado". | | `expiresAt` | Até quando o link aceita pagamentos. | | `askAddress` | O checkout pede o endereço, na mesma tela dos dados. O CEP preenche rua, bairro e cidade. | | `returnUrl` | Para onde o cliente volta depois de pagar (precisa ser `https`). | | `metadata` | Dados seus. Cada cobrança gerada pelo link aponta para ele em `paymentLinkId`. | ## Voltar para a sua loja [#voltar-para-a-sua-loja] Com `returnUrl`, o comprovante mostra o botão **Voltar para a loja** e, logo depois do pagamento, leva o cliente de volta sozinho em 8 segundos (ele pode ficar, se quiser). A URL recebe o id da cobrança paga: ``` https://loja.com.br/obrigado?pedido=1042&wysepay_transaction_id=txn_01k6g8m2v4x7z9b3c5d7f9h0j2 ``` Qualquer pessoa pode abrir essa URL com um id inventado. Use o retorno só para mostrar a página de "obrigado". Libere o pedido quando chegar o webhook `transaction.paid`, ou consultando a transação pela API com a sua chave. ## Como o pagamento aparece para você [#como-o-pagamento-aparece-para-você] Cada vez que alguém gera um Pix no link, nasce uma cobrança (`transaction.created`). Quando paga, chega `transaction.paid`, com `paymentLinkId` apontando para o link e os dados que o cliente preencheu em `customer`. ## Listar, consultar e desativar [#listar-consultar-e-desativar] * [`GET /api/v1/payment-links`](/api/referencia/listar-links): os links, com o filtro `active`. * [`GET /api/v1/payment-links/{id}`](/api/referencia/consultar-link): um link e se ainda aceita pagamentos (`active`). * [`POST /api/v1/payment-links/{id}/deactivate`](/api/referencia/desativar-link): o link para de aceitar pagamentos. Os Pix já gerados por ele continuam valendo até vencer. ## A marca do checkout [#a-marca-do-checkout] Logo, cores, fonte e textos do checkout são configurados no painel, em **Cobranças → Personalizar checkout**, e valem para todos os links. Veja [Personalizar o checkout](/painel/personalizar-checkout). # Modo teste (/api/modo-teste) No modo teste tudo funciona como em produção, mas nada movimenta dinheiro: você cria cobranças e links, recebe webhooks e simula pagamentos. Ele não precisa de conta verificada. ## Como usar [#como-usar] * **Pela API:** use uma chave `wyp_test_`. Tudo que ela cria é de teste (`livemode: false`). * **No painel:** ligue **Modo teste** no topo da tela. Os dados de teste ficam separados dos reais. ## O Pix de teste não pode ser pago [#o-pix-de-teste-não-pode-ser-pago] O código de um Pix de teste é de mentira de propósito: nenhum app de banco aceita. Para "pagar", simule: ```bash curl -X POST https://api.wysepay.com.br/api/v1/sandbox/transactions/{id}/pay \ -H "x-api-key: wyp_test_sua_chave" ``` Também dá para simular pelo painel, no botão **Simular pagamento** da tela do Pix ou da venda. A simulação: * muda a cobrança para `PAID`; * envia o webhook `transaction.paid` aos seus endpoints de teste; * credita o saldo de teste, para você testar também o extrato e os saques no painel. Só cobranças de teste podem ser simuladas. Com uma chave de produção, a rota responde `403`. ## Prazo [#prazo] Um Pix de teste vence em 30 minutos, como um Pix real vence no prazo dele. Depois disso ele aparece como `EXPIRED`, e a simulação responde `400`: gere outro. ## Webhooks de teste [#webhooks-de-teste] Cadastre o endpoint com o modo teste ligado. Ele recebe só eventos de teste; os de produção vão só para endpoints de produção. # OpenAPI, Postman e IA (/api/openapi) ## OpenAPI [#openapi] A especificação completa da API, no formato OpenAPI 3.1, gerada do mesmo código que valida as chamadas: * [openapi.json](/openapi.json) Importe no Insomnia, no Postman ou no gerador de código da sua linguagem. ## Coleção do Postman [#coleção-do-postman] * [wysepay.postman_collection.json](/wysepay.postman_collection.json) No Postman, use **Import** e depois preencha as variáveis da coleção: `apiKey` com a sua chave e, se precisar, `baseUrl`. ## Para assistentes de código (IA) [#para-assistentes-de-código-ia] * Em cada página, o botão **Copiar Markdown** copia o conteúdo para colar no seu assistente. * [/llms.txt](/llms.txt) lista todas as páginas da documentação. * [/llms-full.txt](/llms-full.txt) traz toda a documentação num arquivo só. Lembre-se: nunca cole a sua chave de produção em conversas com assistentes. # Paginação (/api/paginacao) As listas vêm da mais nova para a mais antiga, em páginas: ```json { "data": [ { "id": "txn_01k6…", "…": "…" }, { "id": "txn_01k5…", "…": "…" } ], "hasMore": true } ``` * `limit`: quantos itens por página, de 1 a 100 (padrão 20). * `startingAfter`: o `id` do último item que você recebeu. A próxima página começa depois dele. * `hasMore`: `true` quando há mais páginas. ```bash # Primeira página curl "https://api.wysepay.com.br/api/v1/transactions?limit=50" \ -H "x-api-key: wyp_test_sua_chave" # Próxima: startingAfter = o id do último item da página anterior curl "https://api.wysepay.com.br/api/v1/transactions?limit=50&startingAfter=txn_01k5…" \ -H "x-api-key: wyp_test_sua_chave" ``` Diferente de "página 2, página 3", o cursor não pula nem repete itens quando chegam pagamentos novos enquanto você percorre a lista. ## Filtros [#filtros] | Lista | Filtros | | ----------------------------------------------- | ----------------------------------------------------- | | [Transações](/api/referencia/listar-transacoes) | `status`, `paymentLinkId`, `createdFrom`, `createdTo` | | [Links](/api/referencia/listar-links) | `active` (`true` ou `false`) | | [Clientes](/api/referencia/listar-clientes) | `document` (CPF ou CNPJ) | | [Saques](/api/referencia/listar-saques) | — | O filtro `status=EXPIRED` inclui os Pix que venceram sem pagamento, do mesmo jeito que a consulta de uma transação mostra. # Saldo e saques (/api/saques) ## Saldo [#saldo] [`GET /api/v1/balance`](/api/referencia/consultar-saldo) (permissão `balance:read`): ```json { "availableCents": 125000, "pendingCents": 8900, "blockedCents": 0, "withdrawableNowCents": 124900, "withdrawFeeCents": 100, "livemode": true } ``` * `availableCents`: o que já pode sair. * `pendingCents`: vendas pagas ainda no prazo de liberação. * `blockedCents`: retido, por exemplo, por um [MED](/painel/med). * `withdrawableNowCents`: quanto dá para sacar agora, num saque só. ## Sacar [#sacar] [`POST /api/v1/withdrawals`](/api/referencia/sacar) tira o valor do saldo e envia para uma chave Pix. `withdrawals:write` vem **desligada** em toda chave. Antes de ligar, em **Chaves de API**: * libere só o IP do servidor que vai sacar; * defina um **limite diário** de saque para a chave; * use essa chave só para sacar, separada da que cria cobranças. ```bash curl -X POST https://api.wysepay.com.br/api/v1/withdrawals \ -H "x-api-key: wyp_test_sua_chave_de_saque" \ -H "Content-Type: application/json" \ -H "idempotency-key: repasse-2026-10-05" \ -d '{ "amountCents": 50000, "pixKey": "12345678000190", "pixKeyType": "CNPJ" }' ``` | Campo | O que é | | ------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `amountCents` | Quanto sai do saldo, **já incluindo a taxa de saque**. Mínimo `600` (R$ 6,00). O que chega no destino é `amountCents − taxa`. | | `pixKey` | A chave Pix de destino. | | `pixKeyType` | `CPF`, `CNPJ`, `PHONE` (celular com DDD), `EMAIL` ou `EVP` (chave aleatória). | * **Idempotência:** envie sempre a `idempotency-key`. Repetindo com a mesma chave, o mesmo saque volta e nada sai duas vezes. * **Conta verificada:** em produção, o saque exige a conta verificada, como no painel. * **Aviso por e-mail:** o dono da conta recebe o mesmo e-mail de um saque feito no painel. ## Limite diário [#limite-diário] Com limite definido, a chave só saca até esse valor por dia, contado no horário de Brasília (o dia vira à meia-noite). Entram na conta os saques daquela chave no dia, menos os que falharam. Passou do limite, a resposta é `403` com `code: "WITHDRAW_DAILY_LIMIT"` e diz quanto ainda resta. ## Acompanhar [#acompanhar] O saque começa `PENDING` e termina `PAID`, `PARTIALLY_PAID` (parte voltou ao saldo) ou `FAILED` (tudo voltou). Ele pode ser pago em mais de uma transferência Pix. Use os webhooks `withdrawal.paid`, `withdrawal.partially_paid` e `withdrawal.failed`, ou consulte [`GET /api/v1/withdrawals/{id}`](/api/referencia/consultar-saque). A chave de destino aparece parcialmente escondida nas respostas. ## No modo teste [#no-modo-teste] Com uma chave `wyp_test_`, o saque é simulado: sai do saldo de teste, fica `PAID` na hora e envia `withdrawal.created` e `withdrawal.paid` aos endpoints de teste. Para ter saldo de teste, [simule pagamentos](/api/modo-teste). # Webhooks (/api/webhooks) Um webhook é uma chamada que a WysePay faz para uma URL sua quando algo acontece, como um pagamento confirmado. É o jeito certo de saber que foi pago: chega em segundos e você não precisa consultar a API em loop. ## Cadastrar [#cadastrar] 1. No painel, vá em **Desenvolvedores → Webhooks**. 2. Informe a URL (use `https`) e marque os eventos. 3. Guarde o **segredo** que aparece: ele valida a assinatura. 4. Use **Testar** para conferir se a sua URL responde. Endpoints de teste (cadastrados com o modo teste ligado) só recebem eventos de teste, e os de produção só os reais. ## Eventos [#eventos] | Evento | Quando | Corpo | | --------------------------- | --------------------------------------------------------------- | ---------------------------------------------------------- | | `transaction.created` | Um Pix foi gerado (API, painel ou link). | [Transação](/api/referencia/eventos/transaction-created) | | `transaction.paid` | O pagamento foi confirmado. **Libere o pedido aqui.** | [Transação](/api/referencia/eventos/transaction-paid) | | `transaction.expired` | O Pix venceu sem pagamento. Cancele o pedido ou gere outro Pix. | [Transação](/api/referencia/eventos/transaction-expired) | | `dispute.created` | O pagador contestou o pagamento pelo banco (MED). | [MED](/api/referencia/eventos/dispute-created) | | `dispute.responded` | A sua defesa do MED foi enviada. | [MED](/api/referencia/eventos/dispute-responded) | | `dispute.won` | A contestação foi negada: o valor volta a ficar disponível. | [MED](/api/referencia/eventos/dispute-won) | | `dispute.lost` | A devolução foi confirmada: o valor voltou ao pagador. | [MED](/api/referencia/eventos/dispute-lost) | | `withdrawal.created` | Um saque foi pedido, pelo painel ou pela API. | [Saque](/api/referencia/eventos/withdrawal-created) | | `withdrawal.paid` | O saque chegou ao destino. | [Saque](/api/referencia/eventos/withdrawal-paid) | | `withdrawal.partially_paid` | Parte do saque não foi concluída e voltou ao saldo. | [Saque](/api/referencia/eventos/withdrawal-partially-paid) | | `withdrawal.failed` | O saque não foi feito e o valor voltou ao saldo. | [Saque](/api/referencia/eventos/withdrawal-failed) | | `webhook.test` | Você clicou em **Testar** no painel. | `{ message, sentAt }` | Os eventos de transação mandam a mesma transação que a API devolve, incluindo o seu `metadata`. Use-o para achar o pedido no seu sistema. ## O que chega [#o-que-chega] Um `POST` com o corpo em JSON e estes headers: | Header | O que é | | --------------------- | ------------------------------------------------------------ | | `wysepay-event` | O tipo do evento, como `transaction.paid`. | | `wysepay-signature` | A assinatura, para você conferir que veio da WysePay. | | `wysepay-timestamp` | Quando foi assinado, em milissegundos. | | `wysepay-delivery-id` | O id da entrega. É o mesmo nas novas tentativas automáticas. | | `wysepay-attempt` | O número da tentativa, de 1 a 6. | ## Validar a assinatura [#validar-a-assinatura] A assinatura é um HMAC-SHA256, em hexadecimal, feito com o segredo do endpoint sobre o texto `{wysepay-timestamp}.{corpo}`. Calcule o mesmo no seu servidor e compare. Se não bater, recuse com `401`. Assine o texto bruto da requisição, antes de transformar em objeto. Reescrever o JSON muda espaços e a ordem dos campos, e a assinatura deixa de bater. ```js import crypto from "node:crypto"; import express from "express"; const app = express(); // O corpo cru (Buffer), não o objeto já interpretado. app.post("/webhooks/wysepay", express.raw({ type: "application/json" }), (req, res) => { const timestamp = req.header("wysepay-timestamp"); const signature = req.header("wysepay-signature") ?? ""; const expected = crypto .createHmac("sha256", process.env.WYSEPAY_WEBHOOK_SECRET) .update(`${timestamp}.${req.body}`) .digest("hex"); const valid = signature.length === expected.length && crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected)); if (!valid) return res.sendStatus(401); const event = req.header("wysepay-event"); const data = JSON.parse(req.body.toString("utf8")); if (event === "transaction.paid") { // Libere o pedido data.metadata.orderId (uma vez só: veja "Entregas repetidas"). } res.sendStatus(200); }); ``` ```python import hashlib import hmac import json import os from flask import Flask, abort, request app = Flask(__name__) @app.post("/webhooks/wysepay") def wysepay_webhook(): body = request.get_data() # bytes crus timestamp = request.headers.get("wysepay-timestamp", "") signature = request.headers.get("wysepay-signature", "") expected = hmac.new( os.environ["WYSEPAY_WEBHOOK_SECRET"].encode(), f"{timestamp}.".encode() + body, hashlib.sha256, ).hexdigest() if not hmac.compare_digest(signature, expected): abort(401) data = json.loads(body) if request.headers.get("wysepay-event") == "transaction.paid": pass # libere o pedido data["metadata"]["orderId"] return "", 200 ``` ```php ```go import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "io" "net/http" "os" ) func wysepayWebhook(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) // corpo cru if err != nil { http.Error(w, "", http.StatusBadRequest) return } mac := hmac.New(sha256.New, []byte(os.Getenv("WYSEPAY_WEBHOOK_SECRET"))) mac.Write([]byte(r.Header.Get("wysepay-timestamp") + ".")) mac.Write(body) expected := hex.EncodeToString(mac.Sum(nil)) if !hmac.Equal([]byte(expected), []byte(r.Header.Get("wysepay-signature"))) { w.WriteHeader(http.StatusUnauthorized) return } if r.Header.Get("wysepay-event") == "transaction.paid" { var data struct { Metadata map[string]any `json:"metadata"` } json.Unmarshal(body, &data) // libere o pedido data.Metadata["orderId"] (uma vez só) } w.WriteHeader(http.StatusOK) } ``` ```java // Spring Boot. HexFormat precisa do Java 17+. import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.HexFormat; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController public class WysePayWebhook { @PostMapping("/webhooks/wysepay") public ResponseEntity receive( @RequestBody byte[] body, // corpo cru @RequestHeader("wysepay-timestamp") String timestamp, @RequestHeader("wysepay-signature") String signature, @RequestHeader("wysepay-event") String event) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec( System.getenv("WYSEPAY_WEBHOOK_SECRET").getBytes(StandardCharsets.UTF_8), "HmacSHA256")); mac.update((timestamp + ".").getBytes(StandardCharsets.UTF_8)); String expected = HexFormat.of().formatHex(mac.doFinal(body)); if (!MessageDigest.isEqual( expected.getBytes(StandardCharsets.UTF_8), signature.getBytes(StandardCharsets.UTF_8))) { return ResponseEntity.status(401).build(); } if ("transaction.paid".equals(event)) { // libere o pedido: leia metadata.orderId do JSON em body (uma vez só) } return ResponseEntity.ok().build(); } } ``` ```ruby # Sinatra require 'json' require 'openssl' require 'sinatra' post '/webhooks/wysepay' do body = request.body.read # corpo cru timestamp = request.env['HTTP_WYSEPAY_TIMESTAMP'].to_s signature = request.env['HTTP_WYSEPAY_SIGNATURE'].to_s expected = OpenSSL::HMAC.hexdigest('SHA256', ENV.fetch('WYSEPAY_WEBHOOK_SECRET'), "#{timestamp}.#{body}") halt 401 unless Rack::Utils.secure_compare(expected, signature) data = JSON.parse(body) if request.env['HTTP_WYSEPAY_EVENT'] == 'transaction.paid' # libere o pedido data['metadata']['orderId'] (uma vez só) end status 200 end ``` ## Responda rápido [#responda-rápido] Responda com qualquer status `2xx` em até **8 segundos**. Se o trabalho for demorado (e-mail, nota fiscal), guarde o evento, responda `200` e processe depois. ## Novas tentativas [#novas-tentativas] Se a sua URL não responder `2xx` a tempo, a WysePay tenta de novo depois de **1 minuto, 5 minutos, 30 minutos, 2 horas e 6 horas**: até 6 tentativas no total. Em **Webhooks**, no painel, você vê cada entrega e a resposta do seu servidor, e pode usar **Reenviar evento**: ele cria uma entrega nova, com outro `wysepay-delivery-id` e uma assinatura nova. Se todas as tentativas falharem, você pode ser avisado por e-mail (ligue em **Configurações → Notificações**). ## Entregas repetidas [#entregas-repetidas] O mesmo evento pode chegar mais de uma vez (por exemplo, se a sua resposta se perdeu no caminho). Trate os eventos de forma idempotente: antes de liberar, confira se o pedido daquela transação (`id`) já foi liberado. O `wysepay-delivery-id` ajuda a reconhecer tentativas repetidas, mas um reenvio manual chega com um id novo. # Documentação da WysePay (/) Escolha por onde começar: Gere seu primeiro Pix em 5 minutos, com uma chave de teste e sem dinheiro real. Crie links de pagamento, acompanhe vendas e clientes, saque e responda MEDs. ## Para quem integra [#para-quem-integra] * [Autenticação e permissões](/api/autenticacao): chaves `wyp_test_` e `wyp_`, permissões por recurso e IPs permitidos. * [Webhooks](/api/webhooks): seja avisado quando um pagamento é confirmado, e valide a assinatura. * [Referência da API](/api/referencia/gerar-pix): cada endpoint, com o botão **Testar** para fazer a chamada pela própria página. * [OpenAPI e Postman](/api/openapi): baixe a especificação e a coleção pronta. ## Para quem vende [#para-quem-vende] * [Criar conta e liberar produção](/painel/criar-conta) * [Links de pagamento](/painel/links-de-pagamento) e [personalizar o checkout](/painel/personalizar-checkout) * [Saldo e saques](/painel/saldo-e-saques) * [MED: quando um pagamento é contestado](/painel/med) Dúvidas? Fale com a gente na [comunidade do Discord](https://discord.gg/t7a2ppxjpu) ou pelo chat do painel. # Clientes (/painel/clientes) Em **Clientes** fica a sua carteira, um cliente por CPF ou CNPJ. ## Como alguém vira cliente [#como-alguém-vira-cliente] * Ao preencher um CPF ou CNPJ válido no checkout, mesmo sem pagar. * Quando você cadastra, em **Clientes** ou na hora de gerar um Pix direto. Os dados são atualizados a cada compra. ## O que você vê e faz [#o-que-você-vê-e-faz] * Todas as compras do cliente, pagas ou não. * Editar os dados e o endereço. * Escrever **notas internas** e adicionar **tags** (ex.: VIP) para filtrar a lista. O cliente nunca vê as notas nem as tags. * Gerar um Pix direto para ele. ## Exportar [#exportar] O botão **Exportar CSV** segue os filtros da tela, inclusive a tag escolhida. # Criar conta e liberar produção (/painel/criar-conta) ## Quem pode ter conta [#quem-pode-ter-conta] Pessoas físicas (CPF) maiores de 18 anos e empresas (CNPJ), inclusive MEI. Cada CPF ou CNPJ pode ter uma conta. ## Criar a conta [#criar-a-conta] 1. No [painel](https://app.wysepay.com.br), clique em **Criar conta**. 2. Informe nome completo, e-mail, CPF ou CNPJ e uma senha, e aceite os Termos de Uso e a Política de Privacidade. 3. Digite o código de 6 números que chega no seu e-mail. Não chegou? Confira o spam e peça um novo na mesma tela. Pronto: você já entra no painel. ## Comece no modo teste [#comece-no-modo-teste] Logo depois do cadastro o **modo teste** está liberado: você cria links, testa o checkout, simula pagamentos e integra a API, sem dinheiro real e sem verificação. Ligue pela chave **Modo teste** no topo da tela. Veja [Modo teste](/api/modo-teste). ## Liberar a produção [#liberar-a-produção] Para receber pagamentos reais, criar chaves de API de produção e sacar, faltam três etapas, todas pelo painel: **Complete o perfil** em **Configurações → Conta**: nome fantasia, telefone, site ou Instagram, segmento e faturamento estimado. **Verifique a sua identidade**: um documento com foto e uma selfie, em cerca de 2 minutos. Veja [Verificação](/painel/verificacao). **Verifique a empresa** (só para CNPJ): os dados da Receita e, quando for preciso, documentos como o contrato social. Quando tudo é aprovado, a conta passa a operar em produção e você é avisado no painel e por e-mail. # Guias do painel (/painel) O [painel](https://app.wysepay.com.br) é onde você cria cobranças, acompanha as vendas e cuida do dinheiro. Não precisa de site nem de programação: um link de pagamento enviado pelo WhatsApp já basta para vender. Cadastro, modo teste e o que falta para receber pagamentos reais. Crie um link, envie ao cliente e receba por Pix num checkout com a sua marca. Cada venda, paga ou não, e como recuperar as abandonadas. Quando o dinheiro fica disponível e como sacar. ## Instale como aplicativo [#instale-como-aplicativo] O painel funciona como app no celular e no computador, direto do navegador: * **Android e computador:** use **Instalar aplicativo** no menu do navegador. * **iPhone e iPad:** abra no Safari, toque em **Compartilhar** e depois em **Adicionar à Tela de Início**. Instalado, ele abre em tela cheia e recebe [notificações de venda](/painel/notificacoes). # Links de pagamento (/painel/links-de-pagamento) ## Criar um link [#criar-um-link] 1. Clique em **Nova cobrança** e deixe selecionado **Link de pagamento**. 2. Informe o valor (mínimo R$ 5,00) e a descrição. 3. Em **Mais opções**, se precisar: * **Pedir endereço do cliente**: o checkout pede o endereço, na mesma tela dos dados. O CEP preenche rua, bairro e cidade. * **Expiração**: até quando o link aceita pagamentos. * **Pagamentos aceitos**: uso único, limitado (a quantidade que você definir) ou ilimitado. * **URL de retorno**: para onde o cliente volta depois de pagar. 4. Copie o link ou baixe o QR Code e envie ao cliente. ## Como o cliente paga [#como-o-cliente-paga] 1. Abre o link e preenche, numa tela só, CPF ou CNPJ, nome, e-mail, celular e, se o link pedir, o endereço. 2. Toca em **Pagar com Pix** e recebe o QR Code e o copia e cola, com o prazo em contagem regressiva. 3. Paga pelo app do banco. A tela acompanha sozinha e mostra o comprovante quando confirma. O comprovante também chega por e-mail. Se ele fechar a página e voltar depois no mesmo aparelho, o checkout continua de onde parou. Se o Pix vencer, ele pode gerar outro pelo mesmo link, enquanto o link estiver ativo. ## URL de retorno [#url-de-retorno] Com uma URL de retorno, o comprovante mostra **Voltar para a loja** e, logo depois do pagamento, leva o cliente de volta sozinho em 8 segundos (ele pode escolher ficar). A URL recebe o código da transação no parâmetro `wysepay_transaction_id`. Qualquer pessoa pode abrir a URL de retorno. Confirme o pagamento no painel ou pelo [webhook](/api/webhooks) `transaction.paid` antes de entregar. ## Esgotado [#esgotado] Quando um link atinge o limite de pagamentos, ele mostra "Link esgotado" e não aceita mais pagamentos. # MED (/painel/med) O MED (Mecanismo Especial de Devolução) é a forma, criada pelo Banco Central, de um pagador contestar um Pix pelo banco dele, por exemplo em caso de suspeita de golpe. Quando isso acontece com uma venda sua, o valor contestado fica **bloqueado** no saldo até a análise terminar. ## Como você fica sabendo [#como-você-fica-sabendo] * A contestação aparece em **MEDs**, com um contador no menu. * Por e-mail, se o aviso de MED estiver ligado em **Configurações → Notificações**. * Pelo webhook `dispute.created`, se você usa a API. ## Responder [#responder] Responda assim que receber. Recomendamos manter o aviso de MED sempre ligado. 1. Em **MEDs**, abra a contestação. 2. Responda com evidências da venda: o que foi vendido, quando foi entregue e qualquer comprovante, como nota fiscal, rastreio ou conversas com o cliente. 3. Envie. ## O resultado [#o-resultado] * **Devolução confirmada:** o valor é debitado do seu saldo. * **Devolução negada:** o valor é liberado de novo. # Notificações (/painel/notificacoes) Tudo fica em **Configurações → Notificações**. ## Por e-mail [#por-e-mail] Escolha receber avisos de: * pagamento recebido (com valor, taxa e líquido); * MED aberto (recomendamos manter ligado: o prazo de resposta é curto); * saque solicitado; * webhook com falha. ## No celular e no computador [#no-celular-e-no-computador] Em **Neste dispositivo**, ligue as notificações push. Você escolhe, em cada aparelho, o que receber: venda aprovada, venda pendente (Pix gerado aguardando pagamento, desligada por padrão), MEDs, saques e webhook com falha. A verificação da conta e os saques não concluídos sempre avisam. Em **O que aparece na notificação**, ligue ou desligue separadamente o nome do cliente, o produto e o valor, por exemplo se outras pessoas veem a sua tela de bloqueio. As notificações só funcionam com o painel instalado na tela de início. Veja [como instalar](/painel#instale-como-aplicativo). # Nova cobrança (/painel/nova-cobranca) O botão **Nova cobrança**, no topo do menu, oferece dois caminhos: | | Pix direto | Link de pagamento | | ---------------------- | ---------------------------------- | -------------------------------------------------- | | O que gera | QR Code e copia e cola, na hora | Um checkout para enviar ao cliente | | Quem preenche os dados | Você | O cliente | | Bom para | Atendimento presencial ou por chat | Vender à distância, vários clientes, redes sociais | O valor mínimo é R$ 5,00 nos dois. ## Pix direto [#pix-direto] 1. Escolha **Pix direto**. 2. Informe o valor e a descrição. 3. Escolha o cliente: busque por nome, CPF ou e-mail, ou cadastre um novo ali mesmo. O Pix precisa de nome, CPF ou CNPJ, e-mail e celular. 4. Mostre o QR Code ao cliente ou envie o copia e cola. A tela avisa quando o pagamento cai. ## Link de pagamento [#link-de-pagamento] Veja [Links de pagamento](/painel/links-de-pagamento). # Personalizar o checkout (/painel/personalizar-checkout) Em **Cobranças → Personalizar checkout** você deixa o checkout com a cara da sua marca. Vale para todos os seus links, e a prévia mostra as telas de dados, do Pix e do comprovante, no computador e no celular. ## Logo [#logo] PNG, JPG, WebP ou SVG. Fundo transparente fica melhor. Imagens grandes são reduzidas automaticamente. Sem logo, aparece o nome da conta. ## Cores [#cores] Cada parte tem a sua cor: * **Resumo**: a coluna com a logo, a descrição e o valor (fundo e texto). * **Formulário**: onde o cliente preenche os dados e vê o Pix (fundo e texto). * **Campos**: fundo, borda e a cor de destaque, que também aparece no foco e na barra do prazo do Pix. * **Botão**: fundo e texto do **Pagar com Pix**. Se uma combinação deixar o texto difícil de ler, aparece um aviso com o botão **Corrigir**. ## Fonte e cantos [#fonte-e-cantos] Fontes: Geist, Inter, Poppins, Manrope, Lora ou Pacifico. A Pacifico é cursiva, por isso vale só para o nome da loja e o título; o resto fica numa fonte de leitura fácil. Os cantos podem ser retos, leves, médios ou redondos. ## Textos [#textos] * **Título**: aparece acima da descrição, no resumo. * **Texto do botão**: por padrão, "Pagar com Pix". * **Nota de rodapé**: uma linha abaixo do botão, como uma política de troca. Clique em **Salvar** para aplicar. Para voltar ao visual original, use **Restaurar padrão WysePay**. # Extrato e relatórios (/painel/relatorios) ## Extrato [#extrato] Em **Extrato** você vê todas as entradas e saídas do saldo, por período: vendas pagas, taxas, saques e valores de MED. ## Exportar em CSV [#exportar-em-csv] Para conciliar ou mandar à contabilidade, exporte em CSV: * **Transações**, **saques** e **extrato**, por período. * **Vendas** e **clientes**, seguindo os filtros da tela. Nos seletores de período há opções como **Este mês** e **Mês anterior**, que segue o mês do calendário no horário de Brasília. # Saldo e saques (/painel/saldo-e-saques) ## Os três saldos [#os-três-saldos] Na **Visão geral** do painel: | Saldo | O que é | | -------------- | ------------------------------------------------------------------ | | **Disponível** | O que você já pode sacar. | | **Pendente** | Vendas pagas que ainda estão no prazo de liberação. | | **Bloqueado** | Valor retido, por exemplo, por um [MED](/painel/med) em andamento. | Cada venda entra no saldo já descontada a taxa. Hoje o padrão é liberar no mesmo dia (D+0); o prazo pode ser maior para uma conta específica, quando o risco das operações justificar. ## Sacar [#sacar] 1. Vá em **Saques**. 2. Informe o valor e a chave Pix de destino: CPF, CNPJ, celular, e-mail ou chave aleatória. 3. Confirme. * O mínimo é **R$ 6,00**, e o valor precisa ser maior que a taxa de saque (veja [Taxas e planos](/painel/taxas-e-planos)). * Não pode passar do saldo disponível. * A conta precisa estar verificada. ## Sacar pela API [#sacar-pela-api] Também dá para sacar pela API, com uma chave que tenha a permissão de saques (ela vem desligada). Defina um limite diário e libere só o IP do seu servidor. Veja [Saldo e saques na API](/api/saques). ## Saque em mais de uma transferência [#saque-em-mais-de-uma-transferência] Um saque pode ser pago em mais de uma transferência Pix. Isso é normal: acompanhe em **Saques**, inclusive quando ele é pago só em parte. ## Saque não concluído [#saque-não-concluído] Se um saque (ou parte dele) não for concluído, o valor volta para o seu saldo e você é avisado. Com dúvidas sobre um saque, fale com o suporte informando a data e o valor. ## Saldo negativo [#saldo-negativo] Pode acontecer quando uma devolução de MED é confirmada depois que o valor da venda já foi sacado. O valor devido é descontado das vendas seguintes. # Taxas e planos (/painel/taxas-e-planos) Você paga uma taxa só nas vendas aprovadas. Criar links e testar a integração não custa nada. ## Escolher o plano [#escolher-o-plano] Em **Configurações → Taxas** aparecem os planos lado a lado, com a taxa por venda e por saque de cada um. Clique em **Usar este plano** e confirme. Você pode trocar quando quiser. * Um plano **percentual** costuma sair mais barato em vendas de valor baixo. * Um plano de **valor fixo** costuma sair mais barato em vendas de valor alto. Compare com o valor médio das suas vendas. ## Quando a taxa muda [#quando-a-taxa-muda] A taxa é definida quando a cobrança é criada. Trocar de plano vale para as cobranças criadas depois da troca; as que já existem mantêm a taxa de quando foram criadas. As taxas podem mudar com aviso prévio, e a nova vale para as cobranças criadas depois da mudança. ## Taxa de saque [#taxa-de-saque] Pode existir, conforme o plano da sua conta, e aparece em **Configurações → Taxas**. O valor do saque precisa ser maior que ela. ## Taxa negociada [#taxa-negociada] Contas com taxa negociada pagam a taxa combinada e não veem a escolha de planos. Para volumes maiores, fale com o comercial: [comercial@wysepay.com.br](mailto:comercial@wysepay.com.br). # Vendas (/painel/vendas) Em **Vendas** aparecem todas as vendas, de qualquer origem: link de pagamento, Pix pelo painel ou API. ## Situação e etapa [#situação-e-etapa] Cada venda mostra a situação e, se não foi paga, a etapa em que o cliente parou: | Situação | Quer dizer | | ---------------- | ---------------------------------------------------------------------- | | **Paga** | O pagamento foi confirmado. | | **Em andamento** | O cliente ainda está no checkout ou o Pix ainda não venceu. | | **Abandonada** | O cliente ficou 30 minutos sem avançar, ou o Pix venceu sem pagamento. | As etapas vão de **Abriu o checkout** e **Preenchendo os dados** até **Pix gerado** e **Pago**, passando por **Preenchendo o endereço** quando o link pede endereço. ## Funil [#funil] No topo fica o gráfico do funil dos links de pagamento, da esquerda para a direita: quantos abriram o checkout, começaram a preencher, geraram o Pix e pagaram. Em cada etapa aparece quantos seguiram da etapa anterior; na última, também quanto de quem abriu chegou a pagar. Onde a faixa mais afina é onde os clientes mais desistem. No celular, as etapas aparecem uma embaixo da outra. Use o seletor de período ao lado para comparar, por exemplo, este mês com o mês anterior. ## Recuperar uma venda abandonada [#recuperar-uma-venda-abandonada] Abra a venda. Se o cliente já informou um contato, aparece o bloco **Recuperar venda**, com uma mensagem pronta e botões para enviar no WhatsApp, por e-mail ou copiar o link. O link abre o checkout com os dados que o cliente já tinha preenchido, para ele só terminar. ## Exportar [#exportar] O botão **Exportar CSV** segue os filtros da tela. Veja [Relatórios](/painel/relatorios). # Verificação (/painel/verificacao) ## Identidade [#identidade] Leva cerca de 2 minutos. Tenha em mãos um documento com foto (RG, CNH ou passaporte): 1. Fotografe o documento. 2. Tire uma selfie, que é comparada com a foto do documento. A verificação é feita por um parceiro especializado, com apoio de sistema automatizado. O resultado aparece no painel e chega por e-mail. * **Parou no meio?** Continue de onde parou quando quiser, pelo painel. * **Faltou uma etapa ou a foto ficou ilegível?** Refaça pelo painel. * **Foi recusada?** Fale com o suporte para entender o motivo. Você também pode pedir que uma pessoa revise a decisão automatizada. ## Empresa (CNPJ) [#empresa-cnpj] Consultamos os dados públicos da empresa na Receita Federal, incluindo o quadro de sócios. Podemos pedir: * o **contrato social** (a última alteração contratual consolidada) ou o estatuto com a ata de eleição da diretoria; * uma **procuração**, quando o responsável pela conta não aparece entre os sócios. Os arquivos podem ter até 10 MB. A análise é feita pela equipe da WysePay, normalmente em até 1 dia útil. Se faltar algo, o pedido de ajuste aparece no painel, explicando o que é necessário. Para MEI, a verificação usa os dados do CNPJ na Receita e a verificação de identidade do responsável. # Gerar uma cobrança Pix (/api/referencia/gerar-pix) Cria a cobrança e devolve o código Pix (copia e cola e QR Code). O status começa em `WAITING_PAYMENT`; quando o cliente pagar, chega o webhook `transaction.paid`. Permissão da chave: `charges:write`. # Listar transações (/api/referencia/listar-transacoes) As cobranças da conta, da mais nova para a mais antiga, com filtros. Veja Paginação. Permissão da chave: `transactions:read`. # Consultar uma transação (/api/referencia/consultar-transacao) A situação atual da cobrança. Um Pix vencido sem pagamento aparece como `EXPIRED`. Permissão da chave: `transactions:read`. # Listar links de pagamento (/api/referencia/listar-links) Os links da conta, do mais novo para o mais antigo. Permissão da chave: `payment_links:read`. # Criar um link de pagamento (/api/referencia/criar-link) Cria um checkout com o valor e a descrição. Envie a `url` ao cliente: ele preenche os dados, paga com Pix e vê o comprovante. Permissão da chave: `payment_links:write`. # Consultar um link (/api/referencia/consultar-link) Um link de pagamento e se ele ainda aceita pagamentos (`active`). Permissão da chave: `payment_links:read`. # Desativar um link (/api/referencia/desativar-link) O link para de aceitar pagamentos e o checkout mostra que ele não está disponível. Cobranças já geradas continuam valendo. Permissão da chave: `payment_links:write`. # Listar clientes (/api/referencia/listar-clientes) Os clientes da conta, do mais novo para o mais antigo. Filtre por `document` para achar um CPF ou CNPJ. Permissão da chave: `customers:read`. # Cadastrar um cliente (/api/referencia/cadastrar-cliente) Cadastra o cliente, ou atualiza o que já tem esse CPF ou CNPJ (há um cliente por documento). Campos não enviados ficam como estavam. Permissão da chave: `customers:write`. # Consultar um cliente (/api/referencia/consultar-cliente) Os dados e o endereço de um cliente. Permissão da chave: `customers:read`. # Atualizar um cliente (/api/referencia/atualizar-cliente) Muda os campos enviados. O CPF ou CNPJ não muda. Permissão da chave: `customers:write`. # Consultar o saldo (/api/referencia/consultar-saldo) Disponível, a liberar e bloqueado, e quanto dá para sacar agora. Permissão da chave: `balance:read`. # Listar saques (/api/referencia/listar-saques) Os saques da conta (pelo painel e pela API), do mais novo para o mais antigo. Permissão da chave: `withdrawals:read`. # Sacar para uma chave Pix (/api/referencia/sacar) Tira o valor do saldo e envia para a chave Pix. Precisa da permissão `withdrawals:write`, que vem desligada, e respeita o limite diário e os IPs da chave. Com chave de teste, o saque é simulado e pago na hora. Permissão da chave: `withdrawals:write`. # Consultar um saque (/api/referencia/consultar-saque) A situação de um saque. Permissão da chave: `withdrawals:read`. # Simular o pagamento (/api/referencia/simular-pagamento) Só com chave de teste: marca a cobrança de teste como paga e envia o webhook `transaction.paid`, como num pagamento real. Permissão da chave: `charges:write`. # Cobrança criada (/api/referencia/eventos/transaction-created) Um Pix foi gerado (pela API, pelo painel ou por um link). # Cobrança paga (/api/referencia/eventos/transaction-paid) O pagamento foi confirmado. Use este evento para liberar o pedido. # Cobrança vencida (/api/referencia/eventos/transaction-expired) O Pix passou do `expiresAt` sem pagamento. Cancele o pedido ou gere uma cobrança nova. # MED aberto (/api/referencia/eventos/dispute-created) O pagador contestou um pagamento pelo banco dele. # MED respondido (/api/referencia/eventos/dispute-responded) A sua defesa do MED foi enviada. # MED ganho (/api/referencia/eventos/dispute-won) A contestação foi negada: o valor volta a ficar disponível para você. # MED perdido (/api/referencia/eventos/dispute-lost) A devolução foi confirmada: o valor foi devolvido ao pagador. # Saque criado (/api/referencia/eventos/withdrawal-created) Um saque foi pedido, pelo painel ou pela API. # Saque pago (/api/referencia/eventos/withdrawal-paid) O dinheiro chegou na chave Pix de destino. # Saque pago em parte (/api/referencia/eventos/withdrawal-partially-paid) Parte das transferências do saque não foi concluída; o valor dela voltou ao saldo. # Saque não concluído (/api/referencia/eventos/withdrawal-failed) O saque não foi feito; o valor voltou ao saldo.