Apple Pay and Google Pay setup

Flint-hosted checkout and payment links run on Flint's domain, so Apple Pay and Google Pay work there with no setup. When checkout runs on your own domain, as in Embedded payments or Build your own checkout, Stripe Elements shows wallet buttons only on hostnames you have registered with Flint.

Registration controls whether the buttons render, not which wallets you offer. The order's payment_collection.stripe.elements.digital_wallets lists apple_pay and google_pay from your payment options whether or not the current hostname is registered.

Before you start#

Use an administrative key. Registering needs payments.payment_method_domains.write, which also covers reads. Keep it on a separate key from the one your checkout backend uses for orders.

Finish payment onboarding. Until the environment's payment account is ready, registration returns MERCHANT_ACCOUNT_NOT_READY.

Serve checkout over HTTPS. Wallets do not render on plain HTTP, including http://localhost.

You do not need an Apple Merchant ID, a certificate signing request, or a domain association file. Flint registers the hostname with Stripe on your payment account, and Stripe handles Apple merchant validation.

Register each hostname#

Register every hostname that shows a wallet button. example.com, www.example.com, and shop.example.com are three separate registrations. Send the bare hostname: no scheme, path, port, IP address, or wildcard. Write internationalized hostnames in Punycode.

cURL
curl -X POST https://api.withflintpay.com/v1/payment-method-domains \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
  -H "Idempotency-Key: pmd-shop-example-com" \
  -d '{"domain_name": "shop.example.com"}'
JSON
{
  "data": {
    "payment_method_domain_id": "pmdom_1kmn0aExample",
    "domain_name": "shop.example.com",
    "status": "active",
    "validation_status": "active",
    "payment_options": [
      {"payment_option": "apple_pay", "status": "active"},
      {"payment_option": "google_pay", "status": "active"}
    ],
    "created_at": "2026-09-22T12:00:00Z",
    "updated_at": "2026-09-22T12:00:00Z"
  },
  "request_id": "req_..."
}

A registration belongs to the environment of the key that made it. A sandbox key registers the hostname in that sandbox only, so register again with a live key before going live.

Retrying with the same Idempotency-Key returns the original registration. Registering a hostname that already exists in the environment returns 409 PAYMENT_METHOD_DOMAIN_ALREADY_EXISTS, and the error's details carries the existing payment_method_domain_id.

If your payment form runs in an iframe on a different hostname from the page around it, register both hostnames and add allow="payment" to the iframe.

With the CLI, send the same body from a file:

Shell
flint payment-method-domains create --input request.json

Check each hostname#

Read the registration's validation_status for the overall answer, and payment_options for each wallet's status of active, inactive, or unavailable:

  • active: the registration is on, and Apple Pay and Google Pay are both ready on this hostname.
  • action_required: the registration is inactive, or at least one wallet is not active. Check payment_options.
  • unavailable: Flint could not read a wallet's status, for example while the environment's payment account is not ready. Check onboarding, then re-check the hostname.

List every registration in the environment to audit your hostnames:

cURL
curl "https://api.withflintpay.com/v1/payment-method-domains?page_size=100" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY"

Reads return the result of the most recent check and do not run it again. After you fix a hostname, run the check again by setting the registration's status to active:

cURL
curl -X PATCH https://api.withflintpay.com/v1/payment-method-domains/pmdom_1kmn0aExample \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ADMIN_API_KEY" \
  -H "Idempotency-Key: pmd-shop-example-com-recheck-1" \
  -d '{"status": "active"}'

Setting status to inactive turns wallet buttons off on that hostname.

If a wallet stays inactive after a live check, confirm the registered hostname matches the browser's address bar exactly, run the check again, and ask Flint Help with the payment_method_domain_id if it is still inactive. There is no file to fix: Stripe activates wallets on registration. If every status is active and the button still does not appear, the cause is in your checkout page or the device. See Verified, but still no button.

Test the buttons#

Warning: A sandbox check is not a live check

A sandbox registration reports active right away, even for a hostname that does not exist. It confirms your integration, not your domain. The live registration is the first real check of the hostname.

Test locally through a tunnel. Run a tunnel such as ngrok or cloudflared to get an HTTPS hostname for your local checkout, then register that hostname in your sandbox. Tunnel hostnames often change between sessions, and each new one needs its own registration.

Apple Pay renders in Safari on an Apple device with a card in Apple Wallet. Wallet does not accept test card numbers, so add a real card and pay with a sandbox key.

Google Pay renders in a browser signed in to a Google account with a saved card, such as Chrome. Save a real card to the account and pay with a sandbox key.

A sandbox payment runs in test mode, so the real card is not charged. Use the test cards to exercise declines and 3D Secure through the card form.

Headless Chrome, Playwright, Puppeteer, and CI browsers have no wallet, so the buttons never render there. Test wallets on a real device.

Before you go live:

  1. Register every live checkout hostname with a live key, including both www and the apex domain if checkout runs on both.
  2. Confirm each one returns validation_status: "active".
  3. Load checkout on a real Apple device and in Chrome, and confirm both buttons appear.

Common errors#

Was this helpful?