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 or a processor such as Square, PayPal, Braintree, or Adyen. Stripe no longer uses the file.
Verified against official documentationReviewed Send a correction (opens in a new tab)

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

Shell
# 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:

Shell
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

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

  2. 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 is a documented example: it has blocked Apple's fetch of this exact file.

    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.

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

  4. 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. Processors that issue their own file, such as Square, PayPal, Braintree, and Adyen, 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.

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

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