Reference

Apple Pay domain verification failed

Verification is one thing: Apple's servers fetch /.well-known/apple-developer-merchantid-domain-association from your domain over TLS. Every failure is one of five ways that fetch goes wrong, whether you register through the Apple Developer portal, Stripe, or a commerce plugin.

Verified against official documentation · last reviewed 2026-07-31 · corrections: support@withflintpay.com

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:

Bash
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:

Bash
# 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 an opaque blob. Stripe's file, for example, is about 9 KB of hex-encoded text beginning 7B227073704964. 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:

Bash
openssl s_client -connect yourdomain.com:443 \
  -servername yourdomain.com < /dev/null

Then match what you found:

What you seeCause
curl shows a 3xx status or a Location headerFile not served at the exact URL
The body is HTML, or your app's index pageSPA catch-all rewrite
Loads in your browser, but verification still failsCDN or bot protection
The error mentions TLS, certificates, or cipher suitesTLS trust
It fails only for www, or only for the apex domainPer-hostname files
It worked before and broke around a certificate renewalAutomatic re-verification
Verified in the dashboard, but no button on the pageNot a verification problem
Stripe Connect: the platform is verified, the console still warnsConnected-account registration

The five causes

01

The file is not served at exactly the right URL

Verification fails immediately, often with "the file can't be reached", while the URL opens fine in your browser.

Apple requests the well-known path and requires a 200 response with the file contents in the body. It does not follow redirects. A 301 from apex to www, a trailing-slash rewrite, an http-to-https upgrade that also changes the hostname, or a redirect to your homepage all fail, even though a browser follows them silently. The other silent variant is a single-page-app catch-all that returns index.html with a 200 for every unknown path: the status looks right and the body is wrong.

Confirm it

curl -si the well-known URL. Any 3xx status or Location header is this cause. If the status is 200, read the body: if it looks like your app's HTML, it is the catch-all rewrite.

Fix

Serve the file as a static asset that bypasses redirect rules and SPA rewrites. Most platforms have an exception mechanism for /.well-known/ paths. Verify the apex and www variants separately; each hostname is its own registration.

02

Your CDN, WAF, or bot protection is blocking Apple's fetcher

The file loads fine in every browser you try, and verification still fails. Server logs show a 403 or a challenge page for the verification request, or no request at all.

Apple's verification servers are not a browser. They send different headers than your browser does and do not execute JavaScript challenges, so bot rules that your own testing sails through will block them. Cloudflare's Super Bot Fight Mode has repeatedly blocked Apple's fetch of this exact file, including fetches triggered through Stripe registration.

Confirm it

Check origin access logs for requests to the well-known path around the moment you clicked verify. A 403, a challenge response, or silence while your own curl shows up means the fetch is being intercepted.

Fix

Exempt the /.well-known/ path from bot fighting, managed challenges, and rate limits, or allowlist Apple's published IP ranges. Then re-run verification and confirm the request reaches origin with a 200.

"It loads for me" proves nothing here: your browser passes the challenge, Apple's fetcher does not.

03

Apple does not trust your TLS setup

The failure message mentions your TLS certificate configuration or cipher suites.

The fetch happens over TLS 1.2 or later with a supported cipher suite, and the certificate chain must resolve to a root Apple's operating systems trust. Common breakages: a proxy or load balancer that presents a different certificate than your origin, a missing intermediate certificate (browsers fetch missing intermediates on their own, non-browser clients often do not), a self-signed or internal CA certificate on a staging host, or a path that demands a client certificate.

Confirm it

openssl s_client -connect yourdomain.com:443 -servername yourdomain.com and read the chain and the verify return code. Test from outside your network so you see what Apple sees, not what your VPN sees.

Fix

Serve the full chain for the exact hostname, keep TLS 1.2+ with modern cipher suites, and make sure the well-known path requires no client certificate. Domains on private networks need bi-directional firewall rules that admit Apple's verification servers.

04

The file is wrong, stale, or for a different domain

The file is reachable and verification still fails, or it fails after you re-added a domain.

In the Apple Developer portal flow, the file is generated per domain, is valid for 7 days after generation, and only the most recently generated file for a domain counts. The file for example.com does not verify www.example.com; each hostname needs its own. Processor flows use a long-lived static file instead, but serving it with an appended .txt extension, wrapped in HTML by a CMS page, or truncated by an upload step fails the same way. A CDN can also keep serving the old file after you replaced it.

Confirm it

Byte-compare what the URL serves against the file you downloaded: curl -s the URL to a file and diff it. Confirm the response is raw file bytes, not an HTML page containing them.

Fix

Re-download the current file for this exact hostname, serve it unmodified at the well-known path, purge CDN caches, and verify within the validity window when the portal flow applies.

05

It verified once, then silently broke

Apple Pay disappeared from your site with no deploy, often within a month of a TLS certificate renewal.

Verification is not one-time. Apple re-verifies every registered domain automatically, starting 30 days before your TLS certificate expires and retrying 15 and 7 days out. The re-check requires the association file to still be live and the root domain to return a 200. Teams delete the file after the first success, or renew a certificate onto a different chain, and the domain quietly drops out of verification.

Confirm it

Is the well-known URL still serving the file today? Did the certificate or its chain change recently? Does the bare root domain return a 200 rather than a redirect or an error?

Fix

Treat the file as permanent infrastructure: keep it deployed forever, re-verify after certificate changes, and monitor the well-known URL like any other health check.

Which flow you are in

The fetch is identical everywhere; 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.

  • 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.
  • Stripe. You never touch the Apple portal; Stripe owns merchant validation. Download Stripe's static association file, serve it at the well-known path, then register the domain in the Dashboard or with POST /v1/payment_method_domains. The validate endpoint re-checks after you fix something, and apple_pay.status_details.error_message carries the failure reason.
  • WooCommerce Stripe plugin. The plugin registers the domain through Stripe's API and serves the association file itself through a rewrite. Do not upload the file by hand. When this flow fails, the usual culprits are permalink or rewrite configuration and security plugins intercepting the well-known path.
  • Square, Adyen, Braintree, PayPal. Same model, different console: each has you serve a domain association file and register the domain in their dashboard or API. Every cause on this page applies unchanged; only the registration step moves.

A trap specific to Stripe: test mode does not verify 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 live registration as the first real test of your file.

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:

Bash
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.

Verified, but still no 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 verified, and in the Apple portal flow each needs its own file.

Why did Apple Pay stop working when nothing was deployed?

Apple re-verifies registered domains automatically, starting 30 days before your TLS certificate expires, with retries 15 and 7 days out. If the association 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 verification in Stripe test mode?

No. Registering a domain with a test mode key marks Apple Pay active immediately, even for a domain that does not exist. Test mode tells you nothing about your file, your TLS, or your CDN rules; the real fetch happens when you register the domain in live mode.

Apple Pay on Flint

Flint hosted checkout and payment links run on Flint's domain, so domain verification is Flint's job: Apple Pay and Google Pay work there with none of the setup on this page. For embedded checkout on your own domain, register the checkout hostname once with POST /v1/payment-method-domains; the response reports per-wallet readiness, and the validate endpoint re-checks after you fix the domain using the causes above. See the embedded payments guide and the API reference.

Sources