Registering through Stripe or Flint? Since 2025, Stripe activates Apple Pay when you register the domain, with no file to host and no fetch to fail, so the checks below do not apply. Go to Stripe, Stripe Connect, or Apple Pay on Flint, and Verified, but still no button.
Diagnose it in five minutes
Start with the fetch itself. Browsers follow redirects and pass bot challenges, so "the URL works when I open it" is not evidence. Use curl and read what a machine sees:
curl -si https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association
You want an HTTP 200 with no Location header. Any 301, 302, or 308 fails verification outright, because Apple's fetcher does not follow redirects. Then read the body and check the other hostnames:
# The body must be the file, not your app's HTML
curl -s https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association | head -c 60
# Repeat both checks for every hostname that shows the button
curl -si https://www.yourdomain.com/.well-known/apple-developer-merchantid-domain-association
The body should be the exact file your processor or the Apple portal gave you, byte for byte. If you see your own HTML, a catch-all rewrite is answering instead of the file. Finally, confirm the TLS chain a non-browser client sees:
openssl s_client -connect yourdomain.com:443 \
-servername yourdomain.com < /dev/null
Then match what you found:
The five causes
Which flow you are in
Where a file is involved, the fetch is identical; what differs is who generates the file and where you click register. Diagnose with the checks above, then apply the fix in your flow's console. Stripe is the exception, with no file at all.
- Apple Developer portal, direct. You run your own merchant ID and merchant validation. Download the per-domain file from the portal, serve it at the well-known path, and click verify within 7 days. This is the flow where file expiry and the one-file-per-domain rules bite hardest.
- Square, Adyen, Braintree, PayPal. Same model, different console: each has you serve its domain association file and register the domain in its dashboard or API. The same verification failures apply; only the registration step changes.
- Stripe. No file. Stripe stopped using the association file in 2025, and registration alone activates Apple Pay: register each hostname in the Dashboard or with POST /v1/payment_method_domains, on the account that runs the charge. There is no fetch to debug, so the five causes above do not apply, and a file left over from the old flow does no harm. If apple_pay stays inactive, apple_pay.status_details.error_message gives the reason, and POST /v1/payment_method_domains/{id}/validate re-checks after you fix it.
- WooCommerce Stripe plugin. Current versions register the domain through Stripe's payment method domains API and no longer place a file, so guides that tell you to upload one predate the change. When registration fails, the plugin shows Stripe's error in an admin notice and records it in the WooCommerce logs when logging is enabled.
A trap specific to Stripe: test mode does not check domains. Registering with a test mode key returns apple_pay: active immediately, even for a domain that does not exist. Your staging environment will happily show the button while the same configuration fails in live mode, so treat the live registration's apple_pay status as the first real result.
Stripe Connect: registered on the wrong account
Apple Pay domain registration lives on the Stripe account that runs the charge. With direct charges, that is the connected account, not the platform. Register only on the platform and everything looks verified in the platform dashboard while the payment page logs:
You have not registered or verified the domain, so apple_pay is not enabled in the Express Checkout Element.
The fix is to register the domain on the connected account by passing the Stripe-Account header:
curl https://api.stripe.com/v1/payment_method_domains \
-u "sk_live_...:" \
-H "Stripe-Account: acct_..." \
-d domain_name=checkout.yourdomain.com
Destination charges and separate charges and transfers register on the platform instead, with no Stripe-Account header. Either way, register every hostname that renders a wallet button.
If verification succeeds and the button still does not render, stop re-verifying the domain; the remaining causes live in the payment page and the browser, not the registration.
- Secure context. Wallets require HTTPS. Plain HTTP disables them, including
http://localhost, so local development needs a TLS proxy or tunnel before any wallet button will paint. - Iframe permissions. A payment form inside an iframe needs the embedding page to delegate the payment capability, for Stripe.js:
Permissions-Policy: payment=(self "https://js.stripe.com"). - A wallet-capable browser. The Apple Pay button renders in Safari on a device with a card provisioned in Wallet. Other browsers on the same machine generally show their own wallet or nothing.
- Automation browsers never qualify. Headless Chrome, Playwright, Puppeteer, and CI screenshot environments have no wallet, so the express slot stays empty there no matter how correct the setup is. Test on a real device before concluding anything.
- Account and region. The wallet must be enabled for the processor account, and the card networks involved must be supported for the transaction's country and currency.
Questions, answered
How long does Apple Pay domain verification take?
Verification is a single fetch of the well-known file, not a review queue. Success normally reflects within seconds to a few minutes. A verification that sits pending for hours is a fetch that keeps failing; diagnose it as a failure rather than waiting.
Do www and the apex domain need separate verification?
Yes. Every hostname that shows an Apple Pay button is its own registration: example.com, www.example.com, and shop.example.com each need to be registered, and in the Apple portal flow each needs its own file. This holds with Stripe too, where registration needs no file.
Why did Apple Pay stop working when nothing was deployed?
In flows that use the association file, Apple re-verifies registered domains automatically, starting 30 days before your TLS certificate expires, with retries 15 and 7 days out. If the file was deleted after the first success, or the renewed certificate changed the chain of trust, the re-check fails and Apple Pay drops off without any deploy on your side.
Can I test domain registration in Stripe test mode?
Only your integration. Registering a domain with a test mode key marks Apple Pay active immediately, even for a domain that does not exist. Stripe no longer fetches a file from your domain, so the apple_pay status on the live registration is the first real result. Register every hostname in live mode before launch.
Apple Pay on Flint
Flint hosted checkout and payment links run on Flint's domain, so Apple Pay and Google Pay work there with no domain setup. For checkout on your own domain, register each hostname with POST /v1/payment-method-domains. Flint registers it with Stripe on your payment account, so there is no file to host and the five causes above do not apply. The response reports per-wallet readiness. If a wallet stays inactive after a live registration, confirm the hostname matches the browser's address bar exactly, re-check it by setting the registration's status to active with PATCH, and ask Flint Help with the payment_method_domain_id if it is still inactive. See Apple Pay and Google Pay setup and the API reference.
Sources