Disponibilidade: o checkout transparente está em preparação para o lançamento. O endpoint público do SDK ainda não está disponível; esta página é uma prévia técnica e não deve ser usada em produção enquanto este aviso estiver visível.
No checkout hospedado, o Astro devolve o link do checkout publicado e o comprador paga lá. No checkout transparente, a compra acontece dentro do seu app: você integra os componentes ou a API de pagamentos do Astro no seu frontend, e o usuário nunca troca de página.
Existem três formas de integrar. As três usam a mesma sessão criada pelo seu servidor:
| Forma | Como fica | Quando usar |
|---|---|---|
| Checkout embutido | O checkout completo (resumo, cupom, dados e pagamento) dentro de um bloco do seu app. | Integração mais rápida. |
| Componente de pagamento | Só as formas de pagamento. O resumo e o botão “Assinar” são seus. | Você já tem uma tela de plano e quer só o pagamento. |
| Headless | Nenhum componente do Astro: o seu frontend chama a API da sessão. | Controle total do layout. |
Nas duas primeiras, o Astro desenha o pagamento num quadro seguro (iframe) dentro da sua página. Os dados do cartão vão direto para o gateway e nunca passam pelo seu app nem pelo Astro.
1. Autorize o domínio do seu app
Em Desenvolvedores → Domínios do app, informe o endereço exato do seu app, por exemplo https://app.suaempresa.com. Só esses domínios podem exibir o checkout embutido e chamar a API da sessão pelo navegador. Para testar na sua máquina, http://localhost:5173 também é aceito.
2. Crie a sessão no seu servidor
Com uma chave de API com o escopo checkout_sessions.write, crie a sessão quando o usuário clicar em assinar. A chave nunca pode ir para o navegador.
curl -X POST https://api.seudominio.com/developer/v1/checkout-sessions \
-H "x-api-key: $ASTRO_API_KEY" \
-H "content-type: application/json" \
-d '{
"checkout": "meu-plano",
"items": [{ "priceId": "pri_...", "quantity": 1 }],
"uiMode": "embedded",
"externalReference": "id-do-usuario-no-seu-app",
"customer": { "name": "Maria Souza", "email": "[email protected]" },
"returnUrl": "https://app.suaempresa.com/assinatura/retorno"
}'
| Campo | Para que serve |
|---|---|
uiMode |
embedded para o checkout embutido e o componente de pagamento; custom para headless. hosted (padrão) devolve o link do checkout hospedado. |
externalReference |
O id do usuário no seu app. Volta em todos os webhooks. |
customer |
Opcional. Com ele, o checkout não pede nome e e-mail de novo. |
returnUrl |
Opcional. Para onde o comprador volta quando o pagamento continua fora da página (PayPal). Precisa estar num domínio autorizado. |
A resposta traz o clientSecret, que o seu frontend usa para operar só esta sessão:
{
"data": {
"id": "chs_...",
"uiMode": "embedded",
"clientSecret": "chs_..._secret_...",
"expiresAt": "2026-11-05T15:30:00.000Z"
}
}
Entregue o clientSecret ao frontend do usuário logado e não o registre em logs. Ele vale enquanto a sessão estiver aberta.
3a. Checkout embutido
<div id="pagamento"></div>
<!-- Substitua quando o painel do Astro fornecer a URL pública do SDK. -->
<script src="{{ASTRO_SDK_URL}}/v1/astro.js"></script>
<script>
const checkout = Astro().checkout({ clientSecret });
checkout
.on("success", (payment) => mostrarObrigado(payment.orderId))
.on("pending", () => mostrarAguardandoPix())
.on("retry", () => criarNovaSessaoEMontarDeNovo())
.mount("#pagamento");
</script>
O bloco ajusta a altura sozinho. Em React:
import { AstroCheckout } from "@astro/js/react";
<AstroCheckout clientSecret={clientSecret} onSuccess={() => router.push("/obrigado")} />;
3b. Componente de pagamento
Mostra só as formas de pagamento. O botão de finalizar é o do seu app:
const payment = Astro().payment({ clientSecret });
payment.mount("#pagamento");
botaoAssinar.addEventListener("click", async () => {
const outcome = await payment.confirm();
if (!outcome.ok) return mostrarErro(outcome.message); // ex.: dados do cartão incompletos
if (outcome.status === "approved") return mostrarObrigado(outcome.orderId);
// 'pending': Pix ou boleto emitido, aparece no próprio componente
});
3c. Headless
Sem componente: o seu frontend chama a API da sessão com o clientSecret. Use uiMode: "custom" na criação.
const session = Astro().session(clientSecret);
const { manifest } = await session.checkout(); // formas de pagamento disponíveis
await session.selectPaymentMethod("pay_pix");
await session.confirm();
const result = await session.waitForResult();
mostrarPix(result.payment.artifacts.pix.copyPaste, result.payment.artifacts.pix.qrCodeBase64);
Sem o SDK, as mesmas rotas aceitam Authorization: Bearer <clientSecret> em /public/v1/checkout-sessions/:id (/checkout, /customer, /select-payment-method, /apply-coupon, /confirm, /result).
Cartão no headless: a forma de pagamento com clientIntegration: "card_tokenization" traz cardTokenization.publicKey. Gere o token com o script do gateway no seu frontend (no Mercado Pago, o Card Payment Brick com essa chave) e envie em session.confirm({ card: { token, installments, paymentMethodId, issuerId } }). Os dados do cartão nunca passam pelo Astro. Se o seu app não pode carregar scripts de gateways, use o componente de pagamento.
Eventos
| Evento | Quando |
|---|---|
ready |
O checkout carregou. |
change |
O comprador escolheu outra forma de pagamento. |
success |
Pagamento aprovado. |
pending |
Pix ou boleto emitido, aguardando o pagamento. |
failed |
Pagamento recusado ou expirado. |
retry |
O comprador pediu para tentar de novo: crie outra sessão no servidor e monte de novo. |
redirect |
O pagamento continua no site do gateway (PayPal). O SDK leva a janela do seu app até lá; chame event.preventDefault() para cuidar disso você mesmo. |
error |
Falha de configuração (domínio não autorizado, sessão expirada). |
Libere o acesso pelo webhook. Os eventos do navegador servem para a interface. Quem libera o plano é o webhook
payment.approvedno seu servidor, com oexternalReference. Veja Webhooks.
Aparência
Por padrão, o componente usa o tema do checkout publicado. Para combinar com o seu app:
Astro().checkout({
clientSecret,
appearance: {
variables: {
colorPrimary: "#6048ee",
colorBackground: "#ffffff",
colorText: "#16161d",
borderRadius: "10px",
fontFamily: "Inter, sans-serif",
},
},
});
Para trocar depois de montado, use checkout.update({ appearance }).
Se o seu app tem CSP
Libere o Astro na política de segurança do seu app:
script-src {{ASTRO_SDK_ORIGIN}}
frame-src {{ASTRO_SDK_ORIGIN}}
connect-src {{ASTRO_SDK_ORIGIN}} (só no headless)
Erros comuns
| Código | O que fazer |
|---|---|
EMBED_ORIGIN_REQUIRED |
Autorize o domínio do app antes de criar sessões embedded ou custom. |
EMBED_ORIGIN_NOT_ALLOWED |
A página que chamou não está em Domínios do app. |
CHECKOUT_SESSION_SECRET_REQUIRED |
Envie o clientSecret desta sessão no Authorization: Bearer. |
RETURN_URL_NOT_ALLOWED |
O returnUrl precisa estar num domínio autorizado. |
CARD_TOKEN_REQUIRED |
No headless com cartão tokenizado, envie o card no confirm. |