Documentation Index
Fetch the complete documentation index at: https://developer.pagou.ai/llms.txt
Use this file to discover all available pages before exploring further.
Use this page when you need the exact browser SDK contract for Payment Element v3.
Load the SDK
<script src="https://js.pagou.ai/payments/v3.js"></script>
The script exposes window.Pagou.
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
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:
elements.update({
publicKey: "pk_live_your_public_key",
locale: "en",
});
Create and mount the card field
<div id="card-element"></div>
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
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:
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.
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:
{
"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
{
"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.
{
"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:
const result = await Pagou.handleNextAction(transaction.next_action);
Or pass the transaction to an Elements instance:
const result = await elements.submit({
transaction,
createTransaction: async () => transaction,
});
Reusable token for upsells
For one-click upsell flows, request a reusable token:
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:
Destroy the Elements instance when the entire payment flow is gone:
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.