Agency Workspace
/agency is a separate, white-labeled workspace that sits above a list
of clients. Instead of one Google account owning one set of
locations (the solo flow), an Agency record holds your branding, your
plan, and your default feature access — and each client attached to it
is a real user with their own Google login, their own GBP locations,
and their own credit balance.
The workspace unifies them. You see every client's portfolio on one dashboard, ship branded reports under your domain, and gate which features each client gets. Clients sign in to their dashboard, scoped to their locations, wearing your logo and color.
Setting Up Your Agency
- 1
Sign up at /agency
Open
/agency. If you don't have an agency yet, the page shows AgencySignupFlow — pick Starter or Pro, monthly or annual, set yourbranding.companyNameandprimaryColor, and check out through Stripe. Once the Stripe webhook lands, the workspace provisions and you drop into the agency dashboard. Starter includes 100 locations / month at $500/mo or $5,000/yr; Pro includes 1,000 / month at $4,000/mo or $40,000/yr (AGENCY_PLAN_LIMITSinmodels/Agency.ts). - 2
Configure white-label branding
Open
/agency/settings. Set your logo, primary color, support email, and (Pro) a custom domain. The branding schema (agency.branding) coverscompanyName,logoUrl,faviconUrl,primaryColor,accentColor,customDomain,customDomainVerified,supportEmail, andhidePoweredBy. A second record —AgencySettings— holdslogoUrl,brandColors.primary, andcustomFooterTextused by PDF/PPTX reports. Both layers cascade into client emails, dashboards, and deliverables. - 3
Set per-feature access defaults
Still on
/agency/settings, set the nine feature flags that apply by default to every new client. Each flag is'off','readonly', or'full':heatmap,reviews,posts,analytics,aiContent,qrGenerator,competitorTracking,keywordRankings,profileEdit. Defaults are all'full'(DEFAULT_AGENCY_FEATURES). Changing one here flips the default for every client without an override. - 4
Invite your first client
Open
/agency/clients→ Invite a Client. Enter the email and send. If they already have a GMBMantra account, they're attached immediately (added: truein the invite response). If they don't, we create anAgencyInviterow with a signedtoken, expire it in 7 days (INVITE_TTL_DAYS = 7), and email the link. They sign in with their own Google account — that's how their GBP scope comes through — and the invite flips to'accepted'. - 5
Switch into a client view
From
/agency/clients/[clientId]you can override any of the nine feature flags for that single client (or leave atnullto inherit), toggle Active to pause/resume the link, or hit Impersonate to drop into their dashboard with your agency identity logged on the session. Use impersonate when you need to reproduce something a client is seeing or top up their credits on their behalf.
Key Concepts
One owner, no roles matrix
Agency.ownerId is a single string — there is no team-roles matrix in
the workspace today. Agencies that need multiple humans either share
the owner login or have each teammate operate through their own client
account. If you need granular admin / viewer / billing roles, that's a
roadmap item — email support@gmbmantra.ai.
Plan tiers — Starter vs Pro
The unit is Monthly Active Locations (MAL): a location counts once
per calendar month the first time any billable sync happens for it.
The Agency plan limits live in AGENCY_PLAN_LIMITS:
- Starter —
maxClients: 100, overage $5 per extra location, $500/mo or $5,000/yr. - Pro —
maxClients: 1000, overage $4 per extra location, $4,000/mo or $40,000/yr.
The /agency MAL gauge tracks malCount / malIncludedSeats and
overage routes to a Stripe metered subscription item
(overageStripeItemId).
The nine feature flags
agency.features is the agency-wide default set. Each is one of
'off' | 'readonly' | 'full':
heatmapreviewspostsanalyticsaiContentqrGeneratorcompetitorTrackingkeywordRankingsprofileEdit
The agency-level value is the default for every client. Per-client
overrides on /agency/clients/[clientId] beat the default; null
means "inherit". A client whose analytics flag is 'readonly' sees
the analytics screen but can't edit its filters or schedules.
Invites — 7-day TTL, signed token
AgencyInvite carries a secure random token, an email, an
agencyId, and expiresAt = now + 7d. Status moves
'pending' → 'accepted' (when the invitee signs in via Google) or
'revoked' (if you cancel from the agency UI). MongoDB also TTL-deletes
expired pending rows about 8 days after expiresAt.
White-label cascade — agency, settings, subscription
Three layers of branding are resolved per send, in order: subscription override → agency defaults → system defaults.
agency.branding—companyName,primaryColor,customDomain,faviconUrl,hidePoweredBy,supportEmail. Powers the dashboard chrome and the email wrappers.AgencySettings—logoUrl,brandColors.primary,customFooterText. Powers the PDF/PPTX reports specifically.ReportSubscription.branding—logoR2Key,primaryColor,footerText. Per-subscription override for one client's report.
A verified customDomain (with customDomainVerified: true) flips
your clients onto your hostname, your logo, your color, your support
email, and — if hidePoweredBy: true — drops the GMBMantra footer
entirely.
Pro Tip
CreditAccount is keyed by userId); there is no shared agency credit pool today. For Pro agencies, a central googlePlacesApiKey on the Agency record is the one piece of cost you can centralize, and only for heatmap scans.Frequently Asked
Related
Running an Agency Workspace
The top-level agency overview — sign up, first client, scheduled reports, MAL gauge.
Report Builder
Scheduled PDF/PPTX reports with per-client branding, custom recipients, retry handling, and the three-layer branding cascade.
Credits & Billing
How agency Starter/Pro billing works against MAL, and why each client carries their own credit balance instead of sharing a pool.