@conectores_cielo/cielo-applepay-headless-vtex
v1.0.3
Published
Apple Pay headless orchestration SDK for VTEX + Cielo eWallet checkouts
Maintainers
Readme
@conectores_cielo/cielo-applepay-headless-vtex
SDK de Apple Pay para checkout VTEX com integracao Cielo eWallet.
O pacote publica, em um unico artefato NPM, os modulos:
- core
- adapter
- react
Objetivo
Este SDK acelera a implementacao de Apple Pay em storefronts VTEX headless, centralizando:
- criacao e ciclo da ApplePaySession no navegador
- abertura, confirmacao e cancelamento no connector Cielo
- componentes e hooks React para UX de checkout
Pre-requisitos
Antes da integracao, confirme:
- Node.js 18+
- npm 7+ ou Yarn 1.x
- React 18.2+ (compativel com React 19)
- Aplicacao servida em HTTPS
- Dominio validado no Apple Developer (arquivo apple-developer-merchantid-domain-association publicado na raiz)
- Connector braspag.cielo-ewallet-payment-app habilitado na conta VTEX
Passo 1 - Instalacao
Com npm:
npm install @conectores_cielo/cielo-applepay-headless-vtexCom Yarn:
yarn add @conectores_cielo/cielo-applepay-headless-vtexPasso 2 - Inicializacao do SDK (executar uma unica vez)
Chame Init uma vez no bootstrap da aplicacao, fora de componentes React.
Locais recomendados:
- Next.js App Router: arquivo de entrada client do checkout
- Next.js Pages Router:
_app.tsx - React SPA:
main.tsx
Exemplo minimo (producao)
import { Init } from '@conectores_cielo/cielo-applepay-headless-vtex/adapter'
Init({
strictDeviceValidation: true,
})Exemplo usado em ambiente de desenvolvimento/homologacao
Este formato segue o uso pratico comum em pagina de checkout client-side:
import { Init } from '@conectores_cielo/cielo-applepay-headless-vtex/adapter'
Init({
strictDeviceValidation: false,
})Use strictDeviceValidation: false apenas para facilitar testes em dispositivos sem Apple Pay ativo.
Exemplo com configuracao completa de request Apple Pay
import { Init } from '@conectores_cielo/cielo-applepay-headless-vtex/adapter'
Init({
strictDeviceValidation: true,
ClientRequestConfig: {
countryCode: 'BR',
currencyCode: 'BRL',
merchantCapabilities: ['supports3DS', 'supportsCredit'],
supportedNetworks: ['masterCard', 'visa'],
requiredBillingContactFields: ['postalAddress'],
requiredShippingContactFields: ['name', 'email', 'phone'],
totalLabel: 'Nome da Loja',
totalType: 'final',
},
})Exemplo avancado com funcoes customizadas (clientOpenSession e clientCancel)
Use este padrao quando precisar controlar chamadas HTTP por conta propria (ex.: observabilidade adicional, proxy interno ou camada de seguranca customizada).
Observacao: clientOpenSession e clientCancel sao opcionais. Na maioria dos projetos, a implementacao padrao do adapter ja e suficiente e reduz complexidade operacional.
import {
Init,
type AppPayload,
type ApplePaySessionResponse,
type ApplePayCancelRequest,
} from '@conectores_cielo/cielo-applepay-headless-vtex/adapter'
Init({
strictDeviceValidation: true,
clientOpenSession: async (payload: AppPayload): Promise<ApplePaySessionResponse> => {
// Exemplo ilustrativo: substitua pela chamada real da sua API/proxy.
const response = await fetch('/api/applepay/open-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
if (!response.ok) {
throw new Error(`Falha ao abrir sessao Apple Pay: HTTP ${response.status}`)
}
return (await response.json()) as ApplePaySessionResponse
},
clientCancel: async (
payload: AppPayload,
cancelRequest: ApplePayCancelRequest
): Promise<void> => {
// Exemplo ilustrativo: substitua pela chamada real da sua API/proxy.
const response = await fetch('/api/applepay/cancel', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ payload, cancelRequest }),
})
if (!response.ok) {
throw new Error(`Falha ao cancelar transacao Apple Pay: HTTP ${response.status}`)
}
},
})Opcoes do Init
| Campo | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
| strictDeviceValidation | boolean | nao | Quando true, valida disponibilidade de Apple Pay no dispositivo antes de iniciar o fluxo. Default: true. |
| ClientRequestConfig | Partial ApplePayRequestConfig | nao | Sobrescreve campos da request base enviada para criacao da ApplePaySession. |
| clientOpenSession | funcao | nao | Permite sobrescrever a chamada padrao de abertura de sessao no connector. |
| clientCancel | funcao | nao | Permite sobrescrever a chamada padrao de cancelamento no connector. |
Passo 3 - Iniciar o fluxo no checkout
No checkout real, o fluxo recomendado e:
- validar carrinho, endereco e meio de pagamento antes de abrir o Apple Pay
- salvar profile, shipping e payment no VTEX
- recalcular total apos o shipping para obter o valor final correto
- finalizar pedido e registrar a transacao no VTEX Payments
- iniciar o flow do SDK com callbacks de sucesso/erro
Exemplo pratico:
import { startVtexApplePayFlow } from '@conectores_cielo/cielo-applepay-headless-vtex/adapter'
async function handleApplePayOrder() {
if (items.length === 0) {
setCheckoutError('Seu carrinho esta vazio.')
return
}
if (!isApplePaySelected) {
setCheckoutError('Selecione Apple Pay para continuar com este fluxo.')
return
}
const selectedPaymentSystemNumber = Number(selectedPaymentSystem)
if (!Number.isFinite(selectedPaymentSystemNumber) || selectedPaymentSystemNumber <= 0) {
setCheckoutError('Meio de pagamento Apple Pay invalido.')
return
}
setCheckoutError(null)
void startVtexApplePayFlow({
prepareOrder: async () => {
const normalizedShipping = getNormalizedShipping()
const normalizedDocument = profile.document.replace(/\D/g, '')
const initialPaymentValue = orderValueCents ?? Math.round(orderTotal * 100)
const buildPayment = (value: number) => ({
...payment.payments[0],
paymentSystem: selectedPaymentSystem,
value,
referenceValue: value,
installments: 1,
})
await saveCheckoutData(
{
...profile,
firstName: profile.firstName.trim(),
lastName: profile.lastName.trim(),
document: normalizedDocument,
documentType: 'cpf',
isCorporate: false,
phone: profile.phone.replace(/\D/g, ''),
},
{ selectedAddresses: [normalizedShipping] },
{ ...payment, payments: [buildPayment(initialPaymentValue)] } as Record<string, unknown>
)
const freshContext = await loadCheckoutContext()
const freshTotal = freshContext.orderData?.value ?? initialPaymentValue
setOrderValueCents(freshTotal)
const currentOrderFormId = useCartStore.getState().orderFormId ?? ''
if (freshTotal !== initialPaymentValue && currentOrderFormId) {
await savePaymentAttachment({
orderFormId: currentOrderFormId,
data: { ...payment, payments: [buildPayment(freshTotal)] } as Record<string, unknown>,
})
}
const placed = await finishOrder()
if (!placed) throw new Error('Nao foi possivel finalizar o pedido.')
const orderReference = placed.orderGroup ?? placed.orderId
if (!orderReference) throw new Error('Nao foi possivel obter o orderGroup do pedido.')
if (placed.paymentsUrl && placed.transactionId) {
const applePayPaymentPayload = [
{
paymentSystem: selectedPaymentSystemNumber,
installments: 1,
currencyCode: 'BRL',
value: freshTotal,
installmentsInterestRate: 0,
installmentsValue: freshTotal,
referenceValue: freshTotal,
fields: {},
transaction: {
id: placed.transactionId,
merchantName: placed.merchantName ?? '',
},
},
]
const paymentsResponse = await fetch(placed.paymentsUrl, {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(applePayPaymentPayload),
})
if (!paymentsResponse.ok) {
const errText = await paymentsResponse.text()
throw new Error(`Falha ao registrar pagamento Apple Pay no gateway VTEX (${paymentsResponse.status}): ${errText}`)
}
}
return {
orderReference,
orderId: placed.orderId,
}
},
processPlacedOrder,
cancelOrder,
initialAmount: ((orderValueCents ?? Math.round(orderTotal * 100)) / 100).toFixed(2),
onSuccess: (orderReference) => {
setOrderId(orderReference)
setStep('success')
},
onError: (message) => {
setCheckoutError(message)
},
})
}Neste padrao, o app consumidor continua responsavel pelas chamadas VTEX (checkout e payments), enquanto o SDK orquestra a sessao Apple Pay e a comunicacao com o connector.
Boas praticas de implementacao
- Execute
Initapenas uma vez por ciclo de vida da pagina. - Garanta que
initialAmountrepresente o total final do pedido (produtos + frete). - Em Next.js, mantenha o fluxo de Apple Pay em componente client (
'use client'). - Trate
onErrorcom mensagem clara para o comprador e fallback de meio de pagamento.
Comportamento esperado
- O botao Apple Pay aparece somente em Safari com dispositivo compativel e carteira configurada.
- Em HTTP, o fluxo nao inicia (Apple Pay exige HTTPS).
- Se
strictDeviceValidationestiver ativo e o device nao suportar Apple Pay, o fluxo e interrompido com erro controlado.
Modulos exportados
| Modulo | Uso | |---|---| | @conectores_cielo/cielo-applepay-headless-vtex/core | Tipos e utilitarios agnosticos de framework | | @conectores_cielo/cielo-applepay-headless-vtex/adapter | Orquestracao do fluxo Apple Pay para VTEX + Cielo | | @conectores_cielo/cielo-applepay-headless-vtex/react | Hooks e componentes React (ApplePayButton, ApplePayModal, useApplePay, useApplePaySdk) |
Versao recomendada para clientes
npm install @conectores_cielo/cielo-applepay-headless-vtex@^0.xLicenca
MIT
