# Authentication (https://docs.weetpay.com/en/docs/authentication) Client ID and client secret in the headers of every request. Every API call carries the credentials generated under **Developers** in the dashboard. There is no session token or login step: each request is authenticated on its own, always over HTTPS. ## Accepted formats [#accepted-formats] Use **one** of the three formats (they are equivalent): ```http vspi: weetpay-100123 vsps: 3f1c9a52-7b0e-4d61-9a8c-2e5f4b7d1a90 ``` Same names as the compatible gateway API: migrating requires no code changes, only the URL and keys. ```http x-client-id: weetpay-100123 x-client-secret: 3f1c9a52-7b0e-4d61-9a8c-2e5f4b7d1a90 ``` ```http Authorization: Basic d2VldHBheS0xMDAxMjM6M2YxYzlhNTItN2IwZS00ZDYxLTlhOGMtMmU1ZjRiN2QxYTkw ``` The value is `base64(":")`. ## Examples [#examples] ```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()) ``` ## Authentication responses [#authentication-responses] Messages are returned in Portuguese. | HTTP | `message` | `code` | What to do | | ----- | -------------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------- | | `401` | Credenciais ausentes | — | send the client ID and client secret | | `401` | Credenciais inválidas | — | check your keys; the secret may have been updated in the dashboard | | `403` | Verificação de identidade pendente | `KYC_REQUIRED` | complete identity verification | | `403` | Conta bloqueada. Fale com o suporte. | `ACCOUNT_BLOCKED` | contact support | | `429` | Limite de requisições por minuto atingido | `RATE_LIMITED` | wait and retry ([limits](/en/docs/limits-and-rules)) | | `429` | Muitas tentativas com credenciais inválidas. Tente mais tarde. | `RATE_LIMITED` | the IP sent too many wrong credentials; fix them and wait a few minutes | ## Best practices [#best-practices] The client secret gives access to your balance. **Never** put it in a mobile app, website (browser JavaScript) or repository. Call the API from your server only. * Keep the keys in environment variables or a secrets vault. * If you suspect a leak, use **Update credentials** under Developers: the old secret stops working immediately (the client ID stays the same). * Keep **API payouts** disabled if you only receive payments — even with leaked keys, nobody can withdraw money. * The client secret also signs your transaction callbacks: updating it changes the validation key ([Callbacks](/en/docs/webhooks)). # Errors (https://docs.weetpay.com/en/docs/errors) Single error format, HTTP status codes and the most common messages. Every API error has the same shape: ```json { "response": "ERROR", "message": "amount inválido (em reais, ex.: 10.50)" } ``` Some authentication errors also carry `code` (`RATE_LIMITED`, `ACCOUNT_BLOCKED`, `KYC_REQUIRED`). `message` is in Portuguese and ready to log; to decide what to do in code, use the **HTTP status** (and `code`, when present). ## HTTP status [#http-status] | HTTP | Meaning | Retry? | | --------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | `200` | success | — | | `400` | invalid data or business rule (balance, limit, duplicate `requestNumber`) | no, fix the request | | `401` | missing or invalid credentials | no | | `403` | account blocked, KYC pending or operation not enabled | no | | `404` | transaction or endpoint not found | no | | `409` | idempotency key reused with a different request | no | | `429` | rate limit | yes, with backoff | | `500` / `502` / `503` | temporary failure | yes, with growing backoff — for payouts, **always with the same `Idempotency-Key`** | ## Common messages [#common-messages] ### Charges [#charges] | `message` | Cause | | ---------------------------------------------------------------- | ---------------------------------------------------------------- | | `requestNumber é obrigatório` | field missing or empty | | `requestNumber já utilizado` | a charge with this `requestNumber` already exists on the account | | `amount inválido (em reais, ex.: 10.50)` | zero, negative, non-numeric or more than 2 decimals | | `client.name é obrigatório` | name shorter than 3 characters | | `client.document inválido (CPF ou CNPJ)` | check digits do not match | | `client.email inválido` | malformed e-mail | | `callbackUrl inválida` | not http(s) or longer than 500 characters | | `Split não está liberado nesta conta. Fale com o suporte.` (403) | `split` without Compliance approval | | `split.account inválida para split` | destination account missing, inactive or your own | | `split.percentageSplit deve ser um inteiro entre 1 e 100` | percentage out of range | Amounts below the platform charge minimum or above its maximum also return `400`, with the limit in the message. ### Payouts [#payouts] | `message` | Cause | | ------------------------------------------------------------------------------- | ------------------------------------------------ | | `Saque pela API não está liberado nesta conta. Ative em Desenvolvedores.` (403) | enable API payouts in the dashboard | | `typeKey inválido (use CPF, CNPJ, EMAIL, PHONE ou EVP)` | unknown key type | | `key inválida para o typeKey informado` | key does not match its type | | `document deve ser o mesmo CPF/CNPJ da chave` | CPF/CNPJ key with a different `document` | | `Saque só para a chave CPF/CNPJ do titular da conta…` (403) | account not enabled for third-party payouts | | `insufficient balance` | balance lower than amount + payout fee | | `O valor mínimo para saque é …` / `O valor máximo por saque é …` | outside per-payout limits | | `Limite diário de saque atingido…` | the last 24 h total would exceed the daily limit | | `Esta chave de idempotência já foi usada em outro saque` (409) | same `Idempotency-Key` with another amount/key | | `Pagamento de PIX copia e cola (QRCODE) ainda não está disponível` | `typeKey: "QRCODE"` is not supported | ### Lookup [#lookup] | `message` | Cause | | -------------------------------------------------- | -------------------------------------- | | `Informe requestNumber, idTransaction ou endToEnd` | body without any identifier | | `Transação não encontrada` (404) | not found on your account | | `Endpoint não encontrado` (404) | wrong path (check `/api/v1/gateway/…`) | # Quickstart (https://docs.weetpay.com/en/docs/getting-started) From sign-up to your first paid charge, in five steps. ### Create and verify your account [#create-and-verify-your-account] Sign up at [app.weetpay.com](https://app.weetpay.com) and submit the identity verification documents. **The API only works after approval** — until then every call returns `403` with `code: "KYC_REQUIRED"`. ### Generate credentials [#generate-credentials] In the dashboard, open **Developers** and reveal your keys with your transaction PIN. You get: * **Client ID** — `weetpay-`, never changes; * **Client secret** — a UUID. Keep it in a secrets vault; **Update credentials** issues a new one and revokes the old one immediately. ### Create a charge [#create-a-charge] ```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": "order-12345", "amount": 49.90, "callbackUrl": "https://yourstore.com/webhooks/weetpay", "client": { "name": "Maria da Silva", "document": "12345678909", "email": "maria@email.com" } }' ``` The response contains the PIX code (`paymentCode`) and the QR Code image (`paymentCodeBase64`): ```json { "idTransaction": "cmh1x2y3z0001ab12cd34ef56", "paymentCode": "00020101021226850014br.gov.bcb.pix…", "paymentCodeBase64": "iVBORw0KGgoAAAANSUhEUgAA…", "response": "OK", "status": "WAITING_FOR_APPROVAL" } ``` Show the customer the image `data:image/png;base64,{paymentCodeBase64}` and a "copy" button with `paymentCode`. ### Receive the payment notice [#receive-the-payment-notice] When the PIX is paid, WeetPay sends a `POST` to `callbackUrl`: ```json { "requestNumber": "order-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" } ``` Check the `X-WeetPay-Signature`, release the order and reply `200`. Details in [Callbacks and webhooks](/en/docs/webhooks). ### Check anytime [#check-anytime] Use [Get transaction](/en/docs/transactions/get-transaction) to check the status at any time (for example, when the customer comes back to the order page) and [Get balance](/en/docs/account/balance) to see what is available. ## Reference clients [#reference-clients] Copy-paste ready, no dependencies: * [weetpay-client.mjs](/examples/weetpay-client.mjs) — Node.js 18+ (native `fetch`), with callback validation; * [weetpay-client.php](/examples/weetpay-client.php) — PHP 7.4+ with cURL, with callback validation. ```js import { weetpay } from './weetpay-client.mjs'; const { status, data } = await weetpay('POST', '/api/v1/gateway/request-qrcode', { requestNumber: 'order-12345', amount: 49.9, client: { name: 'Maria da Silva', document: '12345678909' }, }); ``` # Idempotency (https://docs.weetpay.com/en/docs/idempotency) Retry requests safely — a charge or payout is never created twice. Network failures happen: the request reaches WeetPay but the response is lost. The API is designed so you can **repeat the same request without fear**. ## Payouts (`pix-payment`) [#payouts-pix-payment] Send a unique key per payout — ideally the payment ID in your system: ```http POST /api/v1/gateway/pix-payment Idempotency-Key: payout-2026-10-30-0001 ``` The `x-idempotency-key` header is also accepted or, without a header, the `requestNumber` body field. | Situation | Result | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | first time | payout created, `200 { id, status: "processing" }` | | same key, same amount and PIX key | **the same payout** — `200` with the same `id` and the `Idempotent-Replayed: true` header. Nothing is debited again | | same key, different amount or PIX key | `409` — "Esta chave de idempotência já foi usada em outro saque" | | no key at all | the same amount to the same PIX key within **1 minute** returns the previous payout | The key is valid forever on your account (it does not expire) and has at most 100 characters. Generate the key **once** per payment and store it before calling the API. Generating a new key on every retry defeats the protection. ## Charges (`request-qrcode`) [#charges-request-qrcode] `requestNumber` is unique per account: a second charge with the same `requestNumber` is rejected with `400 requestNumber já utilizado`. If the creation response is lost, recover the charge with [Get transaction](/en/docs/transactions/get-transaction) using the `requestNumber` — the PIX code comes back in `pixCopiaECola` while it is pending. ## Callbacks [#callbacks] On your side, notices may also arrive more than once (a retry after a timeout, for example). Process each `idTransaction` / `id` only once. See [Callbacks and webhooks](/en/docs/webhooks#delivery-and-retries). # Introduction (https://docs.weetpay.com/en/docs) Welcome to the WeetPay API documentation Download OpenAPI (Postman/Insomnia) AI guide (llms.txt) Quickstart **WeetPay** is a PIX payment gateway. Through the API your application creates dynamic QR Code charges, gets real-time payment notices, sends PIX to any key and looks up transactions and balance — with a handful of HTTP calls and amounts in BRL reais. ## What you can do [#what-you-can-do] Incoming payments (**cash-in**) become PIX "copia e cola" charges with a ready-to-display QR Code. When the customer pays, the amount is credited to your balance and WeetPay notifies your system at `callbackUrl`. Outgoing payments (**cash-out**) leave your balance to a PIX key, protected against duplicate sending, with the result also delivered by callback. ## Why integrate? [#why-integrate] four endpoints, plain JSON and amounts in reais ( `49.90` ) same paths, fields and responses as the most widely used gateway API — migrate by swapping the URL and keys payment and payout notices with HMAC-SHA256 and automatic retries Idempotency-Key guarantees a PIX is never sent twice PIX code and base64 PNG image in the same response share incoming payments with another WeetPay account (upon approval) ## Modules [#modules] ## Base URLs [#base-urls] | Environment | URL | | ---------------- | ------------------------------------------------------------ | | API (production) | `https://api.weetpay.com` | | Dashboard | `https://app.weetpay.com` — credentials under **Developers** | | Documentation | `https://docs.weetpay.com` | Every request carries the **client ID** and **client secret** in the `vspi` and `vsps` headers. Errors always look like `{ "response": "ERROR", "message": "…" }`. See [Authentication](/en/docs/authentication) and [Errors](/en/docs/errors). ## Next steps [#next-steps] Follow the [Quickstart](/en/docs/getting-started) to create your first charge in minutes. For assistants and coding agents, use [llms.txt](/llms.txt?lang=en) (index) or [llms-full.txt](/llms-full.txt?lang=en) (full content). # Limits and rules (https://docs.weetpay.com/en/docs/limits-and-rules) Request limits, amount limits and the security rules for payouts and split. ## Requests [#requests] | Limit | Value | Response | | -------------------------- | ------------------------------------------------- | ----------------------------- | | Per account (client ID) | **600 requests per minute** | `429`, `code: "RATE_LIMITED"` | | Invalid credentials per IP | 30 failures in 5 minutes block the IP for a while | `429`, `code: "RATE_LIMITED"` | On `429`, wait a few seconds and retry with growing backoff. To track payments, use [callbacks](/en/docs/webhooks) instead of polling. ## Amounts [#amounts] * Amounts are always in **reais**, with up to 2 decimals (`49.9`, `"49.90"` or `"49,90"`). * Charges and payouts have a **per-operation minimum and maximum** set by WeetPay; payouts also have a **daily limit** (rolling 24 h window). When a limit is exceeded, the error message states the allowed value. * **QR Code validity** is set by the platform (default: 1 hour). After that the charge becomes `EXPIRED`. * Incoming and payout fees follow your contract and are shown in the dashboard. Incoming payments are credited net of fees; the payout fee is debited together with the amount. ## API payouts [#api-payouts] **Enabled by you.** API payouts are **off** by default. Turn them on under **Developers** in the dashboard (requires your transaction PIN). While off, `pix-payment` returns `403`. **Destination.** Unless WeetPay enables it, payouts can only go to the **account holder's CPF/CNPJ key**. To pay third parties (suppliers, affiliates, customers), ask support to enable it. **Approval.** Payouts above the platform's auto-approval amount are reviewed by operations before being sent. Meanwhile the payout stays `PROCESSING` and the amount stays reserved. **Result.** Paid or not, the result arrives at `callbackUrl`. A payout that is not paid (rejected on review, unknown key, bank failure) has its amount and fee **refunded** automatically. ## Split [#split] The `split` field on [Create PIX charge](/en/docs/cash-in/create-charge) shares the received amount with another WeetPay account. Since it moves money between accounts, it only works for accounts **enabled by Compliance**. The destination account must be active with approved verification; the percentage is an integer from 1 to 100. ## Identity verification [#identity-verification] The API only answers for accounts with **approved** identity verification (KYC) that are not blocked. Until then, every call returns `403` with `code: "KYC_REQUIRED"`. # Callbacks and webhooks (https://docs.weetpay.com/en/docs/webhooks) Signed payment and payout notices — the right way to reconcile without polling the API. WeetPay notifies your system in two ways, which can be used together: | | **Transaction callback** | **Dashboard webhook** | | --------------- | ------------------------------------------------------- | ---------------------------------------------------------------- | | Where to set it | `callbackUrl` field on each charge or payout in the API | **Webhooks** in the dashboard, one URL per event | | Format | the compatible API payload (amounts in **reais**) | envelope `{ id, event, createdAt, data }` (amounts in **cents**) | | Signed with | the API **client secret** | the webhook secret (`whsec_…`), shown in the dashboard | | Events | charge paid; payout result | charge created, paid, refunded; payout completed, failed | Both: `POST` with `Content-Type: application/json`, signature in the `X-WeetPay-Signature` header and automatic retries on failure. ## Charge paid callback [#charge-paid-callback] Sent to the `callbackUrl` from [Create PIX charge](/en/docs/cash-in/create-charge) when the PIX is paid: ```json { "requestNumber": "order-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" } ``` | Field | Description | | ------------------------------ | --------------------------------------------------- | | `requestNumber` | the identifier you sent on creation | | `statusTransaction` | always `PAID_OUT` (only payments trigger callbacks) | | `idTransaction` | WeetPay charge ID | | `value` | paid amount, in reais (number) | | `debtorName`, `debtorDocument` | who paid, as reported by the bank | | `date` | payment date/time (ISO 8601, UTC) | | `endToEnd` | PIX End-to-End ID | ## Payout callback [#payout-callback] Sent to the `callbackUrl` from [Send PIX](/en/docs/cash-out/pix-payment) when the payout finishes: ```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` is `"sucess"` (spelled this way for compatibility with the original gateway API) or `"not paid"`. A payout that is not paid has its **amount and fee refunded** to your balance automatically; the reason is in `message`. ## Dashboard webhooks [#dashboard-webhooks] Register a URL for each event you want under **Webhooks** in the dashboard. The body comes in an envelope: ```json { "id": "cmh1xa0b10007ab12qq11ww22", "event": "TRANSACTION_PAID", "createdAt": "2026-10-30T13:03:41.000Z", "data": { "id": "cmh1x2y3z0001ab12cd34ef56", "externalId": "order-12345", "status": "PAID", "amount": 4990, "fee": 99, "netAmount": 4891, "description": "Basic t-shirt", "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` | When | `data` | | ---------------------- | ------------------------------------ | ---------------------------------------------- | | `TRANSACTION_CREATED` | charge created | charge | | `TRANSACTION_PAID` | charge paid | charge | | `TRANSACTION_REFUNDED` | charge refunded / disputed | charge + `refund { id, kind, amount, reason }` | | `WITHDRAWAL_COMPLETED` | payout paid | payout | | `WITHDRAWAL_FAILED` | payout rejected or failed (refunded) | payout | On charges, `externalId` is your `requestNumber`; `amount`, `fee` and `netAmount` are in **cents**. Payouts carry `id`, `transactionId`, `status` (`PAID`, `FAILED`, `REJECTED`), `amount`, `fee`, `pixKeyType`, `pixKey`, `endToEndId`, `reason`, `paidAt` and `createdAt`. ## Headers [#headers] | Header | Value | | --------------------- | --------------------------------------------------------------------- | | `X-WeetPay-Signature` | `t=,v1=` — see below | | `X-WeetPay-Event` | event (`TRANSACTION_PAID`, `WITHDRAWAL_COMPLETED`…) | | `X-WeetPay-Delivery` | delivery ID — the same across all attempts; use it to drop duplicates | | `User-Agent` | `WeetPay-Webhooks/1.0` | ## Validating the signature [#validating-the-signature] `v1` is the hex HMAC-SHA256 of `"."`, keyed with the **client secret** (transaction callbacks) or the **webhook secret** (dashboard webhooks). Compute it over the body **exactly as received**, before any parsing, compare in constant time and reject notices whose `t` is too old (e.g. over 5 minutes). ```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)); } ``` ```php $tolerance) return false; return hash_equals(hash_hmac('sha256', $t . '.' . $rawBody, $secret), $parts['v1']); } ``` ```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"]) ``` ## Delivery and retries [#delivery-and-retries] * Reply with any **2xx within 10 seconds**. Any other status, a timeout or a connection error counts as a failure. * Failures are retried after **1, 5, 15, 60, 180, 360, 720 and 1440 minutes** (up to 9 attempts, about 2 days). After that the delivery is marked as failed in the history; you can resend it manually from the dashboard. * The same notice may arrive more than once: key on `idTransaction` / `id` (or `X-WeetPay-Delivery`) and make processing **idempotent**. * The URL must be **public http(s)**. Redirects are not followed and internal network addresses (localhost, 10.x, 192.168.x…) are refused. * Reply fast and process later (queue): the notice does not wait for your system to finish the order. Do not rely on the notice body alone to release a high-value order: validate the signature or confirm with [Get transaction](/en/docs/transactions/get-transaction). # Get balance (https://docs.weetpay.com/en/docs/account/balance) {/* */} # Account (https://docs.weetpay.com/en/docs/account) Available WeetPay wallet balance. `GET /api/v1/gateway/walletBalance` returns the available balance in reais, as a string with two decimals: `{ "currentBalance": "397.70" }`. * Paid charges are credited **net** of the incoming fee. * Payouts reserve the amount **and** the fee when requested; if the payout is not paid, both return to the balance. * Before a payout, check that `currentBalance` covers the amount plus the payout fee — otherwise the API returns `insufficient balance`. Statements, reports and settlements are available in the [dashboard](https://app.weetpay.com). # Create PIX charge (https://docs.weetpay.com/en/docs/cash-in/create-charge) {/* */} # Cash-in (https://docs.weetpay.com/en/docs/cash-in) Receive payments with PIX "copia e cola" and dynamic QR Codes. `POST /api/v1/gateway/request-qrcode` creates a PIX charge. The response contains the PIX code (`paymentCode`) and the QR Code PNG image in base64 (`paymentCodeBase64`) for you to show the customer. ## Flow [#flow] 1. Your server calls [Create PIX charge](/en/docs/cash-in/create-charge) with the order's `requestNumber`. 2. You display the QR Code and a "copy code" button. 3. The customer pays in their banking app. 4. WeetPay credits the amount (net of fees) to your balance and sends a `POST` to `callbackUrl` with `statusTransaction: "PAID_OUT"`. 5. Your system validates the signature, releases the order and replies `200`. ## Displaying the QR Code [#displaying-the-qr-code] ```html PIX QR Code ``` ## Charge status [#charge-status] | `processingStatus` | Meaning | | ---------------------- | ------------------------------------- | | `WAITING_FOR_APPROVAL` | awaiting payment | | `PAID_OUT` | paid — amount credited to the balance | | `EXPIRED` | QR expired unpaid (default: 1 hour) | | `CANCELED` | canceled by operations | | `REFUNDED` | refunded / disputed (MED) | ## Tips [#tips] * Use one `requestNumber` per payment attempt. If the QR expires, create another charge with a new `requestNumber` (e.g. `order-12345-2`). * Send the payer's real CPF/CNPJ in `client.document`: it is validated and forwarded to the bank. * Pass `utm_source`, `utm_campaign`… in the query string to store the sale's origin with the charge. # Cash-out (https://docs.weetpay.com/en/docs/cash-out) Send PIX from your balance to any key, protected against duplicate sending. `POST /api/v1/gateway/pix-payment` debits the amount and fee from your balance and sends a PIX to the given key. The response is immediate (`status: "processing"`); the result arrives at `callbackUrl`. Before the first payout, turn on **API payouts** under **Developers** in the dashboard. Unless WeetPay enables it, the destination must be the account holder's own CPF/CNPJ key. See [Limits and rules](/en/docs/limits-and-rules#api-payouts). ## Key types [#key-types] | `typeKey` | `key` | `document` | | --------- | -------------------------------------------------------------- | ------------------------ | | `CPF` | 11 digits | the same CPF as the key | | `CNPJ` | 14 digits | the same CNPJ as the key | | `EMAIL` | e-mail | key holder's CPF/CNPJ | | `PHONE` | mobile with area code (e.g. `11999998888` or `+5511999998888`) | key holder's CPF/CNPJ | | `EVP` | random key (UUID) | key holder's CPF/CNPJ | ## Flow [#flow] 1. Generate and store an `Idempotency-Key` for the payment ([Idempotency](/en/docs/idempotency)). 2. Call [Send PIX](/en/docs/cash-out/pix-payment). On network errors or `5xx`, retry **with the same key**. 3. The payout stays `PROCESSING` (operations review, when applicable, and bank submission). 4. `callbackUrl` receives `status: "sucess"` with the `endToEnd`, or `status: "not paid"` with the reason in `message` — in which case amount and fee return to the balance. ## Payout status [#payout-status] | `processingStatus` (lookup) | Callback `status` | Meaning | | --------------------------- | ----------------- | -------------------------------- | | `PROCESSING` | — | under review or sent to the bank | | `PAID_OUT` | `sucess` | paid | | `NOT_PAID` | `not paid` | rejected or failed; refunded | # Send PIX (payout) (https://docs.weetpay.com/en/docs/cash-out/pix-payment) {/* */} # Get transaction (https://docs.weetpay.com/en/docs/transactions/get-transaction) {/* */} # Transactions (https://docs.weetpay.com/en/docs/transactions) Look up charges and payouts by any identifier. `POST /api/v1/gateway/walletTransaction` returns a charge (`transactionType: "PIX_IN"`) or a payout (`"PIX_OUT"`) from your account, in the same format. ## Identifiers [#identifiers] | Field | Finds | | --------------- | -------------------------------------- | | `requestNumber` | charge, by the identifier you sent | | `idTransaction` | charge or payout, by WeetPay ID | | `endToEnd` | charge or payout, by PIX End-to-End ID | ## Status [#status] | `processingStatus` | Type | Meaning | | ---------------------- | --------- | ----------------------------------------------- | | `WAITING_FOR_APPROVAL` | `PIX_IN` | awaiting payment | | `PAID_OUT` | both | paid | | `EXPIRED` | `PIX_IN` | expired unpaid | | `CANCELED` | `PIX_IN` | canceled | | `REFUNDED` | `PIX_IN` | refunded | | `PROCESSING` | `PIX_OUT` | under review or being sent | | `NOT_PAID` | `PIX_OUT` | not paid (reason in `message`), amount refunded | ## When to look up [#when-to-look-up] * The customer is back on the order page and you have not received the callback yet. * Reconciliation or fallback (your server was down). * To recover the `pixCopiaECola` of a pending charge. Pending charges are re-checked with the bank on lookup (at most once every 10 s). Do not poll in a loop: use [callbacks](/en/docs/webhooks).