Pricing Specification

Status: Active Owner: @bilal @danny Last Updated: 2026-03-11 Supersedes: sessions/02-commercial-model/pricing-analysis.md, sessions/02-commercial-model/packaging-matrix.md


Overview

Envo operates two commercial motions, each with its own pricing model:

MotionSales ModelPricingTarget Customer
GrowthSelf-serve SaaSFixed monthly tiers (Starter / Pro / Premium)SME landlords, small HMO operators
AcquisitionAgency outbound salesFixed monthly packages (Basic / Standard / Premium)Mid-market landlords, letting agents, property managers

A third motion (Partner — enterprise, custom contracts) is planned but deferred until a signed contract requires it. See ADR-019 Commercial Motions Architecture and Commercial Tiers Scoping for the full three-motion strategy.


Part 1: Envo Growth (Self-Serve SaaS)

Tier Summary

TierPricePropertiesTenantsSMS Cap
Starter£19.99/mo1—5≤5050/mo
Pro£79.99/mo6—2051—200100/mo
Premium£349.99/mo21+200+100/mo

All tiers include:

  • Full dashboard access
  • AI tenant conversations (24/7)
  • Issue management and routing
  • Document uploads and AI ingestion (RAG)
  • Email notifications (free)
  • Compliance tracking (expiry dates, alerts)

Metered Usage (Beyond Base Fee)

ChannelRateIncluded FreeOverage
SMS£0.05/msg50/mo (Starter), 100/mo (Pro/Premium)£0.05/msg
WhatsApp£0.011/msgPer message
VoiceTBDPer minute (future)
EmailFreeUnlimited

Feature Matrix (Growth Tiers)

FeatureStarterProPremium
Tenant Communication
Web chatxxx
WhatsApp (shared Envo number)xxx
WhatsApp (dedicated number)xx
Voice AI (shared Envo line)xx
Voice AI (dedicated / BYOAK)x
SMS + Email notificationsxxx
Email as intake channelxx
Emergency detection + escalationxxx
Configurable emergency keywordsxx
Issue Management
AI auto-creation from conversationsxxx
Auto-categorisation (type + urgency)xxx
Issue workflow + timelinexxx
SLA tracking and alertsxx
Duplicate detectionxx
Dashboard reply to tenantsxx
Custom issue categoriesx
Vendor Management
Manual vendor assignmentxxx
Tokenised vendor links (no login)xxx
Vendor accept / decline / completexxx
Preferred vendor listsxx
Vendor ratings + performancexx
Vendor management portalx
AI-recommended vendor matchingx
Property Management
Property + tenant CRUDxxx
Document upload + storagexxx
Compliance trackingxxx
CSV importxxx
Property activity logxx
Duplicate tenant detectionxx
Bulk operationsxx
AI + Intelligence
AI tenant conversations (Q&A + intake)xxx
Document AI (extract + searchable)xxx
Property document Q&A (RAG)xxx
AI follow-up questions + photo requestsxxx
Hybrid retrieval (vector + keyword fusion)xx
AI quality test suitex
Multilingual AIAdd-on
Reporting + Analytics
Dashboard home with live statsxxx
Compliance alertsxxx
Issue summary reportsxx
Communication logs (regulatory)xx
CSV exportxx
Advanced analytics + trendsx
Custom report builderx
Team + Access
Single user (owner)xxx
Team members (invite + roles)Up to 5Unlimited
Role-based accessxx
SSO / SAMLx
Audit logx
Branding + Customisation
Envo-branded tenant experiencexxx
Custom logo + colour palettexx
Custom email templatesxx
Custom domainx
Remove “Powered by Envo”x
Custom SMS sender IDx
Integrations
Envo shared infrastructurexxx
BYOAK: SendGridxx
BYOAK: LLM (Claude / OpenAI)xx
BYOAK: Twilio (WhatsApp + SMS)x
BYOAK: VAPI / Retell (voice)x
Webhook integrationsx
REST API accessx
Support
Self-service onboardingxxx
AI Help Bot (in-app)xxx
AI Helpline (phone)xxx
Email supportxxx
Priority supportxx
Dedicated onboarding sessionxx
Dedicated account managerx

Cost + Margin Analysis

TierBase FeeTypical Usage CostMarginNotes
Starter£19.99~£3.6282%Acquisition tier; fixed costs amortised
Pro£79.99~£7.0391%Profit engine; where most users land
Premium£349.99~£20.9394%Enterprise margin; high profitability

Cost breakdown detail:

  • Infrastructure is mostly fixed (Supabase Pro £25/mo covers all orgs, CF Workers negligible per-org)
  • WhatsApp (£0.005/msg to us) and SMS (£0.0524/msg to us) are the main variable costs
  • Margins are healthy from month 1 across all tiers
  • Voice (future): £0.15/min cost, targeting 160% markup

Tier Upgrade Triggers

ConditionAction
Starter user >90 days, >3 propertiesPrompt upgrade to Pro for WhatsApp dedicated number
Pro user hitting SMS overage 3+ monthsSuggest WhatsApp (cheaper channel)
Pro user >500 WhatsApp msgs/moSuggest Premium for better rates
Pro user needing team access >5Upgrade to Premium
Any user wanting custom domain / white-labelPremium

Onboarding Flow (Growth) — Implemented

Customer visits ehq.tech → signs up / logs in → lands on /onboarding
  Step 1: Organisation details (name, type)
  Step 2: Plan selection (Starter / Pro / Premium)
    → "Continue to payment" → POST /api/stripe/checkout
    → Redirect to Stripe Checkout (hosted page)
    → User pays
    → Stripe redirects to /onboarding?step=success&session_id={ID}
    → Server calls Stripe API to verify payment + read metadata
    → Creates organisation (plan, name, type all from Stripe — no client tampering)
  Step 3: Import properties (optional — Magic Import or Template)
    → Skip or complete → /dashboard

Safety net: Stripe webhook (checkout.session.completed) creates the org
if the browser redirect never completes (crash, closed tab, etc.).
Both paths are idempotent — no duplicate orgs.

See ADR-004 Billing Integration for the full architecture.

Billing Cycle

  • Billing date: Anniversary of signup
  • Charge timing: Auto-charged via Stripe
  • Payment method: Card on file (required)
  • Invoice: Sent to billing email with itemised breakdown

Free Trial

14-day trial on Pro features, no credit card required. Caps: 10 units (Starter), 25 units (Pro). Downgrades to selected tier after trial ends.


Part 2: Envo Acquisition (Agency Sales)

Overview

Acquisition is an agency-style outbound sales motion. Envo sales agents prospect, demo, and close landlords. Customers are onboarded via envo-admin and receive branded domains. Pricing is fixed monthly packages, not per-enquiry.

Tier Summary

TierPriceEnquiries/moOffersScriptsReportingDashboard
Basic£1,000/mo50011 basic scriptWeekly reportCore access
Standard£2,000/mo1,500Multi-offerMultiple scriptsWeekly + strategy callsCRM tools
Premium£4,000/mo3,000+Full suiteFull copywritingFull analytics + call loggingFull access

Feature Matrix (Acquisition Tiers)

FeatureBasicStandardPremium
Enquiries
Monthly enquiry cap5001,5003,000+
Enquiry tracking + billable taggingxxx
Enquiry analyticsxx
Offers + Scripts
Offer configurations1MultipleFull suite
Script templates1 basicMultipleFull copywriting
Script A/B testingx
Reporting
Weekly summary reportxxx
Strategy callsxx
Full analytics dashboardx
Call logging + documentationx
CRM + Retargeting
Core dashboard accessxxx
CRM toolsxx
Retargeting campaignsx
Support
Email supportxxx
Dedicated account managerxx
VA onboarding callxxx

Enquiry Definition

An “enquiry” is a completed tenant interaction that results in a meaningful outcome (issue created, question answered, escalation to human). Not every message is an enquiry — it is a conversation that reaches resolution.

See Enquiry Billing Model for the full analysis of conversation lifecycle, edge cases, and the hybrid billing approach.

Billing categories:

  • Billable: issue_created, escalation, q_and_a
  • Non-billable: abandoned, spam, identity_failed

Sales Pipeline

  1. Close CRM handles the entire Acquisition pipeline (prospect, outreach, demo, close)
  2. On “Closed Won”, handoff to Envo ops
  3. envo-admin provisions the organisation, configures pricing, sets up custom domain
  4. VA books onboarding call for next day
  5. Customer goes live on branded domain

Billing (Acquisition)

Two payment paths:

  1. Stripe: Automated monthly billing against the fixed package price
  2. Bank transfer + invoicing: For customers who prefer traditional invoicing. Requires invoice generation (PDF), manual payment reconciliation.

Part 3: Optional Credit System (Growth — V2)

Concept

Instead of metered per-message charges, Growth organisations can opt into a credit system that abstracts all costs into a single currency. 1 credit = £0.01.

When to use credits:

  • Organisations prefer predictable budgets
  • Heavy usage (bulk discount via topup packages)
  • White-label orgs (cleaner billing)

Credit Values

ActionCreditsEquivalent Cost
1 WhatsApp message1.1£0.011
1 SMS (overage)5£0.05
1 Voice minute29£0.29
1 Document ingestion0.1£0.001
100 emails0Free

Tier Credit Allowances

TierMonthly AllowanceOverage
Starter300 credits (£3)1 credit = £0.01
Pro5,000 credits (£50)1 credit = £0.01
Premium20,000 credits (£200)1 credit = £0.01

Topup Packages

PackageCreditsCostSavings vs Overage
Small1,000£9.0010%
Medium5,000£40.0020%
Large10,000£75.0025%
EnterpriseCustomCustomNegotiable

Topups are one-time purchases (no auto-renew). Credits from topups roll over indefinitely.

Credit Priority

  1. Monthly allowance consumed first (resets each billing cycle)
  2. Purchased topups consumed second (carry over)

Part 4: Metering + Billing Infrastructure

Current State

Today the codebase tracks token usage at response time (tokensUsed returned from each LLM call) but has no persistent billing table — usage is logged but not aggregated for invoicing. Stripe integration (checkout + webhooks + subscription lifecycle) is merged and live on the magic-import branch. See ADR-004 Billing Integration for the implementation details.

Infrastructure Options

There are three complementary tools for metering AI usage. They solve different problems and can be layered.

Option A: Cloudflare AI Gateway

What it does: Proxies LLM API calls through Cloudflare, providing analytics, caching, rate limiting, and request logging. Sits between our Workers and the LLM providers.

URL: https://developers.cloudflare.com/ai-gateway/

Relevant for us because:

  • We already deploy on Cloudflare Workers
  • Provides per-request analytics (tokens, latency, cost) without custom code
  • Can cache identical requests (e.g., repeated RAG queries for the same document) to reduce LLM spend
  • Rate limiting protects against runaway costs from a single org
  • Logs every request with metadata (org ID, channel, model) for billing reconciliation

Limitations:

  • Observability only — does not handle Stripe billing integration
  • We would still need to aggregate usage per org and feed it into invoices
  • No built-in concept of “customer” or “subscription”

Verdict: Good for observability and cost control. Use it as the logging layer, but it does not replace billing logic.

Option B: Stripe AI Billing (LLM Token Metering)

What it does: Stripe’s new AI billing feature lets you route LLM calls through llm.stripe.com (or integrate via partner SDKs), automatically record token usage per Stripe Customer, and bill with a configurable markup.

Key capabilities (from Stripe announcements):

  • Route requests through Stripe’s LLM proxy or use partner integrations (Vercel, Cloudflare, OpenRouter, Helicone)
  • Pass a Stripe Customer ID on each request — usage is attributed automatically
  • Set a target markup (e.g., 30%) and Stripe calibrates pricing against current model rates
  • Dynamic updates: new subscribers get latest rates automatically
  • Coordinated migrations: existing subscribers update at renewal, not mid-cycle
  • AI and Token Meter SDKs for direct integration

Limitations:

  • Very new (early 2026 launch). Documentation is sparse and the product is evolving.
  • Requires routing all LLM traffic through Stripe’s proxy OR using a supported partner SDK
  • Our current multi-provider architecture (Claude OpenAI Kimi GLM fallback chain) may not map cleanly to Stripe’s gateway model
  • Unclear how it handles non-LLM metered costs (WhatsApp, SMS, voice) — those would still need separate Stripe metered billing
  • Lock-in concern: tying LLM routing to a payment processor

Verdict: Watch closely, but do not adopt yet. The promise is excellent (automatic attribution + markup + invoicing), but the product is too early and our multi-provider fallback chain is a complication. Revisit when Stripe publishes stable docs and supports custom provider routing.

Option C: Build Our Own (Current Path)

What we need to build regardless:

  1. usage_events table — log every billable action (WhatsApp msg, SMS, LLM call, voice minute)
  2. monthly_usage aggregation — per-org monthly totals
  3. Stripe metered billing — report usage to Stripe at billing time, generate itemised invoices
  4. Credit ledger (V2) — optional credit system on top

This is the path we are on. The schema is designed in this spec (see Part 5). Cloudflare AI Gateway can feed into it as the LLM logging source.

LLM Requests
  |
  v
Cloudflare AI Gateway (observability, caching, rate limiting)
  |
  v
Provider SDKs (Anthropic, OpenAI, etc.)
  |
  v
usage_events table (log tokens, cost, org_id)
  |
  v
monthly_usage aggregation (cron or webhook)
  |
  v
Stripe metered billing (invoice at billing date)
  • Phase 1: Ship billing with our own usage tracking (usage_events + monthly_usage + Stripe invoicing)
  • Phase 2: Add Cloudflare AI Gateway for LLM observability and caching
  • Phase 3: Evaluate Stripe AI billing when it matures; migrate if it simplifies the stack

AI SDK Migration Opportunity

Current state: The codebase uses raw provider SDKs (@anthropic-ai/sdk, openai) with a hand-rolled provider abstraction in lib/rag/providers/. This works but means we maintain our own:

  • Provider fallback chain
  • Streaming logic
  • Token counting
  • Tool-use orchestration
  • Retry + backoff logic

Opportunity: The Vercel AI SDK (ai package) provides a unified interface for all of this:

  • Unified provider API: Single interface across Anthropic, OpenAI, Google, Mistral, etc.
  • Built-in streaming: streamText(), streamObject() with backpressure
  • Tool use: First-class tool calling with type-safe schemas (Zod)
  • Structured output: generateObject() for typed JSON responses
  • Token tracking: Built-in usage reporting per call
  • Middleware: Hooks for logging, caching, rate limiting
  • Provider fallback: experimental_customProvider with fallback chains
  • Telemetry: OpenTelemetry integration for observability
  • Edge runtime compatible: Works on Cloudflare Workers

What this replaces in our codebase:

  • lib/rag/providers/ (entire directory) AI SDK provider registry
  • lib/rag/generate.ts generateText() / streamText()
  • lib/rag/intent.ts (LLM path) generateObject() with Zod schema
  • lib/rag/summary.ts generateText()
  • lib/tenant-engine/process.ts (tool orchestration) AI SDK tool use
  • lib/rag/embed.ts embed() / embedMany()
  • Custom retry/fallback logic AI SDK middleware

What it does NOT replace:

  • lib/rag/chunk.ts — chunking is our own logic
  • lib/rag/extract.ts — file extraction is our own
  • lib/rag/retrieve.ts — pgvector queries stay as raw SQL
  • lib/rag/emergency.ts — keyword-based, no LLM
  • lib/rag/config.ts — our config stays

Billing benefit: AI SDK’s built-in token tracking per call maps directly to our usage_events table, making metering simpler and more reliable than parsing provider-specific response shapes.

Recommendation: This is a worthwhile migration. It reduces ~500 lines of provider abstraction code, gives us better streaming, and aligns with the ecosystem (Next.js + Vercel AI SDK is well-tested on Cloudflare Workers). Should be a separate Linear epic, not mixed with billing work.


Part 5: Database Schema

organisations (extended)

-- Existing columns plus:
tier          VARCHAR(20) DEFAULT 'STARTER'
                CHECK (tier IN ('STARTER', 'PRO', 'PREMIUM'))
monthly_charge_pence  INTEGER  -- 1999, 7999, 34999
billing_day_of_month  INTEGER
stripe_customer_id    VARCHAR(255)
billing_model         VARCHAR(20) DEFAULT 'METERED'
                        CHECK (billing_model IN ('METERED', 'CREDITS'))
monthly_credit_allowance INTEGER  -- 300, 5000, 20000 (if credits)
commercial_motion     VARCHAR(20) DEFAULT 'growth'
                        CHECK (commercial_motion IN ('growth', 'acquisition', 'partner'))

monthly_usage

CREATE TABLE monthly_usage (
    id                    UUID PRIMARY KEY,
    organisation_id       UUID REFERENCES organisations(id),
    month                 VARCHAR(7) NOT NULL,  -- '2026-03'
    whatsapp_count        INTEGER DEFAULT 0,
    whatsapp_cost_pence   INTEGER DEFAULT 0,
    sms_count             INTEGER DEFAULT 0,
    sms_overage_count     INTEGER DEFAULT 0,
    sms_overage_pence     INTEGER DEFAULT 0,
    email_count           INTEGER DEFAULT 0,
    llm_tokens_used       INTEGER DEFAULT 0,
    llm_cost_pence        INTEGER DEFAULT 0,
    created_at            TIMESTAMPTZ DEFAULT NOW(),
    updated_at            TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE (organisation_id, month)
);

usage_events

CREATE TABLE usage_events (
    id                UUID PRIMARY KEY,
    organisation_id   UUID REFERENCES organisations(id),
    channel           VARCHAR(20) NOT NULL,  -- 'WHATSAPP', 'SMS', 'EMAIL', 'VOICE', 'LLM'
    count             INTEGER DEFAULT 1,
    credits_used      DECIMAL(10,2),  -- For credit system
    cost_pence        INTEGER,         -- For metered system
    metadata          JSONB,           -- model, tokens_in, tokens_out, etc.
    created_at        TIMESTAMPTZ DEFAULT NOW()
);

credit_ledger (V2)

CREATE TABLE credit_ledger (
    id                UUID PRIMARY KEY,
    organisation_id   UUID REFERENCES organisations(id),
    type              VARCHAR(20) NOT NULL
                        CHECK (type IN ('ALLOWANCE', 'PURCHASE', 'USAGE', 'ADJUSTMENT')),
    credits           DECIMAL(10,2) NOT NULL,  -- Negative for usage
    description       TEXT,
    usage_event_id    UUID REFERENCES usage_events(id),
    invoice_id        UUID REFERENCES invoices(id),
    balance_after     DECIMAL(10,2) NOT NULL,
    created_at        TIMESTAMPTZ DEFAULT NOW()
);

invoices

CREATE TABLE invoices (
    id                  UUID PRIMARY KEY,
    organisation_id     UUID REFERENCES organisations(id),
    type                VARCHAR(20) NOT NULL
                          CHECK (type IN ('SUBSCRIPTION', 'TOPUP', 'OVERAGE')),
    billing_month       VARCHAR(7),
    base_fee_pence      INTEGER,
    whatsapp_cost_pence INTEGER,
    sms_overage_pence   INTEGER,
    llm_cost_pence      INTEGER,
    topup_credits       INTEGER,
    topup_cost_pence    INTEGER,
    total_due_pence     INTEGER NOT NULL,
    stripe_invoice_id   VARCHAR(255),
    paid_at             TIMESTAMPTZ,
    due_date            DATE,
    created_at          TIMESTAMPTZ DEFAULT NOW()
);

enquiries (Acquisition billing)

CREATE TABLE enquiries (
    id                    UUID PRIMARY KEY,
    organisation_id       UUID REFERENCES organisations(id),
    conversation_id       UUID REFERENCES conversations(id),
    issue_id              UUID REFERENCES issues(id),
    channel               VARCHAR(30),
    billing_category      VARCHAR(30),  -- 'issue_created', 'q_and_a', 'escalation', 'abandoned', 'spam'
    billable              BOOLEAN DEFAULT true,
    billed_at             TIMESTAMPTZ,
    billing_period_start  DATE,
    billing_period_end    DATE,
    created_at            TIMESTAMPTZ DEFAULT NOW()
);

Part 6: Implementation Roadmap

Phase 1: Growth Billing (In Progress)

  • Stripe Checkout integration (checkout session + redirect)
  • Stripe Webhook handler (checkout.session.completed, subscription.updated, subscription.deleted)
  • Secure onboarding: plan/name/type from Stripe metadata, not client
  • Webhook safety net: creates org if client never returns
  • Idempotent org creation (no duplicates from race conditions)
  • Feature gating enforcement (plan + limits via lib/plans.ts)
  • Implement usage_events and monthly_usage tables
  • Invoice + payment confirmation emails (Stripe + Resend)
  • Plan upgrade/downgrade UI
  • Stripe billing portal integration

Phase 2: Acquisition Billing

  • envo-admin: organisation creation + package assignment (Basic/Standard/Premium)
  • envo-admin: enquiry tracking dashboard
  • enquiries table + billable tagging logic
  • Fixed monthly billing against package price (Stripe)
  • Invoice generation (PDF) for bank transfer customers
  • Weekly report generation (Basic+)
  • Strategy call scheduling (Standard+)

Phase 3: Observability + Credits

  • Cloudflare AI Gateway integration (LLM observability, caching)
  • Credit system (optional for Growth orgs)
  • Topup purchasing via Stripe
  • Credit analytics dashboard
  • Billing model switching UI (metered > credits)

Phase 4: AI SDK Migration (Separate Epic)

  • Replace lib/rag/providers/ with AI SDK provider registry
  • Migrate generate.ts to generateText() / streamText()
  • Migrate intent.ts to generateObject() with Zod schema
  • Migrate summary.ts to generateText()
  • Migrate tenant-engine tool orchestration to AI SDK tool use
  • Migrate embed.ts to AI SDK embedMany()
  • Wire AI SDK token tracking into usage_events

Phase 5: Stripe AI Billing (Evaluate)

  • Assess Stripe AI billing maturity (docs, partner support, multi-provider)
  • Prototype: route one provider through Stripe’s LLM proxy
  • Compare with our own metering — does it simplify or complicate?
  • Decision: adopt, defer, or reject

Part 7: Risks + Mitigations

RiskImpactMitigation
Starter margin erosion on heavy HMOsRevenue < cost for high-density propertiesSMS cap + WhatsApp metering; upgrade prompts at usage thresholds
Acquisition enquiry definition disputesCustomer challenges billable countClear contractual definition + dispute process (see Enquiry Billing Model)
Stripe AI billing immaturityWasted integration effortWatch-and-wait; build our own metering first
Credit system complexityEngineering overhead, customer confusionShip as V2 opt-in; default to metered
AI SDK migration riskBreaking changes during migrationSeparate epic, comprehensive test coverage, provider-by-provider migration

Part 8: Open Questions

QuestionStatusNotes
Voice pricing per minuteTBD£0.15/min cost; target 160% markup (~£0.39/min)
Annual billing discountTBD20% (2 months free) standard in SaaS; defer until retention data exists
Acquisition overage pricingTBDWhat happens when Basic hits >500 enquiries? Auto-upgrade, overage fee, or hard cap?
HMO density multiplierDeferredPer-property pricing for now; revisit if margin erodes on high-density HMOs
Free tierRejectedEnvo’s costs are usage-based; free tier bleeds cash. 14-day trial instead.