Customer accounts

Every buyer who pays you needs somewhere to go afterward: to find an order, track a parcel, change a card, pause a subscription, or start a return. Flint ships that surface, and you decide how much of it is yours.

You do not have to choose once and live with it. Branding, domain, and who serves the pages are independent, and each one moves without touching the others.

Four things you can decide#

DecisionSettingEffort
Use Flint's account as-isnothingnone
Put your brand on itbrandinga few colors
Serve it from your domaincustomer_account.presentation.custom_domainDNS records shown by Flint
Build the account yourselfcustomer_account.modeyour own front end

The first three are the same account with more configuration. Only the last one is a build.

Start from the default#

New merchants already have a working customer account at account.withflintpay.com. Flint authenticates the buyer, and every account link in a receipt, shipping notice, dunning email, or return update points at it.

If that is enough, you are done. The rest of this guide is for taking it over.

Add your brand#

branding styles hosted checkout, transactional email, and the customer account together.

Bash
curl -X PATCH https://api.withflintpay.com/v1/settings \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "branding": {
      "primary_color": "#1B4D3E",
      "background_color": "#F4EFE5",
      "text_color": "#1A1714",
      "font_family": "system_serif",
      "corner_radius": 4
    }
  }'

font_family takes instrument_sans, system_sans, system_serif, or monospace. corner_radius is pixels, 0 to 32.

Then name the account and take Flint's mark off it:

Bash
curl -X PATCH https://api.withflintpay.com/v1/settings \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_account": {
      "mode": "flint_hosted",
      "presentation": {
        "account_name": "Cedar & Stone",
        "is_flint_branding_hidden": true
      }
    }
  }'

account_name defaults to your business name. is_flint_branding_hidden removes the Flint logo and the "Powered by Flint" credit.

Serve it from your own domain#

A branded account still sits on account.withflintpay.com until you give it a hostname of yours.

Register the hostname for payment methods first

Register the exact hostname through payment method domains before setting custom_domain, or the update fails with CUSTOM_DOMAIN_NOT_VERIFIED. This prepares domain-bound payment methods. Flint separately verifies DNS control before activating the hostname.

Use one exact subdomain per environment, such as account.cedarandstone.com. Apex domains such as cedarandstone.com and wildcard hostnames such as *.cedarandstone.com are not supported. Write internationalized hostnames in ASCII/Punycode form. If your DNS provider can proxy the record through another CDN, publish it as DNS-only.

1

Set the domain#

Bash
curl -X PATCH https://api.withflintpay.com/v1/settings \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_account": {
      "mode": "flint_hosted",
      "presentation": { "custom_domain": "account.cedarandstone.com" }
    }
  }'
2

Read the DNS records Flint needs#

customer_account_domain_status appears on the settings object once provisioning starts. It is the only place these records come from; do not guess them.

Bash
curl https://api.withflintpay.com/v1/settings \
  -H "Authorization: Bearer YOUR_API_KEY"
JSON
{
  "customer_account_domain_status": {
    "hostname": "account.cedarandstone.com",
    "domain_status": "provisioning",
    "dns_records": [
      { "dns_record_type": "cname", "name": "account.cedarandstone.com", "value": "account.withflintpay.com" }
    ],
    "last_checked_at": "2026-08-10T17:00:00Z"
  }
}
3

Publish them and wait#

Add every record returned by Flint at your DNS provider. domain_status moves to active once the records resolve and the certificate issues. If it changes to attention_required, confirm that the records still match the response and are not proxied through another CDN. Contact support if they are correct and the status does not recover.

Account links wait for activation

Flint-generated account links use Flint's standard domain until the custom hostname is active. A direct visit to the custom hostname can fail while its DNS or certificate is incomplete. If an active hostname later becomes unhealthy, newly resolved account links return to Flint's standard domain.

Buyers sign in again on their first visit to the custom hostname. Browser sessions do not move between account.withflintpay.com and a customer-owned domain.

The custom hostname serves only the Flint-hosted customer account. Checkout, Payment Links, invoice payment, receipts, and carrier tracking keep their existing destinations.

Or build the account yourself#

Set mode to merchant_hosted when you want your own pages. Flint then stops serving an account and sends every account link into your application instead.

Bash
curl -X PATCH https://api.withflintpay.com/v1/settings \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_account": {
      "mode": "merchant_hosted",
      "merchant_account_url": "https://cedarandstone.com/account",
      "route_templates": {
        "order": "/orders/{resource_id}",
        "subscription": "/subscriptions/{resource_id}",
        "return": "/returns/{resource_id}"
      }
    }
  }'

merchant_account_url is required, and like a custom domain it must sit on a verified payment method domain or a subdomain of one. Without one you get MERCHANT_ACCOUNT_DOMAIN_NOT_VERIFIED.

route_templates are optional. Each is a relative path containing {resource_id} exactly once; anything else returns INVALID_CUSTOMER_ACCOUNT_ROUTE_TEMPLATE. Omit a template and that resource's links land on merchant_account_url.

Links are resolved when the buyer clicks, not when the email is sent. A receipt from last month follows today's configuration, so changing your route templates fixes old mail too.

Building the account is the rest of the work, and it has its own guide: Build your own customer account.

The two modes accept different fields#

flint_hosted and merchant_hosted are not a superset and a subset. Each rejects the other's fields, so a half-applied switch fails loudly instead of silently doing nothing.

You sentWith modeResult
presentationmerchant_hostedCUSTOMER_ACCOUNT_MODE_CONFLICT
merchant_account_url or route_templatesflint_hostedCUSTOMER_ACCOUNT_MODE_CONFLICT
no merchant_account_urlmerchant_hostedCUSTOMER_ACCOUNT_URL_REQUIRED
a hostname not registered as an active payment method domaineitherCUSTOM_DOMAIN_NOT_VERIFIED
anything at a non-merchant scopeeitherCUSTOMER_SETTINGS_REQUIRE_MERCHANT_SCOPE

customer_account is merchant-scoped. It does not inherit to a location or a device, because a buyer's account is not a per-register concept.

The hosted account cannot be iframed

Flint's hosted account sends frame-ancestors deny, so it cannot be embedded in an iframe and there is no setting to allow it. To put the account inside your own page, build it against /v1/me.

Let the buyer change their own email#

A customer's email is their identity, and PATCH /v1/customers/{customer_id} cannot change it. The buyer changes it themselves by confirming both addresses: Flint mails a code to the current address and a code to the new one, and nothing moves until both are confirmed.

An account with no email on file only has to confirm the new address.

Account deletion#

A buyer can ask you to delete their account from either kind of account surface. The request goes to you, not straight through: someone approves or rejects it, and three webhook events report the outcome.

EventMeans
customer.deletion_requestedThe buyer asked. Nothing has changed yet
customer.deletion_completedApproved. The customer is anonymized
customer.deletion_rejectedDeclined

Completion anonymizes the customer rather than erasing history. Orders, payments, and refunds survive without the buyer's identity attached, which is what retention_policy: "retain_required_commerce_records" means. If you keep your own copy of buyer data, customer.deletion_completed is your cue to delete it.

Next steps#

Rate this doc