Skip to main content
Your deployment can host partners who resell it under their own brands, as the white label overview describes. Each piece turns on once you configure what it needs, so you can start with signup and subdomains and add billing later. This page sets up each piece, and the partner variables describe every setting it names. Set each variable on both the admin and the worker.

Choose who can sign up as a partner

Partners sign up at /partner/signup on your dashboard’s domain. The page creates the person’s account first if they’re signed out, then the partner. Partners sign in at /partner/login. PARTNER_SIGNUP decides who can sign up:
  • open, the default on a self-hosted deployment, lets anyone sign up
  • invite needs a signup link that you create for each partner
To invite a partner, run this from a checkout of the repository, with DATABASE_URL and APP_BASE_URL pointing at your deployment:
The command writes the link to a JSON file in .partner-invites/, named after the invitation, which only your user can read. The link works once, for that email address after its owner verifies it, for 7 days. Send it to the partner, then delete the file.

Give partners subdomains

PARTNER_BASE_DOMAIN is the domain your partners get subdomains of, such as partners.example.com. Pick a neutral domain, because your partners’ clients see it in their address bar and in their emails:
1

Point a wildcard record at your server

At your DNS provider, add a record for *.partners.example.com that points at the server that runs the admin.
2

Set the base domain

Set PARTNER_BASE_DOMAIN=partners.example.com and restart the admin and the worker. Each new partner then reserves a subdomain at signup, and partners who signed up earlier get one when the admin starts.
3

Let your email provider send from it

Partners’ emails go out from no-reply@partners.example.com, under each partner’s name. Verify that sender with your email provider, or the emails fail.
4

Serve HTTPS for the subdomains

With Caddy’s on-demand TLS, Caddy gets a certificate for each partner’s subdomain on its first visit. With another proxy, give it a wildcard certificate for *.partners.example.com.
Without PARTNER_BASE_DOMAIN, partners get no subdomain and their emails go out from EMAIL_FROM. A partner then needs a verified domain of its own before it can create a business or a demo.

Serve partners’ own domains

A partner on a paid tier can connect a subdomain of its own website, such as app.acmeagency.com, or any partner can when you sell no tiers. The partner adds two records that the console shows: a CNAME that points at PARTNER_DOMAIN_CNAME_TARGET, and a TXT record that proves it controls the domain. The worker checks them, and the domain goes live once both check out. Pick one way to issue the certificates.

Caddy on Docker Compose

Compose’s Caddy issues each domain’s certificate the first time someone visits it, after the admin approves the hostname at /api/tls/ask. Set these in .env, open TCP ports 80 and 443 and UDP port 443, and restart the stack:
Partners then point their CNAME at the hostname in APP_BASE_URL, unless you set PARTNER_DOMAIN_CNAME_TARGET. Serve HTTPS from Caddy explains which hostnames Caddy approves.

Cloudflare for SaaS

When the DNS of PARTNER_BASE_DOMAIN is on Cloudflare, Cloudflare can issue partners’ certificates instead. In the zone, enable Cloudflare for SaaS under SSL/TLS > Custom Hostnames. Add a proxied record such as host.partners.example.com as the fallback origin, and set the zone’s encryption mode to Full. Then set CLOUDFLARE_SAAS_API_TOKEN to a token with the Zone > SSL and Certificates > Edit permission, and CLOUDFLARE_SAAS_ZONE_ID to the zone’s ID. Partners point their CNAME at the fallback origin. With both Cloudflare for SaaS and CADDY_ON_DEMAND_TLS set, the deployment uses Cloudflare for SaaS. The Cloudflare for SaaS steps in the Docker Compose guide cover each setting.

Traefik

Traefik routes only the hostnames it has a router for, so partners’ hostnames need one more router that catches every other hostname. Traefik doesn’t issue certificates for hostnames it hasn’t seen, so pair it with Cloudflare for SaaS, which serves partners’ certificates in front of it. This is how LobbyStack’s cloud runs on Dokploy. Add a dynamic configuration file, such as partner-hosts.yml in Traefik’s watched directory:
partner-hosts.yml
Priority 1 ranks these routers below every other route, so your dashboard keeps its own. The second router moves plain HTTP requests to HTTPS. Replace your_admin_service with the admin’s service name on Traefik’s network. The admin answers each partner’s hostname with that partner’s brand, and any other hostname with a 404. Traefik answers partners’ hostnames with its default certificate, which doesn’t name them. Keep the Cloudflare zone’s encryption mode at Full, not Full (strict), so Cloudflare accepts it. For partners’ subdomains, proxy the wildcard record through Cloudflare too.

Let partners bill their businesses through Stripe Connect

Stripe Connect lets each partner connect its own Stripe account and sell packages on it. Set it up once in your Stripe platform account:
1

Turn on Connect

In your Stripe account, turn on Connect.
2

Create the key

Create a secret key or a restricted key with the write access that STRIPE_CONNECT_SECRET_KEY lists, and set it as STRIPE_CONNECT_SECRET_KEY.
3

Create the webhook endpoint

Create an endpoint at your APP_BASE_URL followed by /api/webhooks/stripe, for events on connected accounts, with the events that STRIPE_CONNECT_WEBHOOK_SECRET lists. Set its signing secret as STRIPE_CONNECT_WEBHOOK_SECRET.
4

Restart

Restart the admin and the worker. Each partner’s owner can then connect a Stripe account on the console’s Payments page.
Without both variables, the Payments page tells partners Payments aren’t set up here, and they bill every business themselves.

Sell partners tiers with Polar

Partners buy tiers from the console’s Billing page and pay you through Polar. Create one recurring product for each paid tier and interval, with the prices in this table: The Billing page shows these prices from the code, so give your products the same ones. Then set up billing:
  1. Set the six product IDs: POLAR_PARTNER_STARTER_MONTHLY_PRODUCT_ID, POLAR_PARTNER_STARTER_ANNUAL_PRODUCT_ID, and the same pair for GROWTH and SCALE. Each must be its own product.
  2. Keep POLAR_ACCESS_TOKEN, POLAR_ORGANIZATION_ID and POLAR_WEBHOOK_SECRET set, as your own plans use them.
  3. Add the meters and metered prices that bill pool overage and extra phone numbers, as the Polar billing guide describes.
  4. Restart the admin and the worker. The worker records whether you sell tiers when it starts.
Tier billing turns on only when all six products are set. Partners then need a paid tier to connect their own domain, and each partner’s tier sets its pool and phone numbers.

Run partners without tiers

Leave the POLAR_PARTNER_* products empty, and partners pay you nothing through LobbyStack. Their consoles show no Billing page, and nothing limits their businesses’ minutes, chats or phone numbers. To limit what one partner’s businesses share each month, set its pool from a checkout of the repository, with DATABASE_URL pointing at your database:
That pool is a hard limit, with no overage. At the pool, the partner’s businesses forward their calls and their website chat stops replying until the month starts over. The partner’s owners see the pool on a Billing page, and its owners and admins get emails at 80% and 100%. The pnpm partner-pool:set options are under the partner variables.

List partner hostnames in Turnstile

If you use Cloudflare Turnstile on sign-up, with NEXT_PUBLIC_TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY, its widget renders only on the hostnames you list for it. The admin also accepts a token only from the hostname the visitor solved it on. Add these hostnames to the widget in Cloudflare:
  • PARTNER_BASE_DOMAIN, such as partners.example.com, which covers every partner’s subdomain
  • each partner’s own domain, once it’s live, if people should sign up on it too
Invitations and other email links open on partners’ subdomains, so people sign up there even after a partner connects its own domain. Without PARTNER_BASE_DOMAIN, invitations open on each partner’s own domain, so list each one. On Cloudflare’s Free plan, a widget lists up to 10 hostnames.

Check the setup

Test with a partner of your own before you invite others:
  1. Sign up as a partner at /partner/signup, and open your subdomain from Branding & domain. You should see the sign-in page under the partner’s brand.
  2. Create a business, and check that the owner’s invitation arrives from the partner’s name.
  3. Connect a subdomain of a domain you control, add its two DNS records, and wait for Active.
  4. With Stripe Connect, connect a test Stripe account, create a package and pay for it from a business’s invitation.
  5. With tiers, buy one on the Billing page and check that the pool and phone numbers follow it.