The Checkout Embed SDK allows you to integrate Autra payment links directly into your website. Instead of redirecting the payer to a separate page, the SDK opens the checkout in a modal overlay — keeping the payer on your site throughout the payment flow.
When to use
| Scenario | Recommended approach |
|---|---|
| Payment link via email/WhatsApp | Share the checkoutUrl directly (no SDK needed) |
| Checkout in a modal overlay | Use SDK with mode: 'modal' (default on desktop) |
| Checkout inside a drawer or sidebar | Use SDK with mode: 'inline' and a container element |
| Mobile app | Use redirect mode or open checkoutUrl in a WebView |
| Server-to-server integration | Use the API directly (POST /v1/acquiring/links) |
How it works
Your website Autra
──────────── ─────
1. Payer clicks "Pay"
2. SDK opens modal overlay
3. ──────► Loads checkout page
4. Payer fills in data
5. Payer pays (card/pix/boleto)
6. ◄────── postMessage with result
7. SDK fires onSuccess callback
8. You update your page
The checkout page runs on the Autra domain (autra.io), ensuring full PCI isolation — card data never touches your website.
Quick start
Step 1: Include the SDK
Add the SDK script to your HTML head or body:
<script src="https://www.autra.io/sdk/checkout.js"></script>
Step 2: Open the checkout
Add a button (<button id="pay-btn">Pay now</button>) and initialize the SDK:
document.getElementById('pay-btn').addEventListener('click', function() {
AutraCheckout.open({
slug: 'lnk_a1b2c3d4',
onSuccess: function(data) {
console.log('Payment confirmed!', data);
// data.paymentId — Autra payment ID
// data.status — ACCEPTED, AUTHORIZED, or PAID
// data.amount — payment amount
// data.method — CARD, PIX, or BOLETO
},
onClose: function() {
console.log('Payer closed checkout without paying');
},
onError: function(err) {
console.log('Payment error:', err.code, err.message);
}
});
});Step 3: Done
The SDK handles everything — opening the modal, loading the checkout, listening for the payment result, and closing the modal.
Auto-bind (no JavaScript required)
For simple integrations, you can use the data-autra-checkout attribute on any HTML element. The SDK automatically binds click handlers on page load.
Add the SDK script, then add data-autra-checkout="your-slug" to any button or link:
<button data-autra-checkout="lnk_a1b2c3d4">Pay R$ 150.00</button>
To receive callbacks with auto-bind, set global handlers before loading the SDK:
window._autraOnSuccess = function(data) { console.log('Paid!', data); };
window._autraOnClose = function() { console.log('Closed'); };
window._autraOnError = function(err) { console.log('Error', err); };You can also override the mode and return URL per-button via extra data-* attributes (useful when a specific button needs a different behavior from the global default):
| Attribute | Equivalent option | Example |
|---|---|---|
data-autra-checkout | slug (required) | data-autra-checkout="lnk_a1b2c3d4" |
data-autra-mode | mode | data-autra-mode="redirect" |
data-autra-return-url | returnUrl (only with mode="redirect") | data-autra-return-url="https://yoursite.com/thanks" |
<button
data-autra-checkout="lnk_a1b2c3d4"
data-autra-mode="redirect"
data-autra-return-url="https://yoursite.com/thanks">
Pay R$ 150.00
</button>Options reference
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
slug | string | Yes | — | Payment link slug (e.g. lnk_a1b2c3d4). Obtain from POST /v1/acquiring/links response |
mode | string | No | modal (desktop) / redirect (mobile) | modal opens an overlay. redirect navigates to checkout URL. inline renders inside a container |
container | string or Element | Only for inline mode | — | CSS selector or DOM element where the checkout iframe will be rendered |
returnUrl | string | No | — | URL to redirect after payment. Only used in redirect mode |
onSuccess | function | No | — | Called when the payment is confirmed. Receives a data object (see below) |
onClose | function | No | — | Called whenever the checkout closes — user cancel (X, ESC, click outside), programmatic AutraCheckout.close(), or after onSuccess. See notes below |
onError | function | No | — | Called when a payment error occurs. Receives an error object (see below) |
Methods
| Method | Description |
|---|---|
AutraCheckout.open(options) | Opens the checkout. See options reference above |
AutraCheckout.close() | Closes the checkout modal programmatically. Triggers onClose callback |
AutraCheckout.version | Returns the SDK version string (e.g. "1.0.0") |
Callback data
onSuccess
Fired when the payment is confirmed. The data object contains:
{
"paymentId": "550e8400-e29b-41d4-a716-446655440000",
"status": "ACCEPTED",
"amount": 150.00,
"method": "CARD",
"slug": "lnk_a1b2c3d4"
}| Field | Type | Description |
|---|---|---|
paymentId | string | Autra payment identifier. Use this to query payment details via API |
status | string | Payment status: ACCEPTED (card), AUTHORIZED (Pix), PAID (boleto) |
amount | number | Payment amount in BRL |
method | string | Payment method used: CARD, PIX, or BOLETO |
slug | string | The payment link slug that was paid |
onError
Fired when the payment is declined or an error occurs:
{
"code": "INSUFFICIENT_FUNDS",
"message": "Payment declined"
}| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code |
message | string | Human-readable error description |
onClose
Fired whenever the checkout closes, for any reason. No arguments.
Triggers include:
- Payer clicks the close button (X), presses ESC, or clicks outside the modal
- Your code calls
AutraCheckout.close() - A new
AutraCheckout.open()is called while another checkout is already open (the previous one closes first) - After
onSuccessfires (the checkout page sends a close message once the payment result is delivered)
Practical implication: if you use onClose to track "user gave up", you'll get false positives after every successful payment. Use onSuccess as the source of truth for completion and treat onClose as "modal is no longer visible" — not "user cancelled".
Opening modes
Modal (default on desktop)
Opens the checkout as an overlay on your page. The payer stays on your site.
AutraCheckout.open({
slug: 'lnk_a1b2c3d4',
mode: 'modal',
onSuccess: function(data) { /* handle */ }
});Behavior:
- Full-screen overlay with a centered checkout container (480px max width)
- Close button (X) in the top-right corner
- Click outside the modal or press ESC to close
- Page scroll is disabled while the modal is open
- On mobile screens the modal expands to full screen
Redirect (default on mobile)
Navigates the browser to the Autra checkout page. After payment, the payer is redirected to your returnUrl.
AutraCheckout.open({
slug: 'lnk_a1b2c3d4',
mode: 'redirect',
returnUrl: 'https://yoursite.com/payment/complete'
});Behavior:
- Full page navigation to the Autra checkout URL
- After payment, redirects to
returnUrlwith query parameters:?status=success&paymentId=xxx - If the payer closes the tab, no callback is fired
Inline (embed in your own container)
Renders the checkout iframe inside a container element on your page. Ideal for drawers, sidebars, or custom layouts where you want full control over the UI.
AutraCheckout.open({
slug: 'lnk_a1b2c3d4',
mode: 'inline',
container: '#checkout-container',
onSuccess: function(data) { /* handle */ }
});The container parameter accepts a CSS selector string (e.g. '#my-div', '.checkout-area') or a DOM element reference.
Behavior:
- The iframe fills 100% width and height of the container
- No overlay, close button, or scroll lock is created
- You control the container dimensions and visibility
- All callbacks (
onSuccess,onClose,onError) work the same as other modes
Removing the checkout in inline mode: in the current SDK (1.0.0), AutraCheckout.close() fires the onClose callback but does not remove the iframe from your container — that removal is done by the modal overlay only. In inline mode you should also clear the container yourself:
AutraCheckout.close(); // fires onClose + resets internal state
document.getElementById('checkout-container').innerHTML = ''; // actually removes the iframeExample with a drawer:
// Open a drawer on your page
document.getElementById('pay-btn').addEventListener('click', function() {
document.getElementById('drawer').style.display = 'block';
AutraCheckout.open({
slug: 'lnk_a1b2c3d4',
mode: 'inline',
container: '#drawer-content',
onSuccess: function(data) {
document.getElementById('drawer').style.display = 'none';
alert('Payment confirmed!');
},
onClose: function() {
document.getElementById('drawer').style.display = 'none';
}
});
});Full integration example
// Include in your HTML:
// <script src="https://www.autra.io/sdk/checkout.js"></script>
// <button id="subscribe-btn">Subscribe now</button>
// <div id="result" hidden></div>
document.getElementById('subscribe-btn').addEventListener('click', function() {
AutraCheckout.open({
slug: 'lnk_a1b2c3d4',
onSuccess: function(data) {
// Show confirmation on your page
var result = document.getElementById('result');
result.hidden = false;
result.textContent = data.method + ' payment of R$ ' +
data.amount.toFixed(2) + ' confirmed! ID: ' + data.paymentId;
// Optionally notify your backend
fetch('/api/payment-confirmed', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
paymentId: data.paymentId,
slug: data.slug,
amount: data.amount
})
});
},
onClose: function() {
// Fires on cancel AND after onSuccess — do not treat as "user cancelled"
console.log('Checkout closed');
},
onError: function(err) {
alert('Payment failed: ' + err.message);
}
});
});Idempotency and double-click prevention
The SDK does not enforce idempotency by itself — it just opens a checkout for a slug you already created via POST /v1/acquiring/links. Duplicate-charge prevention lives in two other places:
- When you create the link — pass
externalIdinPOST /v1/acquiring/links. If your backend retries the create, Autra returns the same link (sameslug) instead of a new one. - On the checkout page — Autra deduplicates payment attempts server-side per
slug. A payer refreshing or double-clicking "Pay" inside the checkout does not cause double charge.
Double-click on your own "Pay" button: the SDK itself does not disable your button. If you want to prevent the payer from opening the checkout twice in a row, disable the button on click and re-enable it inside onClose:
var btn = document.getElementById('pay-btn');
btn.addEventListener('click', function() {
btn.disabled = true;
AutraCheckout.open({
slug: 'lnk_a1b2c3d4',
onSuccess: function(data) { /* handle */ },
onClose: function() { btn.disabled = false; },
onError: function(err) { btn.disabled = false; }
});
});Security
| Concern | How the SDK handles it |
|---|---|
| Card data exposure | Card data is entered on the Autra domain. Your site never sees card numbers, CVV, or sensitive data |
| Cross-origin communication | Uses postMessage with strict origin validation. The SDK only accepts messages from https://www.autra.io |
| XSS on merchant site | Even if your site has XSS vulnerabilities, card data remains isolated in the Autra iframe |
| Fake checkout | The checkout runs on the Autra domain — payers can verify the URL in the browser |
| CSRF | The checkout uses the payment link slug (public), not merchant sessions |
Browser support
The SDK uses standard Web APIs and works on all modern browsers:
- Chrome 60+
- Firefox 60+
- Safari 12+
- Edge 79+
- Mobile Safari (iOS 12+)
- Chrome for Android
Troubleshooting
| Issue | Solution |
|---|---|
| Modal does not open | Check that checkout.js loaded correctly (no 404 in console). Verify the slug is valid |
| onSuccess not firing | Ensure the checkout page can send postMessage (not blocked by browser extensions). Check browser console for errors |
| Modal opens but checkout is blank | Check for Content-Security-Policy headers on your site that might block the iframe. Add frame-src https://www.autra.io to your CSP |
| Card payment not accepted in the iframe | The iframe requests allow="payment; clipboard-write". If your site sets a restrictive Permissions-Policy header (e.g. payment=()), the browser silently blocks Payment Request API inside the iframe. Ensure payment=(self "https://www.autra.io") in your Permissions-Policy |
AutraCheckout.close() in inline mode leaves the iframe visible | Known limitation in SDK 1.0.0 — close() only removes overlay-mode DOM. In inline mode, also call container.innerHTML = '' after close(). See Inline section |
| Mobile modal is too small | The SDK auto-detects mobile and uses redirect mode. To force modal, set mode: 'modal' explicitly |
| Payment confirmed but onSuccess not called | The payer may have closed the modal before the callback fired. Use API polling as a fallback to verify payment status server-side |
Related
- Payment Links — Overview of the payment links feature (Funcionalidades)
POST /v1/acquiring/links— Create a payment link (API Reference)GET /v1/acquiring/links/{linkId}— Query payment details (API Reference)
