# Create a Customer
Source: https://developer.pagou.ai/api-reference/customers/create
/api-reference/openapi-v2.json POST /v2/customers
Create a reusable buyer profile.
# Get a Customer
Source: https://developer.pagou.ai/api-reference/customers/get
/api-reference/openapi-v2.json GET /v2/customers/{id}
Retrieve a reusable buyer profile by ID.
# List Customers
Source: https://developer.pagou.ai/api-reference/customers/list
/api-reference/openapi-v2.json GET /v2/customers
List reusable buyer profiles.
# Customers Reference
Source: https://developer.pagou.ai/api-reference/customers/reference
API operations for creating and retrieving reusable buyer profiles.
Use the Customers API when your integration needs reusable buyer profiles for payments and reconciliation.
## Endpoints
* [Create a Customer](/api-reference/customers/create)
* [List Customers](/api-reference/customers/list)
* [Get a Customer](/api-reference/customers/get)
# Create a PIX Payment
Source: https://developer.pagou.ai/api-reference/legacy-v1/create-pix-payment
/api-reference/openapi-v1.json POST /pix/v1/payment
Create a PIX payment through the legacy v1 API.
# Create a Webhook Integration
Source: https://developer.pagou.ai/api-reference/legacy-v1/create-webhook-integration
/api-reference/openapi-v1.json POST /v1/business/integration
Configure webhook integration for a legacy v1 account.
# Get Account Balance
Source: https://developer.pagou.ai/api-reference/legacy-v1/get-account-balance
/api-reference/openapi-v1.json GET /v1/account/balance
Retrieve the account balance for a legacy v1 integration.
# Get a PIX Transaction
Source: https://developer.pagou.ai/api-reference/legacy-v1/get-pix-transaction
/api-reference/openapi-v1.json GET /pix/v1/transactions/{id}
Retrieve a PIX transaction by ID for a legacy v1 integration.
# List PIX Transactions
Source: https://developer.pagou.ai/api-reference/legacy-v1/list-pix-transactions
/api-reference/openapi-v1.json GET /pix/v1/transactions
List PIX transactions for a legacy v1 integration.
# Legacy v1 Reference
Source: https://developer.pagou.ai/api-reference/legacy-v1/reference
Legacy API operations for existing v1 integrations.
Use these endpoints only for existing v1 integrations. New integrations should use the v2 reference pages.
## Endpoints
* [Create a Webhook Integration](/api-reference/legacy-v1/create-webhook-integration)
* [Validate Authentication](/api-reference/legacy-v1/validate-authentication)
* [Get Account Balance](/api-reference/legacy-v1/get-account-balance)
* [List PIX Transactions](/api-reference/legacy-v1/list-pix-transactions)
* [Get a PIX Transaction](/api-reference/legacy-v1/get-pix-transaction)
* [Create a PIX Payment](/api-reference/legacy-v1/create-pix-payment)
* [Refund a PIX Payment](/api-reference/legacy-v1/refund-pix-payment)
* [Withdraw a PIX Payment](/api-reference/legacy-v1/withdraw-pix-payment)
# Refund a PIX Payment
Source: https://developer.pagou.ai/api-reference/legacy-v1/refund-pix-payment
/api-reference/openapi-v1.json POST /pix/v1/payment/refund/{id}
Refund a PIX payment through the legacy v1 API.
# Validate Authentication
Source: https://developer.pagou.ai/api-reference/legacy-v1/validate-authentication
/api-reference/openapi-v1.json GET /v1/health-check
Validate legacy v1 API authentication.
# Withdraw a PIX Payment
Source: https://developer.pagou.ai/api-reference/legacy-v1/withdraw-pix-payment
/api-reference/openapi-v1.json POST /pix/v1/payment/withdraw
Create a PIX withdrawal through the legacy v1 API.
# Create a Transaction
Source: https://developer.pagou.ai/api-reference/transactions/create
/api-reference/openapi-v2.json POST /v2/transactions
Create a Pix, voucher, or card transaction.
## Voucher payments
Use `method: "voucher"` for local payment instructions such as Boleto, SPEI, Mercado Pago, Webpay, CODI, and PSE. Do not send provider-specific method names to this endpoint.
For the complete voucher flow, supported countries, document types, and response-field guidance, see [Accept Voucher Payments](/payments/vouchers/accept-payments).
# Get a Transaction
Source: https://developer.pagou.ai/api-reference/transactions/get
/api-reference/openapi-v2.json GET /v2/transactions/{id}
Retrieve a transaction by ID.
Use this endpoint to reconcile voucher transactions after creation or webhook delivery. The latest response can include normalized `voucher` fields such as `barcode`, `digitable_line`, `url`, `expiration_date`, `instructions`, and `receipt_url`.
Voucher instructions can arrive asynchronously for some payment providers. If the create response returns `status: "pending"` with empty voucher fields, poll this endpoint for user-facing refreshes and keep webhooks as the authoritative source for fulfillment.
# List Transactions
Source: https://developer.pagou.ai/api-reference/transactions/list
/api-reference/openapi-v2.json GET /v2/transactions
List transactions for reconciliation and operations.
For voucher reconciliation, filter by `paymentMethods=voucher`. Voucher covers Boleto, SPEI/bank transfer, Mercado Pago or other local voucher options, Webpay, CODI, PSE, and similar payment-provider-supported instructions under the same public method.
Use `status=pending` to find open voucher instructions and `status=paid` to reconcile confirmed payments.
# Transactions Reference
Source: https://developer.pagou.ai/api-reference/transactions/reference
API operations for creating, reading, updating, and refunding v2 transactions.
Use the Transactions API for Pix, voucher, and card payment creation, status lookup, sandbox updates, and refunds.
## Endpoints
* [Create a Transaction](/api-reference/transactions/create)
* [List Transactions](/api-reference/transactions/list)
* [Get a Transaction](/api-reference/transactions/get)
* [Update a Transaction](/api-reference/transactions/update)
* [Refund a Transaction](/api-reference/transactions/refund)
# Refund a Transaction
Source: https://developer.pagou.ai/api-reference/transactions/refund
/api-reference/openapi-v2.json PUT /v2/transactions/{id}/refund
Refund an eligible transaction.
# Update a Transaction
Source: https://developer.pagou.ai/api-reference/transactions/update
/api-reference/openapi-v2.json PUT /v2/transactions/{id}
Update a transaction in the test environment.
# Cancel a Transfer
Source: https://developer.pagou.ai/api-reference/transfers/cancel
/api-reference/openapi-v2.json POST /v2/transfers/{id}/cancel
Cancel a pending Pix Out transfer.
# Create a Transfer
Source: https://developer.pagou.ai/api-reference/transfers/create
/api-reference/openapi-v2.json POST /v2/transfers
Create a Pix Out transfer.
# Get a Transfer
Source: https://developer.pagou.ai/api-reference/transfers/get
/api-reference/openapi-v2.json GET /v2/transfers/{id}
Retrieve a Pix Out transfer by ID.
# List Transfers
Source: https://developer.pagou.ai/api-reference/transfers/list
/api-reference/openapi-v2.json GET /v2/transfers
List Pix Out transfers for payout reconciliation.
# Transfers Reference
Source: https://developer.pagou.ai/api-reference/transfers/reference
API operations for creating, retrieving, listing, and canceling Pix Out transfers.
Use the Transfers API for Pix Out payout creation, status lookup, cancellation, and reconciliation.
## Endpoints
* [Create a Transfer](/api-reference/transfers/create)
* [List Transfers](/api-reference/transfers/list)
* [Get a Transfer](/api-reference/transfers/get)
* [Cancel a Transfer](/api-reference/transfers/cancel)
# Changelog
Source: https://developer.pagou.ai/changelog/index
Track documentation and public platform changes relevant to Pagou integrations.
## March 2026
### Cursor pagination
* List endpoints use cursor pagination with `cursor`, `limit`, `direction`, `next_cursor`, and `prev_cursor`.
* TypeScript SDK list helpers follow the same contract.
### AI integration assets
* Added `/llms.txt` and `/llms-full.txt` for coding assistants.
* Added an AI-assisted integration guide with a compact context block.
### Documentation rewrite
* Reorganized the docs around v2-first journeys.
* Mirrored the English and PT-BR trees.
* Aligned payments, payouts, webhooks, frontend, SDK, and legacy content around the same terminology.
# Accept a Payment
Source: https://developer.pagou.ai/frontend/payment-element/accept-a-payment
Build a production-safe Payment Element checkout from card input through backend creation, 3DS, and final order state handling.
Use this page when you are moving from a demo integration to a production-safe checkout.
## Production-safe flow
1. Disable duplicate submits in the browser.
2. Call `elements.submit(...)` once per checkout attempt.
3. Let your backend create the transaction.
4. Handle `next_action` when 3D Secure is required.
5. Fulfill only from webhook or reconciliation state.
## Frontend submit pattern
```js theme={null}
let isSubmitting = false;
let lastTokenData = null;
form.addEventListener("submit", async (event) => {
event.preventDefault();
if (isSubmitting) return;
isSubmitting = true;
const result = await elements.submit({
createTransaction: async (tokenData) => {
lastTokenData = tokenData;
const response = await fetch("/api/pay", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
token: tokenData.token,
amount: 2490,
orderId: "order_2001",
}),
});
const payload = await response.json();
return payload.data ?? payload;
},
});
isSubmitting = false;
if (result.status === "error") {
messageEl.textContent = result.error ?? "Payment failed.";
return;
}
if (lastTokenData) {
cardSummaryEl.textContent = `${lastTokenData.brand} ending in ${lastTokenData.last4}`;
}
});
```
`elements.submit(...)` is the tokenization trigger. It creates an Element session if needed, asks the hosted card field to tokenize, then calls your `createTransaction` callback with the token payload.
## Token payload
Your `createTransaction` callback receives non-sensitive card metadata with the token:
```json theme={null}
{
"token": "pgct_token_from_browser",
"brand": "visa",
"last4": "4242",
"exp_month": "12",
"exp_year": "2030"
}
```
Send `tokenData.token` to your backend to create the transaction. Use `brand`, `last4`, `exp_month`, and `exp_year` only for provisional checkout UI or your own backend bookkeeping; final payment state still comes from the transaction response, webhook, or reconciliation.
## Backend request example
```json theme={null}
{
"external_ref": "order_2001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "pgct_token_from_browser",
"installments": 1
}
```
## Backend response example
```json theme={null}
{
"success": true,
"requestId": "req_4003",
"data": {
"id": "tr_2001",
"status": "three_ds_required",
"next_action": {
"type": "three_ds_challenge",
"challenge_session_id": "3ds_1001",
"client_secret": "sec_1001",
"expires_at": "2026-03-16T14:20:00.000Z"
}
}
}
```
## Common error
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "token",
"message": "Token is required for credit card payments",
"code": "invalid_type"
}
]
}
```
Fix: do not create the transaction until the browser has a token from Payment Element. If a challenge flow was interrupted, reconcile the transaction before letting the customer retry.
## Invalid state handling
Keep the submit button disabled until the card field reports a valid state:
```js theme={null}
let cardIsValid = false;
card.on("change", ({ valid, brand, errors }) => {
cardIsValid = valid;
submitButton.disabled = !cardIsValid || isSubmitting;
brandEl.textContent = brand ?? "";
errorEl.textContent = Object.values(errors ?? {})[0] ?? "";
});
form.addEventListener("submit", async (event) => {
event.preventDefault();
if (!cardIsValid || isSubmitting) return;
// Call elements.submit(...) here.
});
```
If `elements.submit(...)` returns `{ "status": "error" }`, do not call your backend again with a missing or stale token. Show the returned error, let the buyer correct the card details, then run a new checkout attempt.
## Final-state rule
A browser success message is not enough to fulfill an order. Final fulfillment belongs to webhook-confirmed or reconciled payment state.
# Appearance and Events
Source: https://developer.pagou.ai/frontend/payment-element/appearance-and-events
Customize the Payment Element card field and react to its lifecycle with supported browser events.
Use this page to style the hosted field and react to state changes without owning raw card input.
## Appearance example
```js theme={null}
const card = elements.create("card", {
theme: "default",
style: {
base: {
color: "#111827",
fontFamily: "Inter, system-ui, sans-serif",
fontSize: "16px",
borderRadius: "8px",
backgroundColor: "#ffffff",
},
focus: {
borderColor: "#2563eb",
},
invalid: {
color: "#dc2626",
},
placeholder: {
color: "#9ca3af",
},
},
});
card.mount("#card-element");
```
Supported themes are `default`, `night`, and `flat`. Use the `style` object for brand-specific colors and typography instead of placing raw card inputs in your own DOM.
## Supported event pattern
```js theme={null}
let cardState = {
valid: false,
brand: null,
errors: {},
};
card.on("ready", () => {
messageEl.textContent = "";
});
card.on("change", (event) => {
cardState = event;
submitButton.disabled = !event.valid;
brandEl.textContent = event.brand ? event.brand.toUpperCase() : "";
messageEl.textContent = Object.values(event.errors ?? {})[0] ?? "";
});
card.on("error", (event) => {
messageEl.textContent = event.message ?? "Unable to initialize the card field.";
});
```
Call `card.off("change", handler)` when your component unmounts if your framework keeps the same card instance alive across renders.
## Event payloads
`ready` fires when the hosted iframe is loaded. It does not mean the card details are valid.
`change` fires whenever card input changes:
```json theme={null}
{
"valid": false,
"brand": "visa",
"errors": {
"number": "Card number is invalid"
}
}
```
When the card brand is unknown, `brand` is `null`. When the current state is valid, `errors` is empty and `valid` is `true`.
`error` fires when the hosted field fails to load or receives a payment failure outside an active tokenization request:
```json theme={null}
{
"code": "mount_timeout_no_load",
"message": "Unable to initialize the card field."
}
```
Known error codes include `card_error`, `iframe_load_failed`, `mount_timeout_no_load`, and `mount_timeout_no_handshake`.
## Invalid states
Use `change.valid` as the only submit gate. Do not infer validity from the card brand alone.
```js theme={null}
card.on("change", ({ valid, brand, errors }) => {
submitButton.disabled = !valid;
cardBrandEl.textContent = brand ?? "";
const firstError = Object.values(errors ?? {})[0];
errorEl.textContent = firstError ?? "";
});
```
The `errors` object is keyed by the hosted field that needs attention. The exact keys are controlled by the hosted card field, so render the messages rather than hardcoding every possible key.
Fix: confirm the script version, environment, and `publicKey`. Event handlers should update UI state only; final payment state still comes from your backend and webhooks.
# Migration from WebSDK
Source: https://developer.pagou.ai/frontend/payment-element/migration-from-websdk
Move from the legacy WebSDK card flow to Payment Element with low operational risk and a stable backend contract.
Use this page when you are replacing a legacy browser card flow.
## What changes
* raw browser tokenization flow -> hosted Payment Element field
* legacy browser-side card orchestration -> `elements.submit(...)`
* custom challenge plumbing -> `next_action` driven flow
* unstable browser contract -> stable backend `POST /v2/transactions`
## Keep stable during migration
* keep your backend transaction route stable
* keep `external_ref`, transaction ID, and `requestId` persistence unchanged
* keep webhook and reconciliation logic unchanged
* migrate one checkout surface at a time
## Backend contract example
```json theme={null}
{
"external_ref": "order_2001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "pgct_token_from_browser"
}
```
## Read next
* [Overview](/frontend/payment-element/overview)
* [Quickstart](/frontend/payment-element/quickstart)
* [Accept a Payment](/frontend/payment-element/accept-a-payment)
# Overview
Source: https://developer.pagou.ai/frontend/payment-element/overview
Understand what Payment Element is, when to use it, and how it fits into Pagou's card payment lifecycle.
Payment Element is the recommended browser integration for new card checkouts.
## When to use it
* You are building a new card checkout.
* You want hosted card fields instead of collecting raw card data.
* You need 3D Secure in the same browser flow.
* Your backend should remain the owner of transaction creation and fulfillment state.
## Browser vs backend
Browser responsibilities:
* load the Pagou script
* mount the card field
* submit through `elements.submit(...)`
* continue browser-side challenge flow when required
Backend responsibilities:
* authenticate with secret credentials
* create `POST /v2/transactions`
* persist `external_ref`, transaction ID, and `requestId`
* fulfill only from webhook or reconciliation state
## Backend request example
```json theme={null}
{
"external_ref": "order_2001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "pgct_token_from_browser",
"installments": 1
}
```
## Backend response example
```json theme={null}
{
"success": true,
"requestId": "req_4001",
"data": {
"id": "tr_2001",
"status": "three_ds_required",
"method": "credit_card",
"next_action": {
"type": "three_ds_challenge",
"challenge_session_id": "3ds_1001",
"client_secret": "sec_1001",
"expires_at": "2026-03-16T14:20:00.000Z"
}
}
}
```
## Common error
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "token",
"message": "Token is required for credit card payments",
"code": "invalid_type"
}
]
}
```
## Start here
* [Quickstart](/frontend/payment-element/quickstart)
* [Accept a Payment](/frontend/payment-element/accept-a-payment)
* [3D Secure](/frontend/payment-element/three-d-secure)
# Quickstart
Source: https://developer.pagou.ai/frontend/payment-element/quickstart
Mount the Payment Element, tokenize card details, and create a card payment through your backend in the shortest possible path.
Use this page for the smallest working Payment Element integration.
## Prerequisites
* a Pagou public key
* a backend route that creates `POST /v2/transactions`
* webhook handling for final payment state
## Load the script
```html theme={null}
```
## Mount the field
```js theme={null}
const elements = Pagou.elements({
publicKey: "pk_test_your_public_key",
locale: "en",
origin: window.location.origin,
});
const card = elements.create("card", { theme: "default" });
card.mount("#card-element");
```
## Submit through your backend
```js theme={null}
const result = await elements.submit({
createTransaction: async (tokenData) => {
const response = await fetch("/api/pay", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
token: tokenData.token,
amount: 2490,
installments: 1,
orderId: "order_2001",
}),
});
const payload = await response.json();
return payload.data ?? payload;
},
});
```
## Backend request example
```json theme={null}
{
"external_ref": "order_2001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "pgct_token_from_browser",
"installments": 1
}
```
## Backend response example
```json theme={null}
{
"success": true,
"requestId": "req_4002",
"data": {
"id": "tr_2001",
"status": "pending",
"method": "credit_card"
}
}
```
## Common error
```json theme={null}
{
"status": "error",
"error": "Unable to initialize the card field."
}
```
Fix: confirm the public key, `origin`, and script environment. Your backend must return the transaction payload without dropping fields such as `id`, `status`, and `next_action`.
## Next steps
* [SDK v3 Reference](/frontend/payment-element/sdk-reference)
* [Accept a Payment](/frontend/payment-element/accept-a-payment)
* [Appearance and Events](/frontend/payment-element/appearance-and-events)
* [Testing and Troubleshooting](/frontend/payment-element/testing-and-troubleshooting)
# SDK v3 Reference
Source: https://developer.pagou.ai/frontend/payment-element/sdk-reference
Use the Pagou browser SDK v3 API to mount hosted card fields, submit card payments, and handle 3D Secure.
Use this page when you need the exact browser SDK contract for Payment Element v3.
## Load the SDK
```html theme={null}
```
The script exposes `window.Pagou`.
```js theme={null}
Pagou.setEnvironment("sandbox");
```
Supported environments:
| Environment | Use |
| ------------ | -------------------------------------------------- |
| `production` | Default. Uses production collection endpoints. |
| `sandbox` | Use for test public keys and sandbox transactions. |
| `local` | Internal development only. |
## Initialize Elements
```js theme={null}
const elements = Pagou.elements({
publicKey: "pk_test_your_public_key",
locale: "en",
origin: window.location.origin,
});
```
Options:
| Option | Required | Description |
| ----------- | ----------------- | ------------------------------------------------------------------------------------ |
| `publicKey` | Yes before submit | Company public key. Use `pk_test_*` in sandbox and `pk_live_*` in production. |
| `locale` | No | Locale forwarded to the hosted card field. Defaults to `pt-BR`. |
| `origin` | No | Checkout origin stored on the Element session. Defaults to `window.location.origin`. |
You can update an existing instance before submit:
```js theme={null}
elements.update({
publicKey: "pk_live_your_public_key",
locale: "en",
});
```
## Create and mount the card field
```html theme={null}
```
```js theme={null}
const card = elements.create("card", {
theme: "default",
locale: "en",
});
card.mount("#card-element");
```
`elements.create("card")` creates one hosted card field. If a card field already exists on the same `elements` instance, the SDK unmounts it before creating the new one.
Card options:
| Option | Description |
| ---------------- | ----------------------------------------------------------------------------- |
| `theme` | `default`, `night`, or `flat`. |
| `locale` | Overrides the Elements locale for this card field. |
| `style` | Style object forwarded to the hosted field. |
| `mountTimeoutMs` | Mount timeout in milliseconds. Defaults to `8000`. |
| `telemetry` | Sends best-effort mount failure telemetry when supported. Defaults to `true`. |
## Card events
```js theme={null}
card.on("ready", () => {
messageEl.textContent = "";
});
card.on("change", (event) => {
submitButton.disabled = !event.valid;
brandEl.textContent = event.brand ?? "";
errorEl.textContent = Object.values(event.errors ?? {})[0] ?? "";
});
card.on("error", (event) => {
errorEl.textContent = event.message;
});
```
Supported events:
| Event | Payload | Use |
| -------- | -------------------------- | ----------------------------------------------------- |
| `ready` | `{}` | Hosted iframe loaded and completed the SDK handshake. |
| `change` | `{ valid, brand, errors }` | Enable submit only when `valid` is `true`. |
| `error` | `{ code, message }` | Show initialization, mount, or card field errors. |
Remove handlers during component teardown when the same card instance can stay alive:
```js theme={null}
card.off("change", handleCardChange);
```
## Submit a payment
`elements.submit(...)` is the main SDK action. It creates an Element session, tokenizes the hosted card field, calls your `createTransaction` callback, and continues 3DS when the transaction response includes `next_action`.
```js theme={null}
const result = await elements.submit({
createTransaction: async (tokenData) => {
const response = await fetch("/api/pay", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
external_ref: "order_2001",
amount: 2490,
currency: "BRL",
method: "credit_card",
token: tokenData.token,
installments: 1,
}),
});
const payload = await response.json();
return payload.data ?? payload;
},
});
```
`createTransaction` receives:
```json theme={null}
{
"token": "pgct_token_from_browser",
"brand": "visa",
"last4": "4242",
"exp_month": "12",
"exp_year": "2029"
}
```
Only send `token` to your backend as the payment credential. Treat `brand`, `last4`, `exp_month`, and `exp_year` as display or bookkeeping metadata.
## Submit result
```json theme={null}
{
"status": "pending",
"transaction": {
"id": "tr_2001",
"status": "pending"
}
}
```
Possible `status` values include:
| Status | Meaning |
| ------------------ | ------------------------------------------------------------------------------------------------ |
| Transaction status | If there is no `next_action`, the SDK returns the transaction status from your backend response. |
| `completed` | Fallback when the backend response has no `status`. |
| `requires_action` | A `next_action` exists and automatic 3DS modal handling is disabled for the Element session. |
| `succeeded` | 3DS challenge completed successfully. |
| `failed` | 3DS challenge or payment failed. |
| `canceled` | Buyer closed the 3DS modal. |
| `timed_out` | 3DS challenge did not finish within the SDK timeout. |
| `error` | Tokenization, session creation, callback, or SDK flow failed. |
Do not fulfill an order from the browser status alone. Use webhook delivery or server-side reconciliation as the final source of truth.
## 3D Secure
When your backend returns a transaction with `next_action`, the SDK can open the challenge modal automatically.
```json theme={null}
{
"id": "tr_2001",
"status": "three_ds_required",
"next_action": {
"type": "three_ds_challenge",
"challenge_session_id": "3ds_1001",
"client_secret": "sec_1001",
"expires_at": "2026-03-16T14:20:00.000Z"
}
}
```
If you already created the transaction server-side and only need to continue an existing action, call:
```js theme={null}
const result = await Pagou.handleNextAction(transaction.next_action);
```
Or pass the transaction to an Elements instance:
```js theme={null}
const result = await elements.submit({
transaction,
createTransaction: async () => transaction,
});
```
## Reusable token for upsells
For one-click upsell flows, request a reusable token:
```js theme={null}
const result = await elements.submit({
saveForUpsell: true,
createTransaction: async (tokenData) => {
return createPaymentWithToken(tokenData.token);
},
});
```
This requests a `pgpm_*` token that can be consumed twice within 5 minutes. Use it only when the same card must be charged for the initial purchase and a follow-up upsell offer.
## Cleanup
Unmount a card field when leaving the checkout screen:
```js theme={null}
card.unmount();
```
Destroy the Elements instance when the entire payment flow is gone:
```js theme={null}
elements.destroy();
```
## Production rules
* Use `pk_test_*` only with `Pagou.setEnvironment("sandbox")`.
* Use `pk_live_*` with the default production environment.
* Never send raw card data to your backend.
* Never log `pgct_*`, `pgpm_*`, `client_secret`, or card data.
* Disable duplicate submits while `elements.submit(...)` is running.
* Return your transaction payload from the backend without removing `id`, `status`, or `next_action`.
* Treat browser status as provisional until webhook or reconciliation confirms the final payment state.
# Testing and Troubleshooting
Source: https://developer.pagou.ai/frontend/payment-element/testing-and-troubleshooting
Validate Payment Element in sandbox, test 3DS paths, and diagnose the most common integration mistakes.
Use this page before launch and whenever browser payment behavior looks inconsistent.
## Test checklist
* confirm the browser uses the sandbox public key
* confirm the backend uses the sandbox secret token
* verify the backend returns the transaction payload intact
* verify webhook delivery before trusting browser state
* reconcile any interrupted 3DS attempt
## Example backend request
```json theme={null}
{
"external_ref": "order_2001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "pgct_token_from_browser"
}
```
## Example backend response
```json theme={null}
{
"success": true,
"requestId": "req_4005",
"data": {
"id": "tr_2001",
"status": "pending"
}
}
```
## Common error
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "token",
"message": "Token is required for credit card payments",
"code": "invalid_type"
}
]
}
```
Fix: if the backend cannot see a valid Payment Element token, stop and verify the browser integration before changing order logic or webhook handling.
# 3D Secure
Source: https://developer.pagou.ai/frontend/payment-element/three-d-secure
Handle automatic and manual 3DS flows with Payment Element without breaking checkout, fulfillment, or reconciliation.
Use this page when a card payment returns `three_ds_required`.
## What triggers 3DS
3D Secure is exposed through `next_action` on the transaction response.
## Example transaction response
```json theme={null}
{
"success": true,
"requestId": "req_4004",
"data": {
"id": "tr_2001",
"status": "three_ds_required",
"next_action": {
"type": "three_ds_challenge",
"challenge_session_id": "3ds_1001",
"client_secret": "sec_1001",
"expires_at": "2026-03-16T14:20:00.000Z"
}
}
}
```
## Handling rule
* Let `elements.submit(...)` continue the flow automatically when supported.
* If the browser session is interrupted, retrieve the transaction before asking the customer to retry.
* Do not treat `three_ds_required` as a failed payment.
## Why this matters
A customer may complete the challenge after your first browser callback. Webhooks and reconciliation keep checkout, fulfillment, and support workflows aligned with the actual final state.
## Read next
* [Accept a Payment](/frontend/payment-element/accept-a-payment)
* [Testing and Troubleshooting](/frontend/payment-element/testing-and-troubleshooting)
# Pagou Developer Docs
Source: https://developer.pagou.ai/index
Integrate Pix, voucher, card payments, payouts, webhooks, and frontend card flows with a v2-first developer journey.
Create a first v2 transaction with the minimum setup, then expand into production-safe flows.
Give Claude Code, Cursor, Codex, Copilot, Windsurf, Lovable, Bolt.new, or v0 the right Pagou context.
## Core integration paths
Model customers, transactions, Pix, vouchers, cards, refunds, and transaction status handling.
Mount hosted card fields, trigger tokenization, handle 3D Secure, and keep secrets on your backend.
Create outbound Pix transfers, cancel pending transfers, and reconcile payout state.
## Build by job
Create Pix transactions, return QR code data to the buyer, and finalize from webhook or reconciliation state.
Create local payment instructions such as Boleto, SPEI, Mercado Pago, Webpay, CODI, or PSE through `method: "voucher"`.
Use `elements.submit(...)` to tokenize cards and pass the token to your backend transaction create route.
Build one ingestion path for payment and payout events with event ID deduplication.
Confirm environment, auth, idempotency, webhook, retry, and reconciliation behavior before production.
## Reference and tools
Browse v2 customers, transactions, transfers, and legacy v1 endpoints by resource.
Configure the official server-side TypeScript SDK for payments and transfers.
Use the schema source of truth for request builders, tests, mocks, and agent validation.
## Production rules
* Create payments and transfers only from your backend.
* Use `external_ref` as your stable write identifier.
* Never invent fields that are not present in the OpenAPI schema.
* Use Payment Element and `elements.submit(...)` for card tokenization.
* Fulfill orders only from webhook-confirmed or reconciled state.
* Deduplicate webhooks by the top-level event `id`.
## Read next
* [Overview](/start-here/overview)
* [Authentication](/start-here/authentication)
* [Errors and Retries](/start-here/errors-and-retries)
* [Changelog](/changelog)
# v1 Account Balance
Source: https://developer.pagou.ai/legacy/v1/account-balance
Query account balance for legacy integrations that still depend on the v1 route family.
Use this endpoint only for merchants that still depend on the v1 balance route.
## Endpoint
`GET /v1/account/balance`
## Example response
```json theme={null}
{
"available_balance": 5000,
"waiting_funds": 1200
}
```
## Interpretation rule
`waiting_funds` is the net receivable amount still pending settlement. It does not represent gross receivables before fees and reserves.
# v1 Authentication
Source: https://developer.pagou.ai/legacy/v1/authentication
Reference the legacy v1 auth model only if you maintain an existing integration.
Use this page only for maintenance of an existing v1 integration.
## Health check
`GET /v1/health-check`
## Example request
```http theme={null}
GET /v1/health-check HTTP/1.1
Host: api.pagou.ai
apiKey: YOUR_V1_TOKEN
```
## Example response
```json theme={null}
{
"status": "ok"
}
```
## Common error
```json theme={null}
{
"message": "Unauthorized"
}
```
Fix: confirm the merchant still uses the correct v1 credential set. New integrations should use [v2 authentication](/start-here/authentication).
# v1 to v2 Migration
Source: https://developer.pagou.ai/legacy/v1/migration-to-v2
Map legacy Pagou route families and operational assumptions to the recommended v2 integration model.
Use this page to migrate incrementally while keeping v2 as the end state.
## Route mapping
| v1 | v2 replacement |
| ---------------------------------- | ----------------------------------------------------------------- |
| `GET /v1/health-check` | `GET /v2/transactions` as an authenticated smoke test |
| `POST /pix/v1/payment` | `POST /v2/transactions` with `method: "pix"` |
| `GET /pix/v1/transactions/{id}` | `GET /v2/transactions/{id}` |
| `POST /pix/v1/payment/refund/{id}` | `PUT /v2/transactions/{id}/refund` |
| `POST /pix/v1/payment/withdraw` | `POST /v2/transfers` |
| `POST /v1/business/integration` | modern webhook handling plus operational configuration discipline |
## Recommended order
1. Standardize credentials and auth handling.
2. Move create and refund writes to v2.
3. Update webhook consumers to the v2 operating model.
4. Leave v1 docs only for long-tail maintenance.
# v1 Overview
Source: https://developer.pagou.ai/legacy/v1/overview
Maintain existing v1 integrations while planning the move to Pagou v2.
Use the v1 archive only to keep an existing integration stable. New work should start on v2.
## What remains in v1
* auth validation via health check
* account balance lookup
* legacy Pix payment routes
* legacy webhook configuration
## Operating rule
Keep v1 changes minimal and operational. Route all net-new product work to v2.
## Read next
* [v1 Authentication](/legacy/v1/authentication)
* [v1 to v2 Migration](/legacy/v1/migration-to-v2)
* [v1 API Reference](/api-reference/openapi-v1.json)
# v1 Pix Payments
Source: https://developer.pagou.ai/legacy/v1/pix-payments
Maintain or migrate legacy Pix payment flows exposed through the v1 route family.
These routes are archived for compatibility. New Pix projects should use `/v2/transactions`.
## Legacy routes
* `POST /pix/v1/payment`
* `GET /pix/v1/transactions`
* `GET /pix/v1/transactions/{id}`
* `POST /pix/v1/payment/refund/{id}`
* `POST /pix/v1/payment/withdraw`
## Migration direction
* create Pix payment -> `POST /v2/transactions` with `method: "pix"`
* retrieve payment -> `GET /v2/transactions/{id}`
* refund -> `PUT /v2/transactions/{id}/refund`
* withdraw -> `POST /v2/transfers`
## Read next
* [Accept Pix Payments](/payments/pix/accept-payments)
* [v1 to v2 Migration](/legacy/v1/migration-to-v2)
# v1 Webhook Configuration
Source: https://developer.pagou.ai/legacy/v1/webhook-configuration
Reference the legacy webhook integration endpoint while moving webhook handling practice to the unified v2 guidance.
Use this page only to keep an old integration running.
## Endpoint
`POST /v1/business/integration`
## Example request
```json theme={null}
{
"url": "https://merchant.example/webhooks/pagou-v1"
}
```
## Example response
```json theme={null}
{
"success": true
}
```
## Migration rule
For webhook behavior, retries, deduplication, and reconciliation, use the modern [webhook guides](/webhooks/overview). Keep v1 configuration changes minimal.
# Card Payments Overview
Source: https://developer.pagou.ai/payments/cards/overview
Choose the recommended card integration pattern and understand how Pagou handles tokenization and 3DS.
Use this section when you are choosing how to accept cards with Pagou.
## Recommended path
Use [Payment Element](/payments/cards/payment-element) for new card checkouts.
Why:
* Card entry stays inside a hosted iframe.
* Tokenization stays outside your DOM.
* `next_action` and 3D Secure continue in the same browser session.
* Your backend keeps control of transaction creation and order state.
## Card payment model
1. The browser mounts Payment Element.
2. Payment Element tokenizes the card.
3. Your backend calls `POST /v2/transactions` with `method: "credit_card"`.
4. Your system waits for final webhook or reconciliation state before fulfillment.
## Read next
* [Payment Element for Cards](/payments/cards/payment-element)
* [Card Transaction Lifecycle](/payments/cards/transaction-lifecycle)
* [3D Secure](/frontend/payment-element/three-d-secure)
# Payment Element for Cards
Source: https://developer.pagou.ai/payments/cards/payment-element
Understand why Payment Element is the default card integration and how it connects to the transactions API.
Use Payment Element when you are building or rebuilding checkout.
## Why Pagou recommends it
* Hosted card fields reduce PCI exposure.
* Tokenization happens in the browser without your backend touching raw card data.
* 3D Secure handoff uses `next_action` in the same flow.
* Your backend contract stays simple: create a transaction with the token returned by the browser.
## Backend request
```bash theme={null}
curl --request POST \
--url https://api.pagou.ai/v2/transactions \
--header "Authorization: Bearer YOUR_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"external_ref": "order_2001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "pgct_token_from_browser",
"installments": 1,
"buyer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"document": {
"type": "CPF",
"number": "12345678901"
}
},
"products": [
{
"name": "Plan upgrade",
"price": 2490,
"quantity": 1
}
]
}'
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1301",
"data": {
"id": "tr_2001",
"status": "three_ds_required",
"method": "credit_card",
"amount": 2490,
"base_price": 2490,
"currency": "BRL",
"next_action": {
"type": "three_ds_challenge",
"challenge_session_id": "3ds_1001",
"client_secret": "sec_1001",
"expires_at": "2026-03-16T14:20:00.000Z"
},
"created_at": "2026-03-16T14:00:00.000Z",
"updated_at": "2026-03-16T14:00:00.000Z",
"paid_at": null
}
}
```
## Common error
Status `422`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "token",
"message": "Token is required for credit card payments",
"code": "invalid_type"
}
]
}
```
Fix: create the token in Payment Element first. Do not collect raw card data in your own form and send it directly to the API.
## Decision rule
* Use Payment Element for new browser card flows.
* Keep older tokenization only when you are maintaining a legacy flow and cannot migrate yet.
## Continue with
* [Frontend Quickstart](/frontend/payment-element/quickstart)
* [Accept a Payment](/frontend/payment-element/accept-a-payment)
* [Migration from WebSDK](/frontend/payment-element/migration-from-websdk)
# Card Refund Behavior
Source: https://developer.pagou.ai/payments/cards/refund-behavior
Model card refunds operationally so your product, support, and finance logic stay aligned.
Card refunds should follow the same operational discipline as any other money-moving write.
## Practical guidance
* Initiate refunds only from your backend.
* Use your own refund request ID to prevent duplicate support actions.
* Wait for the resulting transaction status before updating final customer-facing state.
* Keep refund handling separate from chargeback handling.
## Example request
```json theme={null}
{
"amount": 2490,
"reason": "requested_by_customer"
}
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1302",
"data": {
"transaction_id": "tr_2001",
"status": "refunded"
}
}
```
## Merchant-facing rules
* A partial refund changes accounting state even if the order remains partially fulfilled.
* A full refund should close the customer-facing payment attempt.
* If the refund result is unclear, reconcile the transaction instead of retrying blindly.
## Read next
* [Transaction Statuses](/payments/transaction-statuses)
* [Payment Events](/webhooks/payment-events)
# Card Transaction Lifecycle
Source: https://developer.pagou.ai/payments/cards/transaction-lifecycle
Handle authorization, 3DS, capture outcomes, and terminal states in a predictable card payment flow.
Use this page to map card-specific statuses into order and fulfillment behavior.
## Typical lifecycle
1. `pending`: the transaction was created.
2. `three_ds_required`: the customer must complete authentication.
3. `authorized` or `processing`: the card issuer or payment provider is still working.
4. `captured` or `paid`: the payment is final enough for fulfillment.
5. `refused`, `canceled`, `refunded`, or `partially_refunded`: stop or reverse fulfillment.
## Example response that requires customer action
```json theme={null}
{
"id": "tr_2001",
"status": "three_ds_required",
"method": "credit_card",
"amount": 2490,
"currency": "BRL",
"next_action": {
"type": "three_ds_challenge",
"challenge_session_id": "3ds_1001",
"client_secret": "sec_1001",
"expires_at": "2026-03-16T14:20:00.000Z"
}
}
```
## Status handling guidance
* Do not fulfill on `pending` or `three_ds_required`.
* Fulfill only once when you reach a settled state such as `captured` or `paid`.
* If the browser flow ends unexpectedly, reconcile with `GET /v2/transactions/{id}`.
* Treat refund and chargeback states as separate finance workflows.
## Read next
* [Payment Element for Cards](/payments/cards/payment-element)
* [3D Secure](/frontend/payment-element/three-d-secure)
* [Transaction Statuses](/payments/transaction-statuses)
# Customers
Source: https://developer.pagou.ai/payments/customers
Create and retrieve customer records in Pagou v2 when your product needs reusable buyer profiles.
Use customers when your checkout reuses buyer data across multiple payments.
## Supported operations
* `POST /v2/customers`
* `GET /v2/customers`
* `GET /v2/customers/{id}`
## When to use this resource
* You want a stable Pagou customer ID.
* Your product stores reusable payer profiles.
* You want to create the buyer once and reference it later.
## Example request
```bash theme={null}
curl --request POST \
--url https://api.pagou.ai/v2/customers \
--header "Authorization: Bearer YOUR_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"name": "Ada Lovelace",
"email": "ada@example.com",
"document": {
"type": "CPF",
"number": "12345678901"
},
"externalRef": "customer_1001"
}'
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1101",
"data": {
"id": "cus_1001",
"name": "Ada Lovelace",
"email": "ada@example.com",
"externalRef": "customer_1001"
}
}
```
## Common error
Status `422`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "email",
"message": "Invalid email format",
"code": "invalid_string"
}
]
}
```
Fix: send a valid email and keep the customer linked to your own internal ID. Customer creation does not replace transaction idempotency.
## Next steps
* [Transaction Statuses](/payments/transaction-statuses)
* [Accept Pix Payments](/payments/pix/accept-payments)
# Payments Overview
Source: https://developer.pagou.ai/payments/overview
Understand how customers, transactions, Pix, vouchers, cards, webhooks, and refunds fit together in Pagou v2.
Use this section to choose the right payment path before you implement endpoint details.
## Building blocks
| Capability | Main surface | Use it for |
| ------------ | ------------------------------ | ----------------------------------------------------- |
| Customers | `/v2/customers` | reusable buyer profiles |
| Transactions | `/v2/transactions` | Pix, voucher, and card payment creation and retrieval |
| Refunds | `/v2/transactions/{id}/refund` | full and partial reversals |
| Webhooks | payment event delivery | authoritative async status changes |
## Recommended choices
* Use Pix when you want the fastest collection path in Brazil.
* Use [Voucher payments](/payments/vouchers/accept-payments) for local cash, bank-transfer, boleto, and redirect payment options across supported countries.
* Use [Payment Element](/payments/cards/payment-element) for new card checkouts.
* Keep one canonical status map in [Transaction Statuses](/payments/transaction-statuses).
* Reconcile instead of guessing after network or worker failures.
## Common journeys
* Create a Pix payment, show QR code data, and fulfill on `transaction.paid`.
* Create a voucher payment, show the returned payment instructions, and reconcile when the customer pays through the selected local payment option.
* Create a card payment from a Payment Element token and handle `next_action` when 3DS is required.
* Issue refunds from your backend and wait for the resulting transaction status to settle.
## Read next
* [Customers](/payments/customers)
* [Accept Pix Payments](/payments/pix/accept-payments)
* [Accept Voucher Payments](/payments/vouchers/accept-payments)
* [Card Payments Overview](/payments/cards/overview)
# Accept Pix Payments
Source: https://developer.pagou.ai/payments/pix/accept-payments
Create a Pix transaction, return QR code data to the buyer, and operate the flow with webhooks plus reconciliation.
Use this page for the write path that starts a Pix collection.
## Happy path
1. Create a transaction with `method: "pix"`.
2. Return the Pix QR code data to the buyer.
3. Persist the Pagou transaction `id` and your `external_ref`.
4. Wait for webhook delivery.
5. Reconcile only when the payment state is uncertain.
## Example request
```bash theme={null}
curl --request POST \
--url https://api.pagou.ai/v2/transactions \
--header "Authorization: Bearer YOUR_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"external_ref": "order_1001",
"amount": 1500,
"currency": "BRL",
"method": "pix",
"notify_url": "https://merchant.example/webhooks/pagou",
"buyer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"document": {
"type": "CPF",
"number": "12345678901"
}
},
"products": [
{
"name": "Starter order",
"price": 1500,
"quantity": 1
}
]
}'
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1201",
"data": {
"id": "tr_1001",
"status": "pending",
"method": "pix",
"amount": 1500,
"base_price": 1500,
"currency": "BRL",
"pix": {
"qr_code": "000201010212...",
"expiration_date": "2026-03-16T14:15:00.000Z",
"receipt_url": null
},
"created_at": "2026-03-16T14:00:00.000Z",
"updated_at": "2026-03-16T14:00:00.000Z",
"paid_at": null
}
}
```
## Common error
Status `422`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "buyer.document.number",
"message": "Invalid document number",
"code": "invalid_string"
}
]
}
```
Fix: validate buyer data before calling Pagou. Do not treat `pending` as final. The payment is only settled after a terminal status such as `paid`.
## What your frontend should receive
Return only the buyer-facing Pix data your frontend needs, such as:
* transaction `id`
* current `status`
* `pix.qr_code`
* `pix.expiration_date`
## Next steps
* [Pix Refunds](/payments/pix/refunds)
* [Pix Reconciliation](/payments/pix/reconciliation)
* [Payment Events](/webhooks/payment-events)
# Pix Reconciliation
Source: https://developer.pagou.ai/payments/pix/reconciliation
Use Pagou read APIs to verify transaction state when a webhook is delayed, missed, or operationally ambiguous.
Use reconciliation when the payment state is uncertain after a timeout, worker crash, or delayed webhook.
## Read APIs
* `GET /v2/transactions`
* `GET /v2/transactions/{id}`
## Example request
```bash theme={null}
curl --request GET \
--url https://api.pagou.ai/v2/transactions/tr_1001 \
--header "Authorization: Bearer YOUR_TOKEN"
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1203",
"data": {
"id": "tr_1001",
"external_ref": "order_1001",
"status": "paid",
"method": "pix",
"amount": 1500,
"currency": "BRL",
"paid_at": "2026-03-16T14:03:10.000Z",
"updated_at": "2026-03-16T14:03:10.000Z"
}
}
```
## Common error
Status `404`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "The requested transaction does not exist."
}
```
Fix: verify the transaction ID and your own order-to-transaction mapping before retrying the lookup.
## Reconciliation flow
1. Load the Pagou transaction ID from your payment record or webhook store.
2. Fetch the latest transaction state.
3. Apply only forward-safe transitions in your system.
4. Keep webhooks as the normal update path after recovery.
## Next steps
* [Payment Events](/webhooks/payment-events)
* [Retries and Reconciliation](/webhooks/retries-and-reconciliation)
# Pix Refunds
Source: https://developer.pagou.ai/payments/pix/refunds
Issue full or partial refunds for eligible transactions and align your product and finance state to the resulting statuses.
Use refunds for paid transactions that need full or partial reversal.
## Refund operation
`PUT /v2/transactions/{id}/refund`
## Example request
```bash theme={null}
curl --request PUT \
--url https://api.pagou.ai/v2/transactions/tr_1001/refund \
--header "Authorization: Bearer YOUR_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"amount": 500,
"reason": "requested_by_customer"
}'
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1202",
"data": {
"transaction_id": "tr_1001",
"status": "partially_refunded",
"refunded_amount": 500
}
}
```
## Common error
Status `409`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/conflict",
"title": "Conflict",
"status": 409,
"detail": "The transaction cannot be refunded in its current state."
}
```
Fix: reconcile the transaction first and allow refunds only from eligible paid states in your own product and operator tooling.
## Operational rules
* Use your own refund request ID or ticket ID to prevent duplicate actions.
* Persist the refund request, the transaction ID, and the resulting transaction status.
* Update customer-visible finance state only after webhook confirmation or reconciliation.
## Next steps
* [Transaction Statuses](/payments/transaction-statuses)
* [Payment Events](/webhooks/payment-events)
# Transaction Statuses
Source: https://developer.pagou.ai/payments/transaction-statuses
Use one canonical status map for Pix, voucher, and card transactions in your product, operations, and webhook handlers.
Use this page as the canonical status reference for payment state in your system.
## Canonical statuses
| Status | Meaning | Typical action |
| -------------------- | ---------------------------------------------- | -------------------------------------------------------- |
| `pending` | waiting for the next state change | keep the order open |
| `processing` | provider-side work in progress | wait and monitor |
| `paid` | payment completed | fulfill once |
| `captured` | card capture completed | fulfill once |
| `authorized` | card authorized but not final | keep pending until your business rule allows fulfillment |
| `three_ds_required` | card flow needs customer authentication | continue `next_action` instead of failing |
| `partially_paid` | only part of the amount settled | apply your partial-settlement policy |
| `refunded` | fully refunded | reverse fulfillment and finance state |
| `partially_refunded` | partially refunded | update order and accounting state |
| `canceled` | transaction canceled | close the attempt |
| `expired` | payment timed out | let the customer retry |
| `refused` | provider declined the payment | surface a recoverable failure |
| `chargedback` | dispute or chargeback state | escalate to risk and finance |
| `processed` | provider completed an internal processing step | monitor until a final state |
| `in_protest` | banking or dispute hold | route to operations |
## Rules
* Drive state changes from webhooks first.
* For vouchers, `pending` can mean the payment instruction was issued and the customer still needs to pay through the selected local payment option.
* Treat `paid`, `captured`, `refunded`, `partially_refunded`, `canceled`, `expired`, and `refused` as terminal in most merchant systems.
* Reconcile with `GET /v2/transactions/{id}` whenever a state transition is uncertain.
## Example resource snapshot
```json theme={null}
{
"id": "tr_1001",
"status": "paid",
"method": "pix",
"amount": 1500,
"currency": "BRL",
"paid_at": "2026-03-16T14:03:10.000Z"
}
```
## Read next
* [Accept Pix Payments](/payments/pix/accept-payments)
* [Accept Voucher Payments](/payments/vouchers/accept-payments)
* [Card Transaction Lifecycle](/payments/cards/transaction-lifecycle)
* [Payment Events](/webhooks/payment-events)
# Accept Voucher Payments
Source: https://developer.pagou.ai/payments/vouchers/accept-payments
Create voucher transactions for local payment methods such as Boleto, SPEI, Mercado Pago, Webpay, CODI, PSE, and other country-specific cash or bank-transfer flows.
Use `method: "voucher"` when the customer will pay outside a card or Pix flow through a local payment instruction, bank-transfer reference, redirect, or payable document.
`voucher` is the public Pagou method. The actual local payment option is selected from the company's payment setup, currency, and country. Do not send provider-specific method names such as `boleto`, `spei`, `mercadopago`, `webpay`, or `codi` to the transactions API.
## Regional meaning
| Customer market | Common local payment option behind `voucher` | What the customer receives |
| ---------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Brazil, `BRL` | Boleto | Barcode, digitable line, due date, and boleto URL when available. |
| Mexico, `MXN` | SPEI or local bank transfer | CLABE/account, reference, payment URL, or bank-transfer instructions. |
| Argentina, `ARS` | Local cash or wallet voucher, such as Mercado Pago when enabled for the company | Reference, redirect URL, or local payment instructions. |
| Chile, `CLP` | Webpay or local voucher option | Redirect/payment URL or payment instructions. |
| Colombia, `COP` | PSE or local voucher option | Redirect/payment URL or payment instructions. |
| Peru, `PEN` | Local voucher or bank-transfer option | Reference, payment URL, or payment instructions. |
Availability depends on the merchant configuration and the payment provider enabled for the company. If a country/currency is not enabled for that company, the transaction will be rejected during payment creation.
## Create the transaction
Create a voucher payment with `POST /v2/transactions`.
```json theme={null}
{
"external_ref": "order_3001",
"amount": 125000,
"currency": "MXN",
"method": "voucher",
"buyer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"document": {
"type": "CURP",
"number": "LOLA800101MDFXXX09"
},
"address": {
"street": "Av. Paseo de la Reforma",
"city": "Ciudad de Mexico",
"zipCode": "06600",
"country": "MX"
}
},
"products": [
{
"name": "Annual plan",
"price": 125000,
"quantity": 1
}
],
"notify_url": "https://example.com/webhooks/pagou"
}
```
`amount` and product `price` use the smallest unit of the selected currency. For BRL and MXN, send cents/centavos.
For LATAM voucher payments, send `buyer.document` and `buyer.address.country` whenever possible. Some SPEI configurations can create the payment without a document, but most voucher/bank-transfer options validate the document type for the selected country.
Do not include `token`. Card tokens are only valid for `method: "credit_card"`.
## Accepted document types
Use these values in `buyer.document.type` when the buyer is paying with `method: "voucher"`. The country is read from `buyer.address.country` when present; otherwise Pagou can infer a primary country from `currency`.
| Country | Country code | Accepted document types |
| ---------- | ------------ | ------------------------ |
| Argentina | `AR` | `DNI`, `CUIT` |
| Bolivia | `BO` | `CI`, `CE`, `NIT` |
| Brazil | `BR` | `CPF`, `CNPJ` |
| Chile | `CL` | `RUT`, `RUN` |
| Colombia | `CO` | `CC`, `NIT` |
| Costa Rica | `CR` | `CDI` |
| Ecuador | `EC` | `CI`, `PP`, `RUC`, `PAS` |
| Guatemala | `GT` | `DPI`, `CUI`, `NIT` |
| Mexico | `MX` | `RFC`, `CURP` |
| Panama | `PA` | `CE` |
| Paraguay | `PY` | `CI`, `RUC` |
| Peru | `PE` | `DNI`, `RUC` |
| Uruguay | `UY` | `CI`, `RUC` |
This table lists the document types accepted by the API validation layer. Payment availability for each country still depends on the company's enabled payment setup.
## Present the instructions
The transaction response exposes the normalized `voucher` object.
```json theme={null}
{
"id": "tr_3001",
"status": "pending",
"method": "voucher",
"amount": 125000,
"currency": "MXN",
"voucher": {
"barcode": "646180123456789012",
"digitable_line": "646180123456789012",
"url": "https://provider.example/pay/order_3001",
"expiration_date": "2026-05-12T23:59:59.000Z",
"instructions": "Pay using the bank transfer reference before the expiration date.",
"receipt_url": null
}
}
```
| Field | Meaning |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `voucher.barcode` | Barcode, bank account, CLABE, payment code, or provider reference, depending on the local payment option. |
| `voucher.digitable_line` | Digitable line, bank-transfer reference, CLABE, or equivalent customer-copyable instruction. |
| `voucher.url` | Payment page, boleto URL, redirect URL, QR image URL, or provider-hosted voucher URL. Use it as the main call to action when present. |
| `voucher.expiration_date` | Due date or expiration date for the payment instruction. |
| `voucher.instructions` | Additional bank, payment, or provider instructions. |
| `voucher.receipt_url` | Receipt URL when the provider returns one. It is usually available after payment confirmation. |
Fields are nullable because each country and payment provider returns a different instruction format. Build your checkout to display every field that is present instead of requiring one fixed Boleto-only shape.
## Delayed instruction updates
Some providers return all voucher data in the create response. Others return `status: "pending"` first and deliver the voucher fields through a webhook shortly after.
Use this sequence:
1. Create the transaction with `method: "voucher"`.
2. If `voucher.url`, `voucher.digitable_line`, or `voucher.barcode` is present, show it immediately.
3. Subscribe to [payment webhooks](/webhooks/payment-events) and update the customer-facing page when the same transaction receives voucher instructions.
4. Reconcile with `GET /v2/transactions/{id}` if your worker missed a webhook or if the customer refreshes the checkout.
Redirect-based voucher options such as Webpay or CODI are still voucher payments. Treat their URL as the voucher payment action, not as a card 3DS challenge.
## Relevant endpoints
| Endpoint | Use |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `POST /v2/transactions` | Create the voucher transaction. |
| `GET /v2/transactions/{id}` | Retrieve the latest status and voucher fields. |
| `GET /v2/transactions?paymentMethods=voucher` | List voucher transactions for reconciliation or operations. |
| `PUT /v2/transactions/{id}/refund` | Request a refund after payment is confirmed, when the payment provider and selected payment option support refunds. |
| Payment webhooks | Receive `transaction.pending`, `transaction.paid`, refund, expiration, and chargeback events. |
## Read next
* [Create a Transaction](/api-reference/transactions/create)
* [Get a Transaction](/api-reference/transactions/get)
* [Payment Events](/webhooks/payment-events)
* [Payments with the TypeScript SDK](/sdks/typescript/payments)
# Cancel a Pix Out Transfer
Source: https://developer.pagou.ai/payouts/pix-out/cancel-transfer
Cancel a pending transfer safely and avoid duplicate operator actions during payout management.
Cancel only when the transfer is still in a cancelable state in your own operator workflow.
## Endpoint
`POST /v2/transfers/{id}/cancel`
## Example request
```bash theme={null}
curl --request POST \
--url https://api.pagou.ai/v2/transfers/po_1001/cancel \
--header "Authorization: Bearer YOUR_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"reason": "wrong recipient"
}'
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_2002",
"data": {
"id": "po_1001",
"status": "cancelled"
}
}
```
## Common error
Status `409`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/conflict",
"title": "Conflict",
"status": 409,
"detail": "The transfer cannot be cancelled in its current state."
}
```
Fix: show the cancel action only from states your operators can still stop safely. If the state is unclear, retrieve the transfer first.
## Rules
* Confirm current transfer state before showing a cancel button.
* Reconcile after any uncertain cancellation attempt.
* Update operator UI only after webhook delivery or successful `GET` confirmation.
# Create a Pix Out Transfer
Source: https://developer.pagou.ai/payouts/pix-out/create-transfer
Create a transfer request, persist the Pagou transfer ID, and transition state from webhook delivery.
Use this page for the write path that starts a payout.
## Example request
```bash theme={null}
curl --request POST \
--url https://api.pagou.ai/v2/transfers \
--header "Authorization: Bearer YOUR_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"pix_key_type": "EMAIL",
"pix_key_value": "supplier@example.com",
"amount": 1200,
"description": "Supplier payout",
"external_ref": "payout_1001",
"notify_url": "https://merchant.example/webhooks/pagou/transfers"
}'
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_2001",
"data": {
"id": "po_1001",
"status": "pending",
"amount": 1200,
"pix_key_type": "EMAIL",
"external_ref": "payout_1001",
"created_at": "2026-03-16T14:00:00.000Z"
}
}
```
## Common error
Status `422`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "pix_key_value",
"message": "Invalid PIX key value",
"code": "invalid_string"
}
]
}
```
Fix: send the correct `pix_key_type` and a matching `pix_key_value`. Do not document or depend on unsupported fields such as `recipient_name`.
## What to persist
* your payout request ID or `external_ref`
* Pagou transfer `id`
* current transfer `status`
* Pagou `requestId`
## Production note
Treat the create response as an acknowledgement, not final settlement. Final operational state belongs to webhook delivery and reconciliation.
## Next steps
* [Cancel a Pix Out Transfer](/payouts/pix-out/cancel-transfer)
* [Transfer Reconciliation](/payouts/pix-out/reconciliation)
# Pix Out Overview
Source: https://developer.pagou.ai/payouts/pix-out/overview
Send outbound Pix transfers, track lifecycle changes, and reconcile payout operations safely.
Use Pix Out when your platform sends money out to suppliers, sellers, or internal payout recipients.
## Public operations
* `POST /v2/transfers`
* `GET /v2/transfers`
* `GET /v2/transfers/{id}`
* `POST /v2/transfers/{id}/cancel`
## Operating model
1. Create the transfer from your backend.
2. Persist your payout reference, Pagou transfer ID, and `requestId`.
3. Treat webhook delivery as the primary state update path.
4. Reconcile with `GET /v2/transfers/{id}` when the state is uncertain.
5. Allow cancellation only from states your operators can safely stop.
## Status vocabulary
Use API resource status for payout state and webhook event names for transitions.
* Resource statuses: `pending`, `scheduled`, `in_analysis`, `processing`, `paid`, `rejected`, `cancelled`, `error`, `unknown`
* Webhook events: `payout.created`, `payout.in_analysis`, `payout.processing`, `payout.transferred`, `payout.failed`, `payout.rejected`, `payout.canceled`
## Read next
* [Create a Pix Out Transfer](/payouts/pix-out/create-transfer)
* [Transfer Statuses](/payouts/pix-out/statuses)
* [Transfer Events](/webhooks/transfer-events)
# Transfer Reconciliation
Source: https://developer.pagou.ai/payouts/pix-out/reconciliation
Use Pagou transfer read APIs to recover from delayed events, worker failures, or uncertain payout state.
Use reconciliation as a fallback when webhook processing or operator actions leave transfer state uncertain.
## Read APIs
* `GET /v2/transfers`
* `GET /v2/transfers/{id}`
## Example request
```bash theme={null}
curl --request GET \
--url https://api.pagou.ai/v2/transfers/po_1001 \
--header "Authorization: Bearer YOUR_TOKEN"
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_2003",
"data": {
"id": "po_1001",
"status": "paid",
"amount": 1200,
"external_ref": "payout_1001",
"transferred_at": "2026-03-16T14:05:00.000Z"
}
}
```
## Common error
Status `404`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "The requested transfer does not exist."
}
```
Fix: verify the transfer ID and your own payout mapping before retrying the lookup.
## Reconciliation workflow
1. Load the Pagou transfer ID from your payout record or webhook store.
2. Fetch the latest transfer state.
3. Apply only forward-safe transitions locally.
4. Escalate repeated `error`, `rejected`, or `unknown` states to operations.
# Transfer Statuses
Source: https://developer.pagou.ai/payouts/pix-out/statuses
Map Pagou payout statuses into operator workflows, merchant messaging, and reconciliation jobs.
Use one shared status map for product, operations, and support.
## API resource statuses
| Status | Meaning | Typical action |
| ------------- | --------------------------- | ------------------------------------ |
| `pending` | accepted but not final | monitor |
| `scheduled` | queued for future execution | keep scheduled |
| `in_analysis` | manual or provider review | keep queued and visible to operators |
| `processing` | settlement in progress | wait for webhook or reconcile |
| `paid` | settled successfully | mark payout completed |
| `rejected` | blocked before settlement | route to operator review |
| `cancelled` | intentionally stopped | close the request |
| `error` | failed during processing | investigate retry policy |
| `unknown` | not yet normalized | reconcile immediately |
## Webhook event mapping
Resource status and webhook event names are not identical.
* `payout.transferred` maps to resource status `paid`
* `payout.failed` maps to resource status `error`
* `payout.canceled` maps to resource status `cancelled`
## Why this matters
If your product displays event names as resource statuses, operator tooling becomes ambiguous. Keep one internal mapping and reuse it across webhook handlers, dashboards, and reconciliation jobs.
## Read next
* [Transfer Events](/webhooks/transfer-events)
* [Transfer Reconciliation](/payouts/pix-out/reconciliation)
# Payments with the TypeScript SDK
Source: https://developer.pagou.ai/sdks/typescript/payments
Create Pix, voucher, and card transactions, retrieve and list by cursor, run sandbox updates, and refund safely with the TypeScript SDK.
Use these examples when your service owns payment creation, retrieval, and refund logic.
All examples assume a configured `client` from the [TypeScript SDK Quickstart](/sdks/typescript/quickstart).
## Resource methods
| Method | API operation | Use |
| ------------------------------------------------------------ | ---------------------------------- | -------------------------------------------------------------- |
| `client.transactions.create(params, opts?)` | `POST /v2/transactions` | Create Pix, voucher, card, or other supported payment methods. |
| `client.transactions.retrieve(id, opts?)` | `GET /v2/transactions/{id}` | Read the current transaction state. |
| `client.transactions.list(params?, opts?)` | `GET /v2/transactions` | List transactions with cursor pagination and filters. |
| `client.transactions.update(id, params, opts?)` | `PUT /v2/transactions/{id}` | Update a sandbox/test transaction status. |
| `client.transactions.refund(id, params?, opts?)` | `PUT /v2/transactions/{id}/refund` | Refund a transaction. |
| `client.transactions.listAutoPagingIterator(params?, opts?)` | Cursor helper | Iterate every item across pages. |
## Create a Pix payment
```ts theme={null}
const created = await client.transactions.create(
{
external_ref: "order_1001",
amount: 1500,
currency: "BRL",
method: "pix",
buyer: {
name: "Ada Lovelace",
email: "ada@example.com",
document: { type: "CPF", number: "12345678901" },
},
products: [{ name: "Starter order", price: 1500, quantity: 1 }],
},
{ idempotencyKey: "tx_order_1001" },
);
console.log(created.data.id, created.data.status, created.meta.requestId);
```
`amount` and product `price` are in cents.
## Create a voucher payment
Use `method: "voucher"` for Boleto in Brazil, SPEI or bank transfer in Mexico, Mercado Pago or local voucher options in Argentina, Webpay in Chile, PSE in Colombia, and other configured country-specific payment instructions.
```ts theme={null}
const voucherPayment = await client.transactions.create(
{
external_ref: "order_3001",
amount: 125000,
currency: "MXN",
method: "voucher",
buyer: {
name: "Ada Lovelace",
email: "ada@example.com",
document: { type: "CURP", number: "LOLA800101MDFXXX09" },
address: {
street: "Av. Paseo de la Reforma",
city: "Ciudad de Mexico",
zipCode: "06600",
country: "MX",
},
},
products: [{ name: "Annual plan", price: 125000, quantity: 1 }],
notify_url: "https://example.com/webhooks/pagou",
},
{ idempotencyKey: "tx_order_3001" },
);
console.log(voucherPayment.data.voucher?.url);
console.log(voucherPayment.data.voucher?.digitable_line);
```
Do not pass provider-specific method names such as `boleto`, `spei`, `webpay`, or `mercadopago`. The API receives `voucher` and chooses the local payment option from the company's payment setup, currency, and country.
The normalized `voucher` object can include `barcode`, `digitable_line`, `url`, `expiration_date`, `instructions`, and `receipt_url`. These fields are nullable because each local payment option returns a different instruction format.
## Create a card payment from a Payment Element token
Use the browser SDK v3 to collect card details and send only the resulting `pgct_*` token to your backend.
```ts theme={null}
const cardPayment = await client.transactions.create(
{
external_ref: "order_2001",
amount: 2490,
currency: "BRL",
method: "credit_card",
token: "pgct_token_from_browser",
installments: 1,
buyer: {
name: "Ada Lovelace",
email: "ada@example.com",
document: { type: "CPF", number: "12345678901" },
},
products: [{ name: "Plan upgrade", price: 2490, quantity: 1 }],
},
{ idempotencyKey: "tx_order_2001" },
);
console.log(cardPayment.data.status);
```
Never send raw card data through the TypeScript SDK. Browser card collection belongs in [SDK v3 Reference](/frontend/payment-element/sdk-reference).
## Retrieve and reconcile
```ts theme={null}
const current = await client.transactions.retrieve("tr_1001", {
requestId: "reconcile_tr_1001",
timeoutMs: 10_000,
});
console.log(current.data.status);
```
Use retrieve calls for reconciliation, admin views, and delayed payment-state checks. Fulfillment should still rely on webhooks or server-side reconciliation, not browser status alone.
## List with filters
```ts theme={null}
const page = await client.transactions.list({
limit: 50,
paymentMethods: ["pix", "voucher", "credit_card"],
status: ["pending", "paid"],
email: "@example.com",
});
for (const transaction of page.data.data) {
console.log(transaction.id, transaction.status);
}
if (page.data.next_cursor) {
const nextPage = await client.transactions.list({
cursor: page.data.next_cursor,
direction: "next",
limit: 50,
});
}
```
Supported list filters include `id`, `paymentMethods`, `status`, `deliveryStatus`, `installments`, `name`, `email`, `documentNumber`, `phone`, and `traceable`.
## List with auto-pagination
```ts theme={null}
for await (const item of client.transactions.listAutoPagingIterator({ limit: 100 })) {
console.log(item.id, item.status);
}
```
Use auto-pagination for batch jobs and exports. Use `list(...)` directly when you need to expose `next_cursor`, `prev_cursor`, or `total` to your own UI.
## Refund safely
```ts theme={null}
const refunded = await client.transactions.refund(
"tr_1001",
{ amount: 500, reason: "requested_by_customer" },
{ idempotencyKey: "refund_tr_1001_1" },
);
```
For retry-safe refunds, always set a stable `idempotencyKey`.
## Update sandbox transaction status
`transactions.update(...)` is intended for test/sandbox flows.
```ts theme={null}
const updated = await client.transactions.update(
"tr_1001",
{ status: "paid" },
{ idempotencyKey: "update_tr_1001_paid" },
);
```
## Response shape
Create, retrieve, update, and refund methods return `{ data, meta }`.
List methods return `{ data, meta }`, where `data` is a cursor envelope:
```json theme={null}
{
"success": true,
"requestId": "req_3002",
"data": [],
"next_cursor": "cursor_next",
"prev_cursor": null,
"total": 120
}
```
# TypeScript SDK Quickstart
Source: https://developer.pagou.ai/sdks/typescript/quickstart
Install and configure the official server-side TypeScript SDK, then make safe requests with response metadata, retries, and typed errors.
Use the TypeScript SDK from trusted server-side code. Do not ship secret API keys to the browser.
## Which SDK should I use?
Use the TypeScript SDK in trusted server-side code to create payments, retrieve transactions, issue refunds, and create transfers. Use the browser SDK v3 through Payment Element when you need hosted card fields in a checkout page.
| Need | Use |
| -------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Create Pix, voucher, card, refund, and transfer requests from your backend | TypeScript SDK |
| Mount hosted card fields and tokenize card details in the browser | [SDK v3 Reference](/frontend/payment-element/sdk-reference) |
| Continue a 3D Secure browser challenge | [SDK v3 Reference](/frontend/payment-element/sdk-reference#3d-secure) |
## Requirements
* TypeScript or JavaScript running on your backend.
* A Pagou secret key for the environment you are calling.
* A runtime with `fetch`. If your runtime does not expose global `fetch`, inject a custom implementation in the client options.
## Install
```bash theme={null}
bun add @pagouai/api-sdk
```
## Create a client
```ts theme={null}
import { Client } from "@pagouai/api-sdk";
const client = new Client({
apiKey: process.env.PAGOU_API_KEY!,
environment: "sandbox",
timeoutMs: 30_000,
maxRetries: 2,
});
```
Environments:
| Environment | Base URL |
| ------------ | ------------------------------ |
| `production` | `https://api.pagou.ai` |
| `sandbox` | `https://api.sandbox.pagou.ai` |
You can also pass `baseUrl` for internal tests or controlled proxies.
## Response shape
SDK methods return `{ data, meta }`. `data` is the API payload. `meta` contains HTTP metadata and the request ID used for tracing.
```ts theme={null}
const created = await client.transactions.create({
external_ref: "order_1001",
amount: 1500,
currency: "BRL",
method: "pix",
buyer: {
name: "Ada Lovelace",
email: "ada@example.com",
document: { type: "CPF", number: "12345678901" },
},
products: [{ name: "Starter order", price: 1500, quantity: 1 }],
});
console.log(created.data.id);
console.log(created.data.status);
console.log(created.meta.requestId);
```
## First Pix payment
```ts theme={null}
const created = await client.transactions.create(
{
external_ref: "order_1001",
amount: 1500,
currency: "BRL",
method: "pix",
buyer: {
name: "Ada Lovelace",
email: "ada@example.com",
document: { type: "CPF", number: "12345678901" },
},
products: [{ name: "Starter order", price: 1500, quantity: 1 }],
},
{
idempotencyKey: "tx_order_1001",
requestId: "req_order_1001",
},
);
```
## Request options
Every resource method accepts an optional second argument:
```ts theme={null}
await client.transactions.retrieve("tr_1001", {
requestId: "reconcile_tr_1001",
timeoutMs: 10_000,
signal: abortController.signal,
});
```
| Option | Use |
| ---------------- | ------------------------------------------------------- |
| `idempotencyKey` | Required for safe retries on `POST` and `PUT` requests. |
| `requestId` | Sends `X-Request-Id` for tracing. |
| `timeoutMs` | Overrides the client timeout for one request. |
| `signal` | Cancels the request with an `AbortSignal`. |
## Auth variants
Bearer auth is the default and recommended setup.
```ts theme={null}
new Client({ apiKey: process.env.PAGOU_API_KEY!, auth: { scheme: "bearer" } });
```
Use the other schemes only for legacy integrations or compatibility layers:
```ts theme={null}
new Client({ apiKey: process.env.PAGOU_API_KEY!, auth: { scheme: "basic" } });
new Client({ apiKey: process.env.PAGOU_API_KEY!, auth: { scheme: "api_key_header", headerName: "apiKey" } });
```
## Retry behavior
* Retries cover network failures and `429`, `500`, `502`, `503`, `504`.
* `GET` and `HEAD` retry automatically.
* `POST` and `PUT` retry only when you set `idempotencyKey`.
* Default retry count is `2`.
* Default timeout is `30_000` ms.
Set idempotency keys on any payment, refund, transfer, or cancel request that may be retried:
```ts theme={null}
await client.transactions.refund(
"tr_1001",
{ amount: 500, reason: "requested_by_customer" },
{ idempotencyKey: "refund_tr_1001_1" },
);
```
## Error handling
```ts theme={null}
import { ApiError, NotFoundError, RateLimitError } from "@pagouai/api-sdk";
try {
const transaction = await client.transactions.retrieve("tr_missing");
console.log(transaction.data.status);
} catch (error) {
if (error instanceof NotFoundError) {
console.error("Transaction not found", error.requestId);
} else if (error instanceof RateLimitError) {
console.error("Rate limited", error.status, error.requestId);
} else if (error instanceof ApiError) {
console.error(error.status, error.code, error.requestId, error.details);
} else {
throw error;
}
}
```
Exported SDK errors include `AuthenticationError`, `PermissionError`, `RateLimitError`, `InvalidRequestError`, `NotFoundError`, `ConflictError`, `ServerError`, and `NetworkError`.
## Read next
* [Payments with the TypeScript SDK](/sdks/typescript/payments)
* [Transfers with the TypeScript SDK](/sdks/typescript/transfers)
* [SDK v3 Reference](/frontend/payment-element/sdk-reference)
# Transfers with the TypeScript SDK
Source: https://developer.pagou.ai/sdks/typescript/transfers
Create Pix transfers, retrieve and list them by cursor, cancel safely, and reconcile payout state with the TypeScript SDK.
Use these examples when your service owns payout creation, cancellation, and reconciliation.
All examples assume a configured `client` from the [TypeScript SDK Quickstart](/sdks/typescript/quickstart).
## Resource methods
| Method | API operation | Use |
| --------------------------------------------------------- | -------------------------------- | ----------------------------------------- |
| `client.transfers.create(params, opts?)` | `POST /v2/transfers` | Create a Pix Out transfer. |
| `client.transfers.retrieve(id, opts?)` | `GET /v2/transfers/{id}` | Read the current transfer state. |
| `client.transfers.list(params?, opts?)` | `GET /v2/transfers` | List transfers with cursor pagination. |
| `client.transfers.cancel(id, params?, opts?)` | `POST /v2/transfers/{id}/cancel` | Cancel a pending transfer when supported. |
| `client.transfers.listAutoPagingIterator(params?, opts?)` | Cursor helper | Iterate every transfer across pages. |
## Create a transfer
```ts theme={null}
const transfer = await client.transfers.create(
{
pix_key_type: "EMAIL",
pix_key_value: "supplier@example.com",
amount: 1200,
description: "Supplier payout",
external_ref: "payout_1001",
},
{
idempotencyKey: "transfer_payout_1001",
requestId: "req_payout_1001",
},
);
console.log(transfer.data.id, transfer.data.status, transfer.meta.requestId);
```
`amount` is in cents. Supported Pix key types are `CPF`, `CNPJ`, `EMAIL`, `PHONE`, and `EVP`.
## Retrieve and reconcile
Use retrieve calls for back-office screens, reconciliation jobs, and delayed state checks.
```ts theme={null}
const current = await client.transfers.retrieve("po_1001", {
requestId: "reconcile_po_1001",
timeoutMs: 10_000,
});
console.log(current.data.status);
```
## List transfers
```ts theme={null}
const page = await client.transfers.list({
limit: 50,
status: "pending",
});
for (const transfer of page.data.data) {
console.log(transfer.id, transfer.status);
}
if (page.data.next_cursor) {
const nextPage = await client.transfers.list({
cursor: page.data.next_cursor,
direction: "next",
limit: 50,
});
}
```
List responses include `next_cursor`, `prev_cursor`, and `total`. Use those fields when building your own paginated UI.
## List with auto-pagination
```ts theme={null}
for await (const item of client.transfers.listAutoPagingIterator({ limit: 100 })) {
console.log(item.id, item.status);
}
```
Use auto-pagination for batch jobs, exports, and reconciliation tasks that should consume all available pages.
## Cancel safely
```ts theme={null}
const cancelled = await client.transfers.cancel(
"po_1001",
{ reason: "wrong recipient" },
{
idempotencyKey: "cancel_po_1001_wrong_recipient",
requestId: "cancel_po_1001",
},
);
```
Cancellation depends on the current transfer state and provider support. If cancellation fails, inspect the typed SDK error and reconcile the transfer before retrying.
## Response shape
Create, retrieve, and cancel methods return `{ data, meta }`.
List methods return `{ data, meta }`, where `data` is a cursor envelope:
```json theme={null}
{
"success": true,
"requestId": "req_3003",
"data": [],
"next_cursor": "cursor_next",
"prev_cursor": null,
"total": 80
}
```
## Common rule
Use `pix_key_type` and `pix_key_value` in SDK and API examples. Do not use undocumented input fields such as `pix_key` or `recipient_name`.
# AI-Assisted Integration
Source: https://developer.pagou.ai/start-here/ai-integration
Give AI coding agents the right Pagou docs context before they generate integration code.
Copy this prompt into any AI coding agent:
```text Pagou AI Context theme={null}
Integrate Pagou payments. Docs: https://developer.pagou.ai/llms.txt | Full: https://developer.pagou.ai/llms-full.txt | OpenAPI: https://developer.pagou.ai/api-reference/openapi-v2.json
Rules:
- Validate endpoints/fields against OpenAPI before coding
- Include external_ref on all create requests
- Card tokenization: Payment Element + elements.submit()
- Fulfill only from webhook or reconciled state
- Deduplicate webhooks by top-level event id
```
## Docs reference
`llms.txt` — find the right page quickly
`llms-full.txt` — complete offline docs
OpenAPI — endpoints, fields, webhooks
## Setup by agent
Add to `CLAUDE.md` in project root:
```markdown theme={null}
## Pagou Integration
- Docs: https://developer.pagou.ai/llms.txt
- OpenAPI: https://developer.pagou.ai/api-reference/openapi-v2.json
- Always include external_ref, validate fields against OpenAPI, fulfill only from webhook
```
[Full CLAUDE.md template](/start-here/claude-md-template)
Add to `AGENTS.md` in project root:
```markdown theme={null}
## Pagou Integration
- Docs: https://developer.pagou.ai/llms.txt
- OpenAPI: https://developer.pagou.ai/api-reference/openapi-v2.json
- Always include external_ref, validate fields against OpenAPI, fulfill only from webhook
```
Or run with inline context:
```bash theme={null}
codex "Read https://developer.pagou.ai/llms-full.txt then add Pix checkout"
```
Add to `.cursorrules` in project root:
```markdown theme={null}
## Pagou Integration
- Docs: https://developer.pagou.ai/llms.txt
- OpenAPI: https://developer.pagou.ai/api-reference/openapi-v2.json
- Always include external_ref, validate fields against OpenAPI, fulfill only from webhook
```
[Full .cursorrules template](/start-here/cursorrules-template)
Paste context prompt above at the start of your chat, then ask your question.
If the agent can't fetch URLs, paste the relevant section from [llms-full.txt](https://developer.pagou.ai/llms-full.txt) directly.
Start with this as your first message:
```text theme={null}
Read https://developer.pagou.ai/llms-full.txt for Pagou API context.
Build: [describe your app]
```
Replace `[describe your app]` with what you want to build.
## One-shot prompts
Copy any of these directly into your AI agent:
```text theme={null}
Read https://developer.pagou.ai/llms-full.txt and https://developer.pagou.ai/api-reference/openapi-v2.json
Build a Pix checkout flow:
1. Backend: POST /v2/transactions with method=pix, include external_ref
2. Frontend: display pix_qr_code as QR image, show pix_code as copy-paste fallback
3. Webhook: listen for transaction.paid, update order status
4. Handle expiration: check status via GET /v2/transactions/{id} if no webhook
Use env var for API key. Never expose credentials in frontend.
```
```text theme={null}
Read https://developer.pagou.ai/llms-full.txt and https://developer.pagou.ai/api-reference/openapi-v2.json
Build a card checkout flow:
1. Frontend: load Payment Element from https://js.pagou.ai/payments/v3.js, mount card form
2. On submit: call elements.submit() to tokenize, send token to backend
3. Backend: POST /v2/transactions with method=credit_card, token, installments, external_ref
4. Handle 3DS: if response has next_action, redirect user to complete authentication
5. Webhook: listen for transaction.paid or transaction.failed, update order status
Use env var for API key. Never handle raw card numbers.
```
```text theme={null}
Read https://developer.pagou.ai/llms-full.txt and https://developer.pagou.ai/api-reference/openapi-v2.json
Build a webhook endpoint:
1. POST /webhooks/pagou - accept JSON body
2. Deduplicate by top-level "id" field (same event can be sent multiple times)
3. Route payment events by data.event_type: transaction.paid, transaction.failed, transaction.refunded
4. Route transfer events by type: payout.transferred, payout.failed
5. Return 200 with {"received": true}
6. Process async - respond fast, handle business logic in background
Store processed event IDs to prevent duplicate processing.
```
```text theme={null}
Read https://developer.pagou.ai/llms-full.txt and https://developer.pagou.ai/api-reference/openapi-v2.json
Build a Pix Out transfer flow:
1. Backend: POST /v2/transfers with pix_key_type (CPF/CNPJ/EMAIL/PHONE/EVP), pix_key_value, amount, external_ref
2. Webhook: listen for payout.transferred (success) or payout.failed (error)
3. Status check: GET /v2/transfers/{id} if webhook not received
4. Cancellation: POST /v2/transfers/{id}/cancel (only works if status is pending)
Use env var for API key. Validate recipient Pix key before sending.
```
## Tips for agents
* Keep API keys server-side only, use env vars
* Never log card tokens or Pix keys
* Validate webhook source before processing
* Use HTTPS everywhere
* Test in sandbox first, same code works in prod
* Use ngrok to receive webhooks locally
* Always send external\_ref for idempotency
* Reconcile with GET if webhook fails
## Read next
* [TypeScript SDK Quickstart](/sdks/typescript/quickstart)
* [Accept Pix Payments](/payments/pix/accept-payments)
* [Webhooks Overview](/webhooks/overview)
# Authentication
Source: https://developer.pagou.ai/start-here/authentication
Authenticate Pagou API requests consistently and choose one production standard for your integration.
Every Pagou API request requires authentication.
## Supported methods
1. `Authorization: Bearer `
2. `apiKey: ` header
3. Basic Auth with username `token` and password `x`
Use one method across all services. Bearer token is the recommended default for new integrations.
## Recommended request
```http theme={null}
GET /v2/transactions HTTP/1.1
Host: api.pagou.ai
Authorization: Bearer YOUR_TOKEN
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1000",
"data": {
"data": [],
"total": 0,
"next_cursor": null,
"prev_cursor": null
}
}
```
## Compatibility examples
```http theme={null}
GET /v2/transactions HTTP/1.1
Host: api.pagou.ai
apiKey: YOUR_TOKEN
```
```http theme={null}
GET /v2/transactions HTTP/1.1
Host: api.pagou.ai
Authorization: Basic dG9rZW46eA==
```
## Common error
Status `401`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Authentication credentials were not provided or are invalid."
}
```
Fix: confirm the token belongs to the selected environment and that you are not mixing auth schemes across services.
## Operational rules
* Rotate credentials in your secret manager, not in source code.
* Never log tokens.
* Keep browser code on public keys only. Secret API tokens stay on the backend.
## Next steps
* [Idempotency](/start-here/idempotency)
* [Errors and Retries](/start-here/errors-and-retries)
# CLAUDE.md Template
Source: https://developer.pagou.ai/start-here/claude-md-template
Copy this CLAUDE.md file to give Claude Code full context for Pagou integrations.
Create a `CLAUDE.md` file in your project root. Claude Code reads this automatically.
## Template
````markdown theme={null}
# Pagou Integration
This project integrates with the Pagou.ai payments API.
## API
- Sandbox: https://api-sandbox.pagou.ai
- Production: https://api.pagou.ai
- Docs: https://developer.pagou.ai
## Authentication
Pick one method:
- `Authorization: Bearer `
- `apiKey: ` header
- Basic Auth (username=token, password=x)
## Payments
### Create Pix payment
```
POST /v2/transactions
{
"external_ref": "order_1001",
"amount": 1500,
"currency": "BRL",
"method": "pix",
"buyer": {
"name": "Customer Name",
"email": "customer@example.com",
"document": { "type": "CPF", "number": "12345678901" }
}
}
```
Response includes `pix_qr_code` (base64) and `pix_code` (string).
### Create card payment
```
POST /v2/transactions
{
"external_ref": "order_1001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "",
"installments": 1
}
```
Card payments require Payment Element in browser to tokenize card data.
### Transaction statuses
pending → paid | expired | failed | refunded | chargedback
## Transfers (Pix Out)
```
POST /v2/transfers
{
"pix_key_type": "EMAIL",
"pix_key_value": "recipient@example.com",
"amount": 1200,
"description": "Payout description",
"external_ref": "payout_1001"
}
```
pix_key_type: CPF, CNPJ, EMAIL, PHONE, EVP
### Transfer statuses
pending → in_analysis → processing → paid | error | cancelled
## Webhooks
### Payment event structure
```json
{
"id": "evt_pay_1001",
"event": "transaction",
"data": {
"event_type": "transaction.paid",
"id": "tr_1001",
"status": "paid",
"correlation_id": "order_1001"
}
}
```
### Transfer event structure
```json
{
"id": "evt_payout_1001",
"type": "payout.transferred",
"data": {
"object": {
"id": "po_1001",
"status": "paid"
}
}
}
```
### Payment events
- transaction.created
- transaction.pending
- transaction.paid
- transaction.cancelled
- transaction.refunded
- transaction.chargedback
- transaction.three_ds_required
### Transfer events
- payout.created
- payout.in_analysis
- payout.processing
- payout.transferred
- payout.failed
- payout.canceled
## TypeScript SDK
```bash
bun add @pagouai/api-sdk
```
```ts
import { Client } from "@pagouai/api-sdk";
const client = new Client({
apiKey: process.env.PAGOU_API_KEY!,
environment: "sandbox",
});
// Pix payment
const tx = await client.transactions.create({
external_ref: "order_1001",
amount: 1500,
currency: "BRL",
method: "pix",
});
// Transfer
const transfer = await client.transfers.create({
pix_key_type: "EMAIL",
pix_key_value: "recipient@example.com",
amount: 1200,
external_ref: "payout_1001",
});
```
## Rules
- Always include external_ref for correlation and idempotency
- Use requestId header for request tracing
- Deduplicate webhooks by event id (not transaction/transfer id)
- Reconcile on failures with GET, don't retry POST
- Cards require Payment Element - never handle raw card data
- ACK webhooks with `{ "received": true }`
## Common mistakes to avoid
- Retrying POST on failure (use GET to reconcile instead)
- Deduplicating webhooks by transaction id (same tx emits multiple events)
- Skipping external_ref (makes reconciliation impossible)
- Handling raw card numbers (use Payment Element tokens)
- Ignoring next_action for 3DS flows
````
## Usage
1. Copy the template above to `CLAUDE.md` in your project root
2. Customize the buyer/recipient examples for your use case
3. Run Claude Code from your project directory
Claude Code will automatically read this file and use it as context for all your Pagou integration tasks.
Add project-specific details like your webhook endpoint URL, environment variables, or custom business logic to make the context even more useful.
# .cursorrules Template
Source: https://developer.pagou.ai/start-here/cursorrules-template
Copy this .cursorrules file to give Cursor full context for Pagou integrations.
Create a `.cursorrules` file in your project root. Cursor loads this automatically.
## Template
````markdown theme={null}
# Pagou Integration Rules
This project integrates with the Pagou.ai payments API.
## API Configuration
- Sandbox: https://api-sandbox.pagou.ai
- Production: https://api.pagou.ai
- Documentation: https://developer.pagou.ai
- OpenAPI: https://developer.pagou.ai/api-reference/openapi-v2.json
## Authentication
Use one of these methods:
- Bearer token: `Authorization: Bearer `
- API key header: `apiKey: `
- Basic auth: username=token, password=x
## Endpoint Reference
### Payments
- POST /v2/transactions - Create payment (Pix, voucher, or card)
- GET /v2/transactions/{id} - Get transaction
- PUT /v2/transactions/{id}/refund - Refund transaction
### Transfers
- POST /v2/transfers - Create Pix Out transfer
- GET /v2/transfers/{id} - Get transfer
- POST /v2/transfers/{id}/cancel - Cancel transfer
### Customers
- POST /v2/customers - Create customer
- GET /v2/customers/{id} - Get customer
## Payment Creation
Pix payment request:
```json
{
"external_ref": "order_1001",
"amount": 1500,
"currency": "BRL",
"method": "pix",
"buyer": {
"name": "Customer Name",
"email": "customer@example.com",
"document": { "type": "CPF", "number": "12345678901" }
}
}
```
Card payment request (with Payment Element token):
```json
{
"external_ref": "order_1001",
"amount": 2490,
"currency": "BRL",
"method": "credit_card",
"token": "",
"installments": 1
}
```
Voucher payment request:
```json
{
"external_ref": "order_3001",
"amount": 125000,
"currency": "MXN",
"method": "voucher",
"buyer": {
"name": "Customer Name",
"email": "customer@example.com",
"address": {
"street": "Av. Paseo de la Reforma",
"city": "Ciudad de Mexico",
"zipCode": "06600",
"country": "MX"
}
},
"products": [{ "name": "Annual plan", "price": 125000, "quantity": 1 }]
}
```
## Transfer Creation
```json
{
"pix_key_type": "EMAIL",
"pix_key_value": "recipient@example.com",
"amount": 1200,
"description": "Payout",
"external_ref": "payout_1001"
}
```
pix_key_type values: CPF, CNPJ, EMAIL, PHONE, EVP
## Status Enums
Transaction: pending, paid, expired, failed, refunded, partially_refunded, chargedback
Transfer: pending, in_analysis, processing, paid, error, cancelled
## Webhook Events
Payment events (in data.event_type):
- transaction.created, transaction.pending, transaction.paid
- transaction.cancelled, transaction.refunded, transaction.chargedback
- transaction.three_ds_required
Transfer events (in top-level type):
- payout.created, payout.in_analysis, payout.processing
- payout.transferred, payout.failed, payout.canceled
## TypeScript SDK
```ts
import { Client } from "@pagouai/api-sdk";
const client = new Client({
apiKey: process.env.PAGOU_API_KEY!,
environment: "sandbox",
});
```
## Code Rules
When writing Pagou integration code:
1. Always include external_ref in payment/transfer requests
2. Use requestId header for request tracing
3. Deduplicate webhooks by the top-level event id
4. Handle 3DS by checking for next_action in card payment responses
5. Reconcile state with GET endpoints, don't retry failed POSTs
6. Never handle raw card numbers - use Payment Element tokens
7. ACK webhooks with { "received": true }
8. Store transaction/transfer id alongside your external_ref
## Error Handling
- 400: Validation error - check request body
- 401: Invalid API key
- 404: Resource not found
- 409: Duplicate external_ref (use GET to fetch existing)
- 429: Rate limited - implement backoff
- 500+: Server error - safe to retry with idempotency key
## Payment Element (Cards)
Frontend script: https://js.pagou.ai/payments/v3.js
```js
const elements = Pagou.elements({
publicKey: "pk_test_...",
locale: "en",
origin: window.location.origin,
});
const card = elements.create("card", { theme: "default" });
card.mount("#card-element");
const result = await elements.submit({
createTransaction: async (tokenData) => {
// Call your backend with tokenData.token
},
});
```
````
## Usage
1. Copy the template above to `.cursorrules` in your project root
2. Cursor automatically loads this when you open the project
3. Ask Cursor to implement Pagou features with full context
You can also add this content to your existing `.cursorrules` file if you already have project-specific rules.
# Environments
Source: https://developer.pagou.ai/start-here/environments
Choose the correct base URL, credentials, and release discipline for sandbox and production.
Use the same integration code in both environments. Change configuration, not behavior.
## Base URLs
| Environment | Base URL | Use it for |
| ----------- | ------------------------------ | ----------------------------------------------------------- |
| Sandbox | `https://api-sandbox.pagou.ai` | local development, automated tests, staging verification |
| Production | `https://api.pagou.ai` | live traffic, production reconciliation, operator workflows |
## Rules
* Keep sandbox and production tokens separate.
* Use different webhook endpoints for sandbox and production.
* Never expose production credentials in browser code.
* Roll out by switching config only: token, base URL, webhook target, and monitoring.
## Why this matters
Environment drift is a common source of launch bugs. If your request shapes are identical in both environments, production cutover becomes an operational change instead of a code deploy risk.
## Release checklist
1. Validate auth against sandbox.
2. Run a full happy path with Pix, voucher, or card.
3. Confirm webhook delivery, deduplication, and reconciliation.
4. Verify logs capture `requestId`, resource IDs, and your `external_ref`.
5. Switch only credentials and base URL at go-live.
## Next steps
* [Authentication](/start-here/authentication)
* [Go-live Checklist](/start-here/go-live-checklist)
# Errors and Retries
Source: https://developer.pagou.ai/start-here/errors-and-retries
Interpret Pagou error responses and decide when to retry, fix input, or reconcile state.
Pagou returns standard HTTP status codes and RFC 7807 `application/problem+json` bodies for most errors.
## Retry matrix
| Status | Meaning | What to do |
| ------------- | -------------------------------------------- | --------------------------------------------------------------- |
| `400` | malformed request or unsupported combination | fix the request before retrying |
| `401` / `403` | auth or permission issue | fix credentials or access configuration |
| `404` | resource not found | verify the ID and tenant context |
| `409` | duplicate or conflicting state | reconcile instead of retrying blindly |
| `422` | validation error | fix field data and resend |
| `5xx` | transient server issue | retry with backoff and reconcile if the write result is unknown |
## Example error response
```json theme={null}
{
"type": "https://api.pagou.ai/problems/validation-error",
"title": "Validation Error",
"status": 422,
"detail": "The request contains invalid data.",
"errors": [
{
"field": "buyer.email",
"message": "Invalid email format",
"code": "invalid_string"
}
]
}
```
## Example fix
Request:
```json theme={null}
{
"external_ref": "order_1001",
"amount": 1500,
"currency": "BRL",
"method": "pix",
"buyer": {
"name": "Ada Lovelace",
"email": "ada@example.com"
}
}
```
Response:
```json theme={null}
{
"success": true,
"requestId": "req_1001",
"data": {
"id": "tr_1001",
"status": "pending"
}
}
```
## Practical rules
* Never auto-retry `4xx` writes except behind explicit reconciliation logic.
* Use exponential backoff for `429` and `5xx` responses.
* If the response to a write is lost, retrieve the resource before creating another one.
* Log `requestId`, your `external_ref`, and the Pagou resource ID together.
## Next steps
* [Idempotency](/start-here/idempotency)
* [Webhook Fundamentals](/start-here/webhooks)
* [Retries and Reconciliation](/webhooks/retries-and-reconciliation)
# Go-live Checklist
Source: https://developer.pagou.ai/start-here/go-live-checklist
Use this production checklist before you switch a Pagou integration from sandbox to live traffic.
Use this checklist before sending live traffic to Pagou.
## Required checks
* Production credentials are stored in your secret manager.
* Your backend uses the production base URL and production token only through configuration.
* `external_ref` is persisted for every create operation.
* Webhook ingestion returns `200 OK` quickly and deduplicates by event ID.
* Reconciliation exists for both payments and transfers.
* Logs capture `requestId`, your internal reference, and the Pagou resource ID.
## Strongly recommended checks
* Sandbox happy paths have been run for Pix, voucher, and card, if they are in scope.
* Refund and cancel workflows have an operator-facing playbook.
* Alerting exists for webhook failures, retry storms, and reconciliation backlog.
* Finance and support teams know where to find `requestId` and resource IDs.
* Frontend fulfillment waits for webhook or reconciliation, not only the initial create response.
## Read next
* [Environments](/start-here/environments)
* [Webhook Fundamentals](/start-here/webhooks)
* [Retries and Reconciliation](/webhooks/retries-and-reconciliation)
# Idempotency
Source: https://developer.pagou.ai/start-here/idempotency
Prevent duplicate money movement by treating external_ref as your stable write identifier.
Use idempotency on every write path that can be retried by a user, queue, worker, or network client.
## Recommended rule
Use `external_ref` as the stable identifier for a logical create operation.
* Reuse the same value when retrying the same payment or transfer create.
* Never reuse the same value for a different monetary intent.
* Persist both your `external_ref` and the Pagou resource `id`.
## Example request
```json theme={null}
{
"external_ref": "order_1001",
"amount": 1500,
"currency": "BRL",
"method": "pix"
}
```
## Example success response
```json theme={null}
{
"success": true,
"requestId": "req_1001",
"data": {
"id": "tr_1001",
"status": "pending"
}
}
```
## Common error
Status `409`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/conflict",
"title": "Conflict",
"status": 409,
"detail": "A transaction with external_ref order_1001 already exists."
}
```
Fix: if the retry refers to the same business operation, reconcile the existing resource instead of sending a new create with different intent.
## Where it matters most
* `POST /v2/transactions`
* `PUT /v2/transactions/{id}/refund`
* `POST /v2/transfers`
* `POST /v2/transfers/{id}/cancel`
## Retry pattern
1. Retry safely only when you can prove it is the same logical operation.
2. If a write response is lost, reconcile with `GET` before creating another resource.
3. Keep `requestId`, resource ID, and `external_ref` in the same audit record.
# Overview
Source: https://developer.pagou.ai/start-here/overview
Understand the supported public surface of Pagou.ai before you start integrating.
Use this section if you are designing a new Pagou integration or replacing a legacy one.
## Who this is for
* Backend engineers who own payment and payout APIs
* Platform engineers who own auth, retries, and webhook ingestion
* Product and operations teams who need a shared lifecycle model
## What you can build
* Pix collections with QR code delivery and webhook confirmation
* Voucher payments with local instructions such as Boleto, SPEI, Mercado Pago, Webpay, CODI, and PSE
* Card payments with Payment Element and 3D Secure
* Pix Out transfers with operator-safe cancellation and reconciliation
* Customer records for reusable buyer profiles
## Recommended integration model
1. Create payments and transfers only from your backend.
2. Use `external_ref` as your stable idempotency key for creates.
3. Treat webhooks as the primary source of truth for async state changes.
4. Reconcile with `GET /v2/transactions/{id}` or `GET /v2/transfers/{id}` when the outcome is unclear.
## Public surface
| Capability | Main endpoints | Notes |
| -------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| Authentication | all v2 routes | Choose one auth scheme and keep it consistent |
| Customers | `POST /v2/customers`, `GET /v2/customers`, `GET /v2/customers/{id}` | Optional reusable buyer records |
| Payments | `POST /v2/transactions`, `GET /v2/transactions/{id}`, `PUT /v2/transactions/{id}/refund` | Pix, voucher, and card flows share the transactions API |
| Payouts | `POST /v2/transfers`, `GET /v2/transfers/{id}`, `POST /v2/transfers/{id}/cancel` | Pix Out transfer lifecycle |
| Webhooks | payment and transfer event delivery | Build one ingestion pipeline with deduplication |
| SDK | `@pagouai/api-sdk` | Server-side TypeScript client |
## Before you build
* Get separate sandbox and production credentials.
* Decide where you will store `external_ref`, Pagou IDs, and `requestId` values.
* Expose an HTTPS webhook endpoint before moving to production.
* Keep frontend code away from secret credentials.
## Read next
* [Quickstart](/start-here/quickstart)
* [Authentication](/start-here/authentication)
* [Webhook Fundamentals](/start-here/webhooks)
* [Payments Overview](/payments/overview)
# Quickstart
Source: https://developer.pagou.ai/start-here/quickstart
Create your first successful v2 sandbox transaction with the minimum required setup.
This page is the shortest backend path from credentials to a working sandbox Pix payment.
## Prerequisites
* A sandbox token
* Access to `https://api-sandbox.pagou.ai`
* A stable internal order ID to reuse as `external_ref`
* An HTTPS webhook endpoint or a temporary local plan for reconciliation
## Step 1: verify authentication
```bash theme={null}
curl --request GET \
--url https://api-sandbox.pagou.ai/v2/transactions \
--header "Authorization: Bearer YOUR_SANDBOX_TOKEN"
```
If this returns `200`, your auth and network path are ready.
## Step 2: create a Pix transaction
```bash theme={null}
curl --request POST \
--url https://api-sandbox.pagou.ai/v2/transactions \
--header "Authorization: Bearer YOUR_SANDBOX_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"external_ref": "order_1001",
"amount": 1500,
"currency": "BRL",
"method": "pix",
"notify_url": "https://merchant.example/webhooks/pagou",
"buyer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"document": {
"type": "CPF",
"number": "12345678901"
}
},
"products": [
{
"name": "Starter order",
"price": 1500,
"quantity": 1
}
]
}'
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_1001",
"data": {
"id": "tr_1001",
"status": "pending",
"method": "pix",
"amount": 1500,
"base_price": 1500,
"currency": "BRL",
"pix": {
"qr_code": "000201010212...",
"expiration_date": "2026-03-16T14:15:00.000Z",
"receipt_url": null
},
"created_at": "2026-03-16T14:00:00.000Z",
"updated_at": "2026-03-16T14:00:00.000Z",
"paid_at": null
}
}
```
## Step 3: persist identifiers
Store at least:
* your `external_ref`
* the Pagou transaction `id`
* the current `status`
* the `requestId`
## Step 4: use webhooks for final state
Return `200 OK` quickly and process asynchronously.
```ts theme={null}
app.post("/webhooks/pagou", async (req, reply) => {
const payload = req.body as { id?: string };
if (!payload.id) {
return reply.code(400).send({ error: "missing_event_id" });
}
reply.code(200).send({ received: true });
await queue.enqueue(payload);
});
```
## Step 5: reconcile when you are unsure
```bash theme={null}
curl --request GET \
--url https://api-sandbox.pagou.ai/v2/transactions/tr_1001 \
--header "Authorization: Bearer YOUR_SANDBOX_TOKEN"
```
## Common error
Status `409`
```json theme={null}
{
"type": "https://api.pagou.ai/problems/conflict",
"title": "Conflict",
"status": 409,
"detail": "A transaction with external_ref order_1001 already exists."
}
```
Fix: reuse the same `external_ref` only for the same logical payment attempt. If the network outcome is unclear, reconcile before creating a new transaction.
## TypeScript SDK equivalent
```ts theme={null}
import { Client } from "@pagouai/api-sdk";
const client = new Client({
apiKey: process.env.PAGOU_API_KEY!,
environment: "sandbox",
});
const created = await client.transactions.create({
external_ref: "order_1001",
amount: 1500,
currency: "BRL",
method: "pix",
notify_url: "https://merchant.example/webhooks/pagou",
buyer: {
name: "Ada Lovelace",
email: "ada@example.com",
document: { type: "CPF", number: "12345678901" },
},
products: [{ name: "Starter order", price: 1500, quantity: 1 }],
});
```
## Next steps
* [Authentication](/start-here/authentication)
* [Idempotency](/start-here/idempotency)
* [Accept Pix Payments](/payments/pix/accept-payments)
# Webhook Fundamentals
Source: https://developer.pagou.ai/start-here/webhooks
Use webhooks as the primary source of truth for asynchronous payment and payout updates, with polling only as a fallback.
Use webhooks to drive payment and payout state. Use polling only for debugging, recovery, or reconciliation.
## When to use webhooks
* Payment state changes for Pix, voucher, and card flows
* Pix Out transfer progression and settlement
* Fast order and payout updates without frontend polling
## Delivery patterns
### Central subscriptions
Use one stable endpoint when you want a shared ingestion pipeline for all recurring events.
### Per-request callbacks
Set `notify_url` on a specific transaction or transfer when only one workflow should receive that callback.
## Example request with `notify_url`
```json theme={null}
{
"external_ref": "order_1001",
"amount": 1500,
"currency": "BRL",
"method": "pix",
"notify_url": "https://merchant.example/webhooks/pagou",
"buyer": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"document": {
"type": "CPF",
"number": "12345678901"
}
},
"products": [
{
"name": "Starter order",
"price": 1500,
"quantity": 1
}
]
}
```
## Minimal ACK response
```json theme={null}
{
"received": true
}
```
## Common ingestion error
Status `400`
```json theme={null}
{
"error": "missing_event_id"
}
```
Fix: validate the top-level webhook `id` before enqueueing work. Deduplicate by that ID, then process asynchronously.
## Recommended ingestion flow
1. Accept the HTTPS `POST`.
2. Validate the top-level event ID.
3. Return `200 OK` quickly.
4. Persist or enqueue the payload.
5. Reconcile with `GET` if your worker crashes or a downstream side effect is uncertain.
## Next steps
* [Webhooks Overview](/webhooks/overview)
* [Payment Events](/webhooks/payment-events)
* [Transfer Events](/webhooks/transfer-events)
# Webhooks Overview
Source: https://developer.pagou.ai/webhooks/overview
Build one resilient webhook ingestion path for both payment and payout events.
Pagou currently exposes two public webhook envelope shapes.
## Envelope comparison
| Domain | Top-level event field | Resource field | Concrete event name |
| --------- | ---------------------- | -------------- | ------------------- |
| Payments | `event: "transaction"` | `data` | `data.event_type` |
| Transfers | `type` | `data.object` | top-level `type` |
## Payment webhook example
```json theme={null}
{
"id": "evt_pay_1001",
"event": "transaction",
"api_version": "v1",
"data": {
"id": "tr_1001",
"event_type": "transaction.paid",
"correlation_id": "order_1001",
"method": "pix",
"status": "paid",
"amount": 1500,
"currency": "BRL"
}
}
```
## Transfer webhook example
```json theme={null}
{
"id": "evt_payout_1001",
"type": "payout.transferred",
"api_version": "v2",
"data": {
"object": {
"id": "po_1001",
"status": "paid",
"type": "pix",
"amount": 1200
}
}
}
```
## ACK response
```json theme={null}
{
"received": true
}
```
## Common ingestion error
```json theme={null}
{
"error": "missing_event_id"
}
```
Fix: require the top-level `id`, deduplicate by that value, return `200 OK` quickly, and process asynchronously.
## Mapping guidance
* Drive business state from resource status, not from a frontend guess.
* Map transfer event `payout.transferred` to settled resource status `paid`.
* Reconcile if your worker crashes after acknowledgement.
## Read next
* [Payment Events](/webhooks/payment-events)
* [Transfer Events](/webhooks/transfer-events)
* [Retries and Reconciliation](/webhooks/retries-and-reconciliation)
# Payment Events
Source: https://developer.pagou.ai/webhooks/payment-events
Handle transaction webhooks for Pix, voucher, and card payments using the exact public payload shape Pagou delivers today.
Payment webhooks always use the transaction envelope. The top-level `event` stays `transaction`; the concrete event name is in `data.event_type`.
## Example delivery payload
```json theme={null}
{
"id": "evt_pay_1001",
"event": "transaction",
"api_version": "v1",
"data": {
"id": "tr_3001",
"event_type": "transaction.pending",
"correlation_id": "order_3001",
"method": "voucher",
"status": "pending",
"amount": 125000,
"currency": "MXN",
"voucher": {
"barcode": "646180123456789012",
"digitable_line": "646180123456789012",
"url": "https://provider.example/pay/order_3001",
"expiration_date": "2026-05-12T23:59:59.000Z",
"instructions": "Pay using the bank transfer reference before the expiration date.",
"receipt_url": null
}
}
}
```
## ACK response
```json theme={null}
{
"received": true
}
```
## Event names emitted today
* `transaction.created`
* `transaction.pending`
* `transaction.paid`
* `transaction.cancelled`
* `transaction.refunded`
* `transaction.partially_refunded`
* `transaction.chargedback`
* `transaction.three_ds_required`
## Common ingestion error
```json theme={null}
{
"error": "missing_event_id"
}
```
Fix: deduplicate by the top-level event `id`, not by transaction ID, because the same transaction can emit more than one business event over time.
## Mapping guidance
* Use `transaction.paid` to release goods or services.
* Keep the order open on `transaction.pending`.
* For `method: "voucher"`, `transaction.pending` can also carry payment instructions in `data.voucher`. Show the returned `url`, `digitable_line`, `barcode`, or `instructions` and keep waiting for `transaction.paid`.
* Use refund and chargeback events to drive finance and support flows.
* Route `transaction.three_ds_required` back into your card challenge flow.
# Retries and Reconciliation
Source: https://developer.pagou.ai/webhooks/retries-and-reconciliation
Recover safely from webhook redelivery, worker failures, or uncertain payment and payout state.
Use this page when your webhook pipeline is reliable most of the time but still needs a safe recovery path.
## Recovery rules
* Deduplicate by webhook event ID.
* Make downstream side effects idempotent.
* Reconcile with `GET` when the result of processing is unclear.
* Prefer replaying your internal job from stored payload plus fresh API state instead of re-running business logic blindly.
## Example reconciliation request
```bash theme={null}
curl --request GET \
--url https://api.pagou.ai/v2/transactions/tr_1001 \
--header "Authorization: Bearer YOUR_TOKEN"
```
## Example response
```json theme={null}
{
"success": true,
"requestId": "req_2101",
"data": {
"id": "tr_1001",
"status": "paid",
"updated_at": "2026-03-16T14:03:10.000Z"
}
}
```
## Common error
```json theme={null}
{
"type": "https://api.pagou.ai/problems/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "The requested transaction does not exist."
}
```
Fix: verify the resource mapping you stored from the original create response or webhook payload before retrying recovery.
## Practical workflow
1. Persist the raw webhook payload.
2. Acknowledge quickly.
3. Process asynchronously.
4. If processing fails after acknowledgement, retrieve the latest resource state.
5. Recompute the next safe business transition from that fresh state.
# Transfer Events
Source: https://developer.pagou.ai/webhooks/transfer-events
Handle Pix Out webhook events using the live payout envelope Pagou emits today.
Transfer webhooks use a payout-style envelope. The concrete event name is always the top-level `type`, and the transfer resource is in `data.object`.
## Example delivery payload
```json theme={null}
{
"id": "evt_payout_1001",
"type": "payout.transferred",
"api_version": "v2",
"data": {
"object": {
"id": "po_1001",
"status": "paid",
"type": "pix",
"amount": 1200,
"fee": 50,
"net_amount": 1150,
"transferred_at": "2026-03-16T14:05:00.000Z"
}
}
}
```
## ACK response
```json theme={null}
{
"received": true
}
```
## Event names emitted today
* `payout.created`
* `payout.in_analysis`
* `payout.processing`
* `payout.transferred`
* `payout.failed`
* `payout.rejected`
* `payout.canceled`
## Common ingestion error
```json theme={null}
{
"error": "missing_event_id"
}
```
Fix: deduplicate by the top-level event `id`. Keep your own mapping between webhook event names and resource statuses.
## Mapping guidance
* `payout.transferred` means the resource is settled with status `paid`.
* `payout.failed` usually maps to resource status `error`.
* `payout.canceled` maps to resource status `cancelled`.
* Reconcile when operator state and webhook state disagree.