🍎 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
| Chave | Onde usar | Como enviar |
|---|---|---|
Secret key sk_… | Só no seu backend: cadastro de domínio e criação da transação | Header Authorization, como nas outras rotas (Autenticação) |
Public key pk_… | No navegador: validação da sessão do Apple Pay | Header x-public-key |
Nunca coloque a secret key no código do navegador.
🚀 Fluxo Completo
A integração tem duas partes:
- Configuração do domínio (uma vez por domínio): cadastrar, publicar o arquivo de verificação e validar.
- 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 resposta200. - 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": "…"
}
}
}'
amounteunitPriceem 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.
| Status | Significado | O que fazer |
|---|---|---|
PAID | Pagamento aprovado | Feche a folha com sucesso e confirme o pedido. |
REFUSED | Pagamento recusado | Feche a folha com falha e ofereça outra forma de pagamento. |
WAITING_PAYMENT | Em análise no adquirente | Aguarde o webhook com o status final antes de confirmar o pedido. |
REFUNDED, CHARGEDBACK | Estorno ou chargeback | Chegam depois, por webhook. |
🚨 Erros Comuns
| HTTP | Mensagem | Como resolver |
|---|---|---|
| 400 | Apple 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. |
| 400 | Apple 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. |
| 400 | O campo "domain" deve ser um hostname válido, sem https:// e sem caminho. | Envie só o hostname, por exemplo checkout.minhaloja.com.br. |
| 400 | Adquirente: Não foi possível acessar o arquivo de verificação… | Confira caminho, conteúdo, text/plain, HTTPS e ausência de redirecionamento. |
| 409 | Este domínio já está cadastrado para Apple Pay. | Use o cadastro existente, que vem na resposta, para validar. |
| 400 | Apple 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. |
| 429 | Muitas tentativas. Tente novamente em alguns minutos. | Limite de validações de sessão atingido. Aguarde e tente de novo. |
| 400 | Informe o campo "card" ou "wallet" para esse método de pagamento. | Envie wallet com type: "APPLE_PAY" e o token. |
| 400 | Adquirente: Token Apple Pay inválido. Envie o token sem modificações. | Repasse o event.payment.token inteiro, sem converter nem extrair campos. |
| 400 | Adquirente: 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?
- Cadastre, publique e valide um domínio de testes (passos 1 a 3).
- Abra a página no Safari de um iPhone, iPad ou Mac com cartão Visa ou Mastercard na Wallet.
- Faça uma compra de valor baixo e confira o
data.statuse o webhook. - Estorne a transação depois: as cobranças de teste são reais.
Veja todas as rotas na referência da API.