Skip to main content
Two platform-hosted places carry your patients: the sign-in page (where a login begins) and the member portal (where a patient who has logged in checks out, manages their plan, sees their orders, and completes the hosted identity step). This page covers the sign-in link your storefront uses, what the member portal address is for, and the self-serve path to custom domains. Link your patients to the member portal’s own sign-in route, on your member portal address:
{MEMBER_HOST} is the member portal address in your welcome kit, which shows this exact link. The patient enters their email first, then signs in or signs up on the hosted sign-in page with a password, a passkey, or Google, and lands on their portal home with a member portal session. The test environment’s hosted sign-in page is listed on Environments. The patient must have a member portal session before they pay. The order belongs to the account that is logged in to the portal at payment, and only that account’s portal shows it. Put the sign-in link in front of your buy control. The checkout’s own sign-in step uses the same portal route, so a patient who reaches checkout logged out signs in there before paying.
Do not use the API’s /v1/auth/login as your patients’ sign-in link. The API also serves a sign-in endpoint, $PURPLE_API_BASE/v1/auth/login?brand=brd_.... It signs the patient in on the API host, with a different sign-in application, and returns them there. It does not give the patient a member portal session: a patient who signs in that way is still logged out of the portal, and has to sign in again there before they can see their plan or orders.

The member portal address

The member portal is the platform-hosted address where your logged-in patients land: checkout at /checkout, their orders at /order, their plan, and the hosted identity step at /identity all live there. Your welcome kit names your brand’s member portal address. Use it for your sign-in link, wherever your storefront links a patient “to their account”, and as the base for the checkout and identity handoff links. Until your brand’s member portal address is set up, there is no sign-in link and no checkout.

Custom domains, self-serve

A custom domain is registered per kind — login for the sign-in page, member for the member portal — with your own API key. A brand with no custom domain of a kind simply uses the shared default; nothing in your flow is ever gated on registering one. The ladder is the same for both kinds: choose a hostname → add the CNAME → verify → certificate → active.
In the test environment, a login domain never serves. The calls below answer there, but the CNAME target they return is a placeholder, and your patients keep signing in on the test environment’s hosted sign-in page even when the row reads active.

1. Choose the hostname

The row comes back with the CNAME record to add to your DNS:
Re-sending the same hostname returns the current row unchanged; sending a different hostname for a kind you already registered is a conflict — remove the old one first. Hostnames are globally unique across the platform, so a hostname another brand holds is also a conflict.

2. Add the CNAME record

Create the record exactly as returned — name pointed at value — in your DNS provider. It is a plain hostname pair, never a secret.

3. Verify and advance

Verification checks your CNAME and advances the row toward serving. If DNS has not propagated or the certificate is not ready yet, the row stays where it is and you get a retryable 409 — call it again after a while; the call is idempotent at or past each state it drives to. The two kinds finish differently:
  • A login domain proceeds through certificate issuance to active on its own — verify until the row reads active, and your patients sign in on your hostname.
  • A member domain verifies the same way but stops at the certificate-request state; the final serving switch-on (cert_issued → active) is performed by the platform’s operators once your certificate is issued. You will see the row advance to active without further calls from you.
Read any row back at GET /v1/account/brands/{brand_id}/domains/{kind}, or list both — each row carries its current state, so polling the read is how you watch the ladder move:

Removing a custom domain

DELETE /v1/account/brands/{brand_id}/domains/{kind} removes the row and reverts that kind to the shared-domain default. All the domain endpoints are key-scoped and tenant-isolated the same way as the rest of your account surface: the path brand_id must match your X-Brand-Id, and a foreign, unknown, or mismatched brand answers 404, never 403 — no cross-tenant existence leak.