Insights
What $99 a month buys a clinical practice

A price printed on a page is a promise you cannot quietly take back. Since the end of August, Grow Your Clinical Practice, the subscription I built for therapists, counselors and prescribers, has carried two of them: Foundation at $99 a month, Foundation plus Local at $199 a month, and a $500 setup fee that happens once. I read all three off the live pricing page again on 4 September 2026 before writing this, because a post about your own product is the easiest place in the world to quote yourself from memory and be wrong.
What follows is what those numbers include, and the decision inside the signup that took longest to settle: the card comes after the intake, not before it.
What is in the $99 tier, and what is in the $199 one?
Foundation is the site plus everything that keeps it from going stale. Local adds the pages and the profile work that local search actually rewards. Here is the comparison as the pricing page has it, read on 4 September 2026.
| Foundation, $99 a month | Foundation + Local, $199 a month | |
|---|---|---|
| Site | Built from your intake. Home, about, one page per specialty, fees, contact, privacy. You edit your own copy. | Same, plus a page for each specialty in each city you serve, generated from your profile |
| Forms | Contact and consult request, no third-party scripts, spam screened | Same |
| Consult booking | On your Google Workspace or Outlook calendar; confirmations and a video link go out automatically | Same |
| Google Business Profile | Claimed, categories and services set, hours synced | Plus posts drafted from your pages weekly, approved with one tap |
| Search | Schema, sitemap, IndexNow on publish, Search Console connected, monthly report by email | Plus rank tracking on your specialty terms |
| Audit | Quarterly automated crawl; I read the flags | Same |
| Reviews | Review card that asks every client the same way, never gates | Plus drafted responses for you to send |
| Directory (Oregon) | orcounselors Pro listing, synced from your profile | Featured placement |
| Monitoring | Uptime and SSL, daily | Same |
| Term | Month to month, cancel from the dashboard, no cancellation fee. Setup $500, once, either tier. | |
One row in that table is not portable. The Pro listing sits on the Oregon directory I built and run, where every provider is checked against the state boards, a slower business than it sounds and the subject of building trust with thousands of providers. Everything else works anywhere in the United States.
The page carries its own arithmetic, and I would rather it be checkable than flattering: a private-pay clinician in Oregon charging $150 a session who takes one new client from the site in a year, and sees that client twelve times, has covered Foundation and the setup fee. An illustration of the shape, not a forecast, and the page says so.
Why does the card come after the intake, not before?
Because the intake is the product's first input, not a form standing politely in front of a checkout. A practice site cannot be drafted from an email address. It needs the license type and state, the specialties and populations, the city or telehealth-only, the fee posture, the consult hours, a bio in the clinician's own words. That one record generates the site, the Google profile and the directory listing, which is why the signup is a form first and a payment second.
The whole ordering lives in the last few lines of the handler:
$lead = Leads::create($in, 'gycp', $genuine);
Database::update('leads', ['type' => 'gycp'], 'id = ?', [$lead['id']]);
if ($genuine && function_exists('stripe_gycp_checkout') && ($pay = stripe_gycp_checkout($lead))) {
header('Location: ' . $pay, true, 303);
exit;
}
redirect(trim(GYCP_BASE . '/thanks', '/'));
Three things fall out of writing the lead first. The business associate agreement and the terms are ticked and stamped (baa_accepted_at on the lead's JSON) before any money exists, so consent is recorded even for a signup that never pays. A submission the spam screen does not believe in never becomes a Stripe customer, because $genuine gates the hand-off rather than the storage. And if Stripe is switched off, stripe_gycp_checkout() returns null and the clinician lands on the thanks page with the intake saved, rather than on an error while holding a card.
The session carries both charges: mode=subscription, line item zero the monthly tier price, line item one the $500 setup. The lead id rides along as client_reference_id, the thread that ties a Stripe customer back to the intake it came from, and the idempotency key is built from that id plus a short hash of the email and tier, so a clinician who double-taps submit gets the same session back rather than a second subscription.
What is the webhook actually for?
It is the record. The redirect back to my site is a courtesy. Stripe is unusually blunt about this in its own fulfillment guide:
You can't rely on triggering fulfillment only from your Checkout landing page, because it's not guaranteed customers visit that page. For example, a customer can pay successfully and then lose their internet connection before your landing page loads.
So the payment is recorded by a signed event, and the thanks page only reports status. It will not look up a session id unless that id already sits on one of my own leads, because a page that reads an identifier out of a query string is a page a stranger can point anywhere.
There is no Stripe SDK in this codebase. The client is one file: curl, form-encoded bodies, the API version pinned to 2026-08-26.dahlia in a constant, an Idempotency-Key header on every write, and about twenty lines that verify a signature. Stripe publishes the manual steps for that last part, and they come to HMAC-SHA256 over "{t}.{payload}" with the endpoint secret, compared in constant time, rejected when the timestamp is stale. Their libraries default to a five minute tolerance; mine uses 300 seconds and hash_equals(). Keys and the signing secret live in settings rows, never in code, so the same deployed files run a sandbox locally and the live account in production.
The part worth copying is the replay gate. Stripe's guidance is plain about duplicates:
Webhook endpoints might occasionally receive the same event more than once. You can guard against duplicated event receipts by logging the event IDs you've processed, and then not processing already-logged events.
Mine is a table with one interesting column, the event id as the primary key. The insert is the gate, and only a duplicate-key error counts as "seen":
try {
Database::insert('stripe_events', ['id' => $ev['id'], 'type' => $ev['type'] ?? '', ...]);
} catch (PDOException $e) {
if ((string) $e->getCode() === '23000') { http_response_code(200); echo 'already seen'; return; }
http_response_code(500); echo 'not recorded'; return; // table missing, pool down: let Stripe retry
}
That leaves one hole, and the first version of this handler had it. The event is recorded before the work is done, so a handler that throws halfway through has already told the table this event was processed. Stripe retries, my own gate answers "already seen", and a paid subscription sits in the database as an unpaid lead forever. An adversarial review pass over the diff found it on 27 August 2026, before any of this reached the live account. The fix is four lines.
} catch (Throwable $e) {
/* processing failed after the event was recorded: forget it so the retry
is not answered "already seen" */
Database::query('DELETE FROM stripe_events WHERE id = ?', [$ev['id']]);
http_response_code(500); echo 'failed'; return;
}
The general rule is the one I keep arriving at from different directions, most recently in agentic loops that run unattended: a record that something happened has to be revocable, or it stops being a record and becomes a claim. Stripe retries a failed delivery for up to three days in live mode and does not guarantee event order, so the endpoint has to be safe to hit twice and out of sequence. The writes are a single JSON_MERGE_PATCH statement for that reason: two deliveries landing at the same instant cannot overwrite each other's fields.
Why does a practice site refuse tracking scripts?
Because a booking form on a clinician's website can pull an analytics vendor inside HIPAA, and the Office for Civil Rights wrote down that exact example:
if an individual makes an appointment through the website of a covered health clinic for health services and that website uses third party tracking technologies, then the website might automatically transmit information regarding the appointment and the individual's IP address to a tracking technology vendor. In this case, the tracking technology vendor is a business associate, and a BAA is required.
That bulletin has been narrowed since, and the narrowing matters, so here is the notice HHS now carries at the top of the same page: on 20 June 2024 the US District Court for the Northern District of Texas declared unlawful and vacated the portion of the guidance that triggered HIPAA obligations where a technology connects an individual's IP address with a visit to an unauthenticated public webpage about specific health conditions or providers (Am. Hosp. Ass'n v. Becerra, No. 4:23-cv-1110). Read carefully, what the court took away was the ordinary browsing case. The appointment case above, and anything behind a login, was not touched.
So the line I hold sits inside what survived: no Meta pixel, no third-party analytics, no external chat widget on any page of a clinician's site that carries a form. Traffic is measured from the server log and from Search Console, which reports on searches rather than on people. The one third-party script left on a form page is Cloudflare's spam check, running on the network that already delivers the page.
I ran a private practice from 2019 until I closed it in July 2026, and I still do clinical work, so the test I apply to a script is the one I used to have to answer for myself: would I have wanted this on my own intake page. Faster than a checklist, and it has not yet disagreed with one.
The calendar follows the same logic. Consult bookings are written to the clinician's own calendar rather than one I hold, and onboarding asks for a Google Workspace or Microsoft 365 account rather than a personal one: Google offers a business associate agreement to Workspace customers, and Google Calendar is named on its HIPAA Included Functionality list as of 31 August 2026. A free consumer calendar is on no such list, and the booking page does not go live on one.
Why can the review card not be aimed?
Because the rules my own license sits under say testimonials are not solicited from current clients, and a review tool that lets a practice choose who gets asked is a tool built to break them. Oregon's rule is one sentence:
Testimonials from current clients are not solicited for advertising or other purposes due to the client's vulnerability to undue influence.
That is OAR 833-100-0012(3). The APA's Ethics Code draws its line in the same place at 5.05, which covers current therapy clients and anyone else whose particular circumstances leave them vulnerable to undue influence. The ACA's goes further than both: C.3.b says counselors who use testimonials "do not solicit them from current clients, former clients, or any other persons who may be vulnerable to undue influence."
So the review card asks after care ends, asks everyone the same way, and routes the person to Google's own public review form. Nobody, including me, gets to pick who is invited or to see the rating before it is public. That clears the Oregon rule and the APA code. It does not clear C.3.b by itself, because a former client is exactly who it asks, and a review tool cannot settle that for a counselor who holds to the ACA code. It is a question for the practice, and the page now hands it over as one instead of listing three codes as though they agreed.
Writing this section sent me to the primary source and cost my own page a sentence. My page for therapists said routing reviews this way "is also what the FTC's 2024 review rule requires". The Rule on the Use of Consumer Reviews and Testimonials (16 CFR part 465) took effect on 21 October 2024, and it is narrower than that. Asked whether a business may solicit reviews only from customers it thinks are happy, the FTC's own questions and answers state that "the rule does not contain a specific prohibition against such conduct." A separate answer in the same document notes that "the use of non-representative consumer reviews in marketing could be deceptive in violation of Section 5 of the FTC Act." What 16 CFR part 465 does ban is fake reviews, paying for a particular sentiment, and suppressing the ones you did not like. The boards are the binding rule here. The FTC Act is the backstop. The page overstated it by one word, which I found on the evening of 4 September 2026 while writing this paragraph and corrected before this post went up.
What is deliberately left out?
Ads, social posting and monthly written content, all three of which carry real recurring labor, plus everything an EHR does. Those are not oversights, they are what holds the price. At $99 a month the only shape that survives is a tier where nothing needs a person every month: the search report generates itself, the audit crawls on a schedule, publishing pings the search engines, the listing reads from the same profile as the site.
The choice of what goes in the tier is not arbitrary either. Heard's 2026 Financial State of Private Practice report, a survey of 1,950 therapists across all fifty states and DC, found referrals and word of mouth at 83 percent and online directories at 82 percent of how clinicians get clients, with Google and SEO at 31 percent and social media last at 12 percent. The median practice spends about $500 a year on marketing. Those two facts together decided the product: the money goes to the two channels that already work, and a referral still ends in somebody typing a name into Google, usually on a phone between other things, which is both the moment a stale profile costs a client and the reason every page on the engine is written phone first, for one thumb. I wrote about that failure mode in more detail in why a therapy practice does not show up on Google.
Whitespark's 2026 Local Search Ranking Factors report, published 6 November 2025 from a survey of 47 local search practitioners, puts Google Business Profile signals as the highest weighted group for the local pack, with review signals next. That ordering, rather than any percentage, is what the tiers are built on. It is why the profile is claimed and configured inside Foundation rather than sold as an upgrade.
What writing this post found, and fixed the same evening
Reading my own pages against my own code is an audit, and the pages lost three times. The FTC sentence above is one. The second sits in the same section, which listed the ACA code beside the APA's and Oregon's as though all three stopped at current clients. The third was on the signup page, which promised "a draft link and the setup invoice" and said setup was "$500 once, on the invoice." True of the first version, and not true since 27 August 2026, when Checkout went in: the $500 is a second line item on the same session as the first month, and what arrives is a Stripe receipt and a private billing portal link. The code was right and the copy was behind it.
All three were found on 4 September 2026 while writing this post and rewritten the same evening, along with a fourth edit to the pricing page marking its worked example as an illustration rather than a forecast. The corrected text lives in the module's defaults file, where a fresh install reads it, and reaches the running site through a migration that only replaces a string still holding exactly what shipped, so a sentence someone edited in the dashboard is never overwritten and a second run changes nothing. The screenshots in this post are the pages as they were before that.
The proof page has a harder gap on it, and I am not going to dress that one up. The first clinicians on Foundation are on a three-month pilot: full service, in exchange for permission to publish their monthly search reports, named or not, their choice. No such report exists yet, so what that page currently shows is other people's sites on the same engine and a promise about what will replace them. The number I want there is a clinician's own first month, flat months included. Until one exists, the honest content of a pricing page is arithmetic and a cancel button.
Common questions
How much does the Grow Your Clinical Practice subscription cost?
Foundation is $99 a month and Foundation plus Local is $199 a month, with a $500 setup fee charged once, read off the live pricing page on 4 September 2026. The term is month to month, cancelled from the dashboard, with no cancellation fee. Ads, social posting and monthly written content are not included and are priced separately.
Why does the signup form come before the payment?
Because the intake is the record the site, the Google Business Profile and the directory listing are all generated from, so it is saved first whether or not the card ever clears. Writing the lead first also means the business associate agreement and the terms are stamped before money exists, and a submission the spam screen rejects never becomes a Stripe customer.
Can a therapy practice website run Google Analytics or a Meta pixel?
Not on a page with a form on it, if you want the cautious reading. The HHS Office for Civil Rights gave the example of an appointment booked through a covered clinic website, where the tracking vendor becomes a business associate and a BAA is required. A 2024 court order vacated the part of that guidance covering ordinary unauthenticated browsing, but left the form and booking case standing.
Why does the payment need a webhook if the browser comes back anyway?
Because the browser might not. Stripe states that you cannot rely on fulfillment from the Checkout landing page, since a customer can pay and then lose their connection before it loads. The signed webhook is the record; the redirect only reports status, and only for a session that already belongs to one of my own leads.
Can a therapist ask happy clients for a Google review?
Not current clients. OAR 833-100-0012(3) says testimonials from current clients are not solicited for advertising or other purposes due to vulnerability to undue influence, and the APA Ethics Code says the same at 5.05 for current therapy clients and anyone else vulnerable to undue influence. The ACA Code of Ethics C.3.b goes further and rules out former clients as well, which is a line a counselor has to hold for their own practice. The FTC review rule effective 21 October 2024 is narrower on this specific point, but using non-representative reviews in marketing can still be deceptive under Section 5 of the FTC Act.
Related