Implementação técnica do Checkout via iframe
A implementação do Checkout via iframe reúne as etapas necessárias para que a loja inicie o processo de pagamento, envie as informações para o servidor e carregue o fluxo de checkout diretamente na página. Essa implementação integra três partes principais: front-end, back-end e estrutura da requisição enviada à API Checkout.
Back-end
O back-end é a camada que garante a segurança na criação do checkout. Ele recebe a requisição enviada pelo front-end, adiciona as credenciais da loja e envia a solicitação para a API Checkout. Em seguida, retorna a checkoutUrl, que será utilizada para exibir o fluxo de pagamento no iframe.
Essas responsabilidades impedem que dados sensíveis sejam expostos no navegador e asseguram o funcionamento correto da integração.
Por que o back-end é necessário?
O back-end atua como um proxy seguro. Isso significa que ele:
- Recebe a requisição do front-end;
- Adiciona as credenciais necessárias;
- Envia a requisição para a API Checkout;
- Devolve ao front-end somente os dados necessários, como a
checkoutUrl.
Essa função evita exposição de informações sigilosas e mantém a comunicação compatível com navegadores modernos.
Regras obrigatórias de segurança
- Nunca expor
MerchantIdouMerchantKeyem código JavaScript; - Usar HTTPS/TLS nas requisições do back-end;
- Validar a requisição recebida antes de enviá-lo à API;
- Evitar logs contendo dados sensíveis;
- Configurar timeout adequado;
- Aceitar apenas métodos e origens autorizadas no endpoint;
- Verificar todas as possíveis localizações da
checkoutUrlno retorno (checkoutUrl, url, etc).
Essas regras asseguram conformidade e evitam riscos de segurança.
Exemplo de implementação (Node.js)
A seguir, um exemplo em Node.js que mostra como o back-end cria a página de pagamento e retorna a checkoutUrl. A mesma estrutura pode ser usada em outras linguagens.
// server/checkout.js
import express from 'express';
import axios from 'axios';
const router = express.Router();
// Variável de ambiente com o Merchant ID da Cielo
const CIELO_MERCHANT_ID = process.env.CIELO_MERCHANT_ID;
// POST /api/checkout/create
router.post('/checkout/create', async (req, res) => {
try {
// Corpo da requisição enviado pelo cliente
const payload = req.body; // Deve conter OrderNumber, Cart, Payment, Customer, Shipping, Options
// Chamada à API da Cielo
const { data } = await axios.post(
'https://cieloecommerce.cielo.com.br/api/public/v1/orders/',
payload,
{
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'MerchantId': CIELO_MERCHANT_ID
},
timeout: 10000 // Timeout de 10 segundos
}
);
// Extrai a URL de checkout retornada pela Cielo
const checkoutUrl = data?.CheckoutUrl || data?.checkoutUrl || data?.url;
return res.json({ checkoutUrl });
} catch (err) {
return res.status(err.response?.status || 500).json({
message: 'Falha ao criar checkout',
detail: err.response?.data || err.message
});
}
});
export default router;
Front-end
O front-end é responsável por iniciar a criação do checkout, enviar os dados da compra ao back-end e exibir o fluxo de pagamento dentro do iframe. Ele também controla os estados da interface, como carregamento, exibição do iframe e mensagens de erro.
Chamada ao back-end
A aplicação de front-end não se comunica diretamente com a API Checkout. Em vez disso, faz uma chamada ao back-end da loja, que atua como proxy, adiciona as credenciais e cria o checkout.
No exemplo abaixo, o serviço JavaScript usa a biblioteca Axios para enviar a requisição ao back-end, mas você pode usar qualquer biblioteca HTTP com a mesma estrutura de chamada.
// services/CheckoutFetcher.js
import axios from 'axios';
export default {
async callCreateCheckout(url, payload) {
const response = await axios.post('/checkout/create', {
url,
payload
});
return response;
}
};O front-end envia apenas a URL da API Checkout e a requisição do pedido. O back-end é responsável por incluir as credenciais e retornar a resposta com a checkoutUrl.
Estrutura do componente e estados
O componente de front-end é formado por três partes:
- Template: contém os botões de ação, mensagens de carregamento, área do iframe e exibição de erros;
- Script: gerencia os estados do componente, realiza a chamada ao back-end e atualiza a
checkoutUrl; - Estilos: aplicados no bloco
<style scoped>, organizam o layout do checkout, botões e mensagens na interface.
Os estados mínimos usados no componente são:
loading: indica que o checkout está sendo criado;checkoutUrl: quando preenchida, aciona a renderização do iframe;error: exibe mensagens em caso de falha.
Um exemplo de definição desses estados em Vue.js é:
data() {
return {
checkoutUrl: '',
loading: false,
error: ''
};
}
Os estadosloading,checkoutUrleerrorfuncionam juntos no fluxo de criação da página de pagamento.Quando
loadingé true, o componente exibe a mensagem de carregamento. QuandocheckoutUrlrecebe um valor válido, o iframe é renderizado e, em caso de falha, o componente preencheerrorcom uma mensagem amigável e interrompe o carregamento.Para saber como esses estados se comportam em cenários de erro, consulte a seção Tratamento de erros
Exemplos de implementação
A seguir, duas formas de integrar o checkout no front-end:
- Usando um componente Vue.js;
- Usando HTML e JavaScript sem framework.
<template>
<div class="checkout-poc">
<h2>Checkout via iframe</h2>
<!-- Botões de ação -->
<button
v-if="!checkoutUrl && !loading"
@click="createCheckout"
class="action-btn">
Criar Checkout
</button>
<button
v-if="!checkoutUrl && !loading"
@click="openShortLink"
class="action-btn">
Usar Link Encurtado
</button>
<!-- Indicador de carregamento -->
<div v-if="loading">
<p>Carregando checkout...</p>
</div>
<!-- Iframe com o checkout -->
<div v-if="checkoutUrl">
<iframe
:src="checkoutUrl"
width="100%"
height="600"
frameborder="0"
/>
</div>
<!-- Mensagem de erro -->
<div v-if="error" class="error">
{{ error }}
</div>
</div>
</template>
<script>
import CheckoutFetcher from '@/services/CheckoutFetcher';
export default {
name: 'CheckoutIframe',
data() {
return {
checkoutUrl: '',
loading: false,
error: ''
};
},
methods: {
// Opção 1: Usar link encurtado direto
openShortLink() {
this.checkoutUrl = 'https://cielolink.com.br/SEU_LINK_AQUI';
},
// Opção 2: Criar checkout via API
async createCheckout() {
this.loading = true;
this.error = '';
// URL da API Cielo
const apiUrl = 'https://cieloecommerce.cielo.com.br/api/public/v1/orders';
// Dados do pedido
const payload = {
OrderNumber: 'Pedido0123',
SoftDescriptor: 'Nomefantasia',
Cart: {
Items: [
{
Name: 'Produto01',
Description: 'ProdutoExemplo01',
UnitPrice: 100,
Quantity: 1,
Type: 'Asset',
Sku: 'ABC001',
Weight: 500
}
]
},
Payment: {
BoletoDiscount: 15,
MaxNumberOfInstallments: 12
},
Customer: {
Identity: '45873281890',
FullName: 'João da Silva',
Email: '[email protected]',
Phone: '11988776655'
},
Shipping: {
SourceZipCode: '20020080',
TargetZipCode: '21911130',
Type: 'FixedAmount',
Address: {
Street: 'Alameda Xingu',
Number: '512',
Complement: '21 andar',
District: 'Alphaville',
City: 'Barueri',
State: 'SP'
},
Services: [
{
Name: 'Entrega Express',
Price: 1000,
Deadline: 2
}
]
}
};
try {
// Chama o backend que faz proxy para Cielo
const data = await CheckoutFetcher.callCreateCheckout(apiUrl, payload);
// Extrai a checkoutUrl da resposta
// A URL pode estar em diferentes lugares dependendo da versão da API
let checkoutUrl = '';
if (data?.data?.settings?.checkoutUrl) {
checkoutUrl = data.data.settings.checkoutUrl;
} else if (data?.data?.checkoutUrl) {
checkoutUrl = data.data.checkoutUrl;
} else if (data?.data?.url) {
checkoutUrl = data.data.url;
}
this.checkoutUrl = checkoutUrl;
if (!this.checkoutUrl) {
this.error = 'URL de checkout não encontrada na resposta.';
}
} catch (e) {
this.error = 'Erro ao criar checkout.';
console.error(e);
} finally {
this.loading = false;
}
}
}
};
</script>
<style scoped>
h2 {
font-size: 1.25rem;
font-weight: 700;
color: #2F363E;
}
.checkout-poc {
max-width: 600px;
margin: 40px auto;
padding: 24px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
button {
padding: 10px 24px;
font-size: 16px;
background: #1976d2;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
.action-btn {
margin-right: 16px;
}
.error {
color: #d32f2f;
margin-top: 16px;
}
</style><!-- Container acessível para o checkout embutido -->
<section class="checkout-embed" aria-label="Pagamento seguro">
<div id="checkout-wrapper">
<iframe
id="cielo-checkout"
title="Finalização de pagamento"
allowpaymentrequest
allow="payment *; clipboard-write"
style="width:100%; min-height:640px; border:0; background:#fff; border-radius:12px; box-shadow:0 8px 24px rgba(0,0,0,.12);"
referrerpolicy="no-referrer"
sandbox="allow-scripts allow-same-origin allow-forms"
src=""
<!-- preenchido via JS -->
></iframe>
</div>
<div id="checkout-loading" role="status">Carregando o checkout…</div>
<div id="checkout-fallback" hidden>
Não foi possível carregar o checkout embutido.
<a id="checkout-direct-link" rel="noopener">Abrir pagamento</a>.
</div>
</section>
<script>
// Mock: usar sempre o mesmo link encurtado (fixo) no protótipo
const CHECKOUT_URL = 'https://pay.exemplo/abc123';
const iframe = document.getElementById('cielo-checkout');
const loadingEl = document.getElementById('checkout-loading');
const fallbackEl = document.getElementById('checkout-fallback');
const directLink = document.getElementById('checkout-direct-link');
function loadCheckout(url) {
// Link direto para fallback manual
directLink.href = url;
// Define a URL no iframe
iframe.src = url;
// Estado de carregamento simples (sem depender de mensagens do destino)
let finished = false;
const FAIL_TIMEOUT_MS = 7000; // ajuste conforme sua UX
// Se o documento do iframe carregar, ocultamos o loading
iframe.addEventListener('load', () => {
finished = true;
loadingEl.hidden = true;
// (Opcional) Ajustes de layout adicionais podem ser aplicados aqui
}, { once: true });
// Fallback por timeout: se não carregou em N segundos, exibe alternativa
setTimeout(() => {
if (!finished) {
loadingEl.hidden = true;
fallbackEl.hidden = false;
}
}, FAIL_TIMEOUT_MS);
}
loadCheckout(CHECKOUT_URL);
</script>O exemplo HTML + JavaScript mostra como carregar o iframe diretamente, exibir um indicador de carregamento e apresentar um fallback com link direto caso o carregamento não seja concluído em um tempo definido.
Exemplo visual do checkout exibido no iframe
A imagem a seguir mostra como o checkout é exibido no iframe após a criação da página de pagamento. Esse exemplo é baseado na POC usada durante os testes e tem o objetivo de ilustrar a experiência final da pessoa compradora.
Estrutura da requisição
A criação da página de pagamento exige o envio de uma requisição para a API Checkout. Essa requisição reúne os dados do pedido, da pessoa compradora e das condições de pagamento. O envio deve ser feito pelo back-end da loja para o endpoint:
POST https://cieloecommerce.cielo.com.br/api/public/v1/orders
A lista completa de campos, formatos aceitos e exemplos de requisição está disponível na referência da API, em Criar página de pagamento do Checkout Cielo.
Updated about 2 hours ago