Pular para o conteúdo principal

🍎 Apple Pay

📋 Visão Geral​

O Apple Pay é aceito como uma transação de cartão de crédito: o cliente confirma o pagamento com Face ID ou Touch ID e o seu backend cria a transação com o token gerado pela Apple, no lugar dos dados do cartão.

🍎

Sem conta na Apple

Não é preciso conta de desenvolvedor, Merchant ID nem certificado

💳

Taxas de cartão

As mesmas taxas e o mesmo parcelamento do cartão de crédito

⚡

Mesma rota

A transação usa a rota de transações que você já integra

✅ Antes de Começar​

  • Apple Pay liberado na sua conta. Se a API responder "Apple Pay não habilitado", peça a liberação ao suporte.
  • Um site em HTTPS, num domínio que você controla, onde o botão será exibido.
  • Acesso para publicar um arquivo em https://seu-dominio/.well-known/.
  • Suas chaves de API: a secret key (no backend) e a public key (no navegador).
  • Para testar: iPhone, iPad ou Mac com Safari e um cartão Visa ou Mastercard na Wallet.

Chaves usadas​

ChaveOnde usarComo enviar
Secret key sk_…Só no seu backend: cadastro de domínio e criação da transaçãoHeader Authorization, como nas outras rotas (Autenticação)
Public key pk_…No navegador: validação da sessão do Apple PayHeader x-public-key
Atenção

Nunca coloque a secret key no código do navegador.

🚀 Fluxo Completo​

A integração tem duas partes:

  1. Configuração do domínio (uma vez por domínio): cadastrar, publicar o arquivo de verificação e validar.
  2. Cada pagamento: exibir o botão, validar a sessão com a public key e criar a transação no backend com o token.

Diagrama do Fluxo de Pagamento​

🔧 Implementação​

1. Cadastrar o Domínio​

Feito pelo seu backend, uma vez por domínio. Envie só o hostname, sem https:// e sem caminho. Cada hostname é cadastrado separadamente: loja.com.br e www.loja.com.br são dois domínios.

curl -X POST https://api.fastsoftbrasil.com/api/user/apple-pay/domains \
-H "Authorization: Basic BASE64(x:SECRET_KEY)" \
-H "Content-Type: application/json" \
-d '{
"domain": "checkout.minhaloja.com.br"
}'

Resposta 201:

{
"status": 201,
"message": "Domínio cadastrado. Publique o arquivo de verificação no endereço indicado e depois valide o domínio.",
"data": {
"id": "8f1c2a4e-5b7d-4c3a-9e2f-1a2b3c4d5e6f",
"domain": "checkout.minhaloja.com.br",
"status": "PENDING",
"verifiedAt": null,
"verificationFile": {
"path": "https://checkout.minhaloja.com.br/.well-known/apple-developer-merchantid-domain-association",
"content": "7b2276657273696f6e22…"
}
},
"error": null
}

Guarde o id: ele é usado para validar e consultar o domínio. Se você cadastrar de novo um domínio que já é seu, a API responde 409 com o cadastro existente.

2. Publicar o Arquivo de Verificação​

Feito no servidor do seu site, uma vez por domínio. Crie um arquivo no endereço indicado em verificationFile.path, com o texto de verificationFile.content exatamente como veio.

  • Caminho /.well-known/apple-developer-merchantid-domain-association, sem extensão.
  • Conteúdo idêntico ao recebido, sem decodificar nem formatar.
  • Servido como Content-Type: text/plain, por HTTPS, com resposta 200.
  • Sem redirecionamento e acessível publicamente, sem login nem bloqueio por IP.
  • Mantenha o arquivo publicado depois da validação.

Para conferir antes de validar:

curl -sI https://checkout.minhaloja.com.br/.well-known/apple-developer-merchantid-domain-association
# Esperado: HTTP 200 e content-type: text/plain

💡 Dica: perdeu o conteúdo do arquivo? A listagem de domínios devolve o arquivo de cada um.

3. Validar o Domínio​

Feito pelo seu backend, depois de publicar o arquivo. A API pede ao adquirente para conferir o arquivo publicado.

curl -X POST https://api.fastsoftbrasil.com/api/user/apple-pay/domains/ID_DO_DOMINIO/validate \
-H "Authorization: Basic BASE64(x:SECRET_KEY)"

Resposta 200:

{
"status": 200,
"message": "Domínio verificado para Apple Pay.",
"data": {
"id": "8f1c2a4e-5b7d-4c3a-9e2f-1a2b3c4d5e6f",
"domain": "checkout.minhaloja.com.br",
"status": "VERIFIED",
"verifiedAt": "2026-10-06T16:53:53.448Z",
"verificationFile": { "path": "…", "content": "…" }
},
"error": null
}

Só domínios com status VERIFIED exibem o botão. Para consultar o status a qualquer momento, use a rota de consulta do domínio.

4. Exibir o Botão e Validar a Sessão​

Feito no navegador, a cada pagamento. Carregue o SDK da Apple e exiba o botão só quando o aparelho aceitar Apple Pay. No clique, crie a sessão e chame begin() imediatamente, sem await antes.

<script crossorigin src="https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js"></script>

<apple-pay-button id="apple-pay" buttonstyle="black" type="pay" locale="pt-BR" hidden></apple-pay-button>
const API_URL = 'https://URL_DA_API'; // a mesma URL usada nas outras rotas
const PUBLIC_KEY = 'pk_...';
const button = document.getElementById('apple-pay');

if (window.ApplePaySession && ApplePaySession.canMakePayments()) {
button.hidden = false;
}

button.addEventListener('click', () => {
const session = new ApplePaySession(3, {
countryCode: 'BR',
currencyCode: 'BRL',
supportedNetworks: ['visa', 'masterCard'],
merchantCapabilities: ['supports3DS'],
total: { label: 'Minha Loja', amount: '100.50' },
});

session.onvalidatemerchant = async (event) => {
try {
const response = await fetch(`${API_URL}/api/public/apple-pay/validate-merchant`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-public-key': PUBLIC_KEY },
body: JSON.stringify({
validationUrl: event.validationURL,
domain: window.location.hostname,
}),
});
if (!response.ok) throw new Error('Validação da sessão recusada');
const { data } = await response.json();
session.completeMerchantValidation(data); // repasse "data" sem alterar
} catch (error) {
session.abort();
}
};

session.onpaymentauthorized = async (event) => {
// Envie o token ao SEU backend. Ele cria a transação com a secret key (passo 5)
// e devolve o data.status da resposta.
const { status } = await fetch('/checkout/apple-pay', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: event.payment.token }),
}).then((r) => r.json());

session.completePayment(
status === 'PAID' ? ApplePaySession.STATUS_SUCCESS : ApplePaySession.STATUS_FAILURE,
);
};

session.begin();
});

A rota de validação devolve a sessão dentro de data. Repasse esse objeto inteiro para completeMerchantValidation.

5. Criar a Transação​

Feito pelo seu backend, a cada pagamento. É a mesma rota de transações de cartão: use paymentMethod: "CREDIT_CARD" e envie o token no campo wallet, no lugar de card. O token é o event.payment.token completo, sem nenhuma alteração.

curl -X POST https://api.fastsoftbrasil.com/api/user/transactions \
-H "Authorization: Basic BASE64(x:SECRET_KEY)" \
-H "Content-Type: application/json" \
-d '{
"amount": 10050,
"paymentMethod": "CREDIT_CARD",
"installments": 1,
"customer": {
"name": "Maria Souza",
"email": "maria@exemplo.com.br",
"phone": "(11) 98765-4321",
"document": {
"type": "CPF",
"number": "52998224725"
}
},
"items": [
{
"title": "Pedido 1234",
"unitPrice": 10050,
"quantity": 1,
"tangible": false
}
],
"postbackUrl": "https://minhaloja.com.br/webhooks/pagamentos",
"wallet": {
"type": "APPLE_PAY",
"token": {
"paymentData": {
"version": "EC_v1",
"data": "…",
"signature": "…",
"header": {
"ephemeralPublicKey": "…",
"publicKeyHash": "…",
"transactionId": "…"
}
},
"paymentMethod": {
"displayName": "MasterCard 4835",
"network": "MasterCard",
"type": "credit"
},
"transactionIdentifier": "…"
}
}
}'
  • amount e unitPrice em centavos: 10050 é R$ 100,50.
  • O documento do cliente é obrigatório: o token da Apple não traz CPF nem CNPJ.
  • Parcelamento igual ao do cartão, com mínimo de R$ 5,00 por parcela.
  • Não há 3D Secure: a autenticação já vem no token.

Resposta 200 (trecho):

{
"status": 200,
"message": "Transação criada com sucesso.",
"data": {
"id": "3e9821e1-a95e-4b88-85f5-8a8db91d3882",
"amount": 10050,
"paymentMethod": "CREDIT_CARD",
"installments": 1,
"status": "PAID",
"card": { "brand": "MASTERCARD", "lastDigits": "XXXXXXXXXXXX4835" }
},
"error": null
}

Decida o resultado pelo data.status e devolva ao navegador para fechar a folha do Apple Pay.

📊 Status e Webhooks​

A transação de Apple Pay segue os mesmos status e envia os mesmos eventos de transação que uma transação de cartão.

StatusSignificadoO que fazer
PAIDPagamento aprovadoFeche a folha com sucesso e confirme o pedido.
REFUSEDPagamento recusadoFeche a folha com falha e ofereça outra forma de pagamento.
WAITING_PAYMENTEm análise no adquirenteAguarde o webhook com o status final antes de confirmar o pedido.
REFUNDED, CHARGEDBACKEstorno ou chargebackChegam depois, por webhook.

🚨 Erros Comuns​

HTTPMensagemComo resolver
400Apple Pay não habilitado, caso seja necessário, entre em contato com o suporte.Peça a liberação do Apple Pay (e do cartão de crédito) na sua conta.
400Apple Pay não é suportado pelo adquirente configurado para cartão.O adquirente de cartão da sua conta não aceita Apple Pay. Fale com o suporte.
400O campo "domain" deve ser um hostname válido, sem https:// e sem caminho.Envie só o hostname, por exemplo checkout.minhaloja.com.br.
400Adquirente: Não foi possível acessar o arquivo de verificação…Confira caminho, conteúdo, text/plain, HTTPS e ausência de redirecionamento.
409Este domínio já está cadastrado para Apple Pay.Use o cadastro existente, que vem na resposta, para validar.
400Apple Pay indisponível para este domínio.Na validação da sessão: confira se o domínio da página está VERIFIED e se a public key é da sua conta.
429Muitas tentativas. Tente novamente em alguns minutos.Limite de validações de sessão atingido. Aguarde e tente de novo.
400Informe o campo "card" ou "wallet" para esse método de pagamento.Envie wallet com type: "APPLE_PAY" e o token.
400Adquirente: Token Apple Pay inválido. Envie o token sem modificações.Repasse o event.payment.token inteiro, sem converter nem extrair campos.
400Adquirente: Documento do cliente é obrigatório para Apple Pay.Envie customer.document com CPF ou CNPJ.

📏 Regras e Limites​

  • Bandeiras aceitas: Visa e Mastercard. Moeda: somente BRL.
  • Cada hostname precisa do próprio cadastro e da própria validação.
  • O arquivo de verificação precisa continuar publicado. Se ele sair do ar, a validação de sessão pode deixar de funcionar.
  • A validação de sessão tem limite de chamadas por minuto. Chame a rota só no onvalidatemerchant, nunca antecipadamente.
  • Se o adquirente de cartão da sua conta mudar, a API recadastra os domínios já verificados no primeiro pagamento seguinte. Se isso falhar, cadastre e valide o domínio de novo.

❓ FAQ​

Preciso de conta de desenvolvedor na Apple?​

Não. A validação com a Apple é feita pela API. Você só cadastra e valida o domínio.

Por que o botão não aparece?​

O botão só aparece no Safari, em aparelhos com um cartão Visa ou Mastercard na Wallet. Nos outros casos canMakePayments() retorna false, e isso é esperado.

Posso usar o mesmo domínio em mais de uma conta?​

Sim. Cada conta cadastra e valida o domínio com as próprias chaves. O arquivo de verificação é o mesmo, então basta publicá-lo uma vez.

O Apple Pay aceita parcelamento?​

Sim, com as mesmas regras e taxas do cartão de crédito, incluindo o mínimo de R$ 5,00 por parcela.

Preciso enviar dados 3DS?​

Não. A autenticação do cliente já vem no token do Apple Pay.

Como testar?​

  1. Cadastre, publique e valide um domínio de testes (passos 1 a 3).
  2. Abra a página no Safari de um iPhone, iPad ou Mac com cartão Visa ou Mastercard na Wallet.
  3. Faça uma compra de valor baixo e confira o data.status e o webhook.
  4. Estorne a transação depois: as cobranças de teste são reais.

Veja todas as rotas na referência da API.