Skip to main content

Agency Portal — Overview

Audience: Sales / Agency-success / Management (engineers for the technical section) · Where in app: Agency Portal (separate nav once an agency exists) · Plan availability: Enterprise / agency tier (the agency portal is its own subscription)

The agency portal turns Knock Knock into a reseller-friendly platform. An agency manages many client companies ("sub-accounts") under its own brand, sets its own pricing via custom packages, and bills its clients while paying Knock Knock for the underlying platform.

What it does

  • One owner manages all sub-accounts from a single dashboard.
  • Sell at any markup with agency packages and agency add-ons (custom pricing/currency).
  • Create client accounts directly (no client self-signup needed) — including from a GoHighLevel sub-account.
  • White-label the widget, portal (custom domain), emails, the Nox assistant name, and the desktop app.
  • Track per-sub-account revenue and churn; manage agency staff with scoped permissions.

How it works

An AgencyModel row (collection agencies) is owned by a user and holds the agency's brand, sub-account counts, and references to its packages/add-ons. The agency subscribes to an agency package (AgencyPackageModel) which grants a number of sub-account slots; Stripe bills the agency. The agency then creates client companies, each linked back via companies.agency_id. Each sub-account can have its own company subscription, but the company admin can't change its own plan — they see a "Contact agency" gate. When the agency's subscription renews, sub-account allowances and AI credits are refreshed across all its companies.

Configuration & options

Agency model (AgencyModel, collection agencies)

FieldDefaultWhat
user_idAgency owner
name''Agency name
logo_filenullBranding logo (FileModel ref)
initial_ai_credits1500Pooled AI credits across sub-accounts unless customized
total_sub_accounts / available_sub_accounts0Slot counts (granted vs. remaining)
agency_packages[] / agency_addons[]Refs to the agency's SKUs
theme_colorsteal paletteprimary, secondary, accent, sidebar_bg, sidebar_text, header_bg, header_text
nox_namenullWhite-label display name for the Nox assistant
reply_emailnullSender for automated agency emails
go_high_levelGHL OAuth tokens + config (app_version defaults v1)
trial / trial_duration / trial_activated_at / expiryAgency trial state
payment_issuefalseFlag for billing problems
deleted_atnullSoft-delete

Agency packages (AgencyPackageModel, collection agency_packages)

The SKUs the agency sells to clients (custom title, description, features, limits, user count, AI credits, expiry):

FieldDefaultWhat
name, descriptionPackage identity
amountCustom price
currencyusdAny Stripe-supported currency
sub_accountsSub-account slots granted by this plan
trialfalseTrial package
stripe_product_id / stripe_price_idStripe linkage
package_typeprivateprivate / public
statusactiveactive / inactive

Packages can also restrict access by email allow-list, set an expiry (for time-limited promos), and define user counts and AI-credit allotments (per the customer-facing Packages screen).

Agency add-ons (AgencyAddonModel, collection agency_addons)

FieldDefaultWhat
name, description, amountAdd-on identity + price
currencyusd
typesub_accountAdd-on category
billing_typerecurringone_time / recurring
visibilitypublicprivate / public
statusactiveactive / inactive

The most common add-on is extra sub-accounts. Add-ons can be bought for the agency itself or applied to a specific client company.

Agency subscription (AgencySubscriptionModel, collection agency_subscription)

agency_id, user_id, package_id, new_package_id (scheduled downgrade at cycle end), expiry_date, is_trial, stripe_id, status (active / inactive / canceled), canceled_at, cancel_reason. Renews monthly.

Agency staff

Staff are UserModel rows with user_type: 'agency_staff', linked via agency_id and a parent (the agency owner), carrying a permissions[] array (and optional role). Per the customer-facing permission set, staff permissions include:

Staff permissionWhat it allows
Manage CompaniesCreate/edit/manage client companies
Subscription & PaymentsThe agency's own billing, invoices, payment methods
Manage PackagesCreate/edit/delete the packages sold to clients
Agency SettingsBranding, white-label, agency-wide settings
(revenue/impersonation gates)View revenue; impersonate ("Login as Owner")

Staff can be imported from a client company (promoting a member to agency staff without removing them from the company). Routes: /agency/staff*. Status shows Active (logged in) or Never Logged In.

Agency portal screens

ScreenWhat
DashboardKPIs across sub-accounts (revenue, hot leads, MRR)
CompaniesList + manage all sub-accounts (create, edit, impersonate, add-ons)
StaffAgency users + permissions
PackagesThe agency's product catalog
Add-onsAgency-defined add-ons
Subscription Info / ManagementThe agency's own platform subscription
White-Label DomainsCustom domains for portal/widget
Buy Sub-AccountOne-click create-new-client flow
InvoicesAgency billing history
SettingsAgency branding, working hours, notifications, Nox name

Sub-accounts (companies under an agency)

  • companies.agency_id points to the agency.
  • companies.agency_self_account: true marks the agency's own business company vs. a client sub-account.
  • Subscription bills the agency, not the company directly; the company admin sees a "Contact agency" gate on plan changes.
  • Create a sub-account via Add Company (POST /agencies/companies) or Add from GHL (POST /agencies/companies/ghl).
  • Login as Owner (impersonation) lets agency staff configure or support a client; a "Back to Agency" control returns them.

Behaviors & edge cases

  • Upgrade vs. downgrade: agency upgrades apply immediately (prorated); downgrades are deferred to cycle end via new_package_id. Same model as direct billing — see Plans & Subscriptions.
  • Revoking agency access does not auto-convert sub-accounts to direct billing — that's a manual conversion.
  • Inherited defaults: sub-accounts inherit some agency defaults (working hours, branding) — admins should understand precedence.
  • GHL is agency-aware: company creation, tagging on cancel/reactivate, and install version (app_version) flow through GHL — check the CRM integration docs.
  • Payment-issue flag: agencies.payment_issue / per-company flags (/agencies/payment-issue, /agencies/dismiss-payment-issue) surface billing problems.
  • Agency deletion: soft-delete (deleted_at) plus a hard-delete endpoint exist; the customer-facing "Danger Zone" full self-serve deletion is marked coming soon.

Plan & limits

  • The agency portal is the agency/Enterprise tier — itself a paid subscription.
  • initial_ai_credits default is 1500 (pooled). Per-package sub-account slots, pricing, and AI credits are agency-defined — verify specific numbers against the live data; do not quote fixed prices.

Technical implementation

  • Models: AgencyModel, AgencyPackageModel, AgencyAddonModel, AgencySubscriptionModel, AgencyDomainModel; plus companies.agency_id / agency_self_account / widget_whitelabel/home/bilal/Projects/knock-knock-app/backend/app/models/.
  • Controllers/routes: AgencyController (/agencies* — subscribe, change-package, buy-addon, create company, payment-issue, conversion-requests), AgencyStaffController (/agency/staff*), AgencyDomainController (/agency-domains*).
  • Frontend: frontend/src/views/agency/ (Dashboard, SubscriptionInfo, SubscriptionManagement, WhiteLabelDomains, Settings, BuySubAccount, Invoices) + components/agency/AgencyPermissionGate.vue.
  • Billing flows through Stripe + Xero — see Payments & Invoices. White-label detail: White-Label. CRM/GHL: /subsystems/crm-integration. Engineering: backend service.