The moment you open your second location, your billing stack stops being a spreadsheet question and starts being an architecture question. Members who roam between sites. Different rates per city. One Stripe account or many? One Xero organisation or several? Roll-up dashboards your investors will ask about.
This playbook is the architecture LiteHQ ships out of the box, plus the operator decisions you still have to make. Read it before opening site two. Re-read it before site four — that's the threshold where the “just throw it in one spreadsheet” pattern breaks for everyone we've seen.
One sentence to start with. You have one host (your operator entity), N locations(physical sites), and M tenant companies (your customers, possibly members of multiple locations). The host is the billing recipient; the locations are pricing surfaces; tenants are the consumer of access.
Section 1
Single-tenant vs multi-tenant
15 min · architecture · whiteboard
Coworking billing has two layers — the host layer (you, the operator) and the tenantlayer (your member companies). At one location they collapse together and people miss the distinction. At three locations the distinction starts to matter; at five, it's load-bearing.
The two tenancy patterns
- Single-tenant. One Stripe account, one Xero org, one host record. All N locations bill through this one entity. Simplest. Works up to ~3 sites. Members on a multi-site plan see one charge.
- Multi-tenant. One host that owns N locations, each location with its own legal entity and Stripe account (still under your platform). Members on a multi-site plan see N charges — one per location they visit, or one consolidated charge if you ship a roll-up product. More moving parts; required if locations are in different countries or sub-entities.
Topology
In LiteHQ, the hosts table holds your operator entity; companies with host_id set are your tenants. A tenant company that belongs to a host with multiple locations can be granted access to any subset of those locations via memberships.
We launched two sites on one Stripe account. By site three we'd wired in our accountant 8 times in 6 weeks to chase a reconciliation issue. Splitting tenants out was the single best two-week project we shipped that year.
Sketch your topology on paper before you wire it. If you're <3 sites, single-tenant is fine. If you have any cross-border or sub-entity complexity, plan multi-tenant from the start.
Section 2
Per-location pricing
20 min · rate card per site · the boring grunt work
Each location gets its own rate card. The temptation is to copy-paste from your flagship — don't. CBD rents are 2x suburban; you'd have to either bleed margin or charge premium-flagship rates for an outer-suburb room. Both kill demand.
The three pricing dimensions per location
- Membership tier price. Pegged to the local market. Most chains ship 2-3 price tiers: flagship/CBD, premium/secondary city, standard/suburban.
- Resource price. Meeting rooms, day passes, podcast booths. These are configured per-room (which lives at a location). Token cost is set per-resource; see the token playbook for calibration.
- Token allocation.Members get tokens with their tier; the tokens are spendable at any location they have access to. A “CBD Plus” member might get 300 tokens that work at all 4 sites; a “Local” member might get 200 tokens that only work at one.
{
"host_id": "stretch-nz",
"locations": [
{
"id": "sale-st", "label": "Sale St (CBD)", "tier": "flagship",
"membership_monthly": 349, "day_pass": 45, "room_rate_multiplier": 1.0
},
{
"id": "ponsonby", "label": "Ponsonby (Premium)", "tier": "premium",
"membership_monthly": 279, "day_pass": 38, "room_rate_multiplier": 0.9
},
{
"id": "henderson", "label": "Henderson (Standard)", "tier": "standard",
"membership_monthly": 199, "day_pass": 30, "room_rate_multiplier": 0.75
}
]
}Build a one-page sheet for each location: tier price, day-pass price, room multiplier, token allocation. Walk it past your finance lead before you ship.
Section 3
Cross-location member access
20 min · membership UX · the ‘is it roaming or one-off?’ question
Once you have N locations, members will ask: “Can I work from the other site?” The answer needs to be in your product, not in your front desk's head. Two patterns work; pick one.
The two cross-location patterns
- Home-site + day pass. Member pays at their home site; visits to other sites are charged as day passes (deducted from token bundle or cash). Simple, fair, easy to explain.
- All-sites tier. Premium tier that includes access at all sites with no per-day deduction. Bundle revenue, simpler UX for power users; harder to margin-manage.
Both patterns are first-class in LiteHQ. The membership row carries alocations array — the list of locations the member can access without a day-pass deduction. Other location visits trigger a token-or-cash charge per the local rate card.
Pattern decision tree
Most operators ship this first. Cheaper to run, easier to explain.
Add as a premium tier later, once you have heavy roamers asking for it.
Look at last quarter's data: how many members visited 2+ sites? If <10%, ship home-site + day pass. If >20%, you have a market for an all-sites tier.
Section 4
Roll-up reporting
10 min · the dashboard your investors will ask about
At one site you check the dashboard; at four, you live on the roll-up. The roll-up is the per-host view that aggregates across locations. Three numbers matter; the rest is interesting but not load-bearing.
The three roll-up numbers
- Total host MRR.Sum of all tenants' recurring subscriptions across all locations. The one your investor asks about.
- Per-location MRR + utilisation.A side-by-side that lets you spot underperforming sites in 10 seconds. The lowest-MRR site might be your best-utilised — that's a pricing-power signal, not a problem.
- Cross-site member share. Of all members, what % visit more than one site? Low number = your locations are independent businesses; high number = you have a network effect, price your all-sites tier accordingly.
-- Per-location MRR + utilisation, this month
SELECT l.id, l.label,
sum(s.monthly_amount) AS mrr,
round(avg(b.utilisation), 2) AS avg_utilisation_pct,
count(DISTINCT m.id) AS members
FROM locations l
LEFT JOIN memberships m ON m.location_id = l.id AND m.status = 'active'
LEFT JOIN subscriptions s ON s.id = m.subscription_id
LEFT JOIN room_utilisation b ON b.location_id = l.id
AND b.month = date_trunc('month', now())
WHERE l.host_id = $1
GROUP BY l.id, l.label
ORDER BY mrr DESC;Bookmark the roll-up. Check it Monday morning before you check any individual location. The order is the message — what's upstream, what's downstream.
Section 5
Stripe Connect topology
30-60 min · with your finance lead · once-and-done
LiteHQ uses Stripe Connect — the host is the Connect account holder; tenant payments flow through the platform with the host as the merchant of record. This holds for both single-tenant and multi-tenant models; the only thing that changes is the number of Connect accounts.
Single-tenant Stripe topology
- One Connect account for the host operator (you).
- One Customer per tenant company, with that tenant's billing contact as the cardholder.
- Subscriptions on the Customer, with metadata identifying the location each subscription is billing for.
- Two webhook secrets — platform (your main account) and Connect (for events from the Connect account). LiteHQ verifies both.
Multi-tenant Stripe topology
- One Connect account per legal entity. Most chains have one per country, sometimes one per location.
- Same Customer pattern, but Customers are scoped to the Connect account that owns them. A tenant company billing at two locations might have two Customers under different Connect accounts.
- Roll-up reconciliation happens in LiteHQ, not in Stripe — Stripe shows you per-account totals; LiteHQ joins them via the host record.
single-tenant:
host (Connect account)
└── tenants (Customers)
└── subscriptions (location metadata)
multi-tenant (chain across NZ + AU):
host
├── NZ Connect account
│ └── NZ tenants
│ └── subscriptions
└── AU Connect account
└── AU tenants
└── subscriptionsWe split into two Connect accounts the week we opened in Sydney. It cost two engineering days and saved us a six-figure GST/VAT reconciliation nightmare at year-end.
Whiteboard your Stripe topology before you wire it. The cost of splitting Connect accounts later is one of the highest-friction operations you can do; the cost of splitting up-front is two engineering days.
Section 6
Xero rules
20 min · the bookkeeper will love you · KARO-222 reference
Xero is where the multi-location complexity collapses if you get the rules right. Two rules, both load-bearing.
Rule 1 · One Xero organisation per legal entity
If your locations are in one legal entity, they belong in one Xero org. If they span entities (NZ + AU), each entity gets its own Xero org and its own Connect account. Don't try to model multi-entity in one Xero org — Xero is built around the org-as-entity assumption and you'll fight it forever.
Rule 2 · Per-line tax types, never a standalone GST line
This is the one that bit us hardest, documented as KARO-222 in our internal Linear. LiteHQ invoices have multiple line items: Booking Fee, Stripe Fee, sometimes Room Hire, sometimes Day Pass. Each line gets its own TaxType set explicitly — Booking Fee and Room Hire as OUTPUT2 (standard NZ GST), Stripe Fee as NONE (exempt), with LineAmountTypes: 'Exclusive'on the invoice envelope.
DO NOT add a standalone “GST (15%)” line. Xero will treat it as a taxable line and add 15% on top of it (yes, GST on GST). Invoices end up 15% higher than what we actually charged. The fix lives in xero-client.ts:933 and includes a defensive filter that drops any legacy GST line items still sitting in the DB.
{
"Type": "ACCREC",
"LineAmountTypes": "Exclusive",
"LineItems": [
{ "Description": "Atrium · 14:00-17:00", "UnitAmount": 180.00, "TaxType": "OUTPUT2" },
{ "Description": "Stripe processing fee", "UnitAmount": 5.40, "TaxType": "NONE" }
]
}The void path is inline, not cron-eventual
One more KARO-221 footnote: when a booking is cancelled and its local invoice flips to void, you have to call XeroClient.voidInvoice() inline. The cron-xero-syncdaily job only syncs in-flight invoices — once a local row is in a terminal status it's skipped forever. Don't rely on the cron to catch up.
Audit your current Xero invoices. If any of them have a standalone “GST (15%)” line, you have a 15% overcharge to refund. Run the reconciliation script from KARO-222 to find them.
Key takeaways
Six things to keep, even if you remember nothing else.
- Host / Location / Tenant. Three layers. The host is the billing recipient; locations are pricing surfaces; tenants are the consumer of access.
- Single-tenant up to ~3 sites. Multi-tenant for cross-border or sub-entity complexity.
- Per-location pricing, shared tokens. Rate card differs by site; tokens travel with the member.
- Home-site + day pass first. Ship the simpler pattern; add the all-sites tier when data justifies it.
- Stripe Connect, split early. Splitting later is high-friction. Plan it up-front.
- Xero per-line tax (KARO-222). No standalone GST line, ever. One Xero org per legal entity.