# GHL Payments → Products — Building a Subscription Product in the UI

Field-by-field guide for creating a recurring-subscription product in GHL's Payments UI. Written 2026-08-10 while building "The Premium Line" ($497/mo, $0-today trial billing on the 1st) for the RRR bail-bonds funnel. The Products API is NOT agent-reachable (V3 agency token 401s `/products`, per-endpoint authClass) — this is a UI-only, walk-the-user-through-it surface. Verify results by having the user screenshot the Products list and reading it with vision_analyze.

## The create form, field by field

Path: sub-account view (NOT agency view) → Payments → Products → + Create Product. Confirm the form is BLANK before typing — if it shows an existing product's name/price, the user clicked edit, not create.

| Field | What to set | Notes |
|---|---|---|
| Title | The product name | Watch user typos — they propagate to Stripe |
| Product Label | SKIP | This is a storefront ribbon ("New"/"Sale") with optional start/end DISPLAY dates. Those dates are NOT subscription billing dates — pure marketing decoration for online stores. Irrelevant for funnel-only sales. |
| Product Tax Category | No | RRR = CO LLC selling subscription services; no sales-tax collection at current scale. "Yes" forces Automatic Taxes or an uploaded tax schedule. |
| Statement Descriptor | Leave default | What appears on the customer's bank statement (defaults to the LLC name). |
| Product Media | Skip | Optional thumbnail; services don't need one. |
| Price | e.g. 497 | — |
| Billing Period | Monthly | For recurring subs. |
| Trial Period | NUMBER OF DAYS — see below | The critical field. |
| Number of Payments | blank / ongoing / 0 | "Never expires" for a lifetime-rate subscription. Do NOT cap it. |
| Setup Fee | 0 / blank | When the copy says "Setup: free ($1,500 value)" the $1,500 is marketing framing only — entering it here CHARGES it today. |
| Include in Online Store | OFF | ON = publicly visible/purchasable on the GHL storefront. OFF = invisible publicly but STILL attachable to any funnel Order Form element. Funnel-only sales = OFF. |
| Track Inventory | OFF | Services have no stock count. |
| Product Type | Digital if offered | See quirk below. |

## Product type quirk (confirmed by user 2026-08-10)

GHL offers only **Physical** or **Digital** — there is no Service/Subscription type, and the type is NOT changeable after creation (all of RRR's existing subscriptions are tagged Physical for this reason). Functional difference per GHL docs: **Physical adds shipping-address fields at checkout; Digital skips them.** Prefer Digital for services to keep checkout clean; if the account defaulted to Physical and won't allow changing, it still bills fine — just note the extra shipping block on the order form.

## Trial Period = day count, NOT a date (the fixed-date trap)

The trial field takes a simple integer of days from signup. There is no "bill on the 1st of next month" picker. To honor "$0 today, first charge on the 1st":
- Compute days from TODAY to the target 1st (e.g. Aug 10 → Sep 1 = **22 days**).
- The fixed date only holds for signups during the current month. An Aug 15 signup with a 22-day trial bills Sep 6, not Sep 1.
- **Recompute and edit the trial day-count on the 1st of each month** while the offer runs (Sep 1 → 30 days to Oct 1, etc.). Put this in the operator checklist for any fixed-date trial offer.

## Duplicate-name trap (hit live 2026-08-10)

Renaming an existing product leaves two same-named products with different prices (old "Growth" $479 renamed → duplicate "The Premium Line" rows at $479 and $497). ALWAYS create fresh rather than renaming/reusing a mismatched product, then check the Products list for dupes and delete the stale one. The list view shows name/price/type/updated-timestamp — enough to verify via screenshot + vision_analyze (timestamps disambiguate which row is the new one).

## Verification without API access

Products/payments endpoints 401 under the V3 agency token, so verification is user-screenshot-based:
1. Products list shows the new product at the right price, one row only.
2. Clicking into the product shows an "Additional Information" panel with Internal Product Id + a Stripe integration row (LIVE badge + `prod_...` id) once saved — proof it synced to the connected Stripe account.
3. Old/mismatched products left in the list: have the user delete them via the ⋮ menu to prevent order-form mis-wiring later.
