# CleanEstimate Pro Docs Full Text This file contains the public CleanEstimate Pro documentation catalog and article bodies for AI assistants, retrieval systems, and crawler-style ingestion. Home: https://docs.cleanestimate.pro XML sitemap: https://docs.cleanestimate.pro/sitemap.xml Concise LLM index: https://docs.cleanestimate.pro/llms.txt ## Section Index - Getting Started: https://docs.cleanestimate.pro/getting-started - Set up your account and create your first estimate - Estimating: https://docs.cleanestimate.pro/estimating - Residential, commercial, fleet, and holiday lights - CRM: https://docs.cleanestimate.pro/crm - Clients, leads, pipeline, tags - Messaging: https://docs.cleanestimate.pro/messaging - Inbox, SMS, email, calls, follow-ups - Operations: https://docs.cleanestimate.pro/operations - Schedule, dispatch, jobs, invoicing - Analytics: https://docs.cleanestimate.pro/analytics - Revenue, margins, lead source ROI, pipeline velocity - Mobile App: https://docs.cleanestimate.pro/mobile - Using CE Pro on your phone - AI Features: https://docs.cleanestimate.pro/ai - AI estimate review, lead scoring, AI agents - Settings: https://docs.cleanestimate.pro/settings - Account, integrations, billing, team management - Developers: https://docs.cleanestimate.pro/developers - External API, API keys, pagination, and webhook verification - Troubleshooting: https://docs.cleanestimate.pro/troubleshooting - Fix common issues and get back to work - Automations: https://docs.cleanestimate.pro/automations - Workflow builder, triggers, actions, and auto-call - Marketing: https://docs.cleanestimate.pro/marketing - Public website, campaigns, promotions, and win-back workflows - What's New: https://docs.cleanestimate.pro/whats-new - Latest features and improvements --- URL: https://docs.cleanestimate.pro/ai/agent-access Title: AI Agent Access Description: Grant approved AI assistants secure, scoped access to CE Pro. Category: ai Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-09 --- # AI Agent Access AI Agent Access lets your team connect approved assistants to CleanEstimate Pro without sharing a full user login. Each agent gets its own token, its own tool permissions, and a full activity trail. [SCREENSHOT: AI Agents page showing a list of agent tokens, enabled tools, and recent activity] --- ## What It Is Agent access is designed for cases where you want an assistant to help with real work inside CE Pro, such as reviewing inbox activity, checking estimates, or supporting your team with fast answers. Instead of giving the assistant broad account access, CE Pro creates a scoped token that limits what the agent can do. --- ## Where To Set It Up Go to **Admin > AI > Agents**. From this page you can: - Create a new agent token - Choose which tools the token can use - Keep the token read-only or enable guarded write actions - Revoke a token at any time - Review recent agent activity [SCREENSHOT: New agent token form with name, tool access list, and read-only toggle] --- ## Read-Only Access New tokens should start as read-only. A read-only agent can help your team by retrieving information without changing customer records. Common read-only use cases include: - Reviewing inbox threads before a rep replies - Looking up estimate status or customer history - Summarizing lead activity for managers - Answering internal questions about jobs, clients, or follow-ups --- ## Guarded Write Access If you enable write access, CE Pro still keeps the scope intentionally small. Guarded write tools are meant for low-risk workflow actions, not broad account edits. Current guarded actions include: - Adding an internal note to an inbox thread - Updating whether a thread still needs a response Every write requires a second confirmation step before CE Pro applies the change. [SCREENSHOT: Confirmation prompt showing a pending write action that must be approved before execution] --- ## Activity And Audit Trail Every agent request is logged. Your team can review: - Which token was used - Which tool the agent called - When the action happened - Whether it succeeded or failed Use the activity log to confirm behavior, investigate mistakes, and decide whether an agent needs broader or narrower access. --- ## Best Practices - Start with read-only access and expand later only if needed. - Create separate tokens for separate assistants or workflows. - Revoke any token you no longer use. - Review activity logs regularly, especially after enabling write access. - Limit write access to trusted workflows with clear human oversight. --- URL: https://docs.cleanestimate.pro/ai/overview Title: AI Features Overview Description: Use AI to score leads, draft follow-ups, review pricing, and connect approved agents to CE Pro. Category: ai Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-03-14 --- # AI Features Overview CleanEstimate Pro includes AI-powered tools that help you sell smarter, respond faster, and price more accurately. AI features are managed from **Admin > AI**. [SCREENSHOT: AI Hub page showing cards for Lead Scoring, Pricing Analysis, Conversations, and Agents] --- ## What AI Can Do CE Pro's AI features fall into six categories: | Feature | What It Does | |---------|--------------| | **Lead Scoring** | Automatically scores incoming leads as Hot, Warm, Cool, or Cold based on their profile and behavior | | **Pricing Analysis** | Reviews your pricing history and margins against market benchmarks and recommends adjustments | | **Proposal AI Writer** | Generates professional proposal text, scope descriptions, and follow-up messages | | **AI Draft in Messaging** | Suggests follow-up message drafts when you open a customer conversation | | **Brand Voice & Training** | Lets you define how customer-facing AI should represent your business and learn from approved examples | | **AI Voice Agent** | Handles inbound phone qualification, tries warm transfer, and creates callback fallback when a rep is unavailable | | **AI Agent Access** | Lets approved assistants connect with scoped tokens, read business data, and perform a small set of guarded actions when write access is enabled | --- ## AI Hub Navigation The AI area includes pages for analysis tools as well as agent management. Depending on your plan and permissions, you may see: - **Lead Scoring** - View and manage AI-scored leads - **Pricing Analysis** - Get pricing recommendations - **Conversations** - Browse AI-assisted conversation history - **Voice Agent** - Configure call handling, warm transfer behavior, and outbound AI calling - **Agents** - Create and manage secure access tokens for approved assistants - **Settings** - Configure AI preferences and review usage [SCREENSHOT: AI Hub navigation showing the available sections] --- ## How It Works CE Pro's AI features combine the data already in your account with protected OpenAI model calls and internal business rules. When you use an AI feature, CE Pro sends only the relevant context needed for that task, such as lead details, pricing history, conversation context, and your saved Brand Voice profile for customer-facing replies. For AI agent access, CE Pro issues scoped tokens, limits which tools each token can use, and records activity so your team can review how the agent interacted with your data. If your workspace has not configured an OpenAI key yet, some AI tools fall back to built-in rule checks or statistical summaries instead of failing silently. Business Assistant quick actions run through CleanEstimate Pro's secured app API, which avoids browser-side Edge Function failures and keeps the assistant scoped to your organization data. The Business Assistant now renders markdown-style formatting in the chat panel, so emphasis such as **bold**, *italics*, inline `code`, underlines, and simple bullet lists display properly instead of showing raw symbols. Tone changes in the AI Hub still affect the internal assistant prompt, while the separate Brand Voice profile controls how customer-facing AI drafts, website chat, and the voice agent represent your business. --- ## AI Credits AI features may consume credits depending on your plan and which tool you use. Check your available usage and settings at **Admin > AI**. [SCREENSHOT: AI credit or usage panel in the AI area] --- ## Getting Started If AI is enabled on your account, start with these: 1. **Review your lead scores.** Go to [AI Lead Scoring](https://docs.cleanestimate.pro/ai/lead-scoring) and see which leads are ranked hottest. 2. **Run a pricing analysis.** Go to [AI Pricing Analysis](https://docs.cleanestimate.pro/ai/pricing-analysis) to get recommendations on your rates. 3. **Set up Brand Voice.** Go to [Brand Voice & AI Training](https://docs.cleanestimate.pro/ai/brand-voice) so customer-facing AI uses your wording and examples. 4. **Use AI Draft in Messaging.** Open a conversation and generate a suggested follow-up before sending. 5. **Set up the Voice Agent.** Go to [AI Voice Agent](https://docs.cleanestimate.pro/ai/voice-agent) if you want AI to answer calls and create callback fallback automatically. 6. **Set up agent access.** Go to [AI Agent Access](https://docs.cleanestimate.pro/ai/agent-access) if you want an approved assistant to read CE Pro data or complete guarded inbox actions. --- ## Tips - **AI scores are a starting point.** Always apply your own judgment before acting on a score or recommendation. - **Use AI drafts as templates.** Edit generated text so it matches your voice before sending it to customers. - **Start agents with read-only access.** Enable write access only when your workflow is ready for it. - **Review activity regularly.** Audit logs make it easy to confirm how an agent used its access. - **Public landing page:** You can visit /ai to preview AI features and tool links before signing in to the admin portal. --- URL: https://docs.cleanestimate.pro/ai/lead-scoring Title: AI Lead Scoring Description: Automatically score incoming leads to focus on the hottest prospects first. Category: ai Difficulty: intermediate Roles: owner, manager, sales_rep Last updated: 2026-03-18 --- # AI Lead Scoring AI Lead Scoring ranks your incoming leads so you spend time on the ones most likely to convert. Navigate to **Admin > AI > Leads** to see scored leads. [SCREENSHOT: AI Lead Scoring page showing a list of leads with score badges] --- ## How Scoring Works CE Pro evaluates each lead against multiple signals and assigns a score. The scoring model considers: | Signal | Why It Matters | |--------|---------------| | **Property size** | Larger properties tend to produce higher-value jobs | | **Number of services requested** | Multi-service inquiries signal serious buyers | | **Viewing behavior** | Leads who view the estimate multiple times are more engaged | | **Returning customer** | Past customers convert at higher rates | | **Referral source** | Referrals close more often than cold leads | | **Contact completeness** | Leads who provide phone, email, and address are more serious | | **Response speed** | Leads who reply quickly to outreach are more engaged | | **Estimated value** | Higher-value estimates deserve prioritized attention | The model combines these signals into an overall score and assigns a tier. --- ## Score Tiers Every lead receives one of four tiers: | Tier | Icon | Score Range | Meaning | |------|------|-------------|---------| | **Hot** | Red flame | 80-100 | High likelihood of converting. Prioritize immediately. | | **Warm** | Orange circle | 60-79 | Good prospect. Follow up within 24 hours. | | **Cool** | Blue circle | 40-59 | Moderate interest. Keep in your pipeline but do not rush. | | **Cold** | Gray circle | 0-39 | Low engagement. Follow up if time allows. | [SCREENSHOT: Four leads showing the Hot, Warm, Cool, and Cold tier badges] --- ## Where Scores Appear Lead scores show up in three places: 1. **Leads table** — A score badge appears next to each lead in the main leads list at **Admin > Leads**. 2. **Pipeline cards** — If you use the pipeline view, score badges appear on each card. 3. **AI Leads page** — The dedicated page at **Admin > AI > Leads** lists all scored leads sorted by score. [SCREENSHOT: Leads table with score badges visible in a column] --- ## Using Scores to Prioritize Follow this workflow each morning: 1. Open **Admin > AI > Leads**. 2. Review all Hot leads first. Call or text them before doing anything else. 3. Move to Warm leads. Send follow-up messages or schedule appointments. 4. Check Cool leads for any that have moved up since yesterday. 5. Review Cold leads weekly. Move stale ones to Lost if they have not responded. --- ## Assigning Reps Based on Scores If you have multiple salespeople, route Hot leads to your best closer. This maximizes conversion on your highest-potential opportunities. Go to the lead detail page and use the **Assigned Rep** dropdown to reassign. See [Managing Leads](https://docs.cleanestimate.pro/crm/leads) for details. --- ## Score Changes Over Time Scores update automatically as new signals come in. A Cool lead that views the estimate three times and replies to a follow-up may jump to Warm or Hot. Check the AI Leads page daily to catch leads that have moved up in score. If you click **Recalculate Scores**, CE Pro recomputes scores from your latest estimates immediately. Score persistence now writes the refreshed batch in one save operation instead of one lead at a time, so larger workspaces should see the recalculation finish faster. If your org is still on an older AI schema rollout, the page will still calculate and show fresh scores instead of failing with a server error. --- ## Tips - **Do not ignore Warm leads.** They are one good interaction away from becoming Hot. - **Speed matters most for Hot leads.** Contact them within the first hour if possible. - **Use scores alongside your instincts.** A lead with a Cool score but a large property and specific service requests may still be worth pursuing aggressively. - **Track your results.** Compare close rates for each tier over time. If Hot leads are not converting at a higher rate, review the scoring signals with your team. --- URL: https://docs.cleanestimate.pro/ai/pricing-analysis Title: AI Pricing Analysis Description: Get AI-powered recommendations on your pricing strategy and margins. Category: ai Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-11 --- # AI Pricing Analysis AI Pricing Analysis reviews your pricing data and gives you actionable recommendations. Navigate to **Admin > AI > Pricing** to run an analysis. If OpenAI is not configured for the workspace yet, the page still returns a statistical summary and fallback recommendations instead of showing a dead-end error. [SCREENSHOT: AI Pricing Analysis page showing the analysis summary and recommendation cards] --- ## What the AI Analyzes When you run a pricing analysis, the AI reviews: | Data Point | What It Tells the AI | |------------|---------------------| | **Your historical pricing** | How your rates have changed over time | | **Margins by service** | Which services are most and least profitable | | **Close rates by price point** | Whether higher prices reduce your win rate | | **Market benchmarks** | How your rates compare to industry averages for your region | | **Seasonal patterns** | Whether pricing should shift based on demand cycles | The AI needs at least 30 days of estimate data to generate useful recommendations. More data produces better analysis. --- ## Running an Analysis 1. Go to **Admin > AI > Pricing**. 2. Click **Run Analysis**. 3. Wait a few seconds while the AI processes your data. 4. Review the results on the page. Each analysis uses AI credits. A standard analysis uses 5 credits. [SCREENSHOT: Run Analysis button on the AI Pricing page] --- ## Understanding the Results The analysis produces three sections: ### Pricing Summary A high-level overview of your current pricing position. The AI tells you whether your rates are above, at, or below market averages for each service type. [SCREENSHOT: Pricing summary showing service types with above/at/below market indicators] ### Service-Level Recommendations A card for each service type with a specific recommendation: - **Increase price** — Your win rate is high enough to support a price increase without significant volume loss. - **Hold price** — Your pricing is well-positioned. No change needed. - **Decrease price** — Your win rate for this service is below average. A lower price may recover lost volume. - **Bundle opportunity** — This service pairs well with another. Offering a bundle discount could increase average deal size. Each recommendation includes supporting data: your current rate, suggested range, projected impact on win rate, and projected revenue change. [SCREENSHOT: Service-level recommendation card showing a suggested price increase with supporting data] ### Margin Analysis A table showing your estimated margins per service. The AI flags services where margins are unusually thin or where cost inputs may have changed since you last adjusted pricing. [SCREENSHOT: Margin analysis table showing margin percentages by service] --- ## Acting on Recommendations Recommendations are suggestions, not automatic changes. To adjust your pricing: 1. Review each recommendation carefully. 2. Consider your local market knowledge. The AI uses regional benchmarks, but you know your specific competitive landscape. 3. Go to **Admin > Pricing** to update your rates. See [Setting Up Your Default Pricing](https://docs.cleanestimate.pro/getting-started/setting-up-pricing). 4. Monitor your win rate for the next 30 days after making changes. --- ## Running Follow-Up Analyses Run a new analysis after making pricing changes to see the impact. Wait at least 30 days between analyses to allow enough new data to accumulate. Compare the new analysis to the previous one. Look for improvements in margins and stable or improving close rates. --- ## Tips - **Do not change everything at once.** Adjust one or two services at a time so you can measure the effect of each change. - **Small increases add up.** A 5% price increase across all services can significantly improve profitability without noticeably affecting close rates. - **Review quarterly.** Run an analysis at the start of each quarter to stay aligned with market conditions. - **Factor in your costs.** The AI looks at revenue and close rates. Make sure you also account for changes in your supply costs, labor rates, and fuel expenses. --- URL: https://docs.cleanestimate.pro/ai/voice-agent Title: AI Voice Agent Description: Answer inbound calls with AI, qualify customers, warm-transfer to reps, and fall back to callback tasks. Category: ai Difficulty: intermediate Roles: owner, manager, sales_rep Last updated: 2026-03-14 --- # AI Voice Agent The AI Voice Agent lets CleanEstimate Pro handle customer phone calls with AI before a human jumps in. It can: - Answer inbound calls on your Twilio number - Ask qualifying questions one at a time - Share rough service and pricing guidance - Attempt a warm transfer to an available rep - Fall back to a callback task and follow-up SMS if nobody answers You can manage it from **Admin > AI > Voice Agent**. The voice agent also follows your saved [Brand Voice & AI Training](https://docs.cleanestimate.pro/ai/brand-voice) profile so its spoken replies match how you want the business represented. --- ## What It Handles The voice agent is designed for early-call qualification, not final job booking. Good uses: - New lead intake - Service questions - Rough pricing conversations - After-hours or overflow call handling - Speed-to-lead fallback when a live rep is unavailable Cases that should transfer to a person: - The caller asks for a human - The caller wants exact pricing or firm schedule promises - The caller is upset, confused, or discussing a problem job - The caller is ready for a detailed booking conversation --- ## How The Call Flow Works ### Inbound Calls 1. Customer calls your Twilio number 2. Twilio sends the call to CleanEstimate Pro's voice webhook 3. The AI voice agent greets the caller and starts qualification 4. If the call needs a rep, the system tries a warm transfer 5. If no rep answers, CleanEstimate Pro creates a callback task and can text the caller automatically ### Outbound AI Calls Outbound AI calling currently works in two ways: - **Manual test or follow-up calls** from the Voice Agent page - **Speed-to-lead fallback** when the standard auto-dial flow cannot connect a live rep --- ## Twilio Setup Configure these URLs on the phone number you want the voice agent to use: - **Incoming Voice Webhook:** `/api/webhooks/twilio/voice` - **Voice Status Callback:** `/api/webhooks/twilio/voice/agent-status` - **SMS Webhook:** `/api/webhooks/twilio` If your app runs on `https://app.cleanestimate.pro`, the full voice URLs would be: ```text https://app.cleanestimate.pro/api/webhooks/twilio/voice https://app.cleanestimate.pro/api/webhooks/twilio/voice/agent-status ``` The Voice Agent page shows the exact URLs for your current environment. --- ## Settings The Voice Agent page includes: - **Enable voice agent** - global on/off - **Answer inbound calls** - route incoming Twilio calls into AI - **Outbound AI fallback** - use AI when speed-to-lead cannot reach a live rep - **Warm transfer** - bridge the caller to an available rep - **Follow-up SMS** - text the caller after callback fallback - **Twilio voice** - the text-to-speech voice name used in `` - **Max AI turns** - how long the AI should keep talking before wrapping up - **Greeting** - your opening message --- ## Warm Transfer Behavior When warm transfer is enabled, CleanEstimate Pro checks rep availability and tries to connect the caller live. If a rep answers: - The call is marked as transferred - The rep takes over the conversation If no rep answers: - The call is marked as needing callback - An internal follow-up task is created - A high-priority AI alert is created - An optional SMS confirms that your team will follow up --- ## Where Call History Appears Completed voice sessions create a call summary in the shared inbox. That means your team can see: - The call direction - The qualification summary - Whether the AI requested follow-up - Whether a warm transfer connected Callback fallback also creates an internal task-style note in the conversation thread. --- ## Important Limits - The voice agent speaks with short AI-guided turns, not full free-flowing human conversation. - It can discuss **rough** pricing only. - It should not promise exact availability or commit a crew without human review. - The legacy automation builder's **Make Call** step is still separate. Voice Agent works today even though the older builder step remains unavailable. --- URL: https://docs.cleanestimate.pro/ai/brand-voice Title: Brand Voice & AI Training Description: Teach customer-facing AI how your business should sound across drafts, chat, and voice. Category: ai Difficulty: beginner Roles: owner, manager Last updated: 2026-03-14 --- # Brand Voice & AI Training CleanEstimate Pro lets you train customer-facing AI on how your business should sound before it drafts messages, writes emails, answers website chat, or speaks through the AI Voice Agent. You manage this from **Admin > Settings** in the **Brand Voice** panel. --- ## What Brand Voice Controls Your Brand Voice profile applies to customer-facing AI features such as: - **AI Draft** in the shared inbox - **Customer follow-up emails** generated by AI - **Website chat replies** - **AI Voice Agent** responses on phone calls It does **not** change the internal Business Assistant tone used in the AI Hub. That setting remains separate. --- ## What You Can Configure The Brand Voice panel includes: - **Customer-facing tone** - the default personality for customer replies - **Business identity** - how the AI should describe and represent your company - **Representation guidelines** - style rules such as "helpful, direct, never pushy" - **Values to emphasize** - ideas like responsiveness, property care, premium service, or transparent pricing - **Approved phrases** - wording the AI is encouraged to use - **Avoid phrases** - wording the AI should avoid - **Preferred email sign-off** - the closing style for AI-generated emails - **Training examples** - real customer messages paired with approved replies --- ## How Training Examples Work Training examples are the fastest way to teach the AI your style. For each example, add: 1. A short title 2. The channel it applies to, such as SMS, Email, Website Chat, Voice, or Any 3. The customer's message 4. The reply you want the AI to learn from CleanEstimate Pro uses those examples as prompt guidance, so the AI mirrors your style and representation choices without copying the text word-for-word every time. --- ## Best Practices - Add examples from your best-performing real customer conversations. - Keep approved replies concise and realistic for the selected channel. - Use **Avoid phrases** for wording that feels off-brand, too casual, too aggressive, or too vague. - Review AI drafts before sending, especially after large brand voice changes. - Update the profile when your service mix, positioning, or communication style changes. --- ## Recommended Setup Start with: 1. Choose a customer-facing tone 2. Write one paragraph about how your business should be represented 3. Add 3 to 5 approved phrases your team actually uses 4. Add 3 to 5 real training examples from texts or emails 5. Generate a few AI drafts in the inbox and adjust the profile until the wording feels right --- ## Related Features - Use [Your Messaging Inbox](https://docs.cleanestimate.pro/messaging/inbox) to test AI Draft output - Use [AI Voice Agent](https://docs.cleanestimate.pro/ai/voice-agent) if you also want phone calls to follow the same brand voice - See [AI Features Overview](https://docs.cleanestimate.pro/ai/overview) for the rest of the AI workspace --- URL: https://docs.cleanestimate.pro/analytics/automation-analytics Title: Automation Analytics Description: Monitor speed-to-lead, delivery health, workflow runs, and automation performance. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-20 --- # Automation Analytics The Automations tab inside Analytics shows how well your automated workflows are performing. Open **More > Analytics**, then click **Automations**. You can also view per-workflow analytics directly from the [workflow detail page](https://docs.cleanestimate.pro/automations/monitoring-runs), which shows run counts, success rates, and a 30-day runs chart for that specific workflow. [SCREENSHOT: Automation Analytics page showing speed-to-lead cards, delivery health, and sequence performance] --- ## What It Tracks Use the shared date-range picker in the page header when you want to zoom out to a longer trend or drill into a tighter campaign window. The dashboard summarizes automated outreach and lead response data for the selected range: - **Avg. Time to Contact** - How quickly new leads receive their first response. - **Contact Rate** - The percentage of leads that were successfully contacted. - **Auto-Dial Connect** - The share of automated calls that reached a customer. - **At-Risk Leads** - New leads that still need attention. Below the headline cards, the page also shows: - **Delivery Health** for SMS and email sends - **Lead Intake** by source - **Enrollment totals** for active, paused, completed, and suppressed contacts - **Sequence performance** for each enabled automation --- ## Delivery Health The Delivery Health panel compares sent, delivered, and failed totals for both SMS and email. Use it to spot channel issues quickly. If one channel suddenly shows a higher failure rate, check the related integration settings before you send another campaign or sequence. --- ## Lead Intake The Lead Intake panel breaks recent leads down by source so you can see where automated follow-up volume is coming from. This is especially useful when you want to compare: - website leads versus referrals - paid sources versus organic sources - manual intake versus booking widget volume --- ## Sequence Performance The sequence table shows each automation's status and enrollment counts. Review it regularly to answer three questions: 1. Is the sequence enabled? 2. Are contacts actively moving through it? 3. Are suppressions or completions unusually high? Sequence enrollment totals now load from one org-scoped rollup query instead of one query per sequence, so this section should stay more responsive as you add more legacy follow-up sequences. Use this view alongside [Marketing Campaigns](https://docs.cleanestimate.pro/marketing/campaigns) and [Automations](https://docs.cleanestimate.pro/automations/overview) when you are tuning your post-estimate and win-back flows. --- ## Tips - Check this page after changing follow-up rules so you can confirm enrollments are still flowing. - Watch the At-Risk Leads card during busy days. It is the fastest way to catch response lag. - Pair lead intake trends with [Lead Source ROI](https://docs.cleanestimate.pro/analytics/lead-source-roi) when you want to decide where to invest more marketing budget. - When an automation change just shipped, switch the date range to a tight custom window around that rollout so you can isolate the impact faster. --- URL: https://docs.cleanestimate.pro/analytics/franchise Title: Franchise Reporting Description: Review royalty, ad-fund, and territory-utilization rollups in franchise-enabled workspaces. Category: analytics Difficulty: advanced Roles: owner, manager Last updated: 2026-03-16 --- # Franchise Reporting Franchise Reporting is available only in workspaces where the franchise reporting feature flag is enabled. [SCREENSHOT: Franchise report showing royalty, ad-fund, and territory tables] --- ## What It Includes - Royalty rollups by module - Brand-funded source contribution - Territory utilization The report uses the same shared analytics shell as the rest of reporting, so filters and exports work the same way. --- ## When It Appears You do not need a separate "franchise reporting" switch. This report appears automatically when the workspace already has: - franchise hierarchy enabled, or - a multi-location feature flag enabled If the workspace does not use either of those modes, the report stays hidden. --- ## Brand-Funded Sources Ad-fund reporting depends on the **Brand-funded source** toggle in **Lead Sources**. If a source should contribute to shared-brand reporting, mark it there first. --- ## Territory Utilization The territory table compares ZIP coverage, lead flow, wins, and revenue so you can spot underused or overperforming territories quickly. --- URL: https://docs.cleanestimate.pro/analytics/geography Title: Geography Analytics Description: See where your revenue comes from with geographic performance breakdowns. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-08 --- # Geography Analytics The Geography tab shows where your revenue comes from on a map. Navigate to **Admin > Analytics > Geography** to open it. [SCREENSHOT: Geography analytics page showing the revenue heatmap and area breakdown table] --- ## Geographic Heatmap A map displays your service area with color-coded zones. Darker areas represent higher revenue. Lighter areas represent lower revenue. Zoom in to see detail at the neighborhood level. Zoom out for a regional view. [SCREENSHOT: Heatmap map with darker shading in high-revenue ZIP codes] --- ## Revenue by Area A table below the map lists performance by geographic area: | Column | Description | |--------|-------------| | **ZIP Code / City** | The geographic area | | **Estimates Sent** | Number of estimates sent to addresses in this area | | **Won** | Number of accepted estimates | | **Win Rate** | Percentage of sent estimates that were accepted | | **Revenue** | Total revenue from this area | | **Avg Deal Size** | Average dollar value per won estimate | Sort by Revenue to see your strongest markets. Sort by Win Rate to see where customers are most likely to say yes. [SCREENSHOT: Revenue by area table sorted by revenue showing top-performing ZIP codes] --- ## Identifying Strong Markets Look for areas with both high revenue and high win rates. These are your core markets. You know the area well, your pricing fits, and customers trust you. Consider concentrating your marketing in these areas. Yard signs, door-to-door, and direct mail all work better when you already have a presence. --- ## Identifying Growth Opportunities Areas with a few won estimates and high average deal sizes signal potential. You may not have many customers there yet, but the ones you do have are profitable. Test targeted marketing in these areas. Track whether lead volume and win rates increase over the next quarter. --- ## Spotting Problem Areas Areas with many estimates sent but low win rates may have issues: - **Pricing mismatch.** Your rates may be too high or too low for that market. - **Travel distance.** If the area is far from your base, customers may sense you are not local. - **Competition.** A strong local competitor may be undercutting you. If an area consistently underperforms, consider whether it belongs in your service area at all. --- ## Using Geography for Route Planning Cross-reference your strongest geographic areas with your scheduling and route planning. Clustering jobs in high-density areas reduces drive time and increases daily capacity. See [Route Planning](https://docs.cleanestimate.pro/operations/routes) for more on optimizing routes. --- ## Tips - **Expand from strength.** Start marketing in ZIP codes adjacent to your best-performing areas. - **Track seasonally.** Some areas peak at different times. A lake community may be strongest in spring. - **Use the data for hiring.** If a distant area shows strong demand, consider hiring a crew closer to that market. --- URL: https://docs.cleanestimate.pro/analytics/holiday-lights Title: Holiday Lights Analytics Description: Review seasonal revenue, close rate, rebooking, inventory, and QC metrics for holiday lights. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-20 --- # Holiday Lights Analytics Holiday Lights Analytics is the specialty report for your holiday program. It stays inside the same shared analytics navigation as the rest of reporting and now uses the same preset/custom date-range picker as the other analytics reports. [SCREENSHOT: Holiday Lights analytics page showing seasonal metrics] --- ## What It Tracks - Seasonal revenue - Contract volume - 1-year versus 3-year mix - Close rate - Rebooking rate - Inventory value and low-stock counts - Strand-testing quality metrics - Upcoming installs, takedowns, and service calls --- ## Date Filter Use the date-range picker at the top of the page to jump to a preset window or enter exact start and end dates. This is useful when you want to isolate: - a renewal push - a short install surge - a takedown and QC window - a specific stretch of weather-related service activity --- ## Best Uses - Check rebooking before you start outbound renewals - Watch inventory strain during installation peaks - Keep QC and service calls visible while revenue is still climbing --- URL: https://docs.cleanestimate.pro/analytics/lead-source-roi Title: Lead Source ROI Description: Compare lead quality, revenue, rep contribution, upsell lift, and brand-funded source performance. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-16 --- # Lead Source ROI Lead Source ROI shows which sources create the best opportunities, which reps close them, and which channels deserve more budget. [SCREENSHOT: Lead Source ROI report showing source cards, rep attribution, and the full ROI table] --- ## Filters This report includes two built-in filters: - **Period** - **Module** Use the module filter to isolate Residential, Commercial, Fleet, or Holiday Lights performance without leaving the report. --- ## KPI Cards The summary cards at the top call out: - Total revenue - Win rate - Lead volume - Commission paid - Upsell revenue from existing clients - Revenue from brand-funded sources This lets you see both raw source volume and the quality of the work each channel creates. --- ## Lead Source Performance Table The table shows one row per lead source with these columns: | Column | Description | |--------|-------------| | **Source** | The lead source label plus its category | | **Type** | Whether the source is marked as direct or brand-funded | | **Leads** | Total number of leads from this source | | **Estimates Sent** | Number of estimates sent from that source | | **Won** | Number of accepted estimates or proposals | | **Win Rate** | Percentage of sent work that was won | | **Revenue** | Total revenue from won work | | **Revenue / Lead** | Revenue spread across all leads from that source | | **Upsell** | Won revenue from existing clients who already had completed work | | **Commission** | Estimated commission paid based on the configured rate | | **Top Rep** | Highest-revenue rep attached to wins from that source | Click any column header to sort. Sort by **Revenue**, **Revenue / Lead**, or **Upsell** depending on the question you are answering. [SCREENSHOT: Lead Source ROI table sorted by revenue with brand-funded badges visible] --- ## Rep Attribution and Brand-Funded Sources Two supporting panels sit beside the main chart: - **Rep Attribution** shows which rep is winning the most revenue from each source. - **Brand-Funded Sources** breaks out sources tagged as paid for by the shared brand or ad fund. This is especially useful if you need to separate business-development wins from brand-marketing wins. --- ## Reading the Data Use the report to answer a few distinct questions: - **Which sources close best?** Sort by **Win Rate**. - **Which sources create the most money per opportunity?** Sort by **Revenue / Lead**. - **Which sources are feeding repeat business?** Sort by **Upsell**. - **Which sources depend on one rep to perform?** Compare the table with the rep attribution card. - **Which sources belong in franchise/ad-fund rollups?** Review the brand-funded panel. --- ## Brand-Funded Source Setup Brand-funded reporting depends on the **Brand-funded source** toggle in **Admin > Lead Sources**. Turn this on for channels that should roll into shared-brand or franchise ad-fund reporting. Examples: - Google Ads funded from the brand budget - Meta campaigns funded at the franchise level - Shared directory spend managed centrally Do not enable this for rep-sourced referrals, door knocking, networking, or other direct-origin channels unless those are actually funded centrally. --- ## Tips - **Look past raw lead volume.** Revenue per lead and upsell revenue often tell a truer story than lead count alone. - **Check the top rep column.** A source that only works for one rep may need process coaching or routing changes. - **Pair this with [Franchise Reporting](https://docs.cleanestimate.pro/analytics/franchise)** if you use shared ad-fund accounting. --- URL: https://docs.cleanestimate.pro/analytics/margins Title: Margin Analysis Description: Review gross margin, callback leakage, and sold-to-job conversion quality across your sold work. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-16 --- # Margin Analysis Margin Analysis shows the quality of the work you sold, not just the amount of revenue you booked. [SCREENSHOT: Margin Analysis report showing callback and conversion cards] --- ## What It Tracks This report combines: - Revenue - Estimated or actualized cost - Gross profit - Gross margin - Callback leakage - Sold-to-job conversion coverage You can break that performance down by module, service, client, and crew. --- ## Callback Impact The callback panel now separates two kinds of callback signals: - **Explicit callback jobs** from callback-tracking settings on the job - **Inferred callback jobs** based on job notes and complaint-style wording This helps you distinguish well-tracked callback work from older workspaces that still rely on note-based signals. --- ## Sold-to-Job Conversion The sold-to-job card shows how much accepted work has been linked back to a real job. This matters because: - Crew and callback reporting depends on job links - Margin quality gets stronger when actual field execution is attached - Unlinked sold work points to scheduling or workflow gaps --- ## Best Uses - Review **which services look profitable on paper but fall apart with callbacks** - Compare **crews with high revenue but weak adjusted margin** - Find **sold work that still has no linked job** --- URL: https://docs.cleanestimate.pro/analytics/operations Title: Operations Reporting Description: Combine crew productivity, crew pay, and AR aging in one report. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-16 --- # Operations Reporting Operations Reporting connects crew output to crew pay and accounts receivable so field execution and cash collection can be managed together. [SCREENSHOT: Operations report showing crew productivity and overdue invoices] --- ## What It Includes - Crew pay totals - Crew productivity - AR aging buckets - Overdue invoice list This makes it easier to answer questions like: - Which crews are productive but expensive? - Where is cash stuck in receivables? - Which overdue accounts need a reminder today? --- ## AI Reminder Action The overdue invoice table includes a **Send Reminder** action. That opens the same AI follow-up flow used in the invoices area, so you can generate and send an invoice reminder without leaving reporting. --- ## Best Uses - Review weekly with the office manager - Watch callback-heavy crews beside crew pay totals - Use AR aging to decide when collections work should outrank new quoting --- URL: https://docs.cleanestimate.pro/analytics/rehash Title: Rehash Analytics Description: Track recovered revenue, stage load, and recovered-close attribution for the residential Rehash workflow. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-04-21 --- # Rehash Analytics Open **Analytics > Rehash** to review the residential win-back department as its own reporting surface. This page is separate from the main queue and focuses on the recovery outcomes, template performance, and follow-up pressure instead of the next touch. [SCREENSHOT: Rehash analytics page showing KPI cards, stage load, disposition mix, template performance, queue pressure, split bands, and recent closes] If the analytics page opens with a setup warning instead of chart data, the workspace is still missing part of the latest Rehash database rollout. CE Pro now fails soft with that message instead of leaving the analytics tab on a server error. --- ## What The Report Shows The top cards summarize: - active Rehash quotes - recovery rate - recovered revenue MTD - recovered revenue YTD - average recovery days These numbers are based on the saved Rehash state and recovered-close attribution stored on the estimate. --- ## Stage Load The **Active stage load** panel shows how much quote value is still sitting in each active Rehash stage, along with how many of those quotes are due right now. Use this panel to answer two questions quickly: - Where is the active Rehash value concentrated? - Which stage is starting to backlog? --- ## Disposition Mix The **Disposition mix** panel rolls up how quotes are entering Rehash. This is the fastest way to spot whether the office is mostly losing on price, timing, low interest, or missing the decision-maker during the appointment. If one objection category starts to dominate, fix that issue in the field script before the queue grows larger. --- ## Recovered By Closer The **Recovered by closer** panel attributes won Rehash quotes back to the person who actually closed them. It shows: - recovered quote count - recovered revenue - recovered commission dollars This is the cleanest manager view for seeing who is actually converting win-back work. --- ## Template Performance The **Template performance** panel shows how the automated Rehash templates are actually landing: - sends per template - reply rate per template - conversion rate per template - recovered revenue tied to those converted sends If A/B testing is enabled, Variant A and Variant B are broken out separately so managers can compare which copy gets more replies and closes. --- ## Queue Pressure The **Queue pressure** panel groups active Rehash quotes by overdue age: - current or upcoming - 1-3 days overdue - 4-7 days overdue - 8+ days overdue Use this panel to see whether the queue is staying healthy or whether a backlog is starting to build behind the manual-touch stage. --- ## Split Bands The **Commission split bands** panel groups recovered wins by the saved Rehash timing band: - Day 0-6 - Day 7-14 - Day 15-89 - Day 90+ This helps owners see whether recovered work is mostly closing immediately after the first follow-up or only after long-tail manager effort. --- ## Recent Recovered Closes The final table shows the latest recovered wins with: - quote / customer - timing band - original rep share - closer share - recovered revenue - recovered commission Use it during payroll review or sales-manager check-ins when you need the exact saved split instead of a rough estimate. --- URL: https://docs.cleanestimate.pro/analytics/overview Title: Reporting Overview Description: Understand the shared reporting hub and how the analytics pages fit together. Category: analytics Difficulty: beginner Roles: owner, manager Last updated: 2026-04-21 --- # Reporting Overview CleanEstimate Pro now uses a shared reporting hub for analytics. Open **More > Analytics** to see grouped report cards inside the refreshed admin reporting workspace plus the shared report rail across the top. [SCREENSHOT: Analytics overview page showing grouped report cards] --- ## Why the Hub Exists The old analytics area was already strong, but it centered most traffic around the revenue landing page. The reporting hub keeps those existing pages live and makes it easier to move between: - Sales reporting - Customer-health reporting - Operations reporting - Specialty reports such as Holiday Lights and Automations The overview page is intentionally built as an operator landing surface, not just a list of links. It keeps the highest-value reports visible first, uses the same blue/slate command styling as the rest of the admin shell, and then groups the rest by report family. --- ## Report Families The hub groups reports into a few sections: - **Sales and Growth** for revenue, margins, lead sources, services, geography, and sales cycle - **Customer Health** for retention and at-risk accounts - **Operations** for crew, AR, scheduling, and franchise rollups - **Specialty** for Holiday Lights, Automation analytics, and the Rehash recovery report --- ## Shared Controls Every report added to the new reporting shell uses the same basics: - Shared navigation rail - Shared preset and custom date-range picker, including exact start/end selection on every report page - Shared export flow with CSV and a print-ready HTML export, including the Retention, Operations, Schedule Efficiency, and Franchise rollup reports - Shared empty states - Shared operator cards, blue active tabs, and mono metric readouts for totals That means the analytics area feels consistent even when you move between very different pages. --- ## Where to Start - Start with [Revenue Analytics](https://docs.cleanestimate.pro/analytics/revenue) for overall momentum. - Open [Margin Analysis](https://docs.cleanestimate.pro/analytics/margins) when revenue looks good but cash feels tight. - Use [Retention and At-Risk](https://docs.cleanestimate.pro/analytics/retention) when recurring customers are slipping. - Use [Operations Reporting](https://docs.cleanestimate.pro/analytics/operations) or [Schedule Efficiency](https://docs.cleanestimate.pro/analytics/schedule) when field execution is the issue. - Use [Rehash Analytics](https://docs.cleanestimate.pro/analytics/rehash) when the office is actively working unsold residential quotes back toward a close. --- URL: https://docs.cleanestimate.pro/analytics/retention Title: Retention and At-Risk Description: Flag healthy, at-risk, dormant, and new accounts before they quietly churn. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-16 --- # Retention and At-Risk This report turns client-history data into an account-health view so the office can see which customers are active, drifting, dormant, or new. [SCREENSHOT: Retention report showing account-health cards and the account table] --- ## Health States Accounts are grouped into four buckets: - **Active** - **At Risk** - **Dormant** - **New** The report also layers in open renewal quotes and overdue balances so you can prioritize the accounts that matter most. --- ## Generate Quote Action Each row includes a **Generate Quote** action. Clicking it jumps into the estimate flow with the selected client already attached. Use this when: - A repeat customer has gone quiet - An at-risk account needs a renewal quote - A dormant client is worth reactivating --- ## Best Uses - Review the report weekly for churn prevention - Sort your call list around overdue balance plus days since last job - Pair it with [Lead Source ROI](https://docs.cleanestimate.pro/analytics/lead-source-roi) when you want to compare acquisition quality against long-term customer value --- URL: https://docs.cleanestimate.pro/analytics/revenue Title: Revenue Analytics Description: Use the reporting hub and dedicated Revenue page to track trends, module mix, and accepted-work momentum. Category: analytics Difficulty: beginner Roles: owner, manager Last updated: 2026-03-16 --- # Revenue Analytics Open **More > Analytics** to land in the shared reporting hub. From there, click **Revenue** to open the dedicated revenue report. [SCREENSHOT: Reporting hub with Revenue selected as a report card and the Revenue page open] --- ## Reporting Hub The Analytics area is now organized as a reporting hub instead of a single revenue-first landing page. The hub keeps all of the existing analytics pages live and adds new report families for retention, operations, schedule efficiency, and franchise rollups. Use the hub when you want to: - Jump between report families without losing the page you already use today. - Find the right report faster from grouped cards. - Keep the same date-range, export, and navigation behavior across reports. --- ## Shared Navigation A shared report rail runs across the top of the analytics area. Depending on your workspace features, it includes: - Overview - Revenue - Margins - Lead Sources - Sales Cycle - Services - Geography - Retention - Operations - Schedule - Holiday Lights - Automations - Franchise Reporting when the franchise feature flag is enabled Click any report name to move between pages without leaving the analytics area. --- ## Date Range and Export The Revenue page uses the same shared controls as the rest of reporting: - **30 days** - **90 days** - **6 months** - **1 year** - **YTD** - **All time** Use the export selector on the right to download the current view as **CSV** or **Print**. The **Print** option downloads a print-ready HTML report from the shared analytics export service. Open that file in your browser to print it directly or save it as a PDF from the browser print dialog. If an export cannot be generated, CleanEstimate Pro now shows a visible error toast instead of failing silently. That feedback applies across the shared analytics export flow, including Revenue, Retention, Operations, Schedule Efficiency, and Franchise reports. [SCREENSHOT: Revenue page showing shared period controls and the export menu] --- ## What the Revenue Report Shows The Revenue report remains the high-level sales summary for the business. It includes: - Total accepted revenue in the selected range - Revenue trends over time - Revenue by service - Revenue by module - MRR and ARR approximations based on recent accepted work This page is still the best starting point for overall sales momentum. Use the other reports to drill deeper into margin quality, lead quality, close timing, or customer retention. [SCREENSHOT: Revenue report showing metric cards and revenue-over-time charts] --- ## Tips - **Start here, then branch out.** Revenue tells you what sold. Follow with [Margin Analysis](https://docs.cleanestimate.pro/analytics/margins), [Lead Source ROI](https://docs.cleanestimate.pro/analytics/lead-source-roi), or [Sales Cycle](https://docs.cleanestimate.pro/analytics/sales-cycle) to understand why. - **Compare modules, not just totals.** Residential, fleet, commercial, and holiday lights can move differently inside the same period. - **Use the reporting hub as your entry point.** The hub is the fastest way to jump into the next question once you spot a revenue change. --- URL: https://docs.cleanestimate.pro/analytics/sales-cycle Title: Sales Cycle Analytics Description: Measure how long it takes to close deals and where prospects drop off. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Sales Cycle Analytics The Sales Cycle tab measures how quickly leads move through your pipeline and where they stall or drop off. Navigate to **Admin > Analytics > Sales Cycle** to open it. [SCREENSHOT: Sales Cycle analytics page showing the conversion funnel and timing metrics] --- ## Lead-to-Close Conversion Funnel A funnel chart at the top of the page shows the number of leads at each pipeline stage: 1. **New Lead** — All incoming leads 2. **Appointment Scheduled** — Leads with a booked site visit or call 3. **Estimate Created** — Leads with a drafted estimate 4. **Estimate Sent** — Leads whose estimate was delivered 5. **Approved** — Leads who accepted the estimate 6. **Deposit Collected** — Leads who paid a deposit 7. **Converted** — Leads who became paying customers Each stage shows a count and a conversion rate to the next stage. The biggest drop-off between stages tells you where to focus improvement efforts. [SCREENSHOT: Conversion funnel showing counts and percentages at each stage] --- ## Average Days per Stage A horizontal bar chart shows the average number of days leads spend in each pipeline stage. This reveals bottlenecks. For commercial and fleet records, loss timing now follows the recorded decline timestamp when one exists, so late administrative closeouts do not artificially stretch the earlier stage timing. | What to Look For | What It Means | |-------------------|---------------| | Long time in "New" | Your team is slow to make first contact | | Long time in "Estimate Created" | Estimates sit in draft too long before sending | | Long time in "Estimate Sent" | Customers are not responding quickly | | Long time in "Approved" | Deposit collection or scheduling is delayed | [SCREENSHOT: Horizontal bar chart showing average days in each pipeline stage] --- ## Close Rate Trends A line chart plots your overall close rate (won / sent) over time. Each data point represents one month. A declining close rate signals a problem. Common causes include rising prices without added value, slower response times, or increased competition. A rising close rate means your sales process is improving. Look at what changed and reinforce it. [SCREENSHOT: Close rate trend line chart showing monthly close rates over time] --- ## Breakdown by Estimate Type A table breaks down sales cycle metrics by estimate type: | Estimate Type | Avg Days to Close | Close Rate | Avg Deal Size | |---------------|-------------------|------------|---------------| | Residential | — | — | — | | Commercial | — | — | — | | Fleet | — | — | — | | Holiday Lights | — | — | — | Commercial deals typically take longer to close but have higher values. Residential deals close faster. Knowing these benchmarks helps you set realistic expectations for each type. [SCREENSHOT: Sales cycle breakdown table by estimate type] --- ## Breakdown by Rep If you have multiple salespeople, a second table shows metrics per rep: | Rep | Leads Assigned | Estimates Sent | Won | Close Rate | Avg Days to Close | |-----|---------------|----------------|-----|------------|-------------------| Sort by close rate to identify your top closer. Sort by average days to close to find who moves fastest. Use this data for coaching conversations. [SCREENSHOT: Sales cycle breakdown table by rep name] --- ## Tips - **Speed wins deals.** The faster you move a lead from New to Estimate Sent, the higher your close rate. Aim for same-day estimates when possible. - **Follow up on stalled leads.** If the "Estimate Sent" stage has a long average time, set up automated follow-ups. See [Follow-Up Sequences](https://docs.cleanestimate.pro/messaging/follow-up-sequences). - **Coach with data.** Share rep-level metrics in one-on-ones. Focus on behaviors, not just outcomes. --- URL: https://docs.cleanestimate.pro/analytics/schedule Title: Schedule Efficiency Description: Track production volume, schedule fill, on-time performance, and schedule disruption reasons. Category: analytics Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-16 --- # Schedule Efficiency Schedule Efficiency turns raw scheduling activity into an operations scorecard for dispatch and production. [SCREENSHOT: Schedule Efficiency report showing daily production and crew performance] --- ## Core Metrics This report tracks: - Scheduled jobs - Completed jobs - Schedule fill rate - On-time rate - Rescheduled jobs - Cancelled jobs It also charts daily production so you can spot overloaded or underfilled stretches quickly. --- ## Crew Performance The crew table compares: - Scheduled jobs - Completed jobs - On-time rate - Completion rate This helps you separate staffing problems from routing or dispatch problems. --- ## Reschedule and Cancellation Reasons The right-side reason panels give the office a quick answer to what keeps breaking the schedule. Use them to spot patterns like: - Weather - Customer availability - Material delays - Internal staffing gaps --- URL: https://docs.cleanestimate.pro/analytics/services Title: Service Mix Analytics Description: See which services generate the most revenue and get booked most often. Category: analytics Difficulty: beginner Roles: owner, manager Last updated: 2026-03-08 --- # Service Mix Analytics The Services tab shows how each service type contributes to your revenue and booking volume. Navigate to **Admin > Analytics > Services** to open it. [SCREENSHOT: Services analytics page showing the service mix breakdown] --- ## Service Mix Breakdown A table lists every service type your company offers. Each row includes: | Column | Description | |--------|-------------| | **Service** | Name of the service (House Wash, Roof Wash, Gutters, Driveway, Windows, etc.) | | **Estimates Sent** | Number of estimates that included this service | | **Won** | Number of accepted estimates that included this service | | **Win Rate** | Percentage of sent estimates won for this service | | **Revenue** | Total revenue from accepted estimates for this service | | **Avg Deal Size** | Average dollar amount per accepted estimate for this service | Click any column header to sort. Sort by Revenue to see your top earners. Sort by Win Rate to see which services close most easily. [SCREENSHOT: Service mix table sorted by revenue with House Wash at the top] --- ## Revenue Distribution Chart A pie or donut chart visualizes revenue share by service. Each slice represents one service type. Hover over a slice to see the exact dollar amount and percentage. This makes it easy to see at a glance whether your revenue is concentrated in one service or spread across many. [SCREENSHOT: Revenue distribution donut chart showing percentage breakdown by service] --- ## Volume vs. Revenue Comparison A bar chart plots two bars per service: one for volume (number of estimates won) and one for revenue. This highlights services where you do a lot of jobs but earn less per job, and services where fewer jobs bring in more money. A service with high volume but low revenue per job might benefit from a price increase. A service with high revenue but low volume might be worth marketing more aggressively. [SCREENSHOT: Volume vs. revenue bar chart comparing the two metrics side by side for each service] --- ## Identifying Top Performers Look for services that rank high on both revenue and win rate. These are your strengths. They close easily and bring in good money. Services with a high win rate but low revenue may be underpriced. Consider raising rates and monitoring whether the win rate holds. --- ## Identifying Underperformers Services with low win rates deserve attention. Ask yourself: - Is the price too high for what the market will pay? - Are estimates for this service taking too long to send? - Does your team need training on selling this service? If a service has both low volume and low win rate, consider whether it belongs in your offering at all. --- ## Tips - **Review monthly.** Service mix shifts with seasons. Track changes over time rather than reacting to a single month. - **Cross-reference with pricing.** If a service has a dropping win rate, check whether a recent price increase caused it. - **Use this data in marketing.** Promote your highest-margin, highest-win-rate services in campaigns. See [Marketing Campaigns](https://docs.cleanestimate.pro/marketing/campaigns) for details. --- URL: https://docs.cleanestimate.pro/automations/actions Title: Actions and Step Types Description: Every action type you can add to an automation workflow. Category: automations Difficulty: intermediate Roles: owner, manager Last updated: 2026-04-23 --- # Actions and Step Types Each step in a workflow performs one action. There are 17 step types currently available in the builders, organized into seven categories. This page explains what each one does and how to configure it. --- ## Communication ### Send SMS Sends a text message to the customer. The message body supports [merge fields](https://docs.cleanestimate.pro/automations/merge-fields) for personalization. **Configuration:** - **Template** -- the message text with merge fields like `[customer.first_name]` - **From Number** -- defaults to your organization's active telecom number, or pick a specific one The system checks SMS opt-out status before every send. If the customer has texted STOP, the step is skipped automatically. A character counter and segment calculator show whether your message fits in one SMS segment (160 characters) or will be split into multiple. ### Send Email Sends an email to the customer. **Configuration:** - **Subject** -- email subject line with merge field support - **Body** -- HTML email body with merge field support - **From Name** -- defaults to your organization name - **Reply-To** -- optional override ### Make Call Places an outbound call through your workspace telecom number. **Configuration:** - **Agent Target** -- who should receive the first leg when the step is configured to ring an assigned rep - **Whisper Message** -- TTS message played to the rep before the customer is connected - **Call Timeout** -- how long to ring before giving up - **Record Call** -- toggle call recording on or off - **If No Answer** -- retry, continue to the next step, or drop a voicemail When the step runs, CE Pro uses the assigned rep phone as the live bridge target and the workspace telecom number as the caller ID, so **Make Call** stays a real two-party call instead of falling back to a one-way robot message. CE Pro logs the call into the unified **Messages** thread and keeps the call outcome on the workflow run. ### Voicemail Drop Places an outbound voicemail drop through the same telecom number. **Configuration:** - **TTS Message** -- the text-to-speech message to leave - **Audio URL** -- optional hosted audio file for Twilio voicemail-drop flows - **Voice** -- select from available TTS voices when using text-to-speech The voicemail event is logged into the unified **Messages** thread as a voicemail entry instead of a generic call note. Esendex Phase 1 voicemail drop uses text-to-speech scripting. Custom uploaded audio playback remains a Twilio-only path. --- ## Timing ### Delay Pauses the workflow for a specified duration before moving to the next step. **Configuration:** - **Duration** -- a number - **Unit** -- seconds, minutes, hours, or days If business hours are enabled on the workflow, the delay respects them. A 2-hour delay that lands at 5 PM will resume at 10 AM the next business day (if business hours are 8 AM to 6 PM). The same run is resumed from the waiting step, even for long delays or business-hours holds. --- ## Logic ### Condition Evaluates a TRUE/FALSE expression and branches the workflow. The TRUE path continues down one branch and the FALSE path down another. **Configuration:** - **Conditions** -- one or more field/operator/value rules - **Logic** -- ALL conditions must be true (AND) or ANY can be true (OR) Available condition fields include customer data, estimate totals, job status, tags, and behavioral signals like whether the contact replied or a call connected. In the visual builder, condition nodes have two output handles. Connect the green TRUE handle to the steps that run when the condition passes, and the red FALSE handle to the alternative path. --- ## CRM ### Update Status Changes the status of a lead, estimate, job, or invoice. **Configuration:** - **Entity** -- which record type to update - **New Status** -- the target status value ### Add Tag Adds a tag to the customer record. Tags are useful for segmentation and as condition inputs in later steps or other workflows. **Configuration:** - **Tag Name** -- the tag to add (case-insensitive, skips duplicates) ### Remove Tag Removes a tag from the customer record. **Configuration:** - **Tag Name** -- the tag to remove (no error if it does not exist) ### Assign User Assigns a team member to the lead, estimate, or job. **Configuration:** - **Assignment Mode** -- choose a specific user, use **Round Robin** to rotate through eligible owners/managers/sales reps, or use **Least Loaded** to compare each teammate's active assigned estimates, jobs, and leads before picking the lightest queue ### Create Task Creates an internal follow-up item and assigns it to a team member. **Configuration:** - **Title** -- task title with merge field support - **Assign To** -- specific user or the trigger user (whoever is assigned to the entity) - **Due In** -- hours until the task is due Automation tasks are logged into the unified **Messages** inbox as internal items with assignment and due-date metadata so reps can work the handoff from the same conversation thread. ### Update Field Updates a specific field on a record. Only fields on the allowed list can be updated for safety. **Configuration:** - **Entity** -- lead, estimate, job, invoice, or client - **Field** -- the field name - **Value** -- the new value --- ## Integrations ### Webhook Sends an HTTP request to an external URL. Use this to push data to Zapier, Make, your own API, or any third-party service. **Configuration:** - **URL** -- the endpoint (HTTPS only) - **Method** -- GET or POST - **Body Template** -- JSON body with merge field support The webhook includes SSRF protection. Private IPs, localhost, and cloud metadata endpoints are blocked. ### Internal Note Adds a note to the customer's conversation thread. The note is visible to your team but not to the customer. **Configuration:** - **Note** -- the text to add, with merge field support Internal notes created by automations are written directly into the unified **Messages** inbox thread for that customer or estimate. --- ## Gamification ### Award XP Awards experience points to a team member through the gamification system. **Configuration:** - **Target** -- the assigned rep, crew lead, or a specific user - **Amount** -- number of XP to award - **Reason** -- description that appears in the XP log --- ## Workflows ### Enroll in Workflow Enrolls the current contact into another active workflow. Use this to chain workflows together. **Configuration:** - **Target Workflow** -- pick from your active workflows The system prevents self-enrollment (a workflow cannot enroll into itself) and checks for existing active enrollments to avoid duplicates. ### Remove from Workflow Removes the contact from another workflow if they are currently enrolled. This cancels their active run. **Configuration:** - **Target Workflow** -- pick from your workflows --- ## Tips - Combine SMS and Email in a sequence with delays between them. Customers respond to different channels at different times. - Use conditions after a delay to check if the customer has already responded before sending another message. - Keep webhook payloads simple. Include only the data the receiving system needs. - Award XP after key milestones (booking, review left) to keep your team engaged. --- URL: https://docs.cleanestimate.pro/automations/auto-call Title: Auto-Call Description: Use provider-powered call steps, voicemail drops, and inbound call routing inside Clean Estimate Pro automations. Category: automations Difficulty: intermediate Roles: owner, manager Last updated: 2026-04-23 --- # Auto-Call Clean Estimate Pro supports phone-based automations through the shared phone number in your workspace. The active telecom provider can be **Esendex** or **Twilio**, depending on the setting in **Settings > Phone / Voice**. You can use phone automations for two different jobs: - **Inbound routing** -- customers call your workspace number, CE Pro rings the office forwarding line, and missed calls can trigger follow-up - **Outbound workflow actions** -- automations can place calls or drop voicemails as part of a follow-up sequence The AI Voice Agent is still available as a separate layer if you want AI to answer or qualify calls, but the base call automation steps no longer depend on it. --- ## How It Works ### Inbound customer calls 1. The customer calls your workspace phone number 2. CE Pro logs the inbound call immediately 3. CE Pro rings the configured office forwarding number 4. If nobody answers, CE Pro can record voicemail 5. The call or voicemail appears in the Messages thread and admin alerts ### Outbound workflow calls 1. A workflow trigger fires, such as `Lead Created`, `Estimate Accepted`, or `Missed Call` 2. A **Make Call** or **Leave Voicemail** step runs 3. CE Pro places the call through the active telecom provider using your workspace number 4. The result is logged into the customer thread and workflow run history --- ## Setting Up Auto-Call 1. Configure [Esendex](https://docs.cleanestimate.pro/settings/esendex) or [Twilio](https://docs.cleanestimate.pro/settings/twilio) 2. Save the workspace number in E.164 format 3. Add a forwarding number if you want inbound calls to ring a real phone first 4. Enable voice in the **Phone / Voice** settings card 5. Optional: turn on voicemail, recording, and missed-call alerts 6. Build or edit a workflow that uses a phone trigger or call step --- ## When To Use The AI Voice Agent Instead If your goal is conversational AI, lead qualification, or AI call handling before a human joins, use the [AI Voice Agent](https://docs.cleanestimate.pro/ai/voice-agent) on top of the base phone setup. The AI Voice Agent can: - answer inbound calls to your Twilio number with an AI receptionist when that Twilio voice-agent path is enabled - place outbound qualification calls from the **AI > Voice Agent** page - step in as a fallback when speed-to-lead auto-dial cannot connect an available rep - capture lead details, summarize the call, and create callback notes in the customer's thread - warm-transfer qualified callers to an available rep when routing rules allow it --- ## Step Configuration ### Make Call Use **Make Call** when you want the workflow to place a live outbound call. Important settings: - **Agent Target** -- who should receive the first leg when you are calling an assigned rep flow - **Whisper Message** -- the TTS message the rep hears before the customer is connected - **Call Timeout** -- how long to ring before giving up - **Record Call** -- whether to request call recording - **If No Answer** -- retry, continue, or drop voicemail ### Leave Voicemail Use **Leave Voicemail** when you want the workflow to drop a voicemail without requiring a live rep. Important settings: - **TTS Message** -- the text-to-speech message to leave - **Audio URL** -- optional hosted audio file for Twilio voicemail-drop flows - **Voice** -- the TTS voice to use when no audio file is provided Esendex Phase 1 voicemail-drop automation uses text-to-speech scripting. Custom uploaded audio playback is still a Twilio-only path. --- ## Triggers And Actions Phone automations now support: - **Triggers:** `Call Received`, `Call Answered`, `Missed Call`, `Voicemail Received`, `Call Completed` - **Actions:** `Make Call`, `Leave Voicemail` That means you can build flows like: - missed call -> send SMS -> create task - estimate accepted -> thank-you SMS -> make call to assigned rep - lead created -> make call -> voicemail drop fallback --- ## Best Practices - **Text before you call.** A short SMS before the call improves pickup rates because the customer recognizes the number. - **Keep the whisper short.** One or two sentences with the customer name and source is enough. - **Use voicemail intentionally.** A callback promise and next step work better than a long sales pitch. - **Route missed calls immediately.** A missed-call workflow with SMS + task is usually the fastest operational win. --- ## Monitoring Call Performance Track phone automation performance in two places: - **Workflow run history** -- each run shows whether the call connected, failed, or fell back - **Messages inbox** -- every call and voicemail is attached to the customer thread If your connection rate is low, consider: - adding a pre-call SMS so customers recognize the number - adjusting timeout and retry settings - checking that the active telecom number has proper caller ID configured - confirming the office forwarding number is correct and actually being answered --- URL: https://docs.cleanestimate.pro/automations/overview Title: Automations Overview Description: Build event-driven workflows that send messages, update records, and orchestrate follow-up automatically. Category: automations Difficulty: beginner Roles: owner, manager Last updated: 2026-03-13 --- # Automations Overview Automations let you build multi-step workflows that run automatically when something happens in your business. A lead comes in, an estimate gets sent, a job is completed -- and CE Pro responds with the right sequence of messages, updates, and actions without any manual work. --- ## What Changed from Follow-Up Sequences The previous Follow-Up Sequences system let you set up basic SMS and email sequences for three fixed scenarios: speed-to-lead, estimate follow-up, and post-job. Automations replace that system with a fully flexible workflow engine. Key differences: - **Any trigger, not just three.** Choose from trigger types like lead created, estimate sent, job completed, invoice events, appointment upcoming, and more. - **Branching and conditions.** Add IF/THEN logic that evaluates contact data, estimate totals, tags, or job status to route contacts down different paths. - **More action types.** Beyond SMS and email, you can assign users, create tasks, update fields, add tags, award XP, fire webhooks, and enroll contacts in other workflows. - **Visual canvas builder.** Drag and drop nodes on a canvas to design complex workflows visually. Connect them with edges to define the flow. - **Pre-built templates.** Start from one of 6 test-ready templates and customize from there. - **Run history and analytics.** See every execution, step by step. Know exactly what happened and when. Legacy call-based steps may still appear in older workflows, but **Make Call** and **Voicemail Drop** cannot be added or activated in the current engine. If you have existing follow-up sequences, you can [migrate them](https://docs.cleanestimate.pro/automations/migrating-from-sequences) to the new system. --- ## Where to Find Automations Click **More > Automations** in the sidebar. You will see: - A stats bar showing active workflows, paused workflows, total runs, and success rate - A table listing all your workflows with status, trigger, and run counts - Quick-access tabs to filter by Active, Paused, or Drafts If your workspace is brand new and has no automation history yet, those analytics cards default to zero until the first workflow runs. [SCREENSHOT: Automations list page showing stats bar and workflow table with Active/Paused/Drafts tabs] Access to this area is controlled by the **Automations** permissions in **Team > Permissions**: - **Automations view** lets a teammate open the workflow list, detail pages, run history, and analytics. - **Automations manage** is required to create, edit, activate, pause, test, cancel, or manually enroll contacts in workflows. --- ## How It Works Every automation follows the same cycle: 1. **A trigger fires.** Something happens in your account -- a lead is created, an estimate is sent, a job status changes. 2. **CE Pro matches the event.** The engine checks all active workflows to see which ones match the trigger. 3. **Entry conditions are evaluated.** If you added conditions (like "estimate total is greater than $500"), they are checked before the workflow runs. 4. **Steps execute in order.** Each step runs one at a time -- send an SMS, wait 2 hours, send an email, check a condition, branch left or right. 5. **The run completes.** When all steps finish (or a condition routes to an end), the run is marked as completed. Delays are respected automatically. If a step says "wait 3 days," the engine holds that run and picks it back up at the right time. Messages only send during your configured business hours. If the run pauses for business hours or a long delay, the same run resumes from the exact waiting step instead of restarting the workflow. When you activate a new-engine workflow on **Lead Created**, **Estimate Sent**, or **Job Completed**, CE Pro prefers the automation engine for that trigger so customers do not get duplicate outreach from both the new engine and legacy follow-up sequences. --- ## Core Concepts ### Workflows A workflow is the container. It has a name, a trigger, optional entry conditions, and a list of steps. Workflows can be in one of four states: Draft, Active, Paused, or Archived. ### Steps Each step is an action the workflow takes. Steps run in sequence unless a condition step branches the flow. There are 19 step types grouped into categories like Communication, Timing, Logic, CRM, and Integrations. `Create Task` and `Internal Note` steps are logged into the unified **Messages** inbox as internal thread items so your team can see the automation handoff in the same place as customer communication. ### Runs A run is a single execution of a workflow for one contact. Every time the trigger fires and conditions pass, a new run is created. You can view all runs, see which step they are on, and inspect the output of each step. ### Enrollments An enrollment tracks which contact is in which workflow. The system prevents duplicate enrollments -- a contact cannot be enrolled in the same workflow twice at the same time. Manual enrollment targets only the workflow you selected. Starting one workflow from the detail page does not enroll the contact into other manual-trigger workflows in your account. --- ## Getting Started The fastest way to start is to use a template: 1. Go to **Automations > Templates** 2. Pick a template like `TEST - Speed to Lead - Immediate Response` or `TEST - Estimate Follow-Up` 3. Click **Use Template** -- this clones the workflow into your account 4. Customize the messages, delays, and conditions to match your business 5. Click **Activate** Or build from scratch using the [wizard builder](https://docs.cleanestimate.pro/automations/creating-workflows) or [visual canvas](https://docs.cleanestimate.pro/automations/visual-builder). --- ## What You Can Automate Here are the most common workflows our customers set up: - **Speed-to-Lead:** Immediate SMS, internal handoff, and a conditional follow-up if the lead does not reply - **Estimate Follow-Up:** Multi-day drip of SMS and email reminders after sending an estimate - **Review Request:** Ask for a Google review 1 day after job completion, with a reminder if they do not leave one - **Invoice Reminders:** Escalating reminders before and after an invoice due date - **Appointment Reminders:** Separate reminders for lead or estimate appointments and scheduled jobs - **Win-Back Campaigns:** Quarterly outreach to dormant customers with a discount offer See [Templates](https://docs.cleanestimate.pro/automations/templates) for ready-made versions of all of these. --- URL: https://docs.cleanestimate.pro/automations/creating-workflows Title: Creating Workflows Description: Start in the guided wizard or jump straight into the visual builder to build an automation from trigger to activation. Category: automations Difficulty: beginner Roles: owner, manager Last updated: 2026-03-30 --- # Creating Workflows CleanEstimate Pro now supports two creation paths: - **Wizard builder** for guided step-by-step setup - **Visual builder** for a canvas-first flow with connected steps and branch paths The wizard is still the default starting point. The visual builder is now available before you finish building a workflow, so you can choose the editing style that fits the job. --- ## Choose Your Starting Point 1. Go to **More > Automations** in the sidebar. 2. Click the **New Automation** button in the top right. On the new workflow screen, you now have two clear options: - Stay in the **wizard** and work through Trigger, Conditions, Actions, and Review - Click **Open Visual Builder** to create a draft workflow shell and jump straight into the canvas editor The visual builder is currently optimized for desktop screens. On mobile, the CTA stays visible, but CE Pro will keep you in the wizard flow instead of opening the canvas. [SCREENSHOT: New automation page showing the standard wizard plus the Open Visual Builder action] --- ## Wizard Builder If you stay in the wizard, you will see a step indicator at the top showing four steps: Trigger, Conditions, Actions, and Review. [SCREENSHOT: New automation wizard showing the 4-step indicator with Step 1 (Trigger) active] --- ## Step 1: Choose a Trigger A trigger is the event that starts the workflow. Pick from categories like Lead Activity, Estimates, Jobs, Invoicing, Appointments, and more. Click a category card to expand it and see the available triggers. Select the one that matches when you want the workflow to start. Some triggers require extra configuration. For example: - **Job Status Changed** asks you to pick which status transition should fire the trigger - **Appointment Upcoming** asks how many minutes before the appointment to trigger and whether the reminder is for a lead or estimate visit or a scheduled job - **Phone triggers** like **Call Received** or **Missed Call** can be paired with SMS, task, call, or voicemail actions [SCREENSHOT: Trigger selection showing the Estimates category expanded with "Estimate Sent" selected] Click **Next** when your trigger is set. --- ## Step 2: Entry Conditions (Optional) Conditions let you filter which contacts enter the workflow. If you skip this step, every matching trigger event will start a run. Add conditions by clicking **Add Condition**. Each condition has three parts: 1. **Field** -- what to check (e.g., Estimate Total, Customer State, Service Type) 2. **Operator** -- how to compare (equals, contains, greater than, is empty, etc.) 3. **Value** -- the threshold or match value When you have multiple conditions, choose whether **ALL** must be true (AND logic) or **ANY** can be true (OR logic). Examples: - Estimate Total is greater than $500 - Customer State equals "FL" - Service Type contains "pressure washing" - Customer has no tag "VIP" [SCREENSHOT: Conditions step showing two conditions with ALL logic selected] Click **Next** to continue. --- ## Step 3: Add Actions This is where you build the sequence of steps. The steps display as a numbered timeline. The wizard remains the best choice when you want a guided setup flow and do not need to manually arrange branch paths on a canvas. Click **Add Step** to open the step palette. Steps are organized by category: - **Communication:** Send SMS, Send Email, Make Call, Leave Voicemail, Internal Note - **Timing:** Delay (wait X minutes/hours/days) - **Logic:** Condition (IF/THEN branching) - **CRM:** Update Status, Add Tag, Remove Tag, Assign User, Create Task, Update Field - **Integrations & Workflows:** Webhook, Enroll in Workflow, Remove from Workflow - **Gamification:** Award XP When you add a step, a configuration panel opens where you can: - Set the step label - Write message templates with [merge fields](https://docs.cleanestimate.pro/automations/merge-fields) - Configure delays, conditions, or CRM updates - Preview rendered messages with example data Use the up/down arrows to reorder steps. Click the pencil icon to edit, or the trash icon to delete. [SCREENSHOT: Actions step showing a 5-step timeline with Send SMS, Delay, Send Email, Condition, and Send SMS steps] Click **Next** when your steps are ready. ### Common Recipe: Accepted Estimate Follow-Up One high-value workflow is an immediate post-acceptance handoff: 1. Trigger on **Estimate Accepted** 2. Add a **Send Email** step thanking the customer for approving the estimate 3. Add a **Send SMS** step confirming the team will follow up with next steps and scheduling 4. Add a **Create Task** step so your office or assigned rep has an internal follow-up action right away You can extend the same pattern with a **Make Call** step if you want the assigned rep or office line to be contacted automatically too. This is a good pattern when you want every estimate type that uses the shared acceptance flow to trigger the same customer acknowledgement and internal handoff. --- ## Step 4: Review and Activate The review screen shows everything at a glance: - **Workflow name and description** -- edit these fields to give your automation a clear name - **Trigger summary** -- confirms what event starts the workflow - **Conditions** -- lists any entry conditions you set - **Step timeline** -- compact view of all steps in order - **Delivery window** -- configure business hours if you want messages to only send during work hours ### Business Hours Toggle on business hours to restrict when messages are delivered. Set: - Start and end times (e.g., 8:00 AM to 6:00 PM) - Which days of the week are active - Your timezone Messages scheduled outside business hours will be held until the next available window. [SCREENSHOT: Review step showing workflow summary with business hours configured for Monday-Friday 8AM-6PM] ### Saving You have two options: - **Save as Draft** -- saves the workflow without activating it. Use this when you want to review it later or get approval from your team. - **Activate Automation** -- saves and immediately enables the workflow. It will start running the next time the trigger fires. --- ## Editing an Existing Workflow To edit a workflow you have already created: 1. Go to **Automations** and click on the workflow name 2. Click the **Edit** button in the action bar 3. The wizard opens pre-populated with your existing settings 4. Make your changes and save Changes to active workflows take effect immediately. If you need to make significant changes, consider pausing the workflow first. --- ## When to Use the Visual Builder Use the visual builder when you want to: - see the workflow as a connected graph instead of a timeline - work with branching paths and condition logic more visually - drag steps into place and keep manual layout changes - auto-arrange a workflow into a readable top-to-bottom flow The visual builder now opens from: - the **Open Visual Builder** action on the new workflow page - the **Build Visually** action on template cards - the workflow detail page for existing saved workflows For the full canvas workflow, see [Visual Workflow Builder](https://docs.cleanestimate.pro/automations/visual-builder). --- URL: https://docs.cleanestimate.pro/automations/merge-fields Title: Merge Fields Description: Personalize automation messages with dynamic data from your contacts, estimates, and jobs. Category: automations Difficulty: beginner Roles: owner, manager Last updated: 2026-03-12 --- # Merge Fields Merge fields let you insert dynamic data into your automation messages. Instead of writing a generic message, you can address the customer by name, reference their estimate total, or include a payment link -- all automatically. --- ## Syntax Merge fields use the `[field.name]` format. For example: ``` Hi [customer.first_name], thanks for requesting an estimate! ``` When the workflow runs, the engine replaces `[customer.first_name]` with the actual customer name from the contact record. --- ## Using the Merge Field Toolbar When editing a message template in the wizard or visual builder, a merge field toolbar appears below the text area. It has tabs for each category: - **Customer** -- contact information - **Organization** -- your company details - **Estimate** -- estimate data - **Job** -- job data - **Invoice** -- invoice data - **Appointment** -- scheduling data Click any field pill to insert it at your cursor position in the text area. [SCREENSHOT: Merge field toolbar showing Customer tab with pills for first_name, last_name, full_name, email, phone] --- ## Available Fields ### Customer | Field | Example | |-------|---------| | `[customer.first_name]` | John | | `[customer.last_name]` | Smith | | `[customer.full_name]` | John Smith | | `[customer.email]` | john@example.com | | `[customer.phone]` | (555) 123-4567 | | `[customer.address]` | 123 Main St | | `[customer.city]` | Tampa | | `[customer.state]` | FL | | `[customer.zip]` | 33601 | ### Organization | Field | Example | |-------|---------| | `[company.name]` | Tampa Bay Power Wash | | `[company.phone]` | (813) 555-0100 | | `[company.email]` | info@tbpowerwash.com | | `[company.website]` | www.tbpowerwash.com | | `[company.review_link]` | Google review URL | ### Estimate | Field | Example | |-------|---------| | `[estimate.number]` | EST-001234 | | `[estimate.total]` | $1,250.00 | | `[estimate.link]` | Customer portal link | | `[estimate.services]` | House Wash, Driveway | | `[estimate.expiration_date]` | 03/25/2026 | ### Job | Field | Example | |-------|---------| | `[job.number]` | JOB-005678 | | `[job.date]` | 03/15/2026 | | `[job.time]` | 9:00 AM | | `[job.status]` | Scheduled | | `[job.crew]` | Team Alpha | | `[job.services]` | House Wash | ### Invoice | Field | Example | |-------|---------| | `[invoice.number]` | INV-009012 | | `[invoice.total]` | $1,250.00 | | `[invoice.balance_due]` | $625.00 | | `[invoice.due_date]` | 03/20/2026 | | `[invoice.payment_link]` | Stripe payment URL | ### Appointment | Field | Example | |-------|---------| | `[appointment.date]` | 03/15/2026 | | `[appointment.time]` | 9:00 AM | | `[appointment.type]` | Estimate Walk-through | ### Sales Rep | Field | Example | |-------|---------| | `[rep.first_name]` | Mike | | `[rep.full_name]` | Mike Johnson | | `[rep.phone]` | (813) 555-0199 | | `[rep.email]` | mike@tbpowerwash.com | --- ## Preview When editing SMS or email templates in the wizard builder, a live preview shows the rendered message with example data filled in. Use this to verify your merge fields are correct and the message reads naturally before activating. --- ## Tips - Always include `[customer.first_name]` in your opening line. Personalized messages get higher response rates. - Use `[estimate.link]` or `[invoice.payment_link]` to make it easy for customers to take action directly from the message. - Keep SMS messages short. Merge fields expand to real data at send time, so account for longer names or addresses when estimating message length. - If a merge field cannot be resolved (for example, the customer has no email on file), it is replaced with an empty string. Structure your sentences so they still make sense if a field is blank. --- URL: https://docs.cleanestimate.pro/automations/migrating-from-sequences Title: Migrating from Follow-Up Sequences Description: Move your existing follow-up sequences to the new automation engine. Category: automations Difficulty: intermediate Roles: owner Last updated: 2026-04-23 --- # Migrating from Follow-Up Sequences If you have been using the original Follow-Up Sequences system (speed-to-lead, estimate follow-up, post-job), you can migrate them to the new automation engine. The migration preserves your existing steps, timing, and active enrollments. --- ## What Gets Migrated The migration tool converts each of your follow-up sequences into a new workflow: | Old Sequence Type | New Workflow Category | New Trigger | |---|---|---| | Speed to Lead | Lead Follow-Up | Lead Created | | Estimate Follow-up | Estimate Follow-Up | Estimate Sent | | Post-Job | Review Request | Job Completed | For each sequence: - **Steps** are converted to workflow steps. SMS steps become Send SMS, email steps become Send Email, and auto-dial steps become Make Call. - **Delays** between steps are converted to Delay steps. - **Active enrollments** are converted to workflow runs in "Waiting" status so contacts continue where they left off. - **The old sequence is deactivated** after successful migration to prevent double-sending. Migrated call-based steps now stay active in the new engine. After migration, review the workspace **Phone / Voice** provider settings before you activate any workflow that uses **Make Call** or **Leave Voicemail**. --- ## How to Migrate Migration is available to account owners only. 1. Go to **More > Automations** 2. If you have existing sequences that have not been migrated, you will see a migration prompt 3. Click **Migrate Sequences** 4. The system processes each sequence and reports results: how many were migrated, skipped, or had errors The migration is idempotent. If a workflow with the same name already exists, that sequence is skipped. You can safely run it multiple times. --- ## After Migration Once your sequences are migrated: 1. **Review each new workflow** in the Automations list. Open them to verify the steps and messages look correct. 2. **Activate the workflows** when you are satisfied. Migrated workflows start in Draft status. 3. **Check active enrollments.** Contacts who were mid-sequence will continue from where they were as Waiting runs. 4. **The old sequences are disabled.** You do not need to manually turn them off. --- ## Do I Have to Migrate? No. The old Follow-Up Sequences system continues to work for existing sequences. However, new automations should be built using the new engine. When you activate a new-engine workflow on **Lead Created**, **Estimate Sent**, or **Job Completed**, CE Pro prefers the new automation engine for that trigger so customers do not get duplicate outreach from both systems. The new system offers: - More trigger types - Branching logic - More action types (tasks, tags, XP, webhooks) - Visual builder - Better run history and analytics We recommend migrating when you are ready. There is no deadline or forced migration. --- ## Troubleshooting ### Some steps look different after migration The migration maps channels to the closest step type. If you had a "both" step (sending SMS and email together), it becomes two separate steps -- one Send SMS and one Send Email. The content and timing are preserved. ### Active enrollments are showing as "Waiting" This is expected. Contacts who were mid-sequence are converted to Waiting runs. They will resume execution when their next delay expires, just as they would have in the old system. ### A sequence was skipped If a workflow with the same name and organization already exists, the migration skips that sequence to avoid duplicates. If you want to re-migrate, delete or rename the existing workflow first. --- URL: https://docs.cleanestimate.pro/automations/monitoring-runs Title: Monitoring Workflow Runs Description: Track automation execution, view step-by-step timelines, and troubleshoot failures. Category: automations Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-19 --- # Monitoring Workflow Runs Every time a workflow fires, it creates a run. The run history shows you exactly what happened, step by step, for every contact that entered the workflow. Delayed runs and scheduled reminder checks now use the same internal automation engine auth path behind the scenes, including the same secret precedence and timing-safe bearer-token validation. That reduces environment-specific mismatches where waiting runs and scheduled triggers could be accepted by one internal engine endpoint but rejected by another. When one inbound event or webhook matches multiple runs at once, CE Pro now fans those run executions out in parallel instead of walking them one by one. That keeps the run queue moving faster after bursty events while still capturing per-run failures in the response and audit trail. --- ## Viewing Runs ### From the Workflow Detail Page 1. Go to **Automations** and click on a workflow name 2. Click the **Run History** tab You will see a table of all runs for that workflow. Each row shows: - **Contact name** -- who the workflow ran for - **Started** -- when the run began (relative time like "2h ago") - **Status** -- Running, Waiting, Completed, Failed, or Cancelled - **Current Step** -- which step the run is on (for active runs) - **Duration** -- total elapsed time [SCREENSHOT: Run History tab showing a table of runs with status pills and relative timestamps] ### From the Global Runs Page To see runs across all workflows, use the API at `/api/automations/runs`. The workflow detail page is the primary UI for monitoring. --- ## Run Statuses | Status | Meaning | |--------|---------| | **Running** | Currently executing a step | | **Waiting** | Paused on a delay step, waiting for the timer | | **Completed** | All steps finished successfully | | **Failed** | One or more steps encountered an error during the run | | **Cancelled** | Manually cancelled by a user | | **Paused** | The workflow was paused while this run was active | When a delay expires or a business-hours hold clears, CleanEstimate Pro promotes that same run back to **Running** automatically before the next step executes. The engine now also checks the stored wake time before resuming a waiting run, so internal resume calls cannot skip ahead of a delay or business-hours hold. --- ## Expanding a Run Click on any run row to expand it and see the step-by-step execution timeline. Each step shows: - **Step icon and label** -- what type of action it was - **Status** -- completed, failed, skipped, or pending - **Timestamp** -- when the step executed - **Duration** -- how long the step took - **Output** -- for communication steps, a preview of the message that was sent For failed steps, a red error box shows the error message. For condition steps, the result shows which branch was taken (TRUE or FALSE). If any step fails, the run finishes with a **Failed** status so your run history and success-rate metrics stay accurate. [SCREENSHOT: Expanded run showing a timeline of 5 steps with green check marks, a condition result, and a sent SMS preview] --- ## Test Runs Before activating a workflow, use the **Test Run** button on the workflow detail page. This opens a modal where you can: 1. Enter mock contact data (name, email, phone, estimate total, etc.) 2. Click **Run Test** 3. See a simulation of every step without actually sending messages The test results show: - Whether entry conditions pass or fail - Each step's rendered output with your mock data filled in - Delay durations and computed wake times - Condition evaluation results This is the safest way to verify your workflow before it goes live. [SCREENSHOT: Test run modal showing mock data fields and rendered step previews with green SMS bubbles] --- ## Cancelling a Run To cancel an active run: 1. Expand the run in the Run History tab 2. Click the **Cancel** button This immediately stops the run. Any pending delay steps are abandoned, and no further messages are sent. The associated enrollment is also completed. Cancellation is useful when a customer contacts you directly and you want to stop the automated sequence. --- ## Workflow Overview Stats The **Overview** tab on the workflow detail page shows aggregate metrics: - **Total Runs** -- how many times the workflow has executed - **Completed** -- successful completions - **Failed** -- runs that encountered errors - **Success Rate** -- percentage of runs that completed without errors - **Last Run** -- when the most recent run started A bar chart shows runs per day over the last 30 days, with green bars for completed and red bars for failed runs. [SCREENSHOT: Workflow overview tab showing 5 stat cards and a 30-day runs chart] --- ## Troubleshooting Failures When a run fails: 1. Expand the run to find the failed step (marked with a red X) 2. Read the error message -- common issues include: - **SMS opt-out** -- the customer opted out, so the SMS was skipped - **Rate limited** -- too many messages sent in a short period - **Webhook timeout** -- an external endpoint did not respond in time - **Missing data** -- a required field like phone number was not available 3. Fix the underlying issue (update the contact, check integrations) 4. If needed, manually enroll the contact again to restart the workflow If the failed step was a webhook, double-check that the destination is a public HTTPS endpoint. CE Pro blocks localhost, private-network, and other internal-only targets. --- ## Tips - Check run history after activating a new workflow to confirm it is behaving as expected. - Use the 30-day chart to spot trends. A sudden increase in failures may indicate an integration issue. - Failed runs do not retry automatically. If a transient error caused the failure, you can re-enroll the contact. --- URL: https://docs.cleanestimate.pro/automations/triggers Title: Triggers Description: Every event type that can start an automation workflow. Category: automations Difficulty: intermediate Roles: owner, manager Last updated: 2026-04-23 --- # Triggers A trigger is the event that starts a workflow. When the event fires and any entry conditions pass, a new run is created and the workflow begins executing. Each workflow has exactly one trigger. You choose the trigger in Step 1 of the wizard builder or by placing the trigger node in the visual builder. --- ## Trigger Categories Triggers are grouped into categories based on the area of your business they relate to. ### Lead Activity | Trigger | Fires When | |---------|-----------| | Lead Created | A new lead is added to your account from any source | | Lead Status Changed | A lead's status changes (e.g., new to contacted) | | Lead Source Match | A lead comes in from a specific source you configure | ### Estimates | Trigger | Fires When | |---------|-----------| | Estimate Created | A new estimate is saved | | Estimate Sent | An estimate is delivered to the customer | | Estimate Viewed | The customer opens the estimate link | | Estimate Accepted | The customer signs and accepts | | Estimate Declined | The customer declines the estimate | | Estimate Expired | The estimate passes its expiration date without a response | ### Jobs | Trigger | Fires When | |---------|-----------| | Job Created | A new job is created (usually from an accepted estimate) | | Job Status Changed | A job transitions to a new status (you pick which status) | | Job Completed | A job is marked as completed | | Job Assigned | A job is assigned to a crew member or rep | ### Invoicing | Trigger | Fires When | |---------|-----------| | Invoice Created | A new invoice is generated | | Invoice Sent | An invoice is delivered to the customer | | Invoice Paid | Payment is received for an invoice | | Invoice Overdue | An invoice passes its due date without payment | ### Appointments | Trigger | Fires When | |---------|-----------| | Appointment Scheduled | A new appointment is booked | | Appointment Upcoming | A configured number of minutes before the appointment time | | Appointment Cancelled | An appointment is cancelled | ### Communication | Trigger | Fires When | |---------|-----------| | SMS Received | An inbound text message is received | | Email Received | An inbound email reply is received | | Call Received | An inbound phone call hits your workspace telecom number | | Call Answered | A call is answered and connected | | Missed Call | An inbound call is not answered | | Voicemail Received | A voicemail recording is captured | | Call Completed | A call finishes with final status and duration | ### System | Trigger | Fires When | |---------|-----------| | Manual Trigger | You manually enroll a contact from the workflow detail page | | Webhook Received | An external system sends data to your webhook URL | | Recurring Schedule | On a cron schedule you define (daily, weekly, monthly, etc.) | --- ## Trigger Configuration Some triggers need extra configuration to tell the engine exactly when to fire. ### Job Status Changed When you select this trigger, a dropdown appears asking which status transition should activate the workflow. For example, you might choose "en_route" to send the customer a text that the crew is on the way. ### Appointment Upcoming This trigger asks for a number of minutes before the appointment and which appointment type you want to target: - **Lead or Estimate** for site visits, estimate appointments, and pre-job sales visits - **Job** for scheduled service work - **1440 minutes** (24 hours) for a day-before reminder - **120 minutes** (2 hours) for a same-day heads-up ### Phone Triggers Phone triggers fire from the shared telecom number tied to your workspace. - **Call Received** is the first event, fired as soon as CE Pro accepts the inbound call. - **Missed Call** fires when the office forwarding leg is not answered. - **Voicemail Received** fires after the active provider provides the voicemail recording. In Esendex Phase 1, inbound voicemail recording playback is not live yet. - **Call Answered** fires when a call leg is answered. - **Call Completed** fires only when the call actually completes, not when the call ends as `no-answer`, `busy`, `failed`, or `canceled`. For phone triggers, the workflow context can include caller number, destination number, duration, voicemail transcript, and any confidently matched client or estimate. ### Lead Source Match Enter the lead source name that should activate the workflow. This is useful when you want different follow-up flows for Google Ads leads versus referral leads. ### Recurring Schedule Define a cron schedule and an audience query. The engine evaluates the audience query to find matching contacts, then creates one run per contact. Use this for things like quarterly win-back campaigns or monthly check-ins. --- ## One Trigger Per Workflow Each workflow can only have one trigger. If you need the same set of steps to run for different events, you have two options: 1. **Duplicate the workflow** and change the trigger on the copy. 2. **Use the "Enroll in Workflow" step** from one workflow to chain into another. --- ## Tips - Start with the most common triggers: Lead Created, Estimate Sent, and Job Completed. These three cover the majority of field service automation use cases. - Test your trigger using the **Test Run** button on the workflow detail page before activating. It simulates the trigger with mock data so you can preview what happens. - Recurring schedule triggers are powerful but should be used carefully. Make sure your audience query is scoped correctly so you do not message customers who have opted out or are already in active workflows. If you are replacing a legacy Follow-Up Sequence, activate the new workflow on the same trigger so CE Pro routes new events through the automation engine instead of sending duplicate outreach from both systems. --- URL: https://docs.cleanestimate.pro/automations/visual-builder Title: Visual Workflow Builder Description: Design workflows on a drag-and-drop canvas with connected nodes. Category: automations Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-30 --- # Visual Workflow Builder The visual builder is a canvas-based editor where you drag step nodes, connect them with edges, and see the entire flow at a glance. It is the best tool for building complex workflows with branching logic. The visual builder is available on desktop screens (1024px and wider). On smaller screens, use the [wizard builder](https://docs.cleanestimate.pro/automations/creating-workflows) instead. --- ## Opening the Canvas There are three main ways to open the visual builder: 1. From **New Automation**, click **Open Visual Builder** to create a draft workflow shell and go straight to the canvas. 2. From a template card, click **Build Visually** to clone the template directly into the canvas editor. 3. From an existing workflow detail page, click **Visual Builder** in the action bar. [SCREENSHOT: Visual builder canvas showing a workflow with a trigger node connected to SMS, delay, and condition nodes] --- ## Layout The canvas has three panels: - **Left: Step Palette** -- a collapsible sidebar listing all available step types, organized by category. You can search by name. - **Center: Canvas** -- the main work area where nodes live. Scroll to pan, pinch or use controls to zoom. A dot grid helps with alignment. - **Right: Config Panel** -- appears when you select a node. Shows the configuration form for that step type. A toolbar at the top shows the workflow name, zoom controls, **Auto Arrange**, **Fit Workflow**, **Reset View**, a minimap toggle, and action buttons for saving, testing, and activating. When a workflow opens with missing or bad saved positions, CE Pro now auto-arranges the graph into a readable layered layout instead of stacking every step in a pile. --- ## Adding Nodes Drag a step type from the palette onto the canvas. The node appears where you drop it with a default configuration. Each node type has a distinct visual style: - **Trigger** (blue border) -- the starting point. There is always exactly one trigger node. - **Send SMS** (green border) -- message preview shown on the node - **Send Email** (purple border) -- subject line shown on the node - **Delay** (amber border) -- shows the wait duration - **Condition** (orange border) -- has two output handles: TRUE (green) and FALSE (red) - **Award XP** (yellow border) -- shows XP amount - **Other actions** (gray border) -- shows a summary of the action Call-based steps are fully available in the palette too. **Make Call** and **Leave Voicemail** use the same teal call-node styling so phone actions are easy to spot in larger workflows. --- ## Connecting Nodes Click an output handle and drag to an input handle to create an edge that defines the flow. For condition nodes, there are two output handles at the bottom of the node: - **TRUE** (left branch, green) -- connects to the path taken when the condition passes - **FALSE** (right branch, red) -- connects to the path taken when the condition fails Edges from condition nodes are automatically labeled **TRUE** or **FALSE** so the branch logic stays readable on larger workflows. [SCREENSHOT: A condition node with TRUE edge going right to a Send SMS node and FALSE edge going down to a Delay node] --- ## Configuring Nodes Click any node to select it. The config panel opens on the right with fields specific to that step type. All nodes have a **Label** field for a descriptive name. Beyond that, each type has its own form: - **Send SMS:** Message template textarea with merge field toolbar, character count, and SMS segment counter - **Send Email:** Subject and body fields with merge field toolbar - **Delay:** Duration number and unit selector (seconds, minutes, hours, days) - **Condition:** Field picker, operator, and value - **Update Status:** Entity and new status dropdowns - **Add/Remove Tag:** Tag name input - **Webhook:** URL, HTTP method Changes auto-save with a short debounce. The toolbar now shows clear canvas save states: - **Unsaved changes** - **Saving...** - **Saved** - **Save failed** --- ## Canvas Controls - **Zoom in/out** -- toolbar buttons or scroll wheel - **Auto Arrange** -- rebuilds the graph into a readable layered layout - **Fit Workflow** -- zooms to fit all nodes - **Reset View** -- returns the viewport to the default centered canvas view - **Minimap** -- toggle in toolbar to show a miniature overview in the corner - **Snap to grid** -- nodes snap to a 16px grid for clean alignment - **Delete node** -- select a node and press Delete/Backspace, or use the node's context menu --- ## Saving and Activating The canvas saves as you work: - Node positions auto-save after you move them. - Step labels and step settings auto-save after a short debounce when you edit them in the config panel. - New connections, disconnections, and branch-path edits are saved as soon as you make them. - The canvas viewport is saved separately, so returning to the workflow brings you back to the same zoom/pan state. Use the **Save** button in the toolbar when you want to force a fresh graph save before leaving the page. To activate the workflow directly from the canvas, click the status toggle button. Draft workflows can be activated; active workflows can be paused. --- ## Switching Between Builders You can switch between the wizard and visual builder at any time. Both editors work on the same underlying workflow data. Changes made in one are reflected in the other. - From the canvas toolbar, click **Wizard** to open the step-by-step editor - From the wizard, click **Open Visual Builder** before you finish the workflow, or open the saved workflow later and click **Visual Builder** If a save fails, the toolbar now keeps the error visible instead of pretending the canvas is already saved. Newly dropped nodes and branch connections also now persist through the same UUID-safe graph contract used by the rest of the workflow editor. --- URL: https://docs.cleanestimate.pro/automations/templates Title: Workflow Templates Description: Start fast with pre-built automation templates for common field service scenarios. Category: automations Difficulty: beginner Roles: owner, manager Last updated: 2026-04-23 --- # Workflow Templates Templates are pre-built automations designed for common field service workflows. Instead of building from scratch, pick a template, customize the messages, and activate. --- ## Browsing Templates Go to **More > Automations** and click the **Templates** tab, or visit the template gallery from the empty state when you have no workflows yet. For the built-in QA pack, CleanEstimate Pro also seeds the six `TEST - ...` workflows into the main automations list the first time an owner or manager with automation-manage access opens the Automations page for an org. They are created in **Draft** status so you can review them before activation. Both the main automations list and the template gallery are scoped to the workspace tied to your current signed-in session, so they always show the workflows and templates for the org you are actively viewing. Each template card shows: - Template name and category - Description of what it does - Number of steps - a **Use Template** button - a **Build Visually** button on desktop so you can jump straight into the canvas editor [SCREENSHOT: Template gallery showing 6 template cards in a 3-column grid] --- ## Using a Template You now have two ways to start from a template: ### Use Template 1. Click **Use Template** on the card 2. CE Pro clones the template into your account as a new workflow in Draft status 3. You are redirected to the edit page where you can customize everything 4. Update the message templates with your company details and tone 5. Adjust delays and conditions to match your preferences 6. Click **Activate** when ready ### Build Visually 1. Click **Build Visually** on the card 2. CE Pro clones the template into your account as a new Draft workflow 3. You are routed directly into the visual builder canvas 4. Use drag-and-drop, edge connections, and **Auto Arrange** to shape the flow 5. Save and activate when ready On smaller screens, CE Pro keeps the template flow in the wizard instead of pretending the desktop canvas is available. After the clone is created, it is fully independent from the built-in gallery template. You can rename it, change the trigger, or rebuild the step graph without affecting the original card in the gallery. --- ## Available Templates The current built-in gallery is a six-workflow QA pack. Every template is prefixed with `TEST -` so you can activate, validate, and remove the workflows cleanly after testing. ### TEST - Speed to Lead - Immediate Response **Category:** Lead Follow-Up | **Trigger:** Lead Created | **Steps:** 8 This template is the recommended starting point for speed-to-lead follow-up and can now be extended with call steps if your workspace voice settings are ready: 1. Immediate SMS welcome message 2. Internal note that the lead entered the workflow 3. Task creation for the assigned rep 4. Delay of 15 minutes 5. Condition check: did the customer reply? 6. Follow-up SMS if no reply 7. Lead status update to `contacted` ### TEST - Lead Appointment Reminder **Category:** Appointments | **Trigger:** Appointment Upcoming | **Steps:** 2 Built for estimate visits and site visits tied to leads: 1. SMS reminder 24 hours before the appointment 2. Internal note confirming the reminder was sent ### TEST - Job Appointment Reminder **Category:** Appointments | **Trigger:** Appointment Upcoming | **Steps:** 2 Built for scheduled service jobs: 1. SMS reminder 2 hours before the service window 2. Internal note confirming the reminder was sent ### TEST - Estimate Follow-Up **Category:** Estimate Follow-Up | **Trigger:** Estimate Sent | **Steps:** 13 Multi-touch follow-up sequence over multiple checkpoints: 1. Email summary at 1 day with estimate link 2. SMS check-in at 3 days 3. Condition: is estimate still pending? 4. Email with FAQ at 7 days 5. Manual follow-up task if still unsigned 6. Internal note documenting the pending estimate handoff ### TEST - Post-Job Review Request **Category:** Review Request | **Trigger:** Job Completed | **Steps:** 9 Automates review collection after the job is completed: 1. Thank-you SMS with your review link one day after completion 2. Condition check after 3 days: is a review still missing? 3. Follow-up email if no review has been captured 4. Final review check before awarding XP 5. XP award when the review flag is captured ### TEST - Post-Job Nurture **Category:** Customer Winback | **Trigger:** Job Completed | **Steps:** 7 Long-tail post-job follow-up for maintenance or recurring service: 1. Nurture email 60 days after completion 2. SMS follow-up 2 days later 3. Long delay until the annual re-engagement window 4. Rep task and internal note at the annual follow-up checkpoint --- ## Customizing Templates After cloning a template, you should customize: - **Message content** -- update the tone, company name, and offers to match your brand - **Delays** -- adjust timing based on your experience. Some businesses prefer faster follow-up cadences. - **Conditions** -- modify or remove condition checks based on what data you track - **Merge fields** -- verify that merge fields like `[company.review_link]` are configured in your settings These templates intentionally stay conservative so they work for every workspace, even before voice is configured. If Esendex or Twilio voice is ready in your workspace, you can add **Make Call** or **Leave Voicemail** steps after cloning the template. When a template uses `Create Task` or `Internal Note`, those steps surface in the unified **Messages** inbox as internal thread entries so the handoff stays attached to the customer conversation. Templates are a starting point. The best automations are tuned to your specific business and customer base. --- URL: https://docs.cleanestimate.pro/crm/accounts Title: Client Accounts Description: Group related contacts under a parent account for property managers and commercial clients. Category: crm Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-15 --- # Client Accounts Accounts are parent records that group related contacts together. Use them when you deal with organizations that have multiple people or properties. ## When to Use Accounts Use an account when: - A property management company manages ten buildings, each with a site contact. - A commercial client has a decision maker, a billing contact, and an on-site property manager. - A household has two homeowners who both communicate with your team. - A franchise owner has multiple locations. Use a standalone contact when: - A residential customer is a single person at a single address. - There is only one point of contact and no related records to group. ## Account Types When you create an account, you select a type: | Type | When to Use | |------|-------------| | **Company** | Businesses, corporations, LLCs | | **Household** | Families or couples at a single property | | **Group** | Informal groups like HOA boards or co-ops | | **Other** | Anything that does not fit the above | ## Creating an Account 1. Navigate to **Admin > Clients**. 2. Click **Add Account**. 3. Enter the **Account Name** (usually the company or household name). 4. Select the **Account Type**. 5. Set the **Status** (Lead, Prospect, Active, Inactive, Past). 6. Fill in optional fields: **Industry**, **Email**, **Phone**, **Website**. 7. Click **Save**. The account appears in the Clients table. It has no contacts yet. [SCREENSHOT: Add Account dialog with fields filled in] ## Adding Contacts to an Account Once an account exists, you can nest contacts under it. 1. Click **+ Add Contact** on the Clients page. 2. Fill in the contact's details (name, email, phone, address). 3. In the **Nested Under** dropdown, select the account. 4. Assign a **Role** from the dropdown: - **Decision Maker** — Approves proposals and signs contracts. - **Property Contact** — Handles on-site logistics and scheduling. - **Billing Contact** — Receives invoices and manages payments. - **Member** — General contact with no specific responsibility. 5. Click **Save**. The contact now appears nested under the account in the Clients table. [SCREENSHOT: Add Contact dialog with Nested Under dropdown set to an account and Role set to Property Contact] ## Viewing Account Hierarchy On the Clients page, account rows have an expand arrow on the left. Click it to reveal all nested contacts. Each contact shows their name, role badge, email, and phone. [SCREENSHOT: Expanded account row showing three nested contacts with role badges] ## Setting a Primary Contact One contact in each account should be the **primary contact**. The primary contact receives all communications by default when you send an estimate, invoice, or message to the account. To set a primary contact: 1. Open the account's profile page. 2. Find the contact you want to designate. 3. Click the three-dot menu next to their name. 4. Select **Set as Primary**. A "Primary" badge appears next to the contact's name. Primary-contact changes are saved transactionally now. If two admins update the same account at nearly the same time, the system keeps one primary contact instead of leaving the account with duplicate or missing primaries. Moving a contact into a different account as a regular member no longer clears the destination account's existing primary contact. Only an explicit primary-contact change on that same account will replace or clear the current primary. Account membership moves that also change primary-contact status now apply through the same transactional path. That means moving a current primary to another account or promoting a contact during a move no longer relies on a separate follow-up reconciliation step. [SCREENSHOT: Three-dot menu with Set as Primary option highlighted] ## Account-Level Metrics Accounts roll up financial data from all nested contacts: - **Leads** — The total number of leads tied to every nested contact. - **Lifetime Value** — The total revenue from every contact under the account, combined. - **Open Pipeline** — The total value of unsold estimates across all contacts. These rolled-up numbers appear on the account row in the Clients table and on the account profile page. They give you a true picture of how much an account is worth to your business. ## Account Profile Tabs Open an account profile to see these tabs: - **Contacts** — Every nested contact and their role - **Estimates** — Quotes tied to any contact under the account - **Leads** — Lead records across the whole account - **Invoices** — Billing activity for nested contacts - **Activity** — A combined timeline of the account's recent work The **Leads** tab is especially useful for property managers and commercial groups because it lets you spot every opportunity tied to the account without opening each contact one by one. ## Bulk Scheduling Account Portfolios Account profiles now include a **Bulk Schedule** action for multi-property work. Use it when one account wins a contract that covers many saved locations, such as a franchise group or property-management portfolio. The account entry point preloads: - the selected account - every nested contact under that account - every saved property attached to those contacts From there, the office can select many properties at once, apply shared scheduling and pricing defaults, then override individual rows when a few locations need different line items, notes, crews, or dates. In v1, Bulk Schedule only pulls from saved properties. If a location is missing from the picker, add it to the contact's saved addresses first. ## Managing Contacts Within an Account You can move, reassign, or remove contacts from an account at any time. - **Move a contact to a different account** — Edit the contact and change the Nested Under field. - **Remove a contact from an account** — Edit the contact and clear the Nested Under field. The contact becomes standalone. - **Change a contact's role** — Edit the contact and select a new role from the dropdown. ## Tips - **Create accounts before contacts.** It is easier to nest contacts into an existing account than to reorganize them later. - **Use the Decision Maker role carefully.** Proposals and contracts should go to the decision maker, not the property contact. - **Set a primary contact right away.** If you skip this step, the system may send communications to the wrong person. - **Review account structures periodically.** People change roles. Contacts leave companies. Keep your account hierarchy up to date so communications reach the right people. --- URL: https://docs.cleanestimate.pro/crm/client-profile Title: Client Profile Description: View a client's full history — estimates, jobs, messages, payments, and activity timeline. Category: crm Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-04-18 --- # Client Profile The client profile page shows everything about a single customer. Open it by clicking a client name on the Clients page. The URL is `/admin/clients/[id]`. [SCREENSHOT: Client profile page with contact info, estimates list, and activity timeline] ## Contact Information The top section displays the client's core details: - **Name** - **Email** - **Phone** - **Address** - **Status** (Lead, Prospect, Active, Inactive, Past) - **Tags** - **Lead Source** - **Notes** Click any field to edit it inline. Changes save automatically. [SCREENSHOT: Contact info section with inline edit cursor on the phone field] ## Linked Estimates Below the contact info, you see a list of every estimate tied to this client. Each row shows: - **Estimate number** - **Status** (Draft, Sent, Viewed, Approved, Declined, Expired) - **Total dollar amount** - **Date created** The linked estimate history now uses the same shared indexed history view as the main **Estimates** page, so larger client records still load quickly and keep the newest estimates at the top without waiting on the app to rebuild history in memory. Click an estimate number to open it. ## Addresses The **Addresses** tab stores every saved service location for that client. Use it to: - Add an additional property manually - Bulk upload a list of properties from CSV - Mark one property as the primary address - Start a new lead or estimate from the exact property you want to service Launching a lead or estimate from this tab now carries the selected property details into the next workflow automatically. The office should not need to re-type the customer or service address after starting from a saved client property. If no saved properties exist yet, the tab falls back to the client's main address from the contact record. If saved addresses are not enabled in that workspace yet, the tab shows a warning banner and keeps the main client address available so the team can still launch a lead or estimate while the migration is applied. When saved addresses are enabled, adding a second property now saves directly from the client profile instead of dead-ending on the old migration warning path. The Google Places address picker in the add-address and edit-client dialogs also supports direct mouse selection again, so the office does not need to arrow down and press Enter just to apply a suggested address. ## Leads The **Leads** tab shows every lead tied to that client in one place. Each row includes: - Lead number - Current status - Source - Service address - Created date Click any lead number to open the lead detail page. Company accounts use the same pattern. The account detail page keeps its own **Leads** tab so office staff can review all opportunities tied to that business without backing out to the global leads list. ### Create a New Estimate Click the **New Estimate** button on the profile page to start an estimate with this client's information pre-filled. You skip the client lookup step entirely. That shortcut now preserves the saved customer contact fields and address context more reliably too. If you launch from a linked lead or a specific saved property, the residential wizard carries that client and property data forward instead of opening with blank customer fields. [SCREENSHOT: New Estimate button on the client profile page] ## Jobs History The Jobs section lists all completed and scheduled jobs for this client. Each entry shows the job number, service type, scheduled date, status, and assigned crew. The **New Job** button now opens the full scheduler from the profile. From there the team can choose the service property, optional accepted estimate, truck, crew, and either book a one-time job, generate from an existing recurring template, or create a new recurring job template without leaving the client record. Use this section to quickly check whether a client has had recent service before sending a follow-up or marketing message. ## Communication Timeline The timeline shows every interaction with this client in chronological order: - **SMS messages** sent and received - **Emails** sent and received - **System events** like estimate sent, estimate viewed, proposal signed, and payment received Scroll through the timeline to see the full conversation history without switching to the Messages page. Clicking **Message** from the client profile now opens the full inbox experience in a right-side drawer. You can review the thread, apply the usual inbox filters, and send SMS or email without leaving the client record. [SCREENSHOT: Communication timeline showing SMS, email, and system events interleaved] ## Invoices and Payments This section lists all invoices issued to the client. Each row shows: - Invoice number - Amount - Status (Paid, Unpaid, Overdue, Partial) - Date issued - Date paid (if applicable) Click an invoice number to view or resend it. ## Activity Log The activity log records every change made to this client record. It tracks who made the change, what changed, and when. Examples: - "Jane Smith changed status from Prospect to Active" - "System sent estimate #1042 via email" - "Mike R. added tag: VIP" This log is read-only. Use it for auditing and accountability. ## Deleting a Client Owners and managers can delete a client from the delete action at the bottom of the profile page. CE Pro blocks the delete if that client still has linked estimates, leads, or jobs. Remove or reassign those records first, then return to the client profile to delete it. ## Tips - **Start estimates from the profile page.** It saves time because the client info is already filled in. - **Check the Leads tab before creating a duplicate opportunity.** It shows every lead already tied to that contact. - **Use the Addresses tab for multi-property customers.** This keeps one customer record while still giving you separate service locations for appointments and quotes. - **Check the timeline before calling a client.** You can see their last message, last estimate, and last payment at a glance. - **Use notes for internal context.** Add details like gate codes, preferred contact times, or special instructions. --- URL: https://docs.cleanestimate.pro/crm/commercial-templates Title: Commercial Proposal Templates Description: Create reusable proposal templates with pre-configured services, pricing, and terms for faster commercial quoting. Category: crm Difficulty: intermediate --- # Commercial Proposal Templates Proposal templates save time when you create similar commercial proposals repeatedly. Instead of configuring services, pricing, line items, and terms from scratch for every new deal, you start from a template that has everything pre-filled. Navigate to **Admin > Commercial > Templates** to manage your templates. [SCREENSHOT: Templates list page showing saved templates with name, type, date created, and last-used date] --- ## What Templates Save A template captures the full configuration of a commercial proposal. When you save a template, it stores: | Saved in Template | Not Saved in Template | |---|---| | Service selections and line items | Customer name and contact details | | Pricing structure and rates | Property address | | Quantity defaults | Specific site conditions | | Add-ons and optional items | Scheduling dates | | Terms and conditions text | Proposal number | | Multi-option configurations | Signatures | | Discount structures | | | Notes and scope descriptions | | Templates capture the "what and how much" of a proposal while leaving the "who and where" to be filled in each time. This means you can use the same template for any customer without editing the core pricing and service configuration. --- ## Creating a Template There are two ways to create a template, depending on whether you are starting from an existing proposal or building one from scratch. ### Method 1: Save from an Existing Proposal This is the fastest approach. Build one proposal exactly the way you want it, then save the configuration as a reusable template. 1. Open a completed commercial proposal at **Admin > Commercial > Proposals > [select proposal]**. 2. Click **Save as Template** in the proposal actions. 3. Enter a descriptive template name (e.g., "Standard Office Building Wash - Full Service" or "Fleet Wash - 20 Vehicles Monthly"). 4. Click **Save**. [SCREENSHOT: Save as Template button on a commercial proposal detail page with the template name input field] The template is created immediately and appears in the templates list. The original proposal is not affected. ### Method 2: Create from the Templates Page Use this approach when you want to build a template without creating an actual proposal first. 1. Go to **Admin > Commercial > Templates**. 2. Click **New Template**. 3. Fill in the proposal configuration fields: - Select services and configure line items. - Set pricing and quantities. - Add any standard add-ons. - Enter default terms and conditions. - Configure multi-option pricing if applicable. 4. Enter a template name. 5. Click **Save**. [SCREENSHOT: New Template creation form showing service selection, pricing fields, and template name input] --- ## Template Variables Templates support variable fields that are populated automatically or manually when you create a proposal from the template. ### Auto-Populated Variables These fields are filled in automatically based on the customer and property information you enter when creating the new proposal: | Variable | Source | |---|---| | Customer name | Entered in the proposal's client step | | Company name | Entered in the proposal's client step | | Property address | Entered in the proposal's client step | | Proposal number | Auto-generated by the system | | Proposal date | Set to the creation date | | Expiration date | Calculated from your default expiration period | ### Manually Adjusted Variables These fields carry over from the template but can be adjusted for each proposal: | Variable | Template Default | Can Be Changed | |---|---|---| | Service quantities | Pre-set in template | Yes, per proposal | | Unit prices | Pre-set in template | Yes, per proposal | | Discount percentages | Pre-set in template | Yes, per proposal | | Terms and conditions | Pre-set in template | Yes, per proposal | | Add-on selections | Pre-set in template | Yes, per proposal | | Scope notes | Pre-set in template | Yes, per proposal | This design means the template provides a strong starting point, but every proposal remains fully customizable. --- ## Applying Templates to New Proposals When creating a new commercial proposal, you can start from a template instead of building from scratch. ### Step-by-Step Process 1. Go to **Admin > Commercial > Proposals > New**. 2. On the first step of the proposal builder, locate the **Start from Template** dropdown. 3. Select a template from the list. Templates are listed by name with their type (Commercial Building or Fleet) indicated. 4. The proposal builder pre-fills with all of the template's configuration: services, pricing, quantities, add-ons, terms, and multi-option setups. 5. Enter the customer and property details as you normally would. 6. Review and adjust any pricing, quantities, or terms that differ from the template defaults. 7. Continue through the remaining proposal steps and send. [SCREENSHOT: Template selector dropdown on the new proposal page showing template names with type badges] ### Important Behavior - **The template is a starting point, not a constraint.** You can change anything after applying the template. Adding services, removing line items, adjusting prices -- all modifications are allowed. - **The original template is never modified.** Edits you make to the proposal do not change the template. Each proposal created from a template is independent after creation. - **You can switch templates.** If you select a template and then decide to use a different one, select the new template from the dropdown. The builder resets and pre-fills with the new template's configuration. Any manual changes you made will be replaced. --- ## Managing Templates The templates page at **Admin > Commercial > Templates** provides a list of all saved templates with management actions. ### Viewing Templates The template list shows: - **Template name** -- The descriptive name you assigned. - **Type** -- Commercial Building or Fleet. - **Date created** -- When the template was first saved. - **Last used** -- When the template was last applied to a new proposal. - **Services count** -- How many services are configured in the template. Click any template name to open it for viewing or editing. ### Editing a Template Open a template to modify its configuration. You can change: - Services and line items. - Pricing and quantities. - Add-ons. - Terms and conditions. - Multi-option configurations. - The template name itself. Click **Save** to apply the changes. Future proposals created from this template will use the updated configuration. Existing proposals that were previously created from this template are not affected. [SCREENSHOT: Template editor showing editable service list, pricing fields, and terms text area] ### Duplicating a Template Click the duplicate icon on a template row to create an exact copy. This is useful when you need a variation of an existing template. For example: - Duplicate "Standard Office Wash" and adjust quantities upward to create "Large Office Wash." - Duplicate "Fleet Wash - 10 Vehicles" and change the vehicle count to create "Fleet Wash - 25 Vehicles." - Duplicate a template and modify the pricing for a different market or region. The duplicate is created with the name "[Original Name] (Copy)." Rename it immediately to avoid confusion. [SCREENSHOT: Duplicate button on a template row, with the resulting copy shown in the list] ### Deleting a Template Click the delete icon to remove a template. A confirmation dialog appears before deletion. Deleting a template does not affect any proposals that were previously created from it, since proposals are independent after creation. [SCREENSHOT: Delete confirmation dialog asking "Are you sure you want to delete this template?"] --- ## Template Organization Best Practices As your template library grows, organization becomes important. ### Naming Conventions Use descriptive names that include the job type, scope, and any distinguishing characteristics. Good names make it easy to find the right template quickly. | Good Template Name | Poor Template Name | |---|---| | Restaurant Exterior - Full Service | Template 1 | | Office Building Wash - 3 Story | Office | | Fleet Wash - 20 Vehicles Monthly | Fleet Template | | HOA Common Areas - Quarterly | Quarterly | | Retail Storefront - Pressure Wash Only | Retail | ### Template Categories Consider organizing templates by service line: - **Commercial Building templates** -- Office buildings, retail centers, restaurants, warehouses, HOA communities. - **Fleet templates** -- Vehicle fleet washes by fleet size (small, medium, large). - **Specialty templates** -- Parking garages, industrial facilities, healthcare facilities. ### Template Maintenance Review your template library quarterly to keep it current: 1. **Update pricing.** When you change your rates, update the affected templates so new proposals reflect current pricing. 2. **Archive unused templates.** If a template has not been used in six months, consider whether it is still relevant. 3. **Add new templates.** When you notice yourself building the same type of proposal repeatedly without a template, save one for next time. --- ## Multi-Option Templates Templates can include multi-option configurations for proposals that present the customer with tiered choices (e.g., Basic, Standard, Premium). ### How Multi-Option Templates Work A multi-option template saves: - The number of options (e.g., 3 tiers). - The service configuration for each option. - The pricing for each option. - The option names and descriptions. When you apply a multi-option template to a new proposal, all options are pre-filled. You can then adjust individual options for the specific customer. [SCREENSHOT: Multi-option template showing three pricing tiers with different service configurations] ### When to Use Multi-Option Templates Multi-option proposals are effective for commercial deals where: - The prospect's budget is unknown, and you want to offer a range. - You want to anchor the customer's perception with a high-value option. - Different service levels are genuinely appropriate for the property. Create a template for each multi-option structure you commonly use. --- ## Tips - **Create templates for your most common jobs.** If you quote the same type of work every week, a template cuts proposal creation time significantly. - **Name templates clearly and consistently.** Descriptive names save time when selecting from a long list. - **Review templates quarterly.** Pricing changes over time. Update your templates when you adjust rates so new proposals reflect current pricing. - **Use duplicate to create variations.** Start with a base template and duplicate it for small, medium, and large versions of the same job type. - **Save winning proposals as templates.** When a proposal leads to a closed deal, its configuration is proven. Save it as a template for similar future opportunities. - **Include standard terms.** Pre-filling terms and conditions in templates ensures consistency and reduces the risk of omitting important contract language. --- ## Troubleshooting ### Template dropdown is empty when creating a new proposal No templates have been created yet. Create your first template from an existing proposal (using **Save as Template**) or from the templates page (using **New Template**). ### Template prices are outdated Templates store fixed pricing values from when they were created or last edited. They do not update automatically when you change your default pricing in Settings. Open the template, update the prices, and save. ### Changes to a template did not affect existing proposals This is by design. Templates are applied at creation time. Once a proposal is created from a template, it is fully independent. Changes to the template only affect new proposals created from it going forward. ### Template is missing services I recently added If you added new services to your pricing configuration after creating the template, the template will not include them automatically. Open the template, add the new services, and save. ### Template save failed with a setup or permission issue The templates admin now returns plain-language save and delete errors instead of exposing raw database text. If a template action fails, check that you still have commercial-management access in the active workspace and that the template record belongs to that workspace. The edit form also rejects malformed patch payloads before save. In practice that means fields like the template name and module type must stay valid values, and a stale tab now gets a clean **Template not found** response instead of a generic server failure when the record was removed elsewhere. --- URL: https://docs.cleanestimate.pro/crm/commercial-pipeline Title: Commercial Sales Pipeline Description: Manage commercial deal stages, forecast revenue, track activities, and analyze pipeline performance. Category: crm Difficulty: intermediate Last updated: 2026-03-18 --- # Commercial Sales Pipeline The commercial sales pipeline provides a dedicated board for tracking commercial and fleet deals through your sales process. Unlike the standard residential pipeline with fixed stages, the commercial pipeline uses fully customizable stages that you define to match your sales workflow. Navigate to **Admin > Commercial > Pipeline** to open it. [SCREENSHOT: Commercial pipeline board with custom stages, deal cards, forecast panel, and activity feed] --- ## How the Commercial Pipeline Differs from the Residential Pipeline The standard pipeline at **Admin > Pipeline** handles all deal types with six fixed columns (Lead/Prospect, Site Visit Scheduled, Proposal Drafted, Proposal Sent, Won, Lost). It works well for residential deals that follow a simple flow. Commercial deals are different. They involve longer sales cycles, multiple decision-makers, site surveys, multi-option proposals, contract negotiations, and phased rollouts. The commercial pipeline addresses these differences with: - **Custom stages** that you define and reorder. - **Win probability per stage** for weighted revenue forecasting. - **Stale deal thresholds** that flag deals sitting too long in one stage. - **A dedicated activity feed** that logs every touchpoint. - **A reminder system** for scheduling follow-ups. - **Pipeline analytics** that track conversion rates, velocity, and lost deal reasons. --- ## Managing Deal Stages ### Configuring Custom Stages Admins configure pipeline stages at **Admin > Commercial > Settings > Stages**. The main Commercial Settings page now includes direct links into both the full **Stages** editor and the **Surface Materials** manager, so the two most important commercial configuration screens are easy to reach from one place. [SCREENSHOT: Stage configuration page showing a list of stages with drag handles, color pickers, and win probability fields] Each stage has the following properties: | Property | Description | |---|---| | **Name** | The display label on the pipeline board (e.g., "Initial Contact", "Site Survey", "Proposal Review", "Contract Negotiation"). | | **Color** | The color used for the column header and stage badges on deal cards. | | **Sort Order** | The left-to-right position on the board. Drag stages to reorder them. | | **Win Probability %** | The historical likelihood of closing a deal that reaches this stage. Used for weighted forecasting calculations. | | **Loss Stage** | Marks this stage as a terminal loss endpoint. Deals moved here count as lost and trigger a lost-reason prompt. | | **Hold Stage** | Marks this stage as a hold or pause state. Deals here are excluded from active pipeline metrics and velocity calculations. | | **Stale Threshold (days)** | The number of days a deal can sit in this stage before it is flagged as stale. Stale deals receive a visual warning on the board. | ### Example Stage Configuration A typical commercial cleaning pipeline might use the following stages: | Stage | Win Probability | Stale Threshold | |---|---|---| | Initial Contact | 10% | 7 days | | Discovery / Needs Assessment | 20% | 10 days | | Site Survey Scheduled | 30% | 14 days | | Site Survey Completed | 40% | 7 days | | Proposal Drafted | 50% | 5 days | | Proposal Sent | 60% | 14 days | | Negotiation | 70% | 10 days | | Contract Review | 80% | 7 days | | Won | 100% | -- | | Lost | 0% | -- | You can create as many stages as your process requires. Most commercial teams use between five and ten active stages plus one or two terminal stages (Won, Lost). [SCREENSHOT: Stage editor form showing name, color picker, win probability slider, stale threshold input, and stage type toggles] ### Reordering Stages Drag stages up or down in the configuration list to change their left-to-right position on the pipeline board. The board instantly reflects the new order. Stage-save requests now validate the full batch before applying changes, so malformed stage ids, invalid probabilities, broken colors, or bad stale-threshold values are rejected instead of partially reordering the board. The bulk save also runs in parallel now, which makes larger stage edits feel faster. ### Deleting a Stage You can only delete a stage that contains no active deals. If deals exist in a stage you want to remove, move them to another stage first, then delete the empty stage. --- ## Working with the Pipeline Board ### Deal Cards Each card on the board represents one commercial or fleet proposal. Cards display: - **Company name** and contact person. - **Proposal type badge** -- Commercial Building or Fleet. - **Proposal number** (e.g., #CP-1042). - **Deal value** in large text for quick scanning. - **Assigned sales rep** name or initials. - **Days in stage** -- A counter showing how long the deal has been in its current column. - **Stale indicator** -- A warning icon that appears when the deal exceeds the stage's stale threshold. - **Reminder badge** -- Appears if a follow-up reminder is set for this deal. [SCREENSHOT: Close-up of a commercial deal card showing all display elements] ### Drag and Drop Click and hold a card to drag it between columns. Releasing the card in a new column updates the deal's stage. Column totals and the forecast panel update immediately. **Moving to a Loss Stage:** When you drop a card into a loss stage, a modal prompts you to select a lost reason from a dropdown and add optional notes. This data feeds into your pipeline analytics. **Moving to Won:** When you drop a card into the Won stage, the system marks the proposal as accepted and logs the win event with a timestamp. [SCREENSHOT: Lost reason modal with dropdown showing reasons like "Price too high", "Went with competitor", "Project canceled", "No response"] ### Filtering and Sorting Use the filters above the board to narrow the view: - **Type** -- Show only Commercial Building proposals, only Fleet proposals, or both. - **Assigned Rep** -- Filter by the sales rep assigned to each deal. - **Date Range** -- Show only deals created within a specific period. - **Value Range** -- Filter by minimum or maximum deal value. --- ## Forecasting The forecast panel sits above the pipeline board and aggregates your commercial deal data into revenue projections. [SCREENSHOT: Forecast panel showing deal count, total value, weighted value, and 30/60/90-day projections] ### Forecast Metrics | Metric | What It Shows | |---|---| | **Deal count per stage** | The number of deals currently in each stage. | | **Total value per stage** | The sum of all deal amounts in each stage. | | **Weighted value** | Total value multiplied by the stage's win probability. A $50,000 deal at a stage with 60% win probability shows as $30,000 weighted. | | **30-day projection** | Estimated revenue from deals likely to close within 30 days, based on stage position and historical velocity. | | **60-day projection** | Same projection extended to 60 days. | | **90-day projection** | Same projection extended to 90 days. | ### How Weighted Value Works Weighted pipeline value provides a more realistic revenue forecast than simply summing all deal amounts. The calculation is: **Weighted Value = Deal Amount x Stage Win Probability** If your pipeline contains: - 3 deals worth $40,000 total at "Site Survey Completed" (40% probability) = $16,000 weighted - 2 deals worth $75,000 total at "Proposal Sent" (60% probability) = $45,000 weighted - 1 deal worth $30,000 at "Contract Review" (80% probability) = $24,000 weighted **Total weighted pipeline: $85,000** This number is far more actionable than the raw total of $145,000 because it accounts for the reality that not every deal will close. ### Setting Accurate Win Probabilities The forecast is only as good as your win probabilities. Review your actual conversion rates quarterly and update stage probabilities to match. If your "Proposal Sent" stage historically closes 35% of the time, set it to 35%, not 60%. --- ## Activity Tracking Every pipeline interaction is logged in the activity feed, creating a complete timeline for each deal and for the pipeline as a whole. [SCREENSHOT: Activity feed showing timestamped entries for stage changes, notes, reminders, and value changes] ### What Gets Logged The activity feed records: - **Stage changes** -- Who moved the deal, from which stage, to which stage, and when. - **Notes** -- Free-text notes added to a deal by any team member. - **Follow-up reminders** -- When a reminder was created, when it was completed, and by whom. - **Deal value changes** -- Any modifications to the proposal amount. - **Win events** -- When a deal closed as won, with the final amount. - **Loss events** -- When a deal was lost, including the reason and any notes. - **Proposal actions** -- When a proposal was sent, viewed by the customer, or signed. ### Using the Activity Feed The feed is most valuable during team meetings. Filter by date range to review what happened since the last check-in. Use it to: - Identify deals that have had no activity in the past week. - Verify that follow-up commitments were honored. - Review the context around lost deals. - Celebrate wins and extract lessons from successful closings. --- ## Reminder System Set follow-up reminders on any deal to ensure timely outreach. ### Creating a Reminder 1. Click a deal card on the pipeline board. 2. Select **Set Reminder**. 3. Configure the reminder: - **Date and time** -- When you want to be notified. - **Note** -- Context for the follow-up (e.g., "Call back about revised pricing for the parking garage"). 4. Click **Save**. [SCREENSHOT: Reminder creation form with date picker, time selector, and note field] ### Managing Reminders - Reminders appear in your dashboard notifications on the scheduled date. - Overdue reminders are highlighted with a warning indicator. - Completed reminders are logged in the activity feed. - You can edit or cancel a reminder from the deal card. --- ## Pipeline Analytics The commercial pipeline tracks performance metrics over time. Navigate to **Admin > Commercial > Analytics** for detailed reports. ### Key Metrics | Metric | Description | |---|---| | **Win Rate** | Percentage of deals reaching a win stage out of all deals that reached a terminal stage (won or lost). | | **Average Days to Close** | Mean number of days from deal creation to reaching the won stage. | | **Stage Conversion Rates** | Percentage of deals that advance from each stage to the next. Identifies bottlenecks. | | **Average Deal Size** | Mean deal value for won deals. Track trends over time. | | **Lost Deal Reasons** | Distribution of reasons why deals were lost. | | **Pipeline Velocity** | The rate at which deals move through your pipeline, calculated as: (Number of Deals x Average Deal Size x Win Rate) / Average Sales Cycle Length. | ### Lost Deal Analysis When deals move to a loss stage, the system prompts for a reason. Over time, this data reveals patterns that you can act on. Common lost reasons for commercial cleaning: - Price too high. - Went with a competitor. - Project canceled or postponed. - No response after multiple follow-ups. - Scope mismatch. - Budget not approved. Review lost reasons monthly. If "price too high" dominates, evaluate whether your pricing is competitive or whether you are targeting the wrong prospects. If "no response" is the top reason, your follow-up cadence may need improvement. [SCREENSHOT: Lost deal reasons chart showing the top reasons by percentage with a bar graph] ### Stage Bottleneck Analysis Look at stage conversion rates to identify where deals stall. If 80% of deals advance from "Discovery" to "Site Survey" but only 30% advance from "Proposal Sent" to "Negotiation," the bottleneck is clear. Your proposals may need improvement, your pricing may be off, or your follow-up after sending proposals may be insufficient. --- ## Tips - **Set win probabilities based on historical data, not optimism.** Accurate probabilities make forecasts actionable. - **Use stale thresholds aggressively.** Commercial deals can go quiet without warning. A 14-day stale threshold on "Proposal Sent" ensures you follow up before the deal goes cold. - **Review the forecast weekly.** The 30/60/90-day projections help you plan crew scheduling, equipment needs, and cash flow. - **Log lost reasons consistently.** Avoid using "Other" when a more specific reason applies. Specific data produces actionable insights. - **Clean the pipeline monthly.** Remove or archive deals that are clearly dead but still sitting in active stages. Stale deals inflate your pipeline value and distort forecasts. - **Assign every deal to a specific rep.** Unassigned deals get overlooked. Clear ownership drives accountability. --- ## Troubleshooting ### Pipeline board is empty The commercial pipeline only displays commercial building and fleet proposals. Residential estimates appear on the standard pipeline at **Admin > Pipeline**. Create a commercial proposal at **Admin > Commercial > Proposals > New** to populate the board. ### Stages are not in the correct order Go to **Admin > Commercial > Settings > Stages** and drag stages to reorder them. The pipeline board reflects the configured sort order from left to right. ### Forecast numbers seem inaccurate Verify the win probability percentages on each stage. Weighted values depend entirely on these probabilities being realistic. Also check that deal amounts are entered correctly on each proposal. ### Activity feed is missing entries All stage changes and deal actions are logged automatically. If entries appear to be missing, check the date range filter on the activity feed. You may be viewing a narrow time window that excludes older events. ### Stale indicators are not appearing Verify that stale thresholds are configured on each stage at **Admin > Commercial > Settings > Stages**. A stage with no stale threshold set will never flag deals as stale. --- URL: https://docs.cleanestimate.pro/crm/lead-sources Title: Lead Sources Description: Track where your leads come from and measure which sources generate the most revenue. Category: crm Difficulty: beginner Roles: owner, manager Last updated: 2026-03-18 --- # Lead Sources Lead sources tell you where each customer came from. Every estimate in CleanEstimate Pro requires a lead source. Over time, this data shows you which marketing channels bring in the most revenue and which ones waste money. Navigate to **Admin > Lead Sources** to manage your list. [SCREENSHOT: Lead Sources page showing the list of sources with edit and delete options] ## What Are Lead Sources? A lead source is a label that records how a customer found your business. Common examples: - Google Search - Google Ads - Facebook - Instagram - Referral - Door Hanger - Yard Sign - Repeat Customer - Angi - Thumbtack - Direct Mail You define your own list. Add as many sources as you need to match your marketing channels. ## How Lead Sources Get Assigned When a salesperson creates an estimate, they select a lead source from a dropdown on the estimator. This field is required. The source stays attached to the estimate, the client, and any resulting job or invoice. When a lead comes in through an integration (Angi, web form, and similar sources), the system assigns the source automatically. [SCREENSHOT: Lead source dropdown on the estimate creation screen] ## Managing Your Sources ### Adding a Source 1. Click **Add Source** on the Lead Sources page. 2. Enter the source name. 3. Choose whether it is **Company-generated** or **Self-generated**. 4. Set the **Commission Rate** percentage for that source. 5. Set the **Sort Order** if you want this source to appear earlier or later in estimator dropdowns. 6. Click **Save**. The new source appears in the dropdown on every estimator form immediately. ### Editing a Source Click the edit icon next to any source. You can update the label, category, commission rate, sort order, and active status at any time. The system keeps the source's internal value stable after creation, so edits are safe for reporting and existing linked records. ### Removing a Source Deleting a source from the admin route is a soft delete. The source is marked inactive so historical estimates and reporting stay intact. In the UI, inactive sources stay visible on the Lead Sources page when you load the full list, but they no longer appear in the normal active-only source list used by estimator flows. ## Company-Generated vs Self-Generated Lead sources fall into two categories that affect sales commission calculations: - **Company-generated** - Leads that came from company marketing efforts. The company paid to acquire these leads. - **Self-generated** - Leads that a salesperson sourced on their own. The rep did the work to find these leads. Self-generated leads typically earn a higher commission rate because the salesperson invested their own time and effort. Configure which sources count as company-generated or self-generated in **Admin > Settings > Commissions**. ## Measuring Lead Source Performance The real value of lead sources shows up in analytics. Navigate to **Analytics > Lead Source ROI** to see: - Number of leads per source - Conversion rate per source - Revenue per source - Revenue per lead - Upsell revenue - Rep attribution Use this data to double down on your best-performing channels and cut spending on underperformers. [SCREENSHOT: Lead Source ROI report showing a bar chart of revenue by source] ## Tips - **Be specific with your sources.** "Google" is too vague. Use separate entries for search, ads, and business profile traffic. - **Train your team to select the correct source.** Bad data leads to bad decisions. Make lead source selection part of your sales process. - **Use sort order deliberately.** Put the most common sources near the top so reps can select them quickly in the estimator. - **Review lead source performance monthly.** Shift your marketing budget toward sources with the best ROI. - **Ask every new customer how they found you.** Even with digital tracking, a quick question confirms the source. --- URL: https://docs.cleanestimate.pro/crm/clients Title: Managing Clients Description: Add, edit, organize, and track all your customers in one place. Category: crm Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-03-27 --- # Managing Clients The Clients page is your central address book. Every customer, prospect, and past client lives here. You can search, filter, tag, and drill into any record from one screen. Navigate to **Admin > Clients** to get started. [SCREENSHOT: Clients page showing KPI cards, search bar, and client table] ## Dashboard KPI Cards Five cards sit at the top of the page. They give you a snapshot of your client base. | Card | What It Shows | |------|---------------| | **Accounts** | Total number of account records | | **Total Contacts** | Total number of individual contacts | | **Active Accounts** | Accounts with at least one recent job or open estimate | | **Lifetime Value** | Sum of all revenue across every client | | **Open Pipeline** | Dollar value of unsold estimates still in play | ## Searching and Filtering The search bar sits below the KPI cards. Type a name, email, phone number, or address to find a client instantly. The admin header search at the top of the app also matches client email addresses. Press **Cmd/Ctrl+K** and paste an email if you want to jump straight to the client record from anywhere in admin. Three filter dropdowns let you narrow the list further: - **Status** — Lead, Prospect, Active, Inactive, or Past. - **Health** — Active, At Risk, Dormant, or New. - **Tags** — Select one or more tags to show only matching clients. By default, the main Clients list shows the newest accounts and standalone contacts first so the latest records are easy to spot. [SCREENSHOT: Search bar with Status, Health, and Tags filters expanded] ## Adding a Contact 1. Click the **+ Add Contact** button in the top-right corner. 2. Select **Customer Type** — Residential or Commercial. 3. Enter the contact's **Name**. 4. Choose a **Lead Source** from the dropdown. 5. Fill in **Email** and **Phone**. 6. Start typing the **Address**. Google Places will autocomplete it and fill in City, State, and ZIP automatically without closing or submitting the dialog. 7. Optionally, nest this contact under an existing **Account** by selecting one from the dropdown. If you leave this blank, the contact stays standalone. 8. Save the contact. Additional service properties can then be managed from the client's **Addresses** tab. 9. Click **Save**. [SCREENSHOT: Add Contact dialog with fields filled in] ## Adding an Account Accounts group related contacts together. Use them for property management companies, commercial clients with multiple locations, or households with more than one decision maker. 1. Click **Add Account**. 2. Enter the **Account Name**. 3. Select an **Account Type** — Company, Household, Group, or Other. 4. Set the **Status**. 5. Fill in **Industry**, **Email**, **Phone**, and **Website** as needed. 6. Click **Save**. [SCREENSHOT: Add Account dialog] ## Account Hierarchy Accounts act as parent records. Each account can contain multiple contacts. Expand an account row in the table to see its nested contacts. Saved service properties now live on the individual client profile in the **Addresses** tab. That is where you add extra locations, upload a CSV of properties, and launch a new lead or estimate from a specific address. If that workspace has not applied the saved-address migration yet, the profile shows a warning and falls back to the main client address until extra properties are enabled. The **Edit Client** dialog now keeps address fields in sync with Google Places while you edit an existing record. Selecting an address updates Address Line 1, City, State, and ZIP in-place without closing the dialog or losing the rest of your edits. Both individual clients and company accounts now support **New Job** directly from the customer record. That scheduler lets the team choose the contact, service property, optional accepted estimate, truck, crew, and the rest of the scheduling details before deciding whether to book a one-time job, generate from an existing recurring template, or create a new recurring template on the spot. Each nested contact has a **role** that describes their relationship to the account: - **Decision Maker** — The person who approves proposals. - **Property Contact** — The on-site person for scheduling and access. - **Billing Contact** — The person who receives invoices. - **Member** — A general contact with no specific role. [SCREENSHOT: Expanded account row showing nested contacts with role badges] ## Client Table Columns The main table displays these columns: | Column | Description | |--------|-------------| | **Name / Property** | Client or account name with address | | **Type** | Residential or Commercial | | **Health** | Color-coded badge (green, yellow, red, blue) | | **Open Pipeline** | Dollar value of unsold estimates | | **Lifetime Value** | Total revenue from this client | | **Last Activity** | Date of the most recent interaction | | **Status** | Current status label | | **Actions** | Edit, archive, or open profile | Click any column header to sort the table. ## Bulk Actions Select multiple rows using the checkboxes on the left side of the table. A toolbar appears with these options: - **Set Status** — Change the status of all selected clients at once. - **Add Tags** — Apply one or more tags to the selection. - **Archive** — Move selected clients to the archive. - **Export CSV** — Download the selected records as a spreadsheet. [SCREENSHOT: Bulk action toolbar with four buttons after selecting multiple rows] ## Opening a Client Profile Click any client name in the table. This takes you to the full client profile at `/admin/clients/[id]`. See [Client Profile](https://docs.cleanestimate.pro/crm/client-profile) for details on what you can do there. ## Bulk Address Upload For clients with many service locations: 1. Open the client profile. 2. Go to the **Addresses** tab. 3. Click **Template CSV** to download the address template. 4. Fill one row per property or service site. 5. Click **Bulk Upload** and upload the completed CSV. This is the fastest way to seed a multi-property client with a large list of locations. ## Schedule Jobs From Clients and Accounts Use **New Job** from a client or account page whenever you want to work directly from the customer record. 1. Choose the contact who owns the work. 2. Choose the service property. 3. Attach an accepted estimate if you want estimate pricing and linkage carried into the job. 4. Pick the truck, crew, and scheduling window. 5. Choose whether the work should be a one-time job, generated from an existing recurring template, or saved as a new recurring job template. ## Tips - **Use the Addresses tab for service sites.** Keep the main client record for the person or company, then store their service locations under **Addresses**. - **Use accounts to group related contacts.** A property management company with several stakeholders can still be one account with multiple nested contacts. - **Tag clients early.** Tags make filtering and marketing campaigns much easier down the road. - **Check the Health badge.** At Risk and Dormant clients are good candidates for a follow-up call or re-engagement campaign. ## Deleting Clients Client detail pages now use the shared delete confirmation modal instead of a red danger-zone panel. - Click **Delete Client** at the bottom of the profile - Type `DELETE` to confirm - CE Pro blocks the deletion if linked leads, estimates, jobs, or invoices still exist for that client This keeps the delete warning accurate to the current backend behavior instead of implying a full cascade delete. --- URL: https://docs.cleanestimate.pro/crm/leads Title: Managing Leads Description: Track incoming leads from first inquiry through conversion, including deposits and early split payments. Category: crm Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-04-18 --- # Managing Leads The Leads page tracks every potential customer from first contact to closed deal. Open the **Manage** section in the admin sidebar, then click **Leads** to see your full lead list. [SCREENSHOT: Leads page showing pipeline summary cards and lead table] ## Pipeline Summary Cards Eight status cards sit at the top of the page. Each card shows the number of leads in that stage: | Stage | Description | |-------|-------------| | **New** | Just came in, no action taken yet | | **Appointment Scheduled** | Site visit or phone call booked | | **Estimate Created** | An estimate has been drafted | | **Estimate Sent** | The estimate was sent to the customer | | **Approved** | Customer accepted the estimate | | **Deposit Collected** | Customer paid a deposit | | **Converted** | Lead became a paying customer | | **Lost** | Lead did not convert | Click any card to filter the table to that status. ## Stale Lead Detection Leads that go more than seven days without an update get flagged automatically. A warning badge appears on the lead row. This keeps leads from falling through the cracks. Check for stale leads daily. Either update them with a note or move them to Lost if they are no longer viable. ## Pipeline Value The pipeline value is the sum of estimated dollar amounts for all open leads. It appears near the top of the page and updates in real time as you add or close leads. ## Creating a Lead 1. Click the **Create Lead** button. 2. Search for an existing customer if this is a returning account, or click **Create New Customer** if they are not in the CRM yet. The inline new-customer option appears only for roles that can manage client records. 3. If you are creating a new customer inline, enter at least the customer's **Name**. **Email** and **Phone** are optional, and CE Pro creates the customer record automatically when you save the lead. 4. Select a **Lead Source** from the dropdown. 5. Type the **Service Address**. Google Places autocomplete will help, and you can click a suggestion directly without relying on keyboard navigation. The lead window stays open so you can finish the other fields. 6. If the selected customer already has saved properties, pick the right **Saved Property** before you continue. When there is only one saved property, CE Pro now auto-selects it for you. 7. Add any **Notes** about the inquiry. 8. Assign a **Rep** from the dropdown if you want to route this lead to a specific salesperson. 9. Optionally, add an appointment date, time window, and appointment type. 10. Click **Create Lead**. [SCREENSHOT: Create Lead dialog with fields filled in] ## Lead Table The table displays all your leads with these columns: | Column | Description | |--------|-------------| | **Lead #** | Auto-generated lead number | | **Client** | Customer name | | **Service Address** | Property address | | **Status** | Current pipeline stage | | **Source** | Where the lead came from | | **Assigned Rep** | Salesperson responsible | | **Created** | Date the lead was entered | | **Est. Value** | Dollar value of the potential deal | ## Updating Lead Status Each lead row has a **Status** dropdown. Click it and select the new stage. The change saves immediately and updates the pipeline summary cards. [SCREENSHOT: Status dropdown open on a lead row] ## Editing Lead Details Open any lead to update the record directly from the lead detail page. - Change the **Status** without returning to the list view - Reassign the **Assigned Rep** to any active owner, manager, or sales rep - Update the **Lead Source** from the shared dropdown, or create a new lead source inline - Fix the **service address**, city, state, ZIP, and property square footage - Edit the linked customer's **name, email, and phone** from the same screen - Use the **Appointment** card on the same page to change the scheduled date or time Click **Save Lead Details** after changing the editable fields so the updates are written back to the lead. If the lead is already linked to a client record, CE Pro asks whether you also want to update that linked client. This keeps lead-side property edits separate from the core client record until the office confirms the sync. The lead detail page also includes a shared **Tags** card. Saving tags there updates the linked client record so the same labels stay available in lead, estimate, job, and invoice filters. ## Create an Estimate from a Lead Use the **New Estimate** action on the lead detail page when you want to quote directly from that opportunity. CE Pro now carries the linked client, assigned rep, lead source, service address, ZIP, and saved property square footage into the residential estimate wizard automatically. If the lead is already tied to a client record, the office should not have to re-enter the customer details just to continue into the quote. That estimate draft also autosaves while the office works through the wizard, so lead-launched quotes no longer depend on a manual save before the customer and pricing changes stick. ## Appointment Notifications When you schedule or reschedule a lead appointment from the lead detail page, CE Pro now emails the customer automatically if that lead's client record has an email address on file. - The confirmation includes the appointment date, time window, appointment type, address, and any notes you entered - If there is no customer email saved on the client, the appointment is still booked, but no confirmation email is sent - Customers can reply directly to the email and the reply routes back into your org inbox ## Deposits and Early Payments When a lead has an accepted estimate, the lead detail page shows a **Deposit & Payments** card. Use it to: - Collect a deposit before the job is created - Record cash, check, bank transfer, or other offline tender - Charge a keyed card through Stripe - Create a Stripe pay link for online payment - Split an early payment across multiple methods Example: if a customer wants to pay half by card and half by cash before scheduling, enter the first amount, save it, then add the second payment. The lead and linked estimate stay in sync automatically. ## Lost Reason Tracking When you change a lead's status to **Lost**, a dialog appears. Select a reason from the dropdown: - Price too high - Chose competitor - No response - Not ready - Out of service area - Other Add optional notes for context. Click **Confirm** to save. Tracking lost reasons helps you spot patterns. If most lost leads cite price, you may need to revisit your pricing strategy. [SCREENSHOT: Lost reason dialog with dropdown and notes field] ## Lead Detail Navigation The lead detail page includes direct links back to the related customer record. - The header now includes **Back to Client** whenever the lead is linked to a standalone client. - If that client belongs to a grouped company account, the same header also shows **Back to Account**. - The customer card still includes **View Client** and **View Account** actions deeper on the page. ## Deleting Leads The lead detail page includes a muted **Delete Lead** action at the bottom of the record. - Owners and managers can delete any lead in their organization. - Sales reps can delete only leads assigned to them. - Crew leads and technicians cannot delete leads. If the lead already has linked estimates, CE Pro blocks the delete and tells you to remove those estimates first. ## Search The search bar at the top of the table works across multiple fields. Search by: - Lead number - Address - City - Client name Results filter in real time as you type. The leads toolbar also includes a shared date-range picker. Use it to keep the list on a recent preset or set exact start and end dates when you only want leads created inside a specific follow-up window. ## Tags The leads list now uses a shared **Filter by tag** dropdown instead of showing every tag as a long row of chips. - Click **Filter by tag** to open the searchable tag list - Select one or more tags to narrow the lead list - Tags are color coded so the same labels are easy to spot across leads, jobs, estimates, and invoices - If the tag does not exist yet, type its name in the dropdown and click **Create new** The tag filter works off the same client tag labels used across the rest of the CRM. ## Tips - **Act on new leads fast.** Leads contacted within the first hour convert at much higher rates. - **Pick a saved property when a client has multiple locations.** If the client profile already has addresses saved, the lead dialog lets you choose the right property before scheduling the appointment, and a lone saved property now auto-fills itself. - **Use the inline new-customer path for brand-new inquiries when your role can manage clients.** You no longer need to leave the lead dialog just to create the customer first. - **Use stale lead alerts.** Do not let leads sit for more than a week without a touchpoint. - **Track lost reasons consistently.** The data is only useful if your team fills it in every time. --- URL: https://docs.cleanestimate.pro/crm/rehash Title: Rehash Queue Description: Work unsold residential quotes through the staged Rehash queue, re-quotes, and recovered-close handoff. Category: crm Difficulty: intermediate Roles: owner, manager Last updated: 2026-04-22 --- # Rehash Queue The Rehash queue is the residential win-back workspace for unsold quotes. Open **Rehash** in the admin sidebar to see the quotes that were saved with an active unsold disposition and are now moving through the follow-up sequence. [SCREENSHOT: Rehash dashboard showing summary cards, stage pills, the queue table, and the right-side detail drawer] The queue is now mobile-friendly too. On smaller screens, the stage pills stay horizontally scrollable, the queue collapses into action cards, and the same detail drawer still lets the sales manager text, call, email, re-quote, or mark a quote dead without switching to desktop first. --- ## What Rehash Requires Rehash is only available when all three of these are true: - **Red Line** is enabled in Pricing Manager - **Enable Rehash Department** is turned on in the Red Line settings - The logged-in teammate has **Rehash Access** in Team Management If any of those are off, the Rehash page stays hidden from the sidebar and the analytics page shows a disabled-state message instead of queue data. Direct visits to `/admin/rehash` now follow that same access model cleanly. If the route is available to your role and your Rehash access toggle is on, the queue opens normally instead of bouncing back to the admin dashboard. --- ## Required Dispositions Residential quotes now capture a Rehash disposition as part of the save flow. The main options are: - **HOT** - **WARM** - **PRICE** - **TIMING** - **COLD** - **NO CONTACT** - **DEAD** - **SOLD** These notes are required before save: - **HOT** -- objection details - **PRICE** -- target price or pricing note - **TIMING** -- timing details - **DEAD** -- do-not-contact reason Those saved notes carry into the queue so the sales manager sees the original objection before making the next touch. --- ## Sequence Stages The built-in sequence moves through these stages: - **Day 1** - **Day 3** - **Day 7** - **Day 14** - **Day 21** - **Day 30** - **Day 60** - **Day 90** - **Day 180** Day 7 is the main manual-touch stage. The queue page opens with that stage selected by default so the manager can work the human follow-ups first. The automated touches use the saved Rehash templates behind the scenes. CE Pro seeds those templates for the workspace automatically, then sends or suppresses them based on the saved quote context. If **Enable Rehash template A/B testing** is turned on in Pricing Manager, CE Pro alternates between the seeded Variant A and Variant B templates automatically on a per-template basis. The assigned template label also shows up in the Rehash detail drawer and message history so managers can see exactly which version went out. --- ## Discount Guardrails Day 21 and Day 90 can include the built-in win-back offers, but they still respect Red Line: - Day 21 uses the optional **10%** auto-discount message - Day 90 uses the optional **15%** final-offer message If either offer would push any service below its saved Red Line floor, CE Pro suppresses that automated offer instead of sending a below-floor discount by accident. --- ## Working The Queue The top of the Rehash page shows: - active quote count - active pipeline value - manual touches due - recovered revenue MTD - recovered revenue YTD - recent conversion rate Below that, the stage pills let you switch between the live active stages. The table gives the fastest day-to-day tools: - **Text** - **Call** - **Email** - **Touched** - **Re-Quote** - **Dead** Each queue row now also shows a **Red Line room** badge based on the saved residential service totals versus the saved Red Line floors on that quote: - **Green room badge** -- the quote is still above floor and has discount room left - **Amber at floor badge** -- the quote is already sitting on the floor - **Red below floor badge** -- the quote is already below floor and should be treated like an override case Opening a row slides out the Rehash detail drawer with: - customer contact info - saved disposition and notes - a quote summary card with each service's list price, current quoted price, and saved Red Line floor - inline quoted-price editing for service line items without leaving the Rehash drawer - parent quote link - suggested SMS and email drafts - assigned template labels for those automated drafts - message history - call logging and manual-touch actions Managers can now lower or raise service prices directly inside that quote-summary card and save the line items in place for standard residential service-line quotes. The drawer keeps the **List**, **Red Line**, **Room**, and **Quoted** numbers side by side so it is easy to see how much safe discount room is left before the floor. The inline save blocks any service from being pushed below its saved Red Line floor. If the quote is a proposal package, maintenance-plan quote, or another shape that depends on a fuller pricing graph, the same card stays visible in a read-only state and points the manager to the full quote editor instead of risking a partial inline save. The Rehash popup is now also more fault-tolerant around older or imperfect data. If a saved quote has a broken parent-estimate link, malformed old rep ids, a bad Rehash template row, or an older workspace that is still missing legacy estimate pricing columns like `minimum_adjustment` or `taxable_amount`, the drawer still opens on the quote summary instead of failing the entire request. If the page opens with a setup warning instead of queue data, the workspace is still missing the Rehash estimate/disposition schema rollout itself. Older template storage no longer blocks the queue by itself, CE Pro falls back to the built-in Rehash message copy when needed, and the setup warning now names the exact missing Rehash schema fields instead of collapsing unrelated schema errors into the same generic rollout message. --- ## Re-Quote Flow The **Re-Quote** action duplicates the selected estimate and links the new quote back to the original Rehash chain. That keeps the original quote record intact while letting the office work a revised scope or updated pricing cleanly. Once the recovered quote closes, CE Pro updates the Rehash chain and saves the recovered-close attribution on the estimate. --- ## Recovered-Close Attribution Recovered residential closes now save the default Rehash commission split based on how long it took to close: - **0-6 days** -- original rep keeps the full commission - **7-14 days** -- 50 / 50 split - **15-89 days** -- 25 / 75 split toward the closer - **90+ days** -- closer takes the full commission That saved attribution shows up in: - the estimate detail page - the Rehash analytics page This makes it easier to review recovered revenue and compensation without rebuilding the timeline manually after the close. --- URL: https://docs.cleanestimate.pro/crm/pipeline Title: Sales Pipeline Description: Visualize your deals on a kanban board and track estimates from sent to won. Category: crm Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-03-20 --- # Sales Pipeline The Pipeline page gives you a visual kanban board of every active deal. Drag cards between columns to update their status. Navigate to **Admin > Pipeline** to open it. The board uses the full browser workspace so you can see more columns at once on large screens. On narrower displays, the board still scrolls horizontally when you need to reach later stages. [SCREENSHOT: Pipeline kanban board with six columns and deal cards] ## KPI Cards Six metrics sit above the board: | Metric | Description | |--------|-------------| | **Open Pipeline** | Total dollar value of all unsold deals | | **Weighted Pipeline** | Dollar value adjusted by win probability per stage | | **Active Deals** | Number of deals currently in play | | **Won** | Number of deals closed as won | | **Win Rate (90d)** | Percentage of deals won in the last 90 days | | **Avg Days to Close** | Average number of days from first contact to won | ## Filtering by Type Use the type filter above the board to show only certain deal types: - **All** — Every deal across all service lines. - **Residential** — Residential cleaning estimates. - **Commercial** — Commercial cleaning proposals. - **Fleet** — Fleet wash proposals. - **Holiday Lights** — Holiday lighting estimates. [SCREENSHOT: Type filter bar with All, Residential, Commercial, Fleet, Holiday Lights buttons] The pipeline header now includes the same shared date-range picker used across the office workspace. That lets you review only deals created inside a recent preset or a custom start/end window without leaving the board. ## Kanban Columns The board has six columns. Each column header shows a colored dot, the stage name, the number of deals, and the total dollar value in that stage. | Column | Color | Meaning | |--------|-------|---------| | **Lead / Prospect** | Gray | Early-stage leads not yet quoted | | **Site Visit Scheduled** | Blue | Appointment booked for on-site assessment | | **Proposal Drafted** | Orange | Estimate created but not yet sent | | **Proposal Sent** | Purple | Estimate delivered to the customer | | **Won** | Green | Customer accepted the proposal | | **Lost** | Red | Deal did not close | ## Deal Cards Each card on the board represents one estimate. Cards display: - **Customer name** at the top. - **Estimate type badge** — a small icon indicating the service line (Home, Building, Truck, or Tree). - **Estimate number** (e.g., #1042). - **Total value** in monospace font for easy scanning. - **Location** — city or abbreviated address. - **Lead score badge** — color-coded score if AI lead scoring is enabled. - **Days-in-stage badge** — shows how many days the deal has been in its current column. - **SLA progress bar** — a thin bar that fills as the deal approaches your configured follow-up deadline. [SCREENSHOT: Close-up of a deal card showing all elements] ## Drag and Drop Click and hold a card, then drag it to another column. Release to update the status. The KPI cards and column totals update immediately. ### Moving a Card to Lost When you drop a card into the **Lost** column, a modal appears. Select a **Lost Reason** from the dropdown, add optional notes, and click **Confirm**. This data feeds into your analytics so you can identify patterns. [SCREENSHOT: Lost reason modal with dropdown and notes field] ### Moving a Card to Won When you drop a card into the **Won** column, the system does two things: 1. Marks the estimate as accepted. 2. Creates a job record automatically. A toast notification confirms: "Estimate accepted — Job created for {customer name}." [SCREENSHOT: Toast notification after moving a card to Won] ## Opening an Estimate Click any card to open the full estimate detail page. From there you can edit the estimate, resend it, or view the customer's response. ## Tips - **Check the board daily.** Cards stuck in one column too long need attention. The days-in-stage badge makes them easy to spot. - **Use the SLA progress bar.** If a bar is nearly full, it is time to follow up with the customer. - **Filter by type during team meetings.** Review one service line at a time for a more focused pipeline review. - **Watch your win rate.** A declining win rate over 90 days signals a problem with pricing, follow-up, or lead quality. --- URL: https://docs.cleanestimate.pro/crm/tags-and-segments Title: Tags and Client Segments Description: Organize clients with tags and filter your lists for targeted outreach. Category: crm Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-03-18 --- # Tags and Client Segments Tags are labels you attach to client records. They help you organize, filter, and target groups of customers. Tags have no fixed structure. You create whatever labels make sense for your business. CleanEstimate Pro normalizes tags case-insensitively, so creating **Commercial** and **commercial** results in one shared tag, not two separate ones. ## What Tags Are For Tags let you slice your client list in ways that status and type fields cannot. A client can have multiple tags at once. Examples: - **VIP** - High-value customers who get priority scheduling. - **Commercial** - Business clients. - **Fleet** - Clients with fleet wash contracts. - **Property Manager** - Contacts who manage multiple properties. - **Repeat Customer** - Clients who have booked more than once. - **Referral Source** - Clients who regularly send you new business. - **Do Not Service** - Clients you have chosen not to work with. - **Slow Payer** - Clients with a history of late payments. ## Adding Tags to a Client ### From the Client Profile 1. Open a client's profile page. 2. Find the **Tags** field in the contact info section. 3. Click the field and type a tag name. If the tag already exists, select it from the dropdown. If it does not exist, the system creates it. 4. Press Enter or click to add the tag. 5. Repeat to add more tags. If the new tag does not have a color yet, CleanEstimate Pro assigns a fallback color automatically so it still renders consistently in filters and chips. [SCREENSHOT: Tags field on the client profile with a dropdown showing existing tags] ### From the Clients Table (Bulk) 1. Go to the **Clients** page. 2. Select multiple clients using the checkboxes. 3. Click **Add Tags** in the bulk action toolbar. 4. Choose one or more tags from the dropdown. 5. Click **Apply**. All selected clients receive the tags immediately. [SCREENSHOT: Bulk action toolbar with Add Tags selected and a tag dropdown open] ## Removing Tags Open the client profile and click the **X** next to any tag to remove it. Tags removed from a client are not deleted from the system. They remain available for other clients. ## Filtering by Tags On the Clients page, use the **Tags** filter dropdown above the table. Select one or more tags. The table updates to show only clients that have all selected tags. This is useful when you need a specific list. For example, select "Commercial" and "VIP" to see only your high-value business clients. [SCREENSHOT: Tags filter dropdown with two tags selected and filtered client table below] ## Using Tags for Marketing Campaigns Tags power audience targeting in the Marketing module. When you create a campaign: 1. Go to **Marketing > Campaigns > New Campaign**. 2. In the **Audience** step, select tags to include or exclude. 3. The system builds a recipient list from clients matching your tag criteria. For example, send a spring promotion to all clients tagged "Repeat Customer" but exclude anyone tagged "Do Not Service." See [Marketing Campaigns](https://docs.cleanestimate.pro/marketing/campaigns) for the full campaign setup guide. ## Suggested Tags for Exterior Cleaning Businesses Here is a starter set of tags that works well for pressure washing, window cleaning, and exterior cleaning companies: | Tag | Use Case | |-----|----------| | **VIP** | Top-spending clients who expect premium service | | **Commercial** | Business and commercial property clients | | **Fleet** | Clients with recurring fleet wash needs | | **Property Manager** | Managers overseeing multiple properties | | **Repeat Customer** | Clients who have booked two or more times | | **Referral Source** | Clients who actively refer new business | | **Do Not Service** | Clients you have blacklisted | | **Slow Payer** | Clients with a pattern of late payments | | **Holiday Lights** | Clients interested in holiday lighting services | | **HOA** | Homeowners association contacts | ## Tips - **Keep tag names consistent.** The app deduplicates tags case-insensitively, but a stable naming style still keeps your filters and marketing audiences easier to scan. - **Do not over-tag.** A handful of well-chosen tags is more useful than dozens of rarely-used ones. - **Review tags quarterly.** Remove tags that nobody uses. Consolidate duplicates. - **Use tags instead of mental notes.** If you find yourself remembering things about clients ("that guy always pays late"), turn that knowledge into a tag so the whole team benefits. --- URL: https://docs.cleanestimate.pro/developers/auth-and-scopes Title: Auth and Scopes Description: Create API keys, choose scopes, and understand live vs test access for the external API. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-03-19 --- # Auth and Scopes External API requests authenticate with API keys created in **Settings -> Integrations -> API Keys**. CE Pro shows the raw secret only once when you create the key. After that, the key is stored as a one-way hash and cannot be recovered. ## Key Formats - Live keys begin with `ce_live_` - Test keys begin with `ce_test_` Send the key in the `Authorization` header: ```http Authorization: Bearer ce_live_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx ``` ## Where To Manage Keys From the API Keys settings page you can: - Create a key - Choose live or test mode - Limit the key to specific scopes - Set a per-minute rate limit - Add an optional expiration date - Review request logs - Update or revoke a key later The API key forms now validate the full payload before saving. A key needs at least one scope, the environment must be either **live** or **test**, the per-minute rate limit must be a positive whole number, and malformed expiration values are rejected instead of creating a partial key record. When you revoke a key from the settings UI, the row now flips to its revoked state immediately instead of waiting for a full page refresh. That helps office staff confirm the key is no longer active before they leave the screen. ## Available Scopes - `leads:read` - `leads:write` - `clients:read` - `clients:write` - `estimates:read` - `estimates:write` - `jobs:read` - `jobs:write` - `invoices:read` - `invoices:write` - `webhooks:read` - `webhooks:write` `webhooks:write` covers both outbound webhook destination management under `/api/v1/webhooks` and inbound automation webhook intake at `/api/automations/webhooks/inbound`, and both flows use the same shared API-key rate limiting. Wildcard scopes are supported: - `leads:*` - `clients:*` - `estimates:*` - `jobs:*` - `invoices:*` - `webhooks:*` - `*` ## Live Vs Test Behavior Live keys are meant for real customer and revenue workflows. Test keys are meant for integration development. In v1: - Test keys can read only test records. - Test keys can write only to `leads`, `clients`, and `estimates`. - Test keys cannot create jobs, invoices, or webhook destinations. - Test writes are isolated from normal admin views and operational workflows. Proposal and reporting resources are not part of the current public v1 surface, so CE Pro does not issue separate public scopes for them yet. ## Rate Limits Each key has its own per-minute rate limit. The default is `60` requests per minute, but you can raise or lower it per key. Request-log views also validate their page-size input now, so the admin log panel only accepts limits from `1` to `200` rows per request. Every response includes: - `X-RateLimit-Limit` - `X-RateLimit-Remaining` - `X-RateLimit-Reset` If a key exceeds its allowance, CE Pro returns `429 Too Many Requests` plus `Retry-After`. If the shared rate-limit backend is temporarily unavailable, CE Pro fails closed and returns `503 rate_limit_unavailable` instead of silently skipping protection. Live and test keys are validated against their exact key prefix and environment. A `ce_live_*` key cannot be replayed as `ce_test_*`, and vice versa. ## Common Auth Errors - `401 invalid_api_key`: the header is missing, malformed, expired, or revoked - `403 insufficient_scope`: the key does not include the required scope - `403 unsupported_in_test_mode`: the endpoint is not available to test keys in v1 - `429 rate_limited`: the key exceeded its current minute window - `503 rate_limit_unavailable`: CE Pro could not verify rate limits safely ## Best Practices - Create separate keys per integration, not one shared key for everything. - Start with the narrowest scopes possible. - Use test keys during development. - Revoke keys instead of reusing them after a partner changes ownership. - Store keys in your secret manager or deployment platform, never in frontend code. --- URL: https://docs.cleanestimate.pro/developers/cursor-pagination Title: Cursor Pagination Description: Read large datasets safely with stable cursor-based pagination. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-03-16 --- # Cursor Pagination List endpoints in the external API use cursor pagination instead of page numbers. This is more stable for growing datasets because new records can be created while you are paging without shifting every later result set. ## Query Parameters - `limit`: number of results to return, default `25`, max `100` - `cursor`: opaque cursor from the previous response - `sort`: supported sort field for the endpoint - `order`: `asc` or `desc` ## Response Metadata ```json { "meta": { "next_cursor": "opaque-value", "has_more": true, "limit": 25 } } ``` If `has_more` is `false`, you have reached the end of the collection. ## Example First request: ```bash curl "https://app.cleanestimate.pro/api/v1/leads?limit=25&sort=created_at&order=desc" \ -H "Authorization: Bearer $CEPRO_API_KEY" ``` Next request: ```bash curl "https://app.cleanestimate.pro/api/v1/leads?limit=25&sort=created_at&order=desc&cursor=eyJ2IjoxLCJzIjoiY3JlYXRlZF9hdCIsIm8iOiJkZXNjIiwiazpbIjIwMjYtMDMtMTRUMTQ6MzA6MDBaIiwiLi4uIl19" \ -H "Authorization: Bearer $CEPRO_API_KEY" ``` ## Important Rules - Treat the cursor as opaque. Do not parse or modify it. - Keep `sort` and `order` the same when using a cursor. - Restart from the first page if you want to change sorting or filters. ## Supported Sort Defaults - Leads: `created_at desc` - Clients: `created_at desc` - Estimates: `created_at desc` - Jobs: `scheduled_date desc` - Invoices: `created_at desc` Webhook destination reads are not cursor-paginated in the current public API. --- URL: https://docs.cleanestimate.pro/developers/docs-discoverability Title: Docs Sitemap and LLM Files Description: Use the docs.cleanestimate.pro sitemap, llms.txt, and llms-full.txt files for search, crawl, and AI ingestion workflows. Category: developers Difficulty: beginner Roles: owner, manager, developer, marketing Last updated: 2026-04-25 --- # Docs Sitemap and LLM Files CleanEstimate Pro Docs publishes discovery files for search engines, crawlers, support tooling, and AI assistants. These files live on the docs domain: | URL | Purpose | | --- | --- | | `/site-map` | Human-readable directory of every docs section, article, and machine-readable file | | `/sitemap.xml` | Canonical XML sitemap for docs pages | | `/llms.txt` | Concise plain-text docs index for AI assistants and retrieval systems | | `/llms-full.txt` | Full plain-text export of the public docs article catalog | | `/robots.txt` | Crawler rules and sitemap pointer | ## When to use each file ### `/site-map` Use the HTML site map when you want to browse the full docs structure without relying on sidebar navigation or search. It includes: - top-level docs entry points - every docs category - every public help article - machine-readable discovery files ### `/sitemap.xml` Use the XML sitemap for: - search engine indexing - crawl audits - broken-link checks - SEO validation for `docs.cleanestimate.pro` The sitemap is generated from the same MDX documentation catalog that powers the help center, so new docs pages are included automatically when they have valid frontmatter. ### `/llms.txt` Use `llms.txt` when an AI assistant or retrieval system needs a compact overview of the docs site. It includes: - the docs homepage - the XML sitemap - the full LLM export URL - every docs category - every docs article URL and description ### `/llms-full.txt` Use `llms-full.txt` when an AI system needs article bodies, not just route summaries. It includes: - a section index - each article's canonical URL - title, description, category, role, difficulty, and last-updated metadata - the article body from the MDX source ## Keeping discovery current When you add or update a public docs article, make sure its frontmatter includes: - `title` - `description` - `category` - `last_updated` Those fields keep the docs sitemap, `/site-map`, `llms.txt`, and `llms-full.txt` useful for both people and machines. --- URL: https://docs.cleanestimate.pro/developers/examples Title: Examples Description: Start quickly with curl examples for the current public v1 records and webhook registration. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-03-19 --- # Examples These examples use `curl`, but the same request shapes work in Postman, Zapier, Make, or your own backend. Set your key first: ```bash export CEPRO_API_KEY="ce_live_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxx" ``` ## Create A Lead ```bash curl https://app.cleanestimate.pro/api/v1/leads \ -X POST \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: lead-demo-001" \ -d '{ "customer_name": "Taylor Morgan", "customer_email": "taylor@example.com", "customer_phone": "+15551234567", "service_address": "123 Main St", "city": "Charlotte", "state": "NC", "zip": "28202", "service_interest": ["house-wash"], "notes": "Requested a Saturday estimate" }' ``` ## List Leads ```bash curl "https://app.cleanestimate.pro/api/v1/leads?limit=25&sort=created_at&order=desc&status=new" \ -H "Authorization: Bearer $CEPRO_API_KEY" ``` ## Create A Client ```bash curl https://app.cleanestimate.pro/api/v1/clients \ -X POST \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: client-demo-001" \ -d '{ "name": "Taylor Morgan", "email": "taylor@example.com", "phone": "+15551234567", "address_line1": "123 Main St", "city": "Charlotte", "state": "NC", "zip": "28202" }' ``` ## Write Notes To Clients, Leads, And Jobs The current public v1 API supports note fields on clients, leads, and jobs. You can send notes when you create the record or patch notes onto an existing record later. ### Add Notes To A Client ```bash curl https://app.cleanestimate.pro/api/v1/clients \ -X POST \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: client-notes-demo-001" \ -d '{ "name": "Taylor Morgan", "email": "taylor@example.com", "phone": "+15551234567", "notes": "Prefers text first. Side gate code is 4421.", "status": "active" }' ``` ```bash curl https://app.cleanestimate.pro/api/v1/clients/CLIENT_ID \ -X PATCH \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: client-notes-update-001" \ -d '{ "notes": "Requested Friday afternoon appointments only." }' ``` ### Add Notes To A Lead ```bash curl https://app.cleanestimate.pro/api/v1/leads \ -X POST \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: lead-notes-demo-001" \ -d '{ "customer_name": "Taylor Morgan", "customer_email": "taylor@example.com", "customer_phone": "+15551234567", "service_address": "123 Main St", "city": "Charlotte", "state": "NC", "zip": "28202", "notes": "Requested Saturday estimate. Interested in house wash and driveway.", "source": "api" }' ``` ```bash curl https://app.cleanestimate.pro/api/v1/leads/LEAD_ID \ -X PATCH \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: lead-notes-update-001" \ -d '{ "notes": "Left voicemail. Follow up tomorrow morning." }' ``` ## Create An Estimate ```bash curl https://app.cleanestimate.pro/api/v1/estimates \ -X POST \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: estimate-demo-001" \ -d '{ "customer_name": "Taylor Morgan", "customer_email": "taylor@example.com", "customer_phone": "+15551234567", "address_line1": "123 Main St", "city": "Charlotte", "state": "NC", "zip": "28202", "services": [ { "service_slug": "house_wash", "enabled": true, "sqft": 2400, "stories": 2 } ], "addons": [], "custom_items": [], "dirtiness_level": "light" }' ``` ## Update An Estimate ```bash curl https://app.cleanestimate.pro/api/v1/estimates/ESTIMATE_ID \ -X PATCH \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: estimate-update-demo-001" \ -d '{ "customer_phone": "+15559876543", "assigned_rep_id": "00000000-0000-0000-0000-000000000123", "status": "sent", "expires_at": "2026-04-19T00:00:00.000Z" }' ``` `PATCH /api/v1/estimates/:id` is intentionally narrow. Use it for customer/contact metadata, address/property details, assignment, `draft`/`sent` status, source, and `expires_at`. If the service selection or pricing inputs change, create a fresh estimate instead of trying to reprice through this endpoint. ## Register A Webhook Destination ```bash curl https://app.cleanestimate.pro/api/v1/webhooks \ -X POST \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: webhook-demo-001" \ -d '{ "name": "Ops Sync", "url": "https://example.com/cepro/webhooks", "events": ["lead.created", "estimate.created", "job.completed"] }' ``` The create response includes the webhook secret once. Store it immediately so you can verify signatures later. `ce_test_...` keys cannot call `/api/v1/webhooks` in v1. Use a live key when you are ready to register real outbound destinations. ## Create A Job ```bash curl https://app.cleanestimate.pro/api/v1/jobs \ -X POST \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: job-demo-001" \ -d '{ "client_id": "00000000-0000-0000-0000-000000000001", "service_type": "house_wash", "scheduled_date": "2026-03-20", "scheduled_time_start": "09:00:00", "scheduled_time_end": "11:00:00", "customer_name": "Taylor Morgan", "service_address": "123 Main St", "service_city": "Charlotte", "service_state": "NC", "service_zip": "28202" }' ``` ```bash curl https://app.cleanestimate.pro/api/v1/jobs/JOB_ID \ -X PATCH \ -H "Authorization: Bearer $CEPRO_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: job-notes-update-001" \ -d '{ "notes": "Customer requested a 30-minute arrival call.", "access_notes": "Use side gate. Code 4421.", "special_instructions": "Park on the street, not in the driveway." }' ``` ## List Invoices ```bash curl "https://app.cleanestimate.pro/api/v1/invoices?limit=25&sort=created_at&order=desc&status=sent" \ -H "Authorization: Bearer $CEPRO_API_KEY" ``` Webhook routes are live-only in the current public v1 surface. Use a `ce_live_...` key for `/api/v1/webhooks`. ## Pull The OpenAPI Spec ```bash curl https://app.cleanestimate.pro/api/v1/openapi.json ``` Use the OpenAPI file for: - Swagger UI - Postman import - SDK generation - Contract validation in CI --- URL: https://docs.cleanestimate.pro/developers/external-api-overview Title: External API Overview Description: Use CleanEstimatePro's public REST API for CRM sync, forms, automations, and partner integrations. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-04-14 --- # External API Overview CleanEstimatePro includes a public REST API at `https://app.cleanestimate.pro/api/v1/` for server-to-server integrations. Use it for Zapier, Make, custom CRMs, web forms, internal middleware, and partner apps. The current public v1 API is intentionally scoped to the core workflow plus outbound webhook management: - Leads - Clients - Estimates - Jobs - Invoices - Outbound webhooks - OpenAPI at `/api/v1/openapi.json` Every request is isolated to the organization that owns the API key. The API never accepts a client-supplied `org_id`, and wrong-org records return `404`. ## What v1 Is For Use the external API when you need to: - Create leads from a partner form or marketing source - Sync clients into another system - Write internal CRM notes onto client, lead, and job records from your own middleware or automation layer - Generate estimates from an approved upstream workflow - Patch existing estimate customer details, assignment, draft/sent status, or expiration without recreating the quote - Read jobs or invoices into reporting tools - Trigger downstream automations from outbound webhooks For the current public v1 surface, note fields are available on `clients`, `leads`, and `jobs`. See the Examples page for copy-paste `POST` and `PATCH` requests. Residential estimate creation through `POST /api/v1/estimates` now lands on the same shared quote-core persistence layer as the in-app residential wizard. That keeps API-created residential estimates aligned with canonical quote snapshots and canonical line items while the broader wizard migration is still in progress. Residential estimate updates through `PATCH /api/v1/estimates/{id}` now use that same shared residential quote-core save path too. The endpoint still stays intentionally narrow, but supported residential updates now preserve canonical quote snapshots, canonical line-item sync, delivery-state metadata, and quote events instead of bypassing the shared persistence layer with a raw row update. ## What v1 Does Not Cover Yet The public API still does not expose every internal CE Pro surface. Proposal-family endpoints, report snapshots, team and schedule snapshots, service catalog reads, pricing reads, customer-sign actions, and PDF/duplicate helper routes remain internal for now. The old Phase 2 proposal/reporting docs described a broader future surface that is not part of the current public contract. Use `/api/v1/openapi.json` as the source of truth for what is live today. ## Base URL And Contract - Base URL: `https://app.cleanestimate.pro/api/v1` - Auth: `Authorization: Bearer ce_live_...` or `Authorization: Bearer ce_test_...` - Writes: `POST` and `PATCH` require `Idempotency-Key`, including `PATCH /api/v1/estimates/{id}` - Correlation: every response includes `X-Request-ID` - Rate limits: every response includes `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` - Browser safety: this API is for server-to-server use only. Never expose secret API keys in frontend code. - Schema: `/api/v1/openapi.json` ## Shipped Resource Groups - Core workflow: `leads`, `clients`, `estimates`, `jobs`, `invoices` - Webhook management: `webhooks` ## Response Shape Single-record responses use: ```json { "data": { "id": "..." } } ``` List responses use: ```json { "data": [], "meta": { "next_cursor": "opaque-cursor", "has_more": true, "limit": 25 } } ``` Errors use: ```json { "error": { "code": "validation_error", "message": "Invalid request body", "details": [] } } ``` Common error codes: - `401 invalid_api_key` - `403 insufficient_scope` - `403 unsupported_in_test_mode` - `409 idempotency_conflict` - `409 idempotency_in_progress` - `409 invalid_state` - `422 validation_error` - `429 rate_limited` - `503 rate_limit_unavailable` ## Live And Test Keys CleanEstimatePro supports separate live and test keys: - `ce_live_...` keys can use the full current public v1 surface. - `ce_test_...` keys are for sandbox integrations. In v1, test-key writes are intentionally limited to `leads`, `clients`, and `estimates`. Test-key writes are stored separately from live records and do not trigger normal outbound side effects. Webhook management is live-only in the current public API. Test keys cannot call: - `/api/v1/webhooks` ## Related Inbound Channels Not every integration starts with REST: - Email intake: use the live forwarding address shown in **Settings -> Integrations -> Lead Connectors** after inbound email routing is configured - Booking widget: `/api/portal/[orgSlug]/book` - Automation webhook intake: `POST /api/automations/webhooks/inbound` - Outbound events: register webhook destinations through `/api/v1/webhooks` Automation webhook intake uses the same scoped API key model and shared rate limiting as the public API. Send either `Authorization: Bearer ce_live_...` or `X-API-Key: ce_live_...`, and make sure the key includes `webhooks:write`. If you need a machine-readable contract, start with `/api/v1/openapi.json`. If you need operational guidance, continue with the pages in this Developers section. --- URL: https://docs.cleanestimate.pro/developers/idempotency Title: Idempotency Description: Prevent duplicate records when your integration retries POST or PATCH requests. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-03-19 --- # Idempotency All `POST` and `PATCH` requests to the external API require an `Idempotency-Key` header. That includes every current public write endpoint: - `/api/v1/leads` - `/api/v1/leads/:id` - `/api/v1/clients` - `/api/v1/clients/:id` - `/api/v1/estimates` - `/api/v1/estimates/:id` - `/api/v1/jobs` - `/api/v1/jobs/:id` - `/api/v1/invoices` - `/api/v1/invoices/:id` - `/api/v1/webhooks` This protects you from duplicate writes when a request times out, your worker retries, or a no-code platform like Zapier replays the same step. ## How It Works 1. Your integration sends a unique `Idempotency-Key`. 2. CE Pro stores the request fingerprint and response. 3. If you retry the same request with the same key and the same payload, CE Pro returns the original result instead of creating a duplicate record. 4. If you reuse the same key with a different payload, CE Pro returns `409`. 5. If another request with the same key is still running, CE Pro returns `409 idempotency_in_progress`. ## Header Example ```http Idempotency-Key: cepro-lead-20260314-001 ``` ## When To Reuse A Key Reuse the same key only when you are retrying the exact same operation. Examples: - A lead-create call timed out and you want to retry it safely - A network hop failed after the server already processed the request - A workflow runner retries the same step automatically Create a new key for every new write operation. ## Recommended Strategy Use a key derived from your upstream system's stable id: - Form submission id - CRM record id - Queue message id - Workflow run id plus step id That keeps retries safe even across worker restarts. ## Error Behavior - Same key + same body: CE Pro replays the original response - Same key + different body: `409` - Same key while the original request is still running: `409 idempotency_in_progress` - Missing key on `POST` or `PATCH`: request rejected CE Pro keeps completed and failed idempotency records for 72 hours, which is long enough to cover normal retry windows without storing them forever. ## Practical Tip For No-Code Tools If your tool supports a stable step identifier, map that into `Idempotency-Key`. If it does not, create a deterministic key from the external object id you are syncing. --- URL: https://docs.cleanestimate.pro/developers/operations-runbook Title: Operations Runbook Description: Queue monitoring, structured logs, alerts, and backup/restore expectations for CE Pro. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-03-21 --- # Operations Runbook CE Pro now ships with a more explicit operating model for queue health, structured logs, and restore readiness. ## Structured Logs High-value API and worker paths now emit structured JSON logs instead of ad hoc text-only console lines. The most useful event families are: - `background_job_cron.*` - `background_job_batch.*` - `background_job.retrying` - `background_job.dead_letter` - `admin_email.*` - `campaign_batch.*` - `recovery_email.*` - `health_check.degraded` These logs are designed to help you answer: - Did the worker run? - Did it claim work? - Is one job type failing repeatedly? - Are failures retrying or dead-lettering? ## Queue Monitoring CE Pro still exposes the public `GET /api/health` and `HEAD /api/health` checks for uptime probes. Internal monitors can also call `GET /api/health` with `Authorization: Bearer $CRON_SECRET` to receive a queue snapshot in the response body. That queue snapshot includes: - `pending` - `retrying` - `processing` - `dead_letter` - `oldest_ready_at` - `oldest_ready_age_seconds` ## Recommended Alerts Use these as the baseline alerts: - app health degraded for more than 2 minutes - queue backlog stays above normal for 10 minutes - oldest ready job age grows beyond 5 minutes - dead-letter count becomes non-zero - background worker cron starts failing or stops running - webhook delivery failures spike - admin auth failures spike ## Backup And Restore The production app runs on Supabase-backed Postgres, so the expected backup source of truth is the managed Supabase production project. That expectation still needs to be verified in the live Supabase dashboard. Until that verification is done, treat restore readiness as a tracked operations task, not an assumption. Minimum standard: 1. Automated backups enabled. 2. Retention window documented. 3. Restore owner named. 4. Quarterly restore drill recorded. ## Internal Runbooks The repo also carries internal runbooks for the operating team: - `docs/incident-monitoring-runbook.md` - `docs/backup-and-restore-runbook.md` Use those documents for the concrete response checklist, ownership fields, and restore-drill procedure. ## Stress Validation Before bigger launches, pricing changes, marketing pushes, or other traffic-shaping releases, run the repeatable stress drill documented in [Stress Testing](https://docs.cleanestimate.pro/developers/stress-testing). That drill exists so queue, health, and admin hot-path regressions show up before customers do. If the triggering event is a hosted Supabase project move or a region migration, run the cutover checklist and post-switch validation from [Supabase Region Migration](https://docs.cleanestimate.pro/developers/supabase-region-migration) before you call the environment healthy. --- URL: https://docs.cleanestimate.pro/developers/platform-reliability Title: Platform Reliability Description: Health checks, session refresh, baseline admin API protection, and crash recovery for CE Pro. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-04-28 --- # Platform Reliability CE Pro now includes a shared baseline for session refresh, admin API protection, health checks, and app-level crash recovery. These platform controls are not a replacement for route-level auth, validation, or product-specific permissions. They exist so the app behaves more predictably as traffic grows. ## Production Telemetry Baseline Phase 0 scaling work now starts with production telemetry, not synthetic load tests. Before CE Pro changes database access patterns, adds projections, provisions replicas, or raises infrastructure spend, the team must capture a production baseline that shows: - the top `10` slow app routes by `p95` and `p99` - the top `20` slow SQL statements from `pg_stat_statements` - the current Supabase connection snapshot, including total, active, idle, idle-in-transaction, waiting, and `max_connections` The app collects sampled browser navigation and same-origin API timing events in production. Sampling defaults to `5%` on public/non-admin routes, while authenticated admin pages default to `20%` so workhorse-route regressions show up faster. Override non-admin sampling with `NEXT_PUBLIC_ROUTE_TELEMETRY_SAMPLE_RATE`, override admin sampling with `NEXT_PUBLIC_ROUTE_TELEMETRY_ADMIN_SAMPLE_RATE`, and disable client-side collection with `NEXT_PUBLIC_ROUTE_TELEMETRY_ENABLED=false`. The ingestion endpoint can also be shut off server-side with `ROUTE_TELEMETRY_INGEST_DISABLED=true`. Telemetry ingest uses the in-memory limiter so collecting route timings does not spend another database RPC before writing the actual sample. Telemetry writes land in `route_performance_events`. The export command reads service-role-only RPCs for route timing, `pg_stat_statements`, and connection usage: ```bash npm run telemetry:production -- --days=7 --out=reports/production-telemetry.md ``` The Phase 0 stop condition is strict: if production telemetry shows the current SLOs are already met at the current measured load, halt Phases 1-6 and re-evaluate quarterly instead of making speculative architecture changes. The business-load target is also a hard prerequisite before optimization work beyond telemetry: the business owner must write down `N` simultaneous authenticated active sessions by date `D`, justified by the launch, customer, or usage reason. Without that number, scale work has no anchor. Cost gates stay explicit. Any phase that would push monthly infrastructure spend above `$250` needs Clean Estimate Pro business-owner approval before it starts. A higher ceiling is only unlocked when current MRR supports it: `$500/month` after `$10k MRR`, `$1,000/month` after `$25k MRR`, or a written launch-risk exception from the business owner. ## Auth and Worker Backpressure When Supabase Auth or PostgREST starts returning gateway timeouts, the sign-in screen now fails visibly instead of leaving the user stuck on **Signing in...**. Password sign-in waits up to `15` seconds and then shows a retryable auth-service message. The scheduled worker routes also include incident controls so database pressure can be reduced without changing user-facing app code: - `DISABLE_CRON_JOBS=true` pauses the full scheduled-work layer after each route authenticates and before it opens a Supabase connection. - `DISABLE_SCHEDULED_WORK=true` is an equivalent global scheduler pause switch for incidents where the word "cron" is too narrow. - `DISABLE_BACKGROUND_JOB_CRON=true` pauses only `/api/cron/process-background-jobs`. - `DISABLE_WEBHOOK_DELIVERY_CRON=true` pauses only `/api/cron/process-webhook-deliveries`. - `DISABLE_FOLLOW_UP_CRON=true` pauses only `/api/cron/process-follow-ups`. - `DISABLE_DRIP_CAMPAIGN_CRON=true` pauses only `/api/cron/process-drip-campaigns`. - `DISABLE_EXPIRE_PROPOSALS_CRON=true` pauses only `/api/cron/expire-proposals`. - `DISABLE_AUTOMATION_WAITING_CRON=true` pauses only `/api/automations/engine/process-waiting`. - `DISABLE_AUTOMATION_SCHEDULED_TRIGGER_CRON=true` pauses only `/api/automations/engine/process-scheduled-triggers`. - `DISABLE_FRANCHISE_SUMMARY_CRON=true` pauses only `/api/cron/refresh-franchise-summary`. - `BACKGROUND_JOB_CRON_BATCH_SIZE` and `BACKGROUND_JOB_CRON_CONCURRENCY` can raise or lower the background worker from its conservative defaults of `5` jobs and `1` concurrent dispatch. - `WEBHOOK_DELIVERY_CRON_BATCH_SIZE` can raise or lower webhook delivery claiming from its conservative default of `10` deliveries. The public ingress rate-limit RPC is also lock-bounded. If one hot key is already being updated, the limiter fails closed quickly instead of holding PostgREST workers on a row lock until the platform times out the request. If Supabase warns that the project is about to deplete or has depleted its Disk IO Budget, set the global scheduler pause first, redeploy so every route has the guard, avoid super-admin/dashboard refreshes, then either wait for the next daily IO budget replenishment or temporarily upgrade compute while the team captures `pg_stat_statements` and fixes the disk-heavy queries. Compute add-ons require the Supabase organization to be on a paid plan; free-tier projects must be upgraded to a paid Supabase plan before the emergency compute add-on can be applied. Super-admin pages are dynamic-only so protected platform dashboards never block a Vercel build on live Supabase reads. ## Admin Alert Backpressure The admin alert bell is a read path. It should not regenerate managed alerts or write to `ai_alerts` on every poll. Managed alert generation is reserved for the dashboard alert scope, is throttled by `ADMIN_ALERT_SYNC_TTL_MS` with a five-minute default, and skips unchanged rows so realtime subscriptions do not create read/write feedback loops. If the admin shell feels slow, check `telemetry_route_performance_summary` for `/api/admin/alerts` and `telemetry_pg_stat_statements_top` for `ai_alerts` updates. A healthy alert path should show reads and occasional inserts or updates, not continuous update traffic while the user is idle. ## Admin Navigation Read Pressure The admin shell keeps ordinary page navigation on the lightest available read path. Current controls: - Middleware and server org-context resolution skip the franchise descendant lookup when the selected active org is already a direct user membership. - The sidebar gamification badge is read-only during normal page loads and no longer seeds catalogs, upserts reward rows, recalculates profiles, or records daily-login XP from the shared layout. - Admin API middleware rate limiting uses the in-memory limiter for `/api/admin/*` traffic so ordinary schedule, client, and dashboard reads do not spend a database RPC before the route handler authenticates and authorizes the request. - The Clients list avoids an unused exact count on the standalone contact query and narrows client-health work to the visible client ids when possible. - The Clients page shell no longer blocks server navigation on the heavy account tree API. The page opens with a loading state and hydrates the account/client rows through the existing client-side endpoint. - The Estimates page shell follows the same pattern. It no longer waits on server-side calls back into `/api/admin/estimates` and `/api/admin/team`; the browser hydrates the first list and team filters after the shell is interactive. - The Estimates list API keeps exact visible totals and uses a short-lived cached summary for type/source metadata so the workbench does not show approximate counts. - Dashboard first-load metrics keep exact visible totals, use narrower reads, and cache the expensive chart RPC for five minutes per workspace/month range. - Schedule reference data for crews, team members, trucks, vehicles, services, and crew-pay policies is cached briefly per workspace so repeat visits do not re-run the same setup reads. If most admin pages take multiple seconds to open, first check `telemetry_pg_stat_statements_top` for `get_org_and_descendants`, `check_public_rate_limit`, `user_gamification_profile`, `rewards`, and `get_client_health`. Those should not climb quickly during light single-user navigation. ## Report And Dashboard Accuracy Admin dashboards and analytics reports must not use approximate counts, sampled data, hidden row caps, or whole-dollar rounding for user-facing business totals. Current accuracy controls: - Revenue Analytics loads accepted residential, fleet, commercial building, and holiday lights revenue in paginated batches so it does not silently stop at the platform row limit. - Service mix, sales-cycle, geography, retention, operations, schedule, lead-source ROI, holiday-lights, franchise, and margin reports page through their report inputs instead of relying on the default PostgREST window. - Owner, residential, sales, commercial, fleet, holiday-lights, commissions, crew-pay, client, franchise, and pipeline dashboard totals use exact source rows or exact database counts for visible KPIs. - Schedule calendar metrics now page through the selected range of jobs and sales follow-up events before calculating job counts, scheduled revenue, and average ticket. - User-facing money totals display to the cent across admin dashboards, reports, job details, schedule views, pipeline cards, commissions, crew pay, client LTV/open pipeline, revenue charts, and exports. - Report money is summed as integer cents where precision matters before values are converted back for display/export. - If a report source query fails, the route should fail visibly instead of showing a partial total or fake zero as if it were complete. Forecasts and estimates are still allowed where the workflow is explicitly predictive, such as pipeline forecast scenarios or modeled margin cost. Those surfaces must be labeled as forecasts or estimated costs and must not be presented as actual revenue, payment, or performance history. ## Root Session Proxy Protected app surfaces now pass through a shared root session proxy entrypoint instead of relying on scattered session refresh logic. That middleware covers: - Admin routes - Super-admin routes - Onboarding routes - Logged-in customer routes - Selected public customer-link routes that already use signed tokens The goal is simple: keep authenticated browser sessions fresher and reduce the "randomly got sent back to login" class of failure during normal admin use. For admin workspace resolution, the request-scoped org hint is now treated as a fast-path hint rather than trusted authority. The app still validates that the hinted active org is actually reachable from the selected membership before it reuses that context. The same root session proxy also refreshes browser cookies on mixed-auth API surfaces that can be reached from staff workflows, including: - `/api/email` - `/api/sms` - `/api/estimates/*` - `/api/holiday-lights/*` Those routes still enforce their own route-level auth or customer-token rules. The proxy only refreshes an existing browser session when one is present. Inbound webhook routes are still intentionally excluded from the root session proxy because they authenticate with provider signatures, scoped tokens, or internal secrets instead of browser cookies. The proxy now also strips the internal request-scoped org hint headers from all inbound traffic before forwarding the request deeper into the app. Those headers are only re-applied after the admin session is resolved inside the trusted proxy path, which closes the spoofing gap where an external caller could try to inject active-org context directly. ## Admin API Baseline Rate Limiting All `/api/admin/*` routes now inherit a baseline middleware rate limit of `60` requests per minute before any route-specific limits apply. Important notes: - This is a shared floor, not a replacement for tighter limits on sensitive endpoints. - Existing route-level auth and permission checks still matter. - The middleware limiter uses in-memory protection for admin API traffic to keep protected office reads from paying an extra database RPC. Public and token-based surfaces still use the shared database-backed limiter unless their route opts into a different policy. - The middleware now buckets admin API traffic by authenticated user when one is available, and falls back to an IP-scoped key only when the caller has no usable session. That avoids one fast admin user starving everyone else behind the same office network. ## Health Endpoint CE Pro now exposes: - `GET /api/health` - `HEAD /api/health` Use this endpoint for uptime monitors, platform health probes, and deployment checks. The check verifies: - the app can boot with the required runtime environment - Supabase is reachable from the app runtime Responses are intentionally cheap and uncached. The health path now also uses bounded timeouts for both the dependency check and the optional internal queue snapshot. The Supabase reachability query carries its own abort signal, so a slow dependency check is cancelled at the timeout boundary instead of leaving an upstream request running after the endpoint has already degraded. If Supabase is slow or the queue snapshot cannot complete quickly, the endpoint degrades fast instead of hanging until the platform kills the request. ### Healthy Response ```json { "status": "ok", "checked_at": "2026-03-21T15:00:00.000Z", "services": { "app": "ok", "supabase": "ok" } } ``` ### Degraded Response If the app can respond but a required dependency check fails, CE Pro returns `503` with a `degraded` status. ## Startup Environment Validation The shared Supabase bootstrap path now validates its required environment variables from one place instead of silently failing later in request handling. That baseline validation currently covers the critical Supabase runtime config: - `NEXT_PUBLIC_SUPABASE_URL` - `NEXT_PUBLIC_SUPABASE_ANON_KEY` - `SUPABASE_SERVICE_ROLE_KEY` If one of those values is missing or malformed, the app now fails loudly instead of limping into production with partial behavior. ## Global Error Recovery CE Pro now includes app-wide error boundaries for route-level and full-app crashes. That means a render failure should now fall back to a recovery screen with a retry action instead of dropping the user onto a blank white page with no path forward. Route-specific error boundaries can still exist where a workflow needs a more tailored recovery state. The shared fallback also routes admins, logged-in customers, and public visitors back to the right surface instead of always sending everyone to the admin dashboard. ## Background Delivery Jobs CE Pro now moves more slow outbound delivery work off the request path and onto the shared background jobs queue. That queue now handles: - one-time campaign fan-out batches - manual admin inbox email sends - commercial fleet and building proposal sends, including PDF generation, email, SMS, and delivery-state updates - forgot-password recovery emails - fresh team setup-link emails - self-serve account password reset emails from Settings The main effect is that the app can acknowledge the request faster while the minute-by-minute job worker handles the actual send work in the background. Queued email-style delivery work now also gets retry headroom instead of acting like a one-shot fire-and-forget handoff. That means: - forgot-password sends retry on transient provider failures - setup-link and account-reset sends retry instead of silently dead-lettering after one blip - queued admin inbox emails retry before they are marked failed ### What Users See - Marketing sends now queue batches instead of holding the browser open while every recipient is processed inline. - Manual admin emails show as queued instead of pretending delivery already finished. - Commercial proposal sends now show as queued while the background worker renders the PDF, sends email/SMS, and records delivery state. Set `COMMERCIAL_PROPOSAL_SEND_QUEUE_DISABLED=true` to roll this path back to synchronous delivery. - Password recovery and setup-link requests now rely on the background worker instead of waiting on synchronous provider delivery inside the request. ## Hot-Read Server Caching Phase 2 also adds short-lived server-side caching to a few high-traffic office reads so common dashboard and setup screens stop re-running the same database work on every load. The current cache coverage includes: - admin dashboard metrics - services catalog reads - add-on structure reads - lead source reads and lead-source lookup helpers - pricing config reads - tag summary reads These caches are intentionally short and org-scoped. Important notes: - Admin reference-data writes now invalidate their matching cache tags. - Cached responses still keep the existing browser cache headers where those were already part of the route contract. - Dashboard data currently relies on TTL-based refresh rather than write-trigger invalidation, which keeps the implementation safe while still cutting read pressure. - Lead-source admin reads also now avoid selecting a non-existent `updated_at` column on workspaces where that field is absent, which closes the stress-test `500` that was keeping the lead-source cache path from helping at all. ## Shared Org Cache The short-lived server caches now use a shared org-cache abstraction with standard bucket types instead of one-off inline cache definitions. That makes it easier to review: - cache scope - TTL intent - org isolation - invalidation tags The current buckets in use are: - `reference` - `dashboard` - `settings` ## RSC-First Admin Lists The Jobs and Invoices workspaces now load their first page on the server and hydrate into client-side query state instead of waiting for a mount-time waterfall before anything useful appears. That means: - first paint is more useful on those pages - the first page is already present when the client boots - follow-up pagination and refreshes reuse the same query path ## Query-Backed Pagination The Jobs and Invoices admin workspaces also moved off the old fixed `200` row cap and onto explicit paginated list APIs. That reduces overfetching and gives those pages a clearer path to larger-office datasets. Important note: - Some list-level summary cards still intentionally describe the loaded slice, not the full matching dataset, unless the page explicitly labels otherwise. - Jobs and Invoices search and status filtering now run through the paginated query path too, so records do not appear to vanish just because they live beyond the first loaded page. - Jobs and Invoices now sanitize free-text search terms before they are interpolated into the PostgREST filter DSL, which avoids malformed search expressions on punctuation-heavy queries. - Jobs and Invoices now also have dedicated `(org_id, api_environment, created_at DESC)` indexes for the primary admin list path, so those pages benefit from the same scaling work instead of relying on less-specific secondary indexes. - Jobs and Invoices now also treat out-of-range page offsets as empty pages instead of surfacing a server error when a workspace does not have enough rows to satisfy the requested offset yet. - That out-of-range protection now matches the real PostgREST response shape too, including the `416 Range Not Satisfiable` case where the HTTP status is returned alongside the error payload instead of inside it. ## Super-Admin Browser QA The repo now includes a read-only super-admin portal browser QA script: ```bash npm run qa:super-admin -- --base-url=https://cleanestimate.pro --magic-link ``` Run it with `SUPER_ADMIN_EMAIL`, `NEXT_PUBLIC_SUPABASE_URL`, and `SUPABASE_SERVICE_ROLE_KEY` available in the environment. The script verifies that signed-out users are redirected away from `/super-admin`, signs in through a one-time Supabase magic link for the configured super-admin identity, opens the Dashboard, Organizations, organization detail, Users, Waitlist, and Activity surfaces, and records screenshots plus `report.json` under `output/playwright/super-admin-portal-qa/`. The super-admin Users and Waitlist tables now use deterministic date rendering during hydration so browser QA does not surface React text-mismatch errors on those operational pages. The production CSP also allows the Google Analytics collect endpoint currently used by the deployed tag, which prevents analytics CSP noise from hiding real super-admin portal failures. ## Signup & Onboarding Browser QA The repo now also includes a live self-serve signup and onboarding browser QA script: ```bash npm run qa:signup -- --base-url=https://cleanestimate.pro ``` Run it with `AGENTMAIL_API_KEY`, `NEXT_PUBLIC_SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, and `INTERNAL_API_SECRET` available in the environment. The script creates a fresh AgentMail inbox, signs up a new owner and organization through `/signup`, completes the Company Info, Services, Pricing, and Get Started onboarding steps, verifies the new owner can reach `/admin`, checks the database state for the owner/org/membership/trial, confirms password login from a clean browser session, then sends and opens a real owner access-link email delivered to AgentMail. Evidence is written under `output/playwright/signup-onboarding-qa/` with full-page screenshots and `report.json`. The admin dashboard's Lead Sources shortcut now points at the live `/admin/analytics/lead-source-roi` report instead of prefetching a missing analytics route, which keeps browser QA console output focused on actual signup and auth failures. ## Invoice Number Allocation Invoice creation now allocates invoice numbers through one shared atomic counter path across: - admin single-invoice creation - admin bulk invoice creation - API v1 invoice creation That removes the older count-then-insert race where concurrent creates could reach the same invoice number under load. The allocator also seeds itself from any already-existing invoice numbers for the same org and date, so rollout does not break on workspaces that created invoices before the counter-backed path existed. ## Phase 4 Audit Follow-Up The post-Phase-4 review also shipped a few correctness fixes that are easy to miss if you only look at the higher-level roadmap: - lead-source reference reads now respect the `includeAll=false` active-only filter again - server-hydrated Jobs and Invoices data now marks the initial React Query payload as fresh instead of immediately re-fetching on mount - the background-job cron now claims a smaller bounded batch per run so slow workers are less likely to hit the serverless timeout and leave claimed jobs waiting for stale-lock recovery ## Structured Logging And Queue Health The background job processor and internal delivery workers now emit structured log events instead of free-form console output. Those logs make it easier to separate: - healthy empty worker runs - claimed batch runs - retrying jobs - dead-letter failures The structured logger now also avoids writing full recovery-email and admin-email recipient addresses into production logs. Those logs keep enough masked recipient detail for debugging without leaving plaintext inbox addresses in the log stream. The health endpoint also supports an internal queue snapshot when called with the same bearer secret used by the cron worker. Use the dedicated [Operations Runbook](https://docs.cleanestimate.pro/developers/operations-runbook) for alert thresholds, queue checks, and restore-readiness expectations. Use the dedicated [Stress Testing](https://docs.cleanestimate.pro/developers/stress-testing) guide for the repeatable 1K-user readiness drill, default session mix, cookie-pool setup, and pass/fail thresholds. If you are moving CE Pro to a new hosted Supabase project or region, use the dedicated [Supabase Region Migration](https://docs.cleanestimate.pro/developers/supabase-region-migration) guide before switching traffic. ## Queue Correctness Follow-Up The background job dedupe layer now only blocks duplicate work while a matching job is still in an active queue state: - `pending` - `processing` - `retrying` Completed, failed, and dead-letter jobs no longer permanently reserve the same dedupe key, which means legitimate follow-up queueing can happen again after the earlier work has fully finished. Campaign dispatch stat reconciliation also now runs through a database-side sync step instead of an app-side read-then-write cycle. That removes the race where multiple finishing workers could overwrite each other's campaign status or message totals. The campaign batch worker now isolates failures at the recipient level instead of aborting the whole batch on the first provider error. A single transient email failure no longer prevents the rest of the batch from being attempted, and the stats sync step still runs after the batch work completes. The background-job processor also now reports jobs that got stuck before they could be finalized as a separate `stuck_processing` outcome instead of counting them as dead-letter work they never actually reached. ## Recovery Email Burst Protection Forgot-password requests now rate-limit by normalized email address instead of only by source IP. That means: - rotating IPs or VPN exits no longer bypass the per-address recovery limit - rapid duplicate forgot-password requests collapse onto one queued recovery job instead of stacking multiple identical email sends ## Permission Hardening Follow-Up The Phase 3 admin-route hardening pass now keeps read and destructive permissions separated on the detail routes that were still inconsistent. The two practical outcomes are: - estimate delete operations now require `estimates.manage` instead of slipping through the same top-level gate used for estimate reads - lead detail reads now use the view-side client permission instead of the stronger write tuple used for lead mutation routes - invoice attachment reads and writes now follow billing permissions instead of estimate permissions, so billing-only roles can manage invoice files without inheriting estimate access and estimate-only roles do not gain invoice attachment visibility by accident That keeps destructive behavior aligned with the route intent while avoiding unnecessary lead-detail lockouts for read-capable office roles. ## Log Redaction Follow-Up The Phase 5 structured logging pass now masks email addresses on the enqueue-failure paths too, not just in the background workers that actually deliver mail. That means recovery-email, setup-link, account-reset, and admin-email queue failures no longer write plaintext recipient addresses into structured logs while operators are debugging a queue outage. ## API V1 CORS Cache Safety The API v1 response helper now only emits `Vary: Origin` when it also emitted an `Access-Control-Allow-Origin` header. That makes cached server-to-server responses less likely to interfere with later browser requests on installations that put an edge cache in front of the external API surface. --- URL: https://docs.cleanestimate.pro/developers/proposals-and-reporting Title: Proposal and Reporting API Status Description: Current availability status for the deferred proposal and reporting resources that were previously documented for the external API. Category: developers Difficulty: advanced Roles: owner, manager, developer Last updated: 2026-03-16 --- # Proposal and Reporting API Status The broader Phase 2 external API surface that was previously documented is **not part of the current public `/api/v1` contract**. Today, the public API exposes only: - `leads` - `clients` - `estimates` - `jobs` - `invoices` - `webhooks` - `openapi.json` ## Not Currently Public The following resources remain internal and should not be treated as available public API endpoints: - Proposal-family routes such as commercial building, fleet, and holiday lights proposals - Proposal metadata routes such as templates and pipeline stages - Read-only reports and exports - Team and team activity snapshots - Schedule snapshots - Services and pricing snapshot endpoints If you saw older docs, examples, or changelog entries referencing that larger surface, treat them as deferred roadmap material rather than a live contract. ## Source Of Truth Before building an integration, check the machine-readable contract at: - `GET /api/v1/openapi.json` If an endpoint is not present there, do not assume it is supported publicly. ## What To Use Instead - For customer lifecycle syncs, use the current public core resources plus outbound webhooks. - For internal proposal, reporting, pricing, and schedule workflows, continue using the CE Pro app directly. - For outbound change notifications, register webhook destinations through `/api/v1/webhooks` and verify signatures as described in [Webhook Signing](https://docs.cleanestimate.pro/developers/webhook-signing). --- URL: https://docs.cleanestimate.pro/developers/stress-testing Title: Stress Testing Description: Run the repeatable 1K-user readiness drill against CE Pro before launches and scale changes. Category: developers Difficulty: intermediate Roles: owner, manager, developer Last updated: 2026-04-26 --- # Stress Testing CE Pro now ships with a repeatable stress-test harness for the office and platform paths most likely to matter as traffic grows. The goal is not to win a benchmark. The goal is to answer a much more useful question: Can this deployment handle a realistic jump toward 1,000 users without falling apart on the hot admin, health, and queue paths? ## Telemetry Gate Before Stress Runs Production telemetry comes first. Stress tests are now a validation tool after the team knows which production routes matter, not the first source of truth for Phase 1 work. Before ranking scale fixes, collect `3-7` days of production traffic and export the Phase 0 baseline: ```bash npm run telemetry:production -- --days=7 --out=reports/production-telemetry.md ``` Use that report to identify the top slow routes, run `EXPLAIN ANALYZE` on the top slow SQL statements, and classify each fix as a missing index, N+1 pattern, exact count, bad join, or larger architecture issue. If the report shows current SLOs are already met at the current measured load, halt speculative Phases 1-6 and re-evaluate quarterly. If the report shows real hot paths, run focused stress tests against those routes after the cheap fixes or queueing changes land. ## What The Harness Exercises The default route mix focuses on: - `GET /admin` - `GET /admin/jobs` - `GET /admin/invoices` - `GET /api/admin/jobs?limit=25&offset=*` - `GET /api/admin/invoices?limit=25&offset=*` - `GET /api/admin/services` - `GET /api/admin/lead-sources` - `GET /api/admin/tags` - `HEAD /api/health` - optional `GET /api/health` with the cron bearer secret for queue visibility That mix intentionally leans on the exact paths touched in the scale-hardening work: - paginated Jobs and Invoices reads - short-lived org-scoped cache reads - server-first admin page renders - health and queue visibility ## Why It Uses A Cookie Pool The default test is session-paced, not a single-client flood. That matters because `/api/admin/*` now has a baseline per-user rate limit. If you hammer the admin APIs from one cookie, you mostly learn that your own guardrail works. A realistic office-load test should spread requests across a pool of authenticated admin sessions so the results reflect multi-user behavior. ## Default 1K-Ready Profile The default profile is: - `warmup`: `8` sessions for `60s` - `steady`: `20` sessions for `180s` - `peak`: `40` sessions for `300s` - `spike`: `60` sessions for `120s` Think time defaults to `900ms` through `2500ms` between requests. That is a much better model for a 1,000-user business app than firing 1,000 requests at once from one process. ## Running The Test Create a local file with one full admin `Cookie` header value per line, then run: ```bash STRESS_BASE_URL=https://app.cleanestimate.pro \ STRESS_ADMIN_COOKIE_FILE=.secrets/stress-admin-cookies.txt \ STRESS_CRON_SECRET=replace-me \ npm run test:stress ``` To inspect the resolved plan without sending traffic: ```bash npm run test:stress -- --dry-run ``` Each run writes a JSON report into `stress-reports/` unless you pass a custom `--output`. ## Pass Criteria Treat the default drill as healthy when all of these remain true: - error rate stays at or below `2%` - `429` rate stays at or below `5%` - overall `p95` latency stays at or below `1500ms` - health-check `p95` stays at or below `500ms` - queue backlog does not grow continuously during the run - dead-letter work does not spike during the test window ## When A Run Fails If throttling is the main failure: - add more admin cookies before assuming the app itself is the bottleneck - confirm you are not over-driving the same small set of users into the baseline admin limiter If Jobs or Invoices are the dominant latency source: - review the active list queries - compare the org size against the search terms and offsets used in the run - confirm the latest indexes and migrations are live in the target environment If health checks degrade: - inspect Supabase latency - inspect queue backlog and oldest ready age - confirm the queue snapshot path is still timing out quickly instead of hanging ## Related Docs - [Platform Reliability](https://docs.cleanestimate.pro/developers/platform-reliability) - [Operations Runbook](https://docs.cleanestimate.pro/developers/operations-runbook) - [Supabase Region Migration](https://docs.cleanestimate.pro/developers/supabase-region-migration) --- URL: https://docs.cleanestimate.pro/developers/supabase-region-migration Title: Supabase Region Migration Description: Move CE Pro to a new Supabase region without missing auth, storage, mobile, or stress-validation work. Category: developers Difficulty: advanced Roles: owner, manager, developer Last updated: 2026-03-22 --- # Supabase Region Migration Moving CE Pro to a new Supabase project is not just a database copy. The production stack currently depends on Supabase through: - web runtime envs and service-role helpers - hosted Auth callbacks and redirect allow-lists - storage buckets and signed upload/download flows - Supabase Edge Functions - mobile Supabase config and mobile function invocation If you are migrating from the current Oregon project to a new Virginia project, use this guide as the cutover checklist and validation baseline. ## Cutover Checklist Before switching traffic: 1. Create the new hosted project in Virginia and capture the new project ref, API URL, anon key, service-role key, and DB/pooler strings. 2. Recreate the hosted Auth settings on the new project, including the production `site_url`, redirect allow-list, session limits, refresh rotation, and OTP expiry settings CE Pro expects. 3. Apply the full schema and deploy the required Supabase Edge Functions to the new project. 4. Recreate the storage buckets CE Pro needs and copy storage objects, not just tables. 5. Update the web app envs, mobile envs, and any local ops/scripts that still point to the old project. 6. Drain or pause background jobs and webhook delivery work before the final delta copy so you do not process the same workload in two places. 7. Run smoke checks, then rerun the stress harness against the Virginia-backed stack before calling the move complete. ## Repo Audit Highlights The repo has a few migration-sensitive surfaces worth calling out explicitly. ### Web app The main web runtime is env-driven, so the core cutover values are: - `NEXT_PUBLIC_SUPABASE_URL` - `NEXT_PUBLIC_SUPABASE_ANON_KEY` - `SUPABASE_SERVICE_ROLE_KEY` Those values drive the shared Supabase bootstrap paths, auth callback route, middleware session handling, direct proposal-view tracking, and script helpers. ### Mobile The mobile app has its own Supabase coupling and should be treated as a first-class migration surface. - The runtime reads `EXPO_PUBLIC_SUPABASE_URL` and `EXPO_PUBLIC_SUPABASE_ANON_KEY`. - The current `mobile/eas.json` still contains the old Oregon project ref URL. - The mobile app invokes Supabase Functions directly, including `send-proposal`. If the mobile build or EAS secrets stay pointed at Oregon, the migration is only half-done. ### Auth redirects CE Pro generates hosted auth links for: - password reset - team invite/setup - customer magic-link login - super-admin reset flows That means the new Supabase project must have the correct hosted redirect allow-list for the production app origin and the `/auth/callback` and `/auth/complete` flows CE Pro uses. ### Storage buckets At minimum, verify: - `job-photos` - `record-attachments` - `bug-report-screenshots` Some of these are called out in repo migrations as manual bucket-creation steps on a fresh project, so do not assume `db push` alone makes storage ready. ## Post-migration Validation Run this in order: 1. `GET /api/health` 2. admin login, customer login, forgot-password, and invite flows 3. admin Jobs, Invoices, Services, Lead Sources, and Tags reads 4. job-photo and attachment upload/download 5. proposal send and proposal-view tracking 6. webhook smoke tests for the providers you actively use Also verify: - background-job queue health - webhook-delivery health - no missing Edge Functions on the new project ## Stress Test Rerun After the smoke checks, rerun the same stress harness used during the scale-hardening work. Small shakeout: ```bash STRESS_BASE_URL=https://cleanestimate.pro \ STRESS_ADMIN_COOKIE_FILE=.secrets/va-admin-cookies.txt \ STRESS_CRON_SECRET=replace-me \ npm run test:stress -- --stages='[{"name":"shakeout","sessions":10,"durationSec":120}]' ``` Then the full `1k-ready` profile: ```bash STRESS_BASE_URL=https://cleanestimate.pro \ STRESS_ADMIN_COOKIE_FILE=.secrets/va-admin-cookies.txt \ STRESS_CRON_SECRET=replace-me \ npm run test:stress ``` The March 22, 2026 stabilized Oregon-backed baseline was: - error rate `1.70%` - overall `p95` `2465ms` - health `p95` `351ms` The Virginia cutover should at minimum preserve correctness and improve that latency ceiling. ## Related Guides - [Platform Reliability](https://docs.cleanestimate.pro/developers/platform-reliability) - [Operations Runbook](https://docs.cleanestimate.pro/developers/operations-runbook) - [Stress Testing](https://docs.cleanestimate.pro/developers/stress-testing) --- URL: https://docs.cleanestimate.pro/developers/webhook-signing Title: Webhook Signing Description: Verify outbound webhook deliveries from CleanEstimatePro with HMAC SHA-256. Category: developers Difficulty: advanced Roles: owner, manager, developer Last updated: 2026-03-16 --- # Webhook Signing You can register outbound webhook destinations with the external API or from **Settings -> Integrations -> Webhooks**. Each destination gets a signing secret. CE Pro signs every delivery with HMAC SHA-256 so your server can verify authenticity before processing the payload. ## Supported Events - `lead.created` - `lead.status_changed` - `estimate.created` - `estimate.accepted` - `job.created` - `job.completed` - `invoice.created` - `invoice.paid` ## Delivery Headers Every outbound delivery includes: - `Content-Type: application/json` - `X-Webhook-ID` - `X-Webhook-Signature` - `X-Webhook-Event` - `X-Webhook-Timestamp` - `X-Webhook-Attempt` Use `X-Webhook-ID` as the delivery identifier on your side for dedupe and replay tracking. ## Example Payload ```json { "event": "job.completed", "timestamp": "2026-03-14T16:45:00.000Z", "data": { "job_id": "2d74d878-9a62-45da-84de-74d91c4a2b4d", "status": "complete" } } ``` ## Verify The Signature Compute an HMAC SHA-256 signature of the raw request body using the webhook secret you stored when the destination was created. ### Node.js ```js import crypto from 'crypto' export function verifyCeProWebhook(rawBody, signatureHeader, secret) { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex') const expectedBuffer = Buffer.from(expected, 'utf8') const receivedBuffer = Buffer.from(signatureHeader || '', 'utf8') return ( expectedBuffer.length === receivedBuffer.length && crypto.timingSafeEqual(expectedBuffer, receivedBuffer) ) } ``` ### Python ```python import hashlib import hmac def verify_cepro_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool: expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature_header or "") ``` ## Retry Behavior If your endpoint does not return a `2xx` response, CE Pro queues retries using durable delivery records and retries after approximately `10s`, `60s`, and `300s`. Because retries happen, your endpoint should be idempotent. Store the `X-Webhook-ID` you have already processed and ignore duplicates. Only live webhook destinations are processed in v1. Test API keys cannot register webhook endpoints, and the delivery worker ignores any non-live queue rows. ## Inbound Provider Callbacks To CE Pro CE Pro also receives inbound callbacks from providers such as Mailgun. Those provider-to-CE Pro requests do not use the outbound HMAC scheme above. For inbound email routing, configure your provider to send: - `Authorization: Bearer ` Do not place the inbound secret in the query string. CE Pro no longer accepts query-string-only authentication for inbound email callbacks. Example route target: ```text POST https://your-domain.com/api/webhooks/email-inbound Authorization: Bearer ``` ## URL Restrictions CE Pro accepts only external HTTPS webhook URLs. Localhost, private-network, and internal-only targets are rejected for safety. --- URL: https://docs.cleanestimate.pro/estimating/asphalt-maintenance Title: Asphalt Maintenance Description: Build and send asphalt maintenance quotes with lot square footage pricing, sealcoat scope, crack fill, striping, and patch repair. Category: estimating Difficulty: intermediate Roles: owner, sales_rep, admin Last updated: 2026-03-30 --- # Asphalt Maintenance Asphalt Maintenance is now a live estimating module inside CleanEstimate Pro. It uses the same shared quote core as the rest of the platform, which means asphalt quotes reuse the same: - customer and property records - branded quote links - PDF and send flows - payment state - quote events - estimate list and admin detail views The module focuses on asphalt-specific scope and pricing without introducing a separate estimating stack. --- ## Where To Find It In the admin app you can now start asphalt work from: - **+ New Estimate** → **Asphalt** - **Quick Start** → **Asphalt** - global search → **New Asphalt Quote** Direct links and saved bookmarks to `/admin/asphalt-maintenance` now resolve into the live asphalt quote editor automatically, and the admin route guard now recognizes that module path correctly, so the module entry path and the explicit **New Asphalt Quote** path both open the same working asphalt flow instead of bouncing back to the dashboard. The send flow now also repairs missing shared public-quote tokens on older asphalt drafts before delivery. If secure signing is not configured yet, CE Pro still sends the asphalt quote with a working view-only shared quote link instead of blocking the send with a temporary secure-link error. Saved asphalt quotes reopen through their own dedicated office editor instead of the generic quote editor. --- ## What It Quotes The live asphalt flow currently supports: - sealcoat pricing by **lot square footage** - **single-coat** and **double-coat** scope - **crack fill** by linear foot - **line striping refresh** by count - **patch repair** by square foot Those scope items become shared canonical quote line items under the hood, so the rest of the platform can read, send, and report on them normally. --- ## Pricing Model The asphalt catalog now lives in the shared price-book system. The baseline shared catalog includes: | Catalog Item | Unit | Measurement Contract | |---|---|---| | Sealcoat - Single Coat | `sqft` | `lot_sqft` | | Sealcoat - Double Coat | `sqft` | `lot_sqft` | | Crack Fill | `linear_ft` | `crack_fill_linear_ft` | | Line Striping Refresh | `each` | `line_striping_count` | | Patch Repair | `sqft` | `patch_sqft` | Like the rest of the shared price-book rollout: - the platform keeps one shared default baseline - each workspace can override its own asphalt pricing privately - one workspace's asphalt pricing changes do **not** leak into another workspace --- ## Office Workflow The asphalt editor collects: - customer and site details - lot square footage - coat type - repair and add-on quantities - optional per-quote rate overrides - tax and discount adjustments - internal notes The quote summary is generated from those measurements in real time, then saved through the shared estimate routes with `wizard_key = asphalt_maintenance`. That means reopened asphalt quotes keep their asphalt wizard measurements and pricing context instead of flattening back into a generic freeform quote. --- ## Customer Delivery Asphalt quotes now use the same shared customer delivery behavior as the other quote-core families: - branded email and SMS send copy - shared public quote link - branded PDF selection - shared payment-link and payment-state handling - shared estimate list and admin resend history From the customer's perspective, asphalt quotes behave like a first-class CleanEstimate Pro quote, not a one-off custom workflow. --- ## Notes This module currently ships as an office-side asphalt quote flow, not a self-serve public estimator. The important architectural point is that asphalt is now a real product module on top of the shared quote core, rather than a hidden proof slice. --- URL: https://docs.cleanestimate.pro/estimating/commercial Title: Commercial Estimate Wizard Description: Use the Commercial Estimate Wizard to create multi-service proposals for commercial properties with custom pricing and site conditions. Category: estimating Difficulty: intermediate Roles: owner, sales_rep Last updated: 2026-04-04 --- # Commercial Estimate Wizard Commercial proposals handle multi-service quotes for office buildings, retail centers, warehouses, and other commercial properties. The Commercial Estimate Wizard has five steps: client, property and services, pricing and site conditions, schedule and terms, and review and send. --- ## Step 1 -- Client Search for an existing client or create a new one. [SCREENSHOT: Step 1 client search field with autocomplete results showing existing clients] ### Client Fields | Field | Description | |---|---| | Client Name | Contact person's full name | | Company | Business or organization name | | Email | Primary email for proposal delivery | | Phone | Primary phone number | | Address | Street address with Google Places autocomplete | | City / State / ZIP | Auto-filled from address selection | | Decision Maker | Dropdown to identify the person who approves the proposal | [SCREENSHOT: New client form with all fields filled in and Decision Maker dropdown expanded] If the client already exists in your system, select them from the search results. Their details auto-populate. The commercial client search now merges: - native CRM clients from the main Clients workspace - commercial proposal contacts already created in the module - optional Workiz matches when that integration is available Results are deduped before they render, so you should see one clean match instead of repeated names while typing. This also lets office staff reuse residential-tagged or mixed-use customers in commercial building proposals without rebuilding the contact by hand. When you pick a native CRM contact or a manually entered client for a new commercial building proposal, CleanEstimate Pro now creates or reuses the proposal-side contact record automatically. That keeps proposal creation working even when the source client came from the separate CRM workspace instead of the commercial module. That proposal-side contact creation now validates the saved contact payload before it writes a new commercial client row. Invalid email formats or malformed contact data fail cleanly as input errors instead of creating a half-broken proposal contact behind the scenes. If you launch the wizard from a client shortcut or a lead shortcut that includes `client_id` or `lead_id`, the commercial proposal wizard now preloads that customer on step 1 instead of opening blank or forcing the office to re-enter the contact information by hand. If you need to swap contacts while editing, the **Change** button on the selected client card now clears the current selection cleanly instead of throwing a client-side error. Existing commercial building proposals that still point at a native CRM client keep their shared tags card working on the detail page, and proposals whose old linked contact no longer exists now show a quiet unavailable state instead of firing a noisy **Client not found** toast. The Property Type, Surface Type, Service Type, and pricing-settings catalogs now load for the same set of commercial proposal editors that can build or edit proposals. That keeps the wizard from showing empty picker states when a custom role can work on proposals but does not have the narrower commercial-view-only catalog access path. The selected **Sales Rep** on both fleet and building proposal wizards now saves with the draft instead of living only in the browser state. If you assign the rep on Step 1, that assignment stays attached when the draft autosaves, reloads, or gets reopened later. The commercial building service and surface catalogs now bridge through the shared quote-core price-book foundation too. The wizard and admin settings screens still expose the same service-type and surface-type records, but those reads now prefer the shared `price_book_items` copy and only fall back to the older legacy tables when the bridge has not been populated yet. New commercial building service-type and surface-type saves now also treat that shared price-book write as part of the admin change itself. If CE Pro cannot update the matching shared `price_book_items` row, the catalog create is rolled back instead of quietly leaving the commercial settings table and the shared quote-core catalog on different versions. Those commercial catalog writes are narrower now too. Fleet vehicle-type saves plus commercial building service-type and surface-type creates update only the touched shared `price_book_items` rows instead of rebuilding the full fleet or building catalog bridge after every admin change, which reduces unnecessary shared-catalog churn while keeping the rollback protection in place. Click **Next** to continue. --- ## Step 2 -- Property & Services Define the property details and add service line items. [SCREENSHOT: Step 2 showing property details form on the left and service line items below] ### Property Details For each property included in the proposal, enter: - **Number of Properties** -- how many buildings or locations this proposal covers. - **Per-Property Address** -- each property gets its own address field. - **Square Footage** -- total building area. - **Building Type** -- office, retail, warehouse, industrial, etc. - **Roof Type** -- flat, metal, membrane, etc. - **Floors** -- number of stories. - **Special Conditions** -- notes about access, hazards, or unique features. [SCREENSHOT: Property details for a multi-property proposal showing two properties with addresses and building types] ### Service Line Items Click **Add Service** to add a service to the proposal. Each service line item includes: | Field | Description | |---|---| | Type | Dropdown: building wash, roof cleaning, gutter cleaning, window cleaning, concrete cleaning, etc. | | Description | Free-text description of the work | | Quantity | Number of units | | Unit | Measurement type (sqft, linear ft, per unit, etc.) | | Base Price per Unit | Your rate for this service | Add as many services as needed. Each line item calculates its subtotal automatically. Custom service rows that only store a total price now also derive a consistent per-unit rate when the quantity is greater than `1`. That keeps the Review & Send summary, linked estimate workspace, and downstream PDF/export math aligned instead of showing a unit price that equals the whole line total. The property-type, surface-type, and service catalogs now recover more gracefully if the workspace catalog API cannot load. Instead of rendering blank dropdowns with no explanation, the wizard now warns the office and falls back to the built-in commercial building defaults so Property Type, Primary Surface, and **Add from Catalog** still stay usable while the saved workspace catalog is being checked. New commercial building drafts now also persist the property rows and service line items on the very first save, not only after a later edit pass. Multi-property proposals should reopen with the same saved property details and itemized scope immediately after the first draft save. Commercial building service rows now support two separate text layers: - the customer-facing **Customer Description** field that appears on the proposal - an internal **Crew Alert** note for access instructions, staging reminders, or other field-only guidance That customer-facing text now has its own visible textarea directly on each service row instead of only showing up as a tiny read-only preview line. When you add a service from the catalog, CE Pro first tries to prefill **Customer Description** from the shared price book. If that shared lookup is temporarily unavailable, the row still gets added using the saved service-type notes and the built-in default commercial catalog descriptions so the office is not blocked. Older saved commercial draft rows that were still blank now also repopulate that description field when the proposal is reopened. Crew Alerts save with the proposal and carry into the linked job workflow, but they do not appear on the customer-facing proposal or PDF. [SCREENSHOT: Service line items table with three services added showing type, description, quantity, unit, and price columns] Click **Next** to continue. --- ## Step 3 -- Pricing & Site Conditions Review the total pricing and document site-specific factors. [SCREENSHOT: Step 3 showing the pricing summary on the left and site conditions form on the right] ### Pricing Breakdown The pricing section shows: - Cost breakdown per property and per service. - A calculated total based on your line items. - **Manual Price Override** -- enter a flat price to override the calculated total. Use this when you need to adjust for competitive bidding or negotiated rates. [SCREENSHOT: Pricing breakdown with per-property and per-service subtotals and the manual price override field] ### Margin Calculator The margin calculator shows your estimated profit margin as a percentage. It compares the quoted price against your configured labor and material costs. [SCREENSHOT: Margin calculator showing margin percentage, total cost, and quoted price side by side] Production defaults for commercial surface materials live in **Admin > Commercial > Settings**. Use the **Manage Surface Materials** link on that page when you need to tune production rates before building new proposals. That same screen now includes editable default terms for both commercial building proposals and fleet wash proposals, so proposal PDFs can inherit workspace terms without pasting the same legal language into every quote. The main **Settings** workspace now includes direct **Commercial** and **Commercial Settings** shortcuts too, which makes the commercial dashboard and proposal-defaults screen easier to find from the UI. ### Site Conditions Document anything that affects the job: - **Challenges / Notes** -- free-text area for access issues, building age, surface damage, tenant coordination, or other concerns. - **Safety Requirements** -- checkboxes for fall protection, confined space, chemical handling, PPE requirements, and other safety protocols. - **Parking / Access** -- dropdown for parking availability and equipment access (loading dock, alley access, street parking only, etc.). [SCREENSHOT: Site conditions section with the notes textarea, safety checkboxes, and parking dropdown] Click **Next** to continue. --- ## Step 4 -- Schedule & Terms Set the project timeline and any add-ons or discounts. [SCREENSHOT: Step 4 showing the scheduling section on top and add-ons/discounts section below] ### Scheduling | Field | Description | |---|---| | Proposed Start Date | Date picker for when work begins | | Duration | Estimated number of days to complete | | Crew Size | Number of crew members assigned | | Preferred Schedule | Weekdays, Weekends, or Flexible | [SCREENSHOT: Scheduling fields with a date picker open for the proposed start date] ### Add-ons & Discounts - **Available Add-ons** -- check the boxes for extra services (post-construction cleanup, sealing, graffiti removal, etc.). - **Discount** -- enter a percentage or dollar amount. - **Discount Reason** -- explain the discount for your records. - **Payment Terms** -- net 15, net 30, net 60, due on completion, or custom terms. [SCREENSHOT: Add-ons checkboxes and discount fields with a percentage discount applied] Click **Next** to continue. --- ## Step 5 -- Review & Send Review the complete proposal before sending. [SCREENSHOT: Step 5 full proposal summary showing client, properties, services, pricing, schedule, and terms] ### Proposal Summary The review screen shows every detail from the previous four steps in a read-only format. Scroll through to verify: - Client and company information - Property addresses and building details - All service line items with pricing - Site conditions and safety notes - Schedule, crew size, and payment terms - Discounts and add-ons - Grand Total ### Auto-Save The Commercial Estimate Wizard auto-saves your progress every 30 seconds while editing. If you close the browser or lose your connection, your work is preserved. ### Actions | Button | What It Does | |---|---| | **Back** | Returns to Step 4 | | **Save Draft** | Saves the draft immediately without waiting for auto-save | | **Download PDF** | Opens a PDF copy of the full proposal | | **Send to Client** | Opens the shared email + text send modal | | **Duplicate** | Creates a copy of the current proposal | [SCREENSHOT: Action buttons at the bottom of the review screen] ### Sending the Proposal Click **Send to Client** to open the shared review-and-send modal. The office now gets one editable email preview and one editable SMS preview in the same send screen instead of a separate email-only dialog. Behind those send and public-sign actions, the commercial proposal lifecycle now runs through the shared quote-core lifecycle writer too. Fleet and commercial building proposal sends, accepted signatures, pipeline transitions, and linked-estimate quote events are being consolidated onto the same lifecycle helpers so the proposal workspace and the shared quote workspace stay in sync during delivery and acceptance. The admin-side **View Public Page** action now uses that same linked customer URL too. Fleet and commercial building previews opened from admin now resolve through the linked estimate's saved customer link instead of a raw `/commercial-proposal/...` path, so the office sees the same online approval experience the customer receives after send. When you confirm the send, CleanEstimate Pro emails the PDF proposal and also sends the paired text message in the same action. If the client is missing a phone number, or SMS delivery is unavailable, the proposal email still goes out and the warning area explains why the text message did not send. Commercial building draft creates and edits now write the shared quote-core `created` and `saved` events on the linked estimate workspace too, so the shared estimate history can see building proposal draft activity before the proposal is ever sent to the client. Commercial building proposal sends now also refresh the linked shared estimate workspace before the send flow returns. That keeps the online proposal link and the shared estimate send history aligned with the latest proposal instead of relying on a delayed background sync after the client email already went out. That ownership line tightened again for office-side edits and sends too. Commercial building draft status bookkeeping, shared quote-link preparation, and linked-estimate refresh now live in the shared quote-core lifecycle services instead of staying split between the admin route handlers and later compatibility sync helpers. Fleet and commercial building sends now also preserve the same shared quote token on later resends instead of silently minting a different customer review link each time. Once the linked estimate has a shared public quote token, CE Pro keeps reusing that link for future sends and resend history. Those linked commercial estimate links now open through the shared `/quote/[token]` page too. The shared quote route now knows how to render fleet and commercial building proposal views from the linked estimate workspace, so customer-facing linked-estimate previews can use the same persisted quote token model as the newer generic and residential quote flows without losing the commercial proposal layout. That shared commercial quote-link handoff now also reuses the existing saved public quote token before it ever falls back to a one-off signed estimate URL. Resends and office previews should keep opening the same shared `/quote/[token]` link when a linked commercial estimate already has a persisted quote token, and CE Pro now refuses to show a mismatched generic/residential quote screen if the source commercial proposal can no longer be reloaded behind that linked estimate. Those shared commercial quote pages now validate approval directly against that saved public quote token too. If the workspace customer-token signing secret is temporarily unavailable, fleet and commercial building customers can still accept from `/quote/[token]`, and office-side **View Public Page** previews no longer drop into the false "online approval unavailable" state just because the page could not mint a second signed estimate token. The first public proposal open now uses the same shared quote-core viewed-event helper too. When a customer opens a sent commercial building proposal for the first time, CE Pro records the source proposal view, advances the commercial pipeline, updates the linked estimate workspace to **Viewed**, and writes the shared quote event from one path instead of leaving the linked-estimate update to a background sync after the page render. [SCREENSHOT: Shared send modal with editable email and SMS copy] After sending, the proposal status changes from **Draft** to **Sent**. The client receives the PDF by email, and when secure customer-link signing is configured the email also includes the online proposal link. The commercial building review step now confirms the destination email after a successful send and keeps any follow-up bookkeeping problems as office-facing warnings instead of reporting the whole send as a failure after the email already went out. If the PDF email is delivered but the proposal history or pipeline update needs manual cleanup, the screen explains that separately. Customer-facing fleet and commercial building proposal totals now only apply tax when the saved proposal actually carries a tax rate. If a proposal intentionally leaves tax blank, the online customer page no longer assumes a default 6% tax and inflate the displayed total on its own. Fleet and commercial building proposal signatures now also run through the same shared acceptance helper behind the scenes, so signature uploads, accepted alerts, pipeline movement, linked-estimate sync, and accepted-estimate automation follow the same reliability rules across both commercial proposal types. Commercial proposal signature capture now also self-recovers if the proposal-signature storage bucket is missing on a newly bootstrapped or partially migrated workspace. If that storage bucket has not been provisioned yet, CE Pro recreates it before retrying the signature upload instead of failing the customer's acceptance. The office-side commercial pipeline now uses that same quote-core accepted follow-up path too. When staff manually move a building proposal to a won stage, the linked estimate workspace and accepted follow-up automation are updated through the same shared lifecycle instead of a separate internal-only branch. If the legacy Workiz integration is unavailable, the commercial builder now falls back cleanly to native CRM client search instead of blocking the proposal flow with a server error. Office staff can still save drafts, export PDFs, and send proposals as long as they have commercial or estimate access. If the proposal-level custom terms box is blank, the commercial building PDF now pulls the workspace default building terms from **Admin > Commercial > Settings** instead of reverting to a hidden hardcoded fallback. Commercial building draft saves now also finish their linked estimate sync before the API returns. If the shared estimate workspace cannot be updated, the proposal save rolls back instead of leaving the source proposal and linked estimate on different versions of the scope. That linked-estimate write now lives in the commercial building draft-save service itself instead of a later projection helper. The saved proposal and the shared estimate workspace now succeed or fail together more consistently during draft create/edit work. ### Working the Proposal After It Is Sent Commercial building proposal detail pages now expose the same shared estimate workflow used by residential: - **Open Estimate Workspace** opens the unified estimate record linked to the proposal. - **Convert to Job** creates the production job directly from the proposal detail page. - **View Job** replaces the convert action once the work is booked. - **Create Recurring Template** is available after acceptance for maintenance-style work. That recurring-template shortcut now prefers the canonical shared quote-core line items from the linked estimate workspace when they exist, and the created template keeps a source-estimate link so later recurring-template automation and reporting can follow it back to the accepted commercial quote. Behind that linked workspace, commercial building proposals now also feed canonical shared quote-core line items instead of only the legacy compatibility snapshot. Those canonical rows now preserve the real shared `price_book_item_id` for bridged service types too, so the linked estimate can reuse the same catalog identity the settings screens and future quote-core pricing flows expect. The building proposal routes still own the source proposal tables for now, but the shared estimate record now carries a structured per-property service breakdown aligned to the same quote-core direction used by generic, residential, and fleet work. Commercial proposal detail pages also include a shared **Tags** card for the linked contact record. Those tags now flow into the unified Estimates list filters, which means commercial building and fleet proposals can be filtered with the same tag-based workflow used elsewhere in the CRM. Commercial proposal detail and review screens now normalize missing legacy totals and null numeric fields before they render. That keeps older proposals with incomplete saved totals from crashing the workspace while still showing the correct derived annual value. Linked commercial estimates also fall back to saved line items if the older record does not have residential-style `services_selected` data. If square footage or story counts were never stored on the linked estimate, the workspace now opens safely and shows the rest of the estimate instead of throwing a client-side error. --- ## Tips - Add all properties in Step 2 before adding service line items. This keeps your proposal organized. - Use the margin calculator in Step 3 to verify profitability before sending. - Document site conditions thoroughly. This protects you during the job and sets clear expectations with the client. - Auto-save runs every 30 seconds, but click **Save as Draft** before stepping away from a long proposal. --- URL: https://docs.cleanestimate.pro/estimating/fleet Title: Fleet Wash Estimate Wizard Description: Use the Fleet Wash Estimate Wizard to build proposals for fleet vehicle washing with per-vehicle pricing and multi-option quotes. Category: estimating Difficulty: intermediate Roles: owner, sales_rep Last updated: 2026-04-04 --- # Fleet Wash Estimate Wizard Fleet proposals are built for companies that need vehicle washing services -- delivery fleets, service vans, truck yards, and rental lots. The Fleet Wash Estimate Wizard has five steps: client, fleet inventory, schedule and site, pricing and options, and review and send. --- ## Step 1 -- Client Enter the client's contact information. [SCREENSHOT: Step 1 client form with name, company, email, phone, and address fields] ### Client Fields | Field | Description | | ----------------- | ----------------------------------------------------------------------- | | Client Name | Contact person's full name | | Company | Fleet operator or business name | | Email | Primary email for the proposal | | Phone | Primary phone number | | Address | Company or fleet yard address | | Contact Selection | Choose the primary contact if the company has multiple contacts on file | [SCREENSHOT: Contact selection dropdown showing multiple contacts for the same company] Search for an existing client or enter new details. Click **Next** to continue. If you open the fleet wizard from a client shortcut or a lead shortcut that includes `client_id` or `lead_id`, the selected CRM customer now preloads into step 1 automatically instead of forcing a re-search or leaving the proposal blank. Native CRM customers from that lead flow now save correctly on the first fleet draft too, so the office does not need to swap them to a custom manual client just to continue. When the same office has older saved proposal contacts on file, the wizard now reuses the right saved contact safely instead of rewriting a different contact record that happens to share the same company email or phone. If the fleet proposal starts from a lead record, the wizard now also preloads that lead's source into the **Lead Source** picker and carries it through the first draft save automatically. Offices no longer need to reselect the lead source by hand just to keep reporting, commission tracking, and the proposal detail workspace aligned with the original lead. --- ## Step 2 -- Fleet Inventory Define the vehicles that need service. [SCREENSHOT: Step 2 showing the fleet size input and vehicle types table] ### Fleet Size Enter the total number of vehicles in the **Fleet Size** field. This sets the baseline for pricing calculations. ### Vehicle Types Table Build the fleet breakdown in the vehicle types table. Each row represents one category of vehicle. The wizard now pulls the same active fleet vehicle types configured in admin settings, so standard and specialty vehicle cards show up again when your org catalog is set up. | Column | Description | | ------------------- | ----------------------------------------------------------------- | | Vehicle Type | Pickup, van, box truck, semi, flatbed, bus, etc. | | Count | Number of vehicles of this type | | Year / Make / Model | Optional detail for the proposal | | Size Category | Small, medium, large, extra-large -- determines base pricing tier | [SCREENSHOT: Vehicle types table with three rows: 10 pickups, 5 box trucks, and 2 semis] Click **Add Row** to add another vehicle type. Click the delete icon on any row to remove it. The total vehicle count across all rows should match the fleet size. The shipped default fleet vehicle types now also carry ready-to-use scope descriptions behind the scenes in the shared price-book bridge. Stock rows like semis, box trucks, vans, buses, and specialty equipment no longer normalize into blank shared line-item notes when those defaults are reused downstream in the linked estimate workspace. Each selected fleet row now includes a **Customer Description** field in the builder. New rows seed that text from the saved fleet vehicle-type notes when default scope copy exists, and reps can edit the description before the proposal is reviewed or sent. Click **Next** to continue. --- ## Step 3 -- Schedule & Site Set the project timeline and location details. [SCREENSHOT: Step 3 showing schedule fields and site access notes] ### Scheduling | Field | Description | | ------------------- | ---------------------------------------------------------------------- | | Proposed Start Date | Date picker for the first wash | | Duration | Estimated time to complete the job | | Location Address | Where the washing takes place (fleet yard, client site, your facility) | | Frequency | One-time or recurring (weekly, bi-weekly, monthly) | [SCREENSHOT: Frequency selector showing one-time and recurring options with interval settings] Seasonal fleet schedules now stay intact after the first draft save. If you split a proposal into one cadence for part of the year and another cadence for the rest, the review screen, public proposal page, and exported PDF all keep the same saved month ranges and visit counts instead of falling back to generic full-year biweekly math. The exported fleet PDF now separates the standard schedule and alternate schedule on the pricing page when a proposal is seasonal. The Scheduling & Service Plan page also lists each month in the split service calendar, so customers can see exactly which months run monthly versus biweekly. ### Site Access Notes Enter any details about getting to the vehicles. Examples: gate codes, hours of access, staging area, water hookup location, or contact person on site. [SCREENSHOT: Site access notes textarea with example text about gate access and water hookup] Click **Next** to continue. --- ## Step 4 -- Pricing & Options Configure pricing, add-ons, discounts, and multi-option quotes. [SCREENSHOT: Step 4 showing base pricing, add-ons, and the multi-option builder] ### Base Pricing - **Base Price per Unit** -- your rate per vehicle or per vehicle type. - **Total Fleet Price** -- calculated automatically from the vehicle types table and base prices. [SCREENSHOT: Base pricing fields showing per-unit rate and calculated fleet total] ### Add-ons Check the boxes for extra services to include in the proposal: - **Detailed Interior Cleaning** -- full interior wipe-down and vacuuming. - **Tire Treatment** -- tire shine and wheel cleaning. - **Window Service** -- interior and exterior glass cleaning. Each add-on increases the per-vehicle or per-wash total. Selected add-ons now also include a **Customer Description** editor. Default fleet add-ons start with their built-in scope copy, and any edits you make there now stay visible in Review & Send, the customer proposal page, and the exported PDF. Optional fleet add-ons that are not marked included and still price at `$0.00` no longer show up as fake line items in the shared quote-core estimate breakdown. If an add-on is only meant to appear when it is actually billed, it now stays hidden until it carries a real price or is explicitly flagged as included. [SCREENSHOT: Add-ons section with three checkboxes, two of them checked] ### Discount Apply a discount as a percentage or a flat dollar amount. Enter the value and select the type. [SCREENSHOT: Discount field with percentage/dollar toggle] ### Multi-Option Builder Create multiple service tiers so the client can choose their preferred level. Click **Add Option** to create a new tier. Each option has its own name, description, included services, and total price. Common setups: - **Basic** -- exterior wash only. - **Standard** -- exterior wash plus windows and tires. - **Premium** -- full detail including interior. The client sees all options side by side when they view the proposal. [SCREENSHOT: Multi-option builder with three tiers showing different service levels and prices] ### Vehicle-by-Vehicle Pricing Preview Below the options, a preview table shows the price breakdown per vehicle type. This includes the base price, add-ons, discount, and tax for each category. [SCREENSHOT: Vehicle-by-vehicle pricing table with columns for vehicle type, count, unit price, add-ons, and line total] Click **Next** to continue. --- ## Step 5 -- Review & Send Review the full proposal and send it to the client. [SCREENSHOT: Step 5 full proposal summary showing client, fleet inventory, schedule, pricing options, and totals] ### Proposal Summary The review screen shows: - Client and company details - Fleet inventory breakdown - Vehicle and add-on customer descriptions exactly as the client will read them - Schedule and site information - Pricing options (if multi-option) or single price - Add-ons, discounts, and tax - Grand Total The fleet review margin summary now uses the quote's saved fleet pricing, wash-time assumptions, visit schedule, and fleet cost settings. That means the Pricing & Options step, the Review & Send margin summary, and the AI review all read from the same quote-level net-margin math instead of showing different results from a hardcoded preview calculator or only one season's pricing. ### Actions | Button | What It Does | | ----------------- | ------------------------------- | | **Back** | Returns to Step 4 | | **Save as Draft** | Saves without sending | | **Export PDF** | Downloads the proposal as a PDF | | **Send Proposal** | Opens the send modal | [SCREENSHOT: Action buttons at the bottom of the review screen] ### Sending the Proposal Click **Send to Client** to open the shared review-and-send modal. That screen now shows the same two-part delivery review used elsewhere in the product: one editable email preview and one editable SMS preview side by side before anything goes out. When you confirm the send, CleanEstimate Pro emails the PDF proposal and also texts the client in the same send action. If the client does not have a phone number on file, or if SMS delivery is unavailable, the proposal email still sends and the office sees a warning explaining why the text message was skipped. Fleet proposal sends now also refresh the linked shared estimate workspace before the send flow finishes. That keeps the online proposal link and the shared estimate send history aligned with the latest fleet proposal details instead of treating the linked estimate sync as a background afterthought. Behind the office-side draft edit and send routes, more of that fleet proposal lifecycle now runs through the shared quote-core services directly too. Status-field bookkeeping, linked-estimate send-link preparation, and linked estimate refresh now live in the shared fleet/commercial quote services instead of staying split across the route handlers. The first public fleet proposal open now follows the same shared quote-core viewed-event path too. When the customer opens a sent fleet proposal for the first time, CE Pro records the source proposal view, advances the commercial pipeline, updates the linked estimate workspace to **Viewed**, and writes the shared quote event from one helper instead of firing a best-effort linked-estimate sync after the page already rendered. [SCREENSHOT: Proposal status badge showing "Sent" after delivery] When the customer signs the public fleet proposal, CE Pro now validates and stores the drawn signature image before the proposal flips to accepted. The assigned rep, plus owners and managers, also get an immediate admin-bell alert that the fleet proposal was signed, and the bell itself refreshes live instead of waiting for the older 30-second poll cycle. If later follow-up steps like activity logging, pipeline history, or linked-estimate automation hit a temporary issue after the customer signs, the signature still sticks and the proposal stays accepted instead of bouncing back with a false failed-sign result. Fleet and commercial building proposal signatures now run through the same shared acceptance flow behind the scenes, so signature uploads, accepted-alert writes, pipeline movement, linked-estimate sync, and accepted-estimate follow-up automation stay aligned across both commercial proposal types. That same quote-core follow-up path now also runs when the office manually moves a fleet proposal to a won stage in the commercial pipeline. CE Pro no longer treats those office-side accepted moves as a separate bookkeeping branch, so the linked estimate workspace, accepted automations, and downstream follow-up stay aligned whether acceptance came from the customer signature flow or an internal pipeline action. Fleet proposal review now auto-prepares the draft only when the form data is valid, and the review actions stay available even if the legacy Workiz lookup is offline. Native CRM results still appear first, and duplicate client matches are filtered before they render. If you choose a native CRM contact or enter a fleet client manually, the proposal flow now creates the proposal-side contact record behind the scenes instead of passing a synthetic client id into the save API. That keeps new fleet proposals from failing on contact selection edge cases. Seasonal annual totals in review now use the saved cadence for each season, so splits like monthly April-October plus biweekly November-March keep the expected 7 and 10 visit counts all the way through the client view and PDF export. Fleet draft saves now finish their linked estimate sync before the save request returns. If the shared estimate workspace cannot be updated, the proposal draft save fails and rolls back cleanly instead of leaving the proposal and linked estimate out of step. Those fleet draft create/edit saves now also write the shared quote-core `created` and `saved` events on the linked estimate workspace as soon as the sync succeeds, so downstream reporting and timeline surfaces can treat fleet drafts like the other migrated quote wizards instead of leaving that activity invisible until send time. That linked-estimate write now happens inside the fleet draft-save service itself instead of a later projection-style follow-up helper. In practice that means the saved fleet proposal and the shared estimate workspace now commit or fail together more consistently during draft create/edit work. If the proposal-level terms box is blank, the fleet PDF now falls back to the workspace default fleet wash terms from **Admin > Commercial > Settings** instead of using a hidden hardcoded paragraph set. The main **Settings** workspace now includes direct shortcuts to both **Commercial** and **Commercial Settings**, so the commercial dashboard and proposal-defaults screen are easier to reach from the UI. Fleet vehicle-type settings now bridge through the shared quote-core price-book layer too. The Fleet Settings screens and fleet wizard picker still show the same vehicle-type rows, but those reads now come from the shared `price_book_items` bridge when it is available, with the legacy fleet table only acting as the fallback source during the migration window. Those fleet vehicle-type admin saves now also treat the shared price-book update as part of the save itself. If CE Pro cannot write the matching shared catalog row, the vehicle-type create, update, or delete rolls back instead of leaving the legacy fleet table and the shared quote-core catalog out of sync. The dedicated **Admin > Fleet > Settings** screen still handles vehicle types, cost assumptions, and discount references for fleet teams, and it now includes a direct **Edit Proposal Terms** shortcut into the shared commercial-settings defaults editor. ### Working the Proposal After It Is Sent Once a fleet proposal is open in the detail view, the action bar now matches the unified estimate workspace flow more closely: - **Open Estimate Workspace** jumps into the shared estimate record tied to the fleet proposal. - **Convert to Job** books the proposal directly into the jobs calendar without leaving the proposal page. - **View Job** replaces the convert button after the first job is created. - **Create Recurring Template** appears for accepted fleet work that should repeat on a route. That recurring-template shortcut now prefers the canonical shared quote-core line items from the linked estimate workspace when they are available, and the created template keeps a source-estimate link so recurring automation can trace it back to the accepted fleet quote later. Behind that workspace jump, fleet linked estimates now carry canonical shared quote-core line items too instead of only the older JSON line-item snapshot. Those canonical rows also keep the real shared `price_book_item_id` link for bridged fleet vehicle types, so downstream pricing, analytics, and future wizard reuse can follow the same catalog item instead of relying only on copied vehicle metadata. The fleet proposal routes still own the main proposal tables for now, but the shared estimate record now keeps a structured fleet service/add-on breakdown that matches the quote-core direction used by generic and residential work. Fleet detail pages also include a shared **Tags** card for the linked commercial contact. Those tags now feed the unified Estimates list filters, so fleet and commercial proposal records can be segmented with the same tag workflow the residential CRM already uses. Older proposal-side contacts now load in that card reliably too, even on workspaces where the `proposal_clients` table never had an `updated_at` column. --- ## Tips - Break the fleet into vehicle types even if prices are the same. This gives the client a clear picture of what they are paying for. - Use the multi-option builder to upsell. Most clients choose the middle tier when presented with three options. - For recurring contracts, set the frequency in Step 3. The proposal shows the per-wash and annual totals. - Double-check the vehicle count. The total across all rows in the vehicle types table should match the fleet size number. - If a fleet vehicle-type save fails in the admin setup flow, the workspace now shows a plain-language error instead of a raw system message, which makes permission or setup problems easier to correct. - If another admin deletes a saved vehicle type while you still have it open, updates now return a clean not-found message instead of a generic server failure, so refreshing the fleet setup view gets you back in sync faster. --- URL: https://docs.cleanestimate.pro/estimating/generic-quotes Title: Generic Quote Builder Description: Create custom quotes with manual line items for ad-hoc projects. Category: estimating Difficulty: beginner Roles: owner, sales_rep Last updated: 2026-04-04 --- # Generic Quote Builder The Generic Quote Builder lets you create custom quotes for projects that do not fit your standard service-based pricing. Open the **Manage** section in the admin sidebar, click **Estimates**, then choose **New Quote**. [SCREENSHOT: Generic Quote Builder page showing the line items table and totals panel] ## When to Use Generic Quotes Use this builder when: - The job is a one-off project outside your normal service menu. - You need to quote specialty work like custom restoration, construction cleanup, or equipment rental. - A customer requests a service you have not added to your pricing configuration yet. - You want full manual control over every line item and price. For standard residential or commercial cleaning, use the dedicated estimate wizards instead. They pull pricing from your configured defaults and save time. --- ## Adding Line Items Click **+ Add Line Item** to add a new row to the quote. Each row has four fields: | Field | Description | | --------------- | -------------------------------------------- | | **Description** | Free-text description of the service or item | | **Quantity** | Number of units | | **Unit** | Measurement type for this item | | **Unit Price** | Price per unit in dollars | [SCREENSHOT: A line item row with description, quantity, unit dropdown, and unit price fields] ### Unit Types The unit dropdown offers five options: | Unit | When to Use | | ------------- | ------------------------------------------------------------ | | **Flat** | Fixed-price items with no quantity multiplier | | **Each** | Per-item pricing (e.g., per window, per fixture) | | **Sq Ft** | Area-based pricing (e.g., floor cleaning, surface treatment) | | **Linear Ft** | Length-based pricing (e.g., gutter work, fencing) | | **Hour** | Time-based pricing (e.g., labor charges, consultation) | ### Managing Rows - Click **+ Add Line Item** to add more rows. There is no limit. - Click the delete button on any row to remove it. - The line total for each row updates automatically as you change quantity or unit price. Each row's details area also includes an internal **Crew Alert** field. Use that space for access codes, setup reminders, parking instructions, or other job-execution notes that should stay with the quote internally. Crew Alerts now save with the draft when you reopen the quote later, carry into jobs created from that quote, and show up in both the web job detail view and the mobile crew job screen without appearing on the customer-facing quote page or PDF. That same details area also includes the customer-facing description text for the line item. Anything entered there now shows under the line title on the shared quote page and in the generic quote PDF, so the office can keep extra scope detail visible to the customer without mixing it into the main line-item title. [SCREENSHOT: Multiple line item rows with different unit types and a delete button on each row] --- ## Totals Panel The totals panel on the right side updates in real time as you add or edit line items. [SCREENSHOT: Totals panel showing subtotal, discount, taxable amount, tax, and total] The panel displays: - **Subtotal** -- the sum of all line item totals (quantity x unit price). - **Discount** -- an optional flat-dollar or percentage reduction. - **Taxable Amount** -- the amount remaining after the discount is applied. - **Tax** -- calculated from your organization's configured tax rate. - **Total** -- subtotal plus tax. --- ## Property Visuals And Photos As soon as you enter the service address, the Generic Quote Builder now shows the same shared property-visual workspace used in the other quote builders. [SCREENSHOT: Generic Quote Builder showing the property visual panel below the quote form] The panel gives the office quick context without leaving the quote: - **Street View** for the curbside and front-of-property view - **Satellite** imagery for rooflines, lot shape, and surrounding access - **CompanyCam** links for jobsite photo references - **Site Photos** for estimate-linked photo uploads that stay attached to the quote after you reopen it later On a brand-new standalone quote, the panel will ask you to **Save Draft To Enable Photos** the first time you open the Site Photos tab. After that draft record exists, photo uploads use the same saved estimate-photo gallery shown elsewhere in CE Pro. This is especially useful for standalone quotes where you still need location context but do not want to run the full residential or commercial wizard. --- ## Saving and Sending Three actions are available at the bottom of the page: | Button | What It Does | | ------------------ | ---------------------------------------------------------------------------------------------------------------- | | **Save as Draft** | Saves the quote without sending it, then returns you to the estimates list. | | **Preview Quote** | Saves the latest draft state if needed, then opens the customer-facing quote in a new tab. | | **Send to Client** | Saves the quote first, then opens the shared send modal where you can review email and SMS copy before delivery. | [SCREENSHOT: Save as Draft, Preview Quote, and Send to Client buttons at the bottom of the builder] When you click **Send to Client**, the same shared review-and-send modal used by the other estimate and proposal wizards appears. Review the pre-filled email and SMS copy, edit it if needed, and click **Confirm & Send**. The customer receives the quote email and, when a phone number is available, the matching text message in the same send action. They can open the quote online, accept it with an e-signature, or decline it. Generic quotes now preview, send, and reopen through the same shared quote-core customer page. That means the draft save response, customer link, preview tab, resend flow, and acceptance path all point to the same quote record instead of hopping between separate generic-only view logic. The customer-facing page also uses the workspace's organization name in the header instead of a hardcoded platform brand. If secure customer-link signing is temporarily unavailable, generic quotes that already have a persisted shared `/quote/[token]` link can still stay interactive. The shared quote page now validates approval, PDFs, payment actions, and other customer interactions against that saved public quote token directly, so customers and office previews can keep working from the shared quote URL instead of dropping into a false read-only state. Older signed estimate-only links still depend on the customer-token signing secret. If CE Pro cannot generate any usable customer quote link at all, the send flow now stops before delivery instead of emailing or texting a broken quote URL. Generic quote acceptance now also runs through the shared quote-core acceptance helper. Customer signatures and manual accepted-status changes still behave the same in the UI, but the accepted event log, webhook dispatch, pipeline transition, gamification credit, and accepted-estimate automation all now come from one shared path instead of a separate generic-only side-effect branch. Saved drafts now reopen in the **same Generic Quote Builder** instead of dropping you into the residential estimate wizard. Your manual line items, discount, tax settings, and assigned rep are restored when you come back to edit the quote later. Quote descriptions, internal notes, and estimated hours now round-trip with the saved draft too, so reopening the quote restores the same review context the office had when it was first created. Quote creation, quote saves, and quote edits now all use the same resilient response path, so a successful draft save no longer shows a false server-error toast after the quote is already stored. --- ## Tips - **Add a detailed description** to each line item. Customers trust itemized quotes more than lump-sum pricing. - **Use the correct unit type.** Choosing "Sq Ft" or "Linear Ft" shows the customer exactly what they are paying for and how quantities were measured. - **Save as Draft first** if you need to verify pricing with a manager before sending. - **Check your tax rate** in Settings before sending. The totals panel uses your organization's default tax rate. --- ## Troubleshooting ### Line item total shows zero Make sure both the quantity and unit price fields have values greater than zero. A missing quantity defaults to zero, which zeroes out the line total. ### Tax is not calculating Verify that your organization has a tax rate configured. Go to **Settings > Pricing** and check the tax rate field. If it is set to zero, no tax will be added. --- URL: https://docs.cleanestimate.pro/estimating/holiday-lights Title: Holiday Lights Estimate Wizard Description: Use the Holiday Lights Estimate Wizard to design holiday lighting proposals with visual design tools, zone mapping, and contract pricing. Category: estimating Difficulty: intermediate Roles: owner, sales_rep Last updated: 2026-03-29 --- # Holiday Lights Estimate Wizard The Holiday Lights Estimate Wizard combines visual design tools with automated pricing. You trace gutter lines on satellite or street view imagery, assign lighting zones, and generate a proposal with installation, materials, and removal costs. --- ## Step 1 -- Customer & Property Enter the customer and property information. [SCREENSHOT: Step 1 showing customer type selector and client details form] ### Customer Type Select **Residential** or **Commercial** at the top of the form. This determines the pricing tier and proposal template. [SCREENSHOT: Residential/Commercial toggle at the top of the form] ### Client Details Search for an existing client or enter new information. | Field | Description | |---|---| | Customer Name | Full name of the homeowner or business contact | | Email | For proposal delivery | | Phone | For SMS delivery | | Address | Google Places autocomplete | | City / State / ZIP | Auto-filled from address selection | [SCREENSHOT: Client details form with address autocomplete dropdown visible] Click **Next** to continue. --- ## Step 2 -- Design & Quote This step has three tabs: Design Canvas, Bundle, and Quote Preview. [SCREENSHOT: Step 2 tab bar showing Design Canvas, Bundle, and Quote Preview tabs] --- ### Tab 1 -- Design Canvas The design canvas is where you trace light lines and define zones on the property. [SCREENSHOT: Full design canvas view with satellite imagery, drawing tools on the left, and design summary on the right] #### Canvas Views The left panel has three canvas tabs: | Tab | What It Shows | |---|---| | **Satellite** | Aerial view of the property from above | | **Street View** | Ground-level view of the front of the property | | **Property Photo** | Upload a customer photo of the home | Switch between tabs to trace lines from different angles. [SCREENSHOT: Canvas tab switcher showing Satellite, Street View, and Property Photo tabs] #### Drawing Tools Use the drawing tools to trace gutter lines, mark zones, and place light positions on the canvas. - **Gutter Line Tool** -- click to place points along the roofline. The system measures the total linear footage. - **Zone Tool** -- draw enclosed areas for accent lighting, bushes, or ground features. - **Light Placement** -- mark individual fixture locations for spotlights or ground stakes. [SCREENSHOT: Gutter line being traced along a roofline on the satellite view with measurement labels] #### Color Picker Select the light color for each line or zone. Options include: - Warm white - Cool white - Multi-color - Red - Green - Blue - Custom (enter hex code) [SCREENSHOT: Color picker expanded showing warm white, cool white, multi-color, and individual color options] #### AI Measurement Click **Measure with AI** to let the system estimate linear footage from a property photo. Upload a clear photo of the home, and the AI traces the gutter lines and returns measurements. [SCREENSHOT: Measure with AI button and the resulting auto-traced gutter lines on a property photo] AI measurement works best with: - Clear, well-lit photos - Unobstructed views of the roofline - Standard residential architecture The AI measurement tool is an authenticated office-side action. The signed-in team member needs Holiday Lights manage, Estimates create, or AI access before CE Pro will call the measurement service. Street View image loading now also runs through authenticated internal map routes. That means the signed-in teammate needs estimate-view access, and CE Pro prefers `GOOGLE_MAPS_SERVER_API_KEY` for those requests. If the dedicated server key is missing, the office environment falls back to `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY`. If that public Maps key is browser-only, referrer-restricted, or missing Street View access, the design canvas keeps the plain-language unavailable message instead of falling through to a misleading address or image-load error. For complex rooflines, trace manually for better accuracy. #### Design Summary Panel The right panel updates in real time as you draw. It shows: | Metric | Description | |---|---| | Linear Feet | Total length of all traced lines | | Zones | Number of defined lighting zones | | Color Breakdown | Footage per color selection | | Mini Light Strands | Number of strands needed (calculated from linear feet) | | Roof Pitch | Flat, Standard, or Steep -- affects installation pricing | | Unit Price per Foot | Your configured rate | | Subtotal | Linear feet multiplied by unit price | [SCREENSHOT: Design summary panel showing linear feet, zones, color breakdown, strands, roof pitch, and subtotal] --- ### Tab 2 -- Bundle Link the holiday lights estimate to an existing power wash estimate for combined pricing. [SCREENSHOT: Bundle tab showing the option to link a power wash estimate and the calculated bundle savings] #### How Bundling Works 1. Select an existing power wash estimate for the same customer. The system searches by customer name and address. 2. The combined price appears with the bundle discount applied. 3. Enter the **Bundle Discount** amount (percentage or dollar value). Bundling a power wash with holiday lights increases the average ticket value and gives the customer a reason to book both services at once. [SCREENSHOT: Bundle discount field with percentage applied and the updated combined total] --- ### Tab 3 -- Quote Preview The quote preview shows exactly what the customer will see. [SCREENSHOT: Quote preview tab showing the full estimate with customer info, design details, and pricing] #### Customer Info Name, email, phone, and property address. #### Design Details - Linear feet - Number of zones - Colors used - Roof pitch #### Pricing Breakdown | Line Item | Description | |---|---| | Installation | Per-foot rate multiplied by total linear feet | | Mini Lights | Cost of light strands | | Removal | Included if a 3-year contract is selected | | Subtotal | Before discount and tax | | Bundle Discount | Applied if a power wash is linked | | Tax | Based on your configured tax rate | | **Total** | Final price | [SCREENSHOT: Pricing breakdown table showing installation, lights, removal, subtotal, bundle discount, tax, and total] #### Contract Term Select between two options: - **1-Year Contract** -- single-season installation and removal. - **3-Year Contract** -- locked pricing for three seasons. Removal costs are included in the annual price. If your office uses the AI estimate-review tools on a holiday lights quote, the nearby-comparison benchmark now follows the first-year annual contract price when it exists. That keeps the review aligned with what the customer would actually pay for the selected contract instead of comparing an annual contract against install-only historical subtotals. [SCREENSHOT: Contract term radio buttons showing 1-Year and 3-Year options with price comparison] #### Proposal Media Attach visual materials to the proposal: - **Photos** -- property photos used during the design. - **Mockups** -- renderings of the home with lights applied. - **Installation Blueprints** -- annotated diagrams for the install crew. The customer sees these attachments when they open the proposal link. When the wizard creates the paired holiday-lights sidecar for a bundled residential estimate, CE Pro now keeps the follow-up client-link update scoped to the same workspace that created the quote. That prevents cross-workspace retry or rollback paths from touching the wrong holiday-lights record. ### AI Mockup Guardrails Mockup generation is an authenticated office-side action. The signed-in teammate must have **Holiday Lights manage** permission before CE Pro will call the AI image editor. CE Pro also applies two protections before sending a mockup request: - Uploaded source images must be `5 MB` or smaller. - Each teammate is rate-limited to a small burst of mockup generations per minute. These guardrails help prevent accidental spend spikes and keep the tool available for active estimators. [SCREENSHOT: Proposal media section showing attached photos, a mockup rendering, and an installation blueprint] --- ## Saving and Sending The same action buttons appear at the bottom of the screen regardless of which tab is active. | Button | What It Does | |---|---| | **Save Draft** | Saves the estimate without sending | | **Preview PDF** | Opens a PDF preview of the full proposal | | **Send Estimate** | Opens the send modal | [SCREENSHOT: Action buttons at the bottom -- Save Draft, Preview PDF, Send Estimate] ### Send Modal Click **Send Estimate** to open the same shared review-and-send modal used by the other estimate and proposal wizards. The subject line, email body, and SMS body are pre-filled. Edit them if needed. For SMS, the character counter shows your message length against the 160-character limit. [SCREENSHOT: Shared send modal with editable email and SMS copy] Click **Confirm & Send**. CE Pro now confirms the holiday-lights email and text send before it reports success back to the office, and the admin quote header uses that same shared modal instead of bypassing the review step with a direct-send button. - If the send succeeds, the estimate moves to **Sent** and the office gets a success confirmation with the destination email address. - If the email send fails, the wizard keeps the estimate retriable instead of silently claiming success. - After the first successful send, the same header action becomes **Resend Proposal** so the office can send the holiday-lights email again without rebuilding the quote. The matching **View Public Page** action now follows that same live customer-link path too. If the linked estimate already has a shared quote token, the office preview opens the shared `/quote/[token]` page; otherwise CE Pro falls back to the seasonal portal URL instead of a tokenless estimate link that would open in read-only mode. - If the client has no phone number on file, or if SMS delivery is unavailable, the email still sends and the office sees a warning explaining why the text message did not go out. Holiday-lights sends now stay on the seasonal delivery path inside the shared send module. That keeps the outgoing email and SMS pointed at the holiday-lights workflow instead of falling back to the standard residential estimate sender, while the linked shared estimate workspace records the send history and sent quote event from the same send completion path. When a linked holiday-lights estimate already has a persisted shared public quote token, the delivered email and SMS now prefer that shared `/quote/[token]` link first and only fall back to the older holiday-lights portal URL if the shared quote link is unavailable. That keeps seasonal sends aligned to the same durable quote-core public link model the other migrated estimate types already use. When a customer opens that holiday-lights portal from the delivered quote link, CE Pro now runs the same shared quote-core viewed-event bookkeeping there too. The latest open holiday-lights quote for that customer records the public portal view back into the linked estimate workspace instead of leaving the seasonal portal outside the shared send/view history. That same seasonal view bridge now also runs when a customer opens the shared `/quote/[token]` page for a holiday-lights quote. Shared public quote links still render from the linked estimate workspace, but the underlying holiday-lights source quote now records its own viewed timestamp and seasonal pipeline move from that same open instead of only the linked estimate seeing the activity. The first holiday-lights customer open now also advances the source seasonal quote from **Sent** to **Viewed** instead of only stamping `viewed_at`. That keeps viewed-status filters, dashboard counts, and seasonal reporting aligned with the first actual customer open. Once a seasonal quote has been viewed, the office can still resend it normally. CE Pro now treats **Viewed** holiday-lights quotes as resendable proposal records instead of blocking delivery after the first customer open. Shared `/quote/[token]` opens now record as shared quote opens in the holiday-lights sales history instead of being mislabeled as portal-only opens, which keeps the seasonal activity trail aligned with the public path the customer actually used. Holiday-lights draft saves and status changes now run through the same shared quote-core service layer too. Saving or editing a seasonal quote now keeps the linked shared estimate, attached design snapshot, and bundled power-wash link aligned from one save path, and manual **Declined** or **Expired** updates now write the matching shared quote event onto the linked estimate instead of stopping at the seasonal source record. Older workspaces that still had the earlier holiday-lights estimate-list projection function now stay compatible too. Seasonal quote saves now keep the shared estimate-list projection writing `delivery_state` as JSON, so holiday-lights draft creates no longer fail on production databases that were partially through the quote-core rollout. When you reopen an existing holiday lights estimate from admin, the header now includes the office-side actions you expect: - **View Public Page** - **Download PDF** - **Send Proposal** or **Resend Proposal** after the first successful delivery - **Open Estimate Workspace** - **Convert to Job** after the linked estimate exists Behind that linked estimate workspace, holiday lights quotes now also feed canonical shared quote-core line items instead of only the older compatibility `line_items` JSON. The holiday-lights save routes still own the source `holiday_lights_estimates` table for now, but the linked estimate record now carries structured holiday-lights line items and quote snapshots aligned to the same quote-core direction used by generic, residential, fleet, and commercial work. That linked estimate workspace now also carries the source holiday-lights estimate id directly, which lets shared quote-core public links rebuild the seasonal summary from the linked estimate record instead of losing the holiday-lights context when staff or customers open the shared quote page outside the dedicated portal send flow. Holiday-lights quote-core syncing now follows the saved contract term too. When a quote has zone-based annual pricing, the linked estimate workspace uses the selected **1-Year** or **3-Year** annual contract total instead of falling back to the older midpoint install range, and reopening the office editor keeps the saved term, premium, and proposal media selections in place instead of snapping back to the default 1-year view. Editing an existing holiday-lights quote now also keeps the saved **Price Guarantee Years** value aligned with the latest seasonal pricing config. Traced quotes that start from zone-derived linear footage no longer fail validation just because the office left the manual linear-feet field at `0` while the traced roofline still measures correctly. That same saved contract-term total now carries through the rest of the workflow too. Holiday-lights send copy, AI review comparisons, client-detail estimate totals, and admin revenue / lead-source reporting now read the saved selected annual contract price before they fall back to the older low/high range fields, which keeps the office-facing numbers aligned with what the customer actually accepted. The office-side holiday-lights inventory list now follows that same shared catalog direction too. The inventory admin screen and the dashboard low-stock count read from the shared `price_book_items` bridge when those SKU rows exist, and legacy SKU create/update actions refresh that shared copy after the write so the seasonal inventory catalog stops depending on a separate read-only table path. Those holiday-lights inventory saves now also fail closed if the shared price-book bridge cannot be updated. If CE Pro cannot persist the matching shared SKU row, the office-side inventory create or edit is rolled back instead of leaving `inventory_skus` and the shared quote-core catalog out of sync. Holiday-lights inventory writes now only touch the matching shared SKU rows too. Admin inventory creates and edits update the specific bridged `price_book_items` record for that SKU instead of rebuilding the whole holiday-lights inventory bridge after every change, which keeps the shared price-book copy aligned with far less write churn. Accepted holiday-lights quotes now reuse the shared quote-core accepted follow-up helper too. When a customer accepts from the seasonal status flow or the office signs the linked holiday-lights contract, CE Pro re-syncs the linked estimate workspace first and then runs the same accepted-event, pipeline, webhook, gamification, and accepted-job follow-up path used by the newer shared estimate flows instead of keeping a separate seasonal-only acceptance branch. Holiday-lights contract signing continues to store the captured signature directly on the contract record, and that signature-backed acceptance path is now regression-tested alongside the shared estimate-signature and commercial proposal-signature flows so CE Pro can harden all public signature collection paths together instead of patching them one module at a time. That acceptance bridge now also owns the source holiday-lights quote update itself. Customer status changes and office-side contract signing both flow through the same helper, so the seasonal sales pipeline records the acceptance from one path, and already-accepted quotes no longer rewrite `accepted_at` just because the office reapplies a signed contract record later. --- ## Tips - **Use the satellite view** to trace gutter lines accurately. The overhead angle gives the clearest picture of the full roofline. - **AI measurement works best** with clear property photos taken during the day. Avoid photos with heavy shadows or tree cover blocking the roofline. - **3-year contracts include removal** pricing in the estimate. This simplifies the proposal for the customer and locks in recurring revenue. - **Bundle with a power wash** for a higher ticket value. Customers who are already spending on holiday lights are good candidates for a fall cleaning package. --- ## Troubleshooting ### AI measurement returned inaccurate results The AI works best on standard rooflines with clear photos. For L-shaped homes, complex dormers, or multi-level roofs, trace manually using the gutter line tool. You can combine AI-traced lines with manual adjustments. ### Colors do not match the design summary Make sure you select the color before drawing each line segment. If you need to change a color after drawing, select the line on the canvas and use the color picker to update it. ### Bundle discount is not applying Confirm that the linked power wash estimate belongs to the same customer (matched by name and address). The bundle discount only applies when both estimates are active and not already sent. --- URL: https://docs.cleanestimate.pro/estimating/maintenance-plans Title: Maintenance Agreement Builder Description: Create recurring service plans with discounted pricing, send maintenance proposals, and manage auto-renewing contracts. Category: estimating Difficulty: intermediate Last updated: 2026-03-29 --- # Maintenance Agreement Builder The maintenance agreement builder lets you offer customers recurring service plans with discounted per-visit pricing. Instead of quoting each visit as a standalone job, you bundle multiple visits into an annual plan at a reduced rate. This creates predictable revenue for your business and gives customers a reason to commit long-term. [SCREENSHOT: Maintenance plan builder showing visit count, services per visit, discount fields, and annual pricing summary] --- ## What Is a Maintenance Plan A maintenance plan is a recurring service agreement between your company and a customer. It includes: - A defined number of visits per year. - Specific services performed at each visit. - A discounted rate compared to one-time pricing. - An annual or monthly total the customer commits to paying. - Optional auto-renewal terms for subsequent years. Maintenance plans are attached to residential estimates. The customer receives the maintenance proposal as a separate document from their one-time estimate, and they can now clearly choose between the one-time service and the recurring maintenance plan inside the customer portal. They can accept one, both, or neither independently. --- ## Creating a Maintenance Plan Maintenance plans are built inside the Residential Estimate Wizard during Step 2 (Services and Pricing). ### Step-by-Step Process 1. Open the Residential Estimate Wizard and complete Step 1 (Client and Property). 2. On Step 2, configure the one-time services as you normally would. 3. Scroll below the main services section. 4. Click **+ Add Maintenance Plan**. [SCREENSHOT: The "+ Add Maintenance Plan" button below the services section on Step 2] The maintenance plan builder opens as an expanded section within the estimate. It does not replace the one-time estimate -- it supplements it. --- ## Configuring the Plan The plan builder has several configuration sections that control the structure and pricing of the agreement. ### Number of Visits Set how many visits the plan includes per year. The visit count determines the overall plan value and the per-visit pricing. | Visits Per Year | Typical Use Case | |---|---| | 2 | Biannual cleaning (spring and fall) | | 3 | Quarterly without winter | | 4 | Quarterly cleaning | | 6 | Every other month | | 12 | Monthly service | Choose a visit count that matches the customer's property needs and your service capacity. Biannual plans are the easiest entry point for customers who are new to recurring service agreements. [SCREENSHOT: Visit count selector showing options from 2 to 12 visits per year] ### Services Per Visit Select which services are included in each scheduled visit. You can choose any combination of your configured services. The builder lists all available services with checkboxes. Common service combinations for maintenance plans: | Plan Type | Services Typically Included | |---|---| | **Basic Exterior** | House wash, gutter cleaning | | **Full Exterior** | House wash, gutter cleaning, window cleaning, driveway | | **Premium** | House wash, gutter cleaning, window cleaning, driveway, deck, patio | | **Roof Care** | Roof treatment, gutter cleaning | Each visit in the plan receives the same service mix by default. If you need different services on different visits (for example, roof treatment only on the spring visit), note this in the plan terms. [SCREENSHOT: Service selection checkboxes within the plan builder showing multiple services checked] ### Discount Percentages Two discount types apply to maintenance plans, and they can be used independently or together. | Discount Type | Description | Typical Range | |---|---|---| | **All-visit discount** | A percentage discount applied to every visit in the plan. Rewards the customer for committing to multiple visits. | 10-20% | | **Multi-year discount** | An additional percentage discount for customers who sign a multi-year agreement. Stacks on top of the all-visit discount. | 3-5% | The all-visit discount is the primary incentive. It should be large enough to make the plan clearly cheaper than booking each visit individually, but not so large that it erodes your margin below acceptable levels. The multi-year discount is a retention tool. Even a small additional discount (3-5%) significantly increases the likelihood that a customer renews for a second or third year. [SCREENSHOT: Discount percentage fields showing all-visit discount at 15% and multi-year discount at 5%] --- ## How Pricing Works The plan builder calculates pricing in a specific order: 1. **Start with the one-time price** for each selected service. These are the same base prices used in the standard estimate. 2. **Apply the all-visit discount** to get the discounted per-visit price. 3. **Multiply the per-visit price** by the number of visits to get the annual total. 4. **If a multi-year discount applies**, reduce the annual total by that percentage for Year 2 and beyond. ### Example Calculation Assume the following one-time service prices: - House wash: $350 - Gutter cleaning: $200 - Window cleaning: $250 - **Total per visit (one-time rates):** $800 With a 4-visit plan and a 15% all-visit discount: - Discounted per-visit price: $800 x 0.85 = $680 - Annual total: $680 x 4 = $2,720 - Customer saves: ($800 x 4) - $2,720 = $480 per year With an additional 5% multi-year discount in Year 2: - Year 2 annual total: $2,720 x 0.95 = $2,584 - Year 2 savings vs. one-time: ($800 x 4) - $2,584 = $616 per year The builder shows the full breakdown for the annual plan: subtotal, maintenance discount, taxable amount, sales tax when applicable, and total. Multi-year plans also show the separate agreement discount so the customer can see exactly how the contract total was reached. [SCREENSHOT: Pricing summary showing per-visit price, annual total, and savings compared to one-time pricing] --- ## Sending Maintenance Proposals When you send an estimate that includes a maintenance plan, the system generates two separate deliverables. ### What the Customer Receives 1. **The standard estimate** -- Showing the one-time pricing for immediate services. This is the regular proposal the customer views and accepts. 2. **A separate maintenance proposal** -- Showing the plan details, visit schedule, per-visit subtotal and discount, taxable amount, savings summary, sales tax when applicable, and the final annual or multi-year total. In the combined estimate portal, the customer sees a choice card at the top so they can jump straight to either the one-time service tab or the maintenance plan tab without guessing which action accepts which offer. The maintenance proposal is sent as its own email with a distinct subject line and body. This keeps the two offers clearly separated so the customer can evaluate each one on its own merits. Because the maintenance proposal is queued as its own background delivery, it can arrive a short moment after the main estimate email while the system finishes generating attachments and send tasks. [SCREENSHOT: Customer view of the maintenance proposal showing annual cost, per-visit breakdown, and savings compared to one-time pricing] ### Maintenance Proposal Email The maintenance proposal email includes: - A summary of the plan (number of visits, services per visit, pricing). - The total savings compared to booking each visit individually. - The same subtotal, discount, taxable amount, tax, and total structure the customer sees on the web proposal. - A direct link to view and sign the maintenance agreement online. [SCREENSHOT: Maintenance proposal email as it appears in the customer's inbox] ### Signing the Agreement The customer signs the maintenance agreement at a dedicated URL. This page displays: - The full plan details (visits, services, pricing, terms). - The savings summary. - Visit, yearly, and agreement breakdowns with subtotal, discounts, taxable amount, tax, and total. - An e-signature capture pad. The maintenance agreement signature is independent of the one-time estimate acceptance. A customer can accept the one-time estimate without signing the maintenance plan, sign the maintenance plan without accepting the one-time estimate, accept both, or decline both. Each accepted path now triggers the same downstream estimate acceptance workflow so scheduling, win tracking, and automations continue correctly. When a customer accepts the maintenance agreement, CE Pro now also creates the recurring job-template series automatically. The current recurring-template engine stores one repeating template per seasonal visit pattern in the agreement, so a spring/fall plan becomes two linked recurring templates instead of leaving the office to rebuild those visits by hand later. [SCREENSHOT: Maintenance agreement signature page with plan summary, savings callout, and signature pad] --- ## Auto-Renewal Maintenance plans support automatic renewal at the end of each contract period. ### How Auto-Renewal Works When auto-renewal is enabled on a plan: 1. The agreement terms specify that the plan renews automatically at the end of each year unless the customer cancels. 2. Before the renewal date, the system can trigger a notification to the customer reminding them of the upcoming renewal. 3. If the customer does not cancel, the plan rolls into the next year at the agreed-upon rate (with the multi-year discount applied, if configured). ### Configuring Auto-Renewal In the plan builder, toggle the **Auto-Renewal** option. When enabled, the plan terms automatically include renewal language in the agreement the customer signs. You can also set: - **Renewal notice period** -- How many days before the renewal date the customer is notified (e.g., 30 days). - **Price adjustment cap** -- An optional maximum percentage by which you can increase pricing at renewal (e.g., 5% annual increase cap). [SCREENSHOT: Auto-renewal settings showing the toggle, renewal notice period, and price adjustment cap fields] ### Cancellation Customers can cancel a maintenance plan by contacting your office before the renewal date. When a customer cancels, update the plan status in the client profile to stop future renewal notifications. --- ## Managing Active Plans After a customer signs a maintenance agreement, the plan appears on their client profile under the Maintenance Plans section. ### Client Profile View The client profile shows: - **Plan status** -- Active, Pending Renewal, Expired, or Cancelled. - **Visits completed** -- How many of the scheduled visits have been performed this year. - **Visits remaining** -- How many visits are left in the current period. - **Next scheduled visit** -- The date of the next planned visit, if scheduled. - **Annual revenue** -- The total annual value of the agreement. [SCREENSHOT: Client profile maintenance plan section showing status, visit count, and annual revenue] ### Scheduling Plan Visits Accepted maintenance agreements now seed their recurring visit templates automatically under **Admin > Jobs > Templates**. The office can review or adjust those templates there before the lead window starts generating jobs. Maintenance plan visits should be scheduled through the regular scheduling system. When creating a job for a plan visit, link it to the maintenance agreement so the visit count updates automatically. --- ## Pricing Maintenance Contracts Effectively Setting the right discount level is critical. Too small and customers see no reason to commit. Too large and you erode your margins. ### Guidelines for Discount Levels | Scenario | Recommended All-Visit Discount | Rationale | |---|---|---| | New customer, first plan | 10-12% | Modest discount to introduce the concept without giving away too much. | | Existing customer, proven relationship | 15-18% | Stronger discount rewards loyalty and locks in recurring revenue. | | Competitive market | 18-20% | Larger discount to differentiate from competitors who do not offer plans. | | Premium services (roof, windows) | 8-12% | High-value services already carry good margins; smaller discounts are sufficient. | ### Margin Check Always review the margin calculator after adding a maintenance plan to an estimate. The discounted pricing affects your overall margin. If the maintenance plan pushes the margin below your target, adjust the discount percentage or the per-visit service mix. --- ## Tips - **Lead with the savings.** Customers respond to concrete dollar amounts. "Save $480 per year" is more compelling than "15% off per visit." - **Start with biannual plans.** Two visits per year is an easy commitment for homeowners who are new to recurring service agreements. You can always upgrade them to quarterly in the second year. - **Offer multi-year discounts** to lock in long-term customers. Even a small additional discount (3-5%) increases retention significantly. - **Send the maintenance proposal as a follow-up.** If the customer accepts the one-time estimate but does not respond to the maintenance plan, follow up with a separate email or phone call focused on the plan's value. - **Track renewal rates.** The percentage of maintenance plans that renew each year is one of the most important metrics for recurring revenue health. Aim for 75% or higher. - **Bundle the plan into the initial conversation.** Presenting the maintenance plan alongside the one-time estimate during the first interaction is more effective than introducing it later. --- ## Troubleshooting ### Maintenance plan option is not available The maintenance plan builder is only available in the Residential Estimate Wizard during Step 2. It is not available in the Generic Quote Builder or the Commercial Estimate Wizard. Make sure you are creating a residential estimate. ### Discount is not applying correctly Verify the discount percentages in the plan builder. The all-visit discount applies to the base price of each service. If the base service price is incorrect, the discount will produce unexpected results. Check your service pricing at **Settings > Pricing**. ### Customer received the estimate but not the maintenance proposal The maintenance proposal is sent as a separate email with its own subject line. Check the message log on the estimate detail page to confirm whether the maintenance proposal email was sent. If it was not delivered, resend it from the estimate detail page. ### Auto-renewal notification did not send Verify that the auto-renewal toggle is enabled on the maintenance plan and that the renewal notice period is set. Check the customer's email address for accuracy. Review the message log for delivery errors. ### Plan visits are not decrementing Scheduled jobs must be linked to the maintenance agreement for the visit count to update automatically. When creating a job for a plan visit, select the associated maintenance plan in the job creation form. --- URL: https://docs.cleanestimate.pro/estimating/mapmeasure Title: MapMeasure Description: Use MapMeasure in the shared satellite workspace to trace roofs, footprints, lots, gutters, and other measurements directly on the map. Category: estimating Difficulty: intermediate Roles: owner, manager, sales_rep Last updated: 2026-03-26 --- # MapMeasure MapMeasure is the shared measurement workspace inside the satellite view of the Property Visual Panel. It lets you trace polygons and lines on the live Google map, store those measurements with the estimate or proposal, and apply supported values back into pricing inputs. MapMeasure is available in: - Residential estimates - Commercial building proposals - Fleet proposals - Holiday lights estimates The same saved measurements reopen with the record, including map center, zoom, tilt, and heading. ## Open MapMeasure Open the record you are working on, then open the **Property Visual Panel** and switch to the **Satellite** tab. When MapMeasure is enabled for that workflow, you will see the measurement toolbar on top of the map. Use MapMeasure when you need values such as: - Building footprint square footage - Lot size - Roof area - Gutter length - Fence length - Driveway area - Parking or curb reference measurements ## Drawing Tools MapMeasure supports two draw modes: - **Polygon** for areas like roofs, footprints, driveways, parking, and lots - **Line** for gutters, fences, frontage, curbs, and other linear measurements While you draw, MapMeasure shows live geodesic totals on the map: - Polygons show **area** and **perimeter** - Lines show **length** All saved totals are recalculated on the server from latitude and longitude points before they are stored. ## Keyboard Shortcuts During draw mode, these shortcuts are available: - `Escape` cancels the active draft and exits draw mode - `Ctrl+Z` or `Cmd+Z` removes the last draft vertex Polygon drafts can be completed by clicking the first vertex again or by double-clicking after at least three points. Line drafts complete on double-click after at least two points. Undo is draft-aware all the way down to the last point. If you remove the final vertex, MapMeasure keeps the active draft category and styling in place so you can keep drawing without reselecting the tool. ## Editing Saved Measurements After a measurement is saved, you can: - Select it from the map or the measurement list - Rename it - Recolor it - Duplicate it - Delete it - Reopen it later with the same geometry and map view Saved measurements are attached to the active record, and when the workflow has a reusable property address on file they can also be loaded from that property-level address context. MapMeasure saves are scoped to the current organization and target record before the server accepts them, which helps prevent cross-record or cross-org mixups during shared office workflows. Map preview lookups now load through the app's internal map routes with request throttling and permission checks. That means failed address or Street View lookups show clearer inline errors instead of leaving the visual panel stuck in a loading state, and upstream non-image responses are rejected before they can be shown in the admin UI. Measurement save/load failures now surface plain-language admin messages instead of raw database text, while detailed diagnostics stay in server logs for support. ## Smart Apply MapMeasure can do more than store reference shapes. In supported workflows it can push measured values back into the actual pricing inputs. ### Residential Estimates Residential smart apply updates both the property summary fields and the pricing-driving service selections used by the estimate engine. When you apply a supported residential measurement, Clean Estimate Pro also saves the estimate's `property_data_source` as `mapmeasure` and records the measurement-source metadata used for that estimate revision. That makes later edits and reopen flows preserve the fact that the value came from saved map geometry instead of a manual guess. Current mappings: - `footprint` or `custom_area` -> `house-wash.sqft` and top-level `property_sqft` - `roof` -> `roof-cleaning.roof_sqft` and top-level `roof_sqft` - `gutter` -> `gutters.gutter_linear_ft` and top-level `gutter_linear_ft` - `driveway` -> `driveway.driveway_sqft` - `fence` -> `fence.fence_linear_ft` The apply dialog shows the current value and the proposed measured value before you confirm the overwrite. ### Commercial Building Proposals Commercial building proposals can apply supported measurements to the active property inside the portfolio builder. Proposal property saves now replace the full property graph through one atomic database transaction, so a failed save cannot partially delete and reinsert child rows. ### Fleet and Holiday Lights Fleet and holiday lights can capture and save measurements in the shared satellite workspace, but their use is intentionally lighter in v1: - Fleet keeps measurements available for reference and workflow support - Holiday lights keeps the existing design canvas as the pricing source, with MapMeasure available as a saved map reference ## Edit and Reopen Behavior Residential estimate reconstruction was hardened so saved values round-trip more cleanly when you reopen an estimate for editing. When legacy estimates contain service-specific inputs, Clean Estimate Pro now preserves those values before falling back to generic defaults. That includes fields such as: - `roof_sqft` - `roof_type` - `roof_half` - `gutter_linear_ft` - `driveway_sqft` - `fence_linear_ft` - `stories` - `sqft` This is especially important when a MapMeasure-applied estimate is saved, reopened, and edited again later. ## Deployment Note MapMeasure and the shared Property Visual Panel prefer the server-side `GOOGLE_MAPS_SERVER_API_KEY` environment variable for geocoding, Static Maps, and Street View proxy requests. If that dedicated server key is missing, CE Pro falls back to `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` for those internal map requests. If that public Maps key is browser-only, referrer-restricted, or missing Geocoding / Street View access, saved map previews and measurement workflows keep the unavailable message instead of acting like the address itself could not be found. ## Best Practices - Use category-specific shapes whenever possible so the apply suggestions stay relevant. - Keep separate shapes for separate pricing surfaces instead of tracing one large custom polygon. - Apply measurements only after confirming the category matches the pricing field you want to update. - For holiday lights, keep using the holiday lights design canvas for production pricing and installation planning. --- URL: https://docs.cleanestimate.pro/estimating/margin-calculator Title: Margin Calculator Description: Understand your profit margins on every estimate before you send it, using the built-in residential margin panel. Category: estimating Difficulty: intermediate --- # Margin Calculator The margin calculator is a real-time profitability panel built into the Residential Estimate Wizard. When your organization has cost data configured, it appears alongside the pricing breakdown and updates instantly as you add services, adjust quantities, or change prices. It ensures you never send an estimate without knowing your projected profit. [SCREENSHOT: Margin calculator panel in the Residential Estimate Wizard showing margin percentage and cost breakdown] --- ## Margin vs. Markup Before using the calculator, it helps to understand the difference between margin and markup. These two terms are often confused, but they produce different numbers from the same data. | Term | Formula | Example | |---|---|---| | **Margin** | (Revenue - Cost) / Revenue | A $1,000 job with $600 in costs has a 40% margin. | | **Markup** | (Revenue - Cost) / Cost | The same job has a 66.7% markup. | CleanEstimate Pro uses **margin** as the primary metric. Margin expresses profit as a percentage of revenue, which makes it easier to compare across jobs of different sizes. A 40% margin means you keep $0.40 of every dollar collected, regardless of whether the job is $500 or $50,000. Markup, by contrast, expresses how much you added on top of your costs. While useful in some contexts, markup percentages can be misleading when comparing jobs because a 100% markup on a $200 cost ($400 revenue) produces only $200 in profit, whereas a 50% markup on a $2,000 cost ($3,000 revenue) produces $1,000. The margin calculator eliminates this confusion by presenting one consistent metric across all estimates. --- ## How the Calculator Works The calculator uses a straightforward formula: **Margin = (Revenue - Total Costs) / Revenue** Revenue is the total price quoted to the customer, including all services, add-ons, and custom line items, minus any discounts. Total costs are the sum of your internal expenses for delivering the work. The panel recalculates instantly every time a value changes in the Residential Estimate Wizard. [SCREENSHOT: Margin calculator showing the formula applied to a sample estimate with revenue, costs, and resulting margin percentage] --- ## Cost Categories The margin calculator factors in three categories of cost. Each one pulls from values you configure in your pricing settings. ### Crew Pay Crew pay represents the labor cost for completing the job. CleanEstimate Pro supports two crew pay models: - **Commission percentage** -- A percentage of the commissionable work subtotal paid to the crew. Tax, lift charges, equipment adders, and subcontractor scope are excluded before commission is calculated. - **Hourly rate** -- A fixed rate per hour multiplied by estimated job duration. The calculator uses whichever model your organization has configured. If you use commission-based pay, the crew cost scales with the labor portion of the estimate rather than the full taxed ticket. ### Materials Material costs include cleaning chemicals, consumable supplies, equipment wear, and any products used on the job. These values are set per service in your pricing configuration. For example, a house wash might have $15 in chemical costs, while a roof treatment might use $45 in product. The calculator sums material costs across all selected services in the estimate. ### Franchise Fees If your business operates under a franchise agreement, you likely pay a percentage of revenue to your franchisor. A typical franchise fee is 10%. The calculator applies this percentage to the total revenue. Set the franchise fee to zero if you are not a franchisee. The field disappears from the cost breakdown when set to zero. | Cost Category | Source | Scales With | |---|---|---| | **Crew pay** | Settings > Pricing | Revenue (commission) or hours (hourly) | | **Materials** | Per-service configuration | Number and type of services selected | | **Franchise fees** | Settings > Pricing | Revenue | [SCREENSHOT: Cost breakdown panel showing crew pay, materials, and franchise fees as separate line items with dollar amounts] --- ## Using the Residential Margin Panel The margin panel appears on the right side of the Residential Estimate Wizard during Step 2 (Services and Pricing). It sits below the pricing summary. ### Reading the Panel The panel displays: 1. **Margin percentage** -- The headline number, shown in large text with color coding. 2. **Revenue** -- The total quoted price before any adjustments. 3. **Total costs** -- The sum of crew pay, materials, and franchise fees. 4. **Profit** -- Revenue minus total costs, shown in dollars. 5. **Cost breakdown** -- An itemized list of each cost category with its dollar amount. [SCREENSHOT: Full margin panel showing margin percentage, revenue, total costs, profit, and cost breakdown] ### Color Coding The margin percentage uses color coding to provide an instant visual signal: | Color | Meaning | Recommended Action | |---|---|---| | **Green** | Above your target margin. The estimate is profitable. | Safe to send. | | **Amber** | Close to your target but thin. Limited room for error. | Review pricing before sending. Consider whether the margin covers overhead. | | **Red** | Below your target margin. The estimate may lose money. | Raise prices, remove low-margin services, or confirm you have a strategic reason to proceed. | The thresholds that trigger each color are based on your target margin setting. If your target is 45%, margins above 45% show green, margins between 35% and 45% show amber, and margins below 35% show red. These thresholds are approximate and designed to give you a quick read. [SCREENSHOT: Three side-by-side examples showing green, amber, and red margin indicators on different estimates] --- ## Setting Target Margins Your target margin defines what "good" looks like for your business. Configure it at **Settings > Pricing** under the margin target field. ### Choosing a Target Target margins vary by business model, but here are common benchmarks for exterior cleaning companies: | Business Type | Suggested Target Margin | Reasoning | |---|---|---| | **Owner-operator** | 50-60% | Lower overhead, fewer fixed costs. | | **Small crew (2-5 people)** | 40-50% | Moderate labor costs, manageable overhead. | | **Franchise operation** | 35-45% | Franchise fees consume 8-12% of revenue off the top. | | **Multi-crew operation** | 30-40% | Higher labor, vehicle, and administrative costs. | These are gross margin targets. Your net margin after accounting for insurance, fuel, vehicle payments, rent, software, and administrative time will be lower. ### Why Margins Matter for Exterior Cleaning Exterior cleaning businesses face a cost structure that compresses margins quickly. Consider a franchise operation with the following costs: - **Franchise fee:** 10% of revenue - **Crew commission:** 19% of revenue - **Materials:** approximately 3-5% of revenue Those three line items alone consume 32-34% of revenue before you account for insurance, fuel, vehicle costs, marketing, or administrative overhead. On a $1,000 job: - $100 goes to franchise fees. - $190 goes to crew pay. - $40 goes to materials. - That leaves $670 to cover everything else. If your total overhead runs 25% of revenue, your net profit is around $420, or 42% gross margin. Drop the price by $100 to win the job, and your gross margin falls to 37%. Drop it by $200 and you are at 31%. The margin calculator makes these dynamics visible before you commit to a price. --- ## How Margin Affects Pricing Decisions The margin panel is not just informational. It should actively influence how you price estimates. ### Adjusting Prices to Hit Your Target If the margin indicator shows amber or red, you have several options: 1. **Raise individual service prices.** Adjust the price of specific services in the Residential Estimate Wizard. Watch the margin percentage update in real time until it reaches your target. 2. **Remove or substitute services.** Some services carry better margins than others. If a low-margin service is dragging down the overall estimate, consider whether it is essential or whether you can offer it as a separate add-on. 3. **Reduce the package discount.** If a multi-service discount is compressing your margin, consider reducing the discount percentage or setting a minimum margin floor. 4. **Accept the lower margin strategically.** There are valid reasons to send a below-target estimate: winning a high-value recurring customer, breaking into a new market, or securing a reference job. When you do this, make the decision consciously, not accidentally. [SCREENSHOT: Adjusting a service price in the estimator and watching the margin indicator change from red to green] ### Package Discounts and Margins When a customer selects three or more services, the automatic package discount reduces the total price. This discount lowers revenue but does not change your costs, so the margin decreases. The margin calculator reflects the post-discount margin. If your pre-discount margin is 48% and a 10% package discount applies, the margin drops. Check the panel after the discount is applied to confirm the estimate is still above your target. --- ## Configuring Your Cost Data The margin calculator only appears when your cost data is configured. Without cost data, the system cannot compute margins and the panel is hidden. ### Required Configuration Go to **Settings > Pricing** and fill in the following fields: | Field | Description | |---|---| | **Crew pay rate** | Commission percentage (e.g., 19%) or hourly rate (e.g., $25/hour). | | **Material costs** | Per-service material cost estimates. Set these for each service type. | | **Franchise fee percentage** | The percentage of revenue paid to your franchisor. Set to 0 if not applicable. | [SCREENSHOT: Pricing settings page showing crew pay rate, material costs per service, and franchise fee fields] ### Keeping Costs Current Review your cost data quarterly. Material prices fluctuate, crew pay rates may change, and franchise fee structures can be renegotiated. Outdated cost data produces inaccurate margin calculations, which defeats the purpose of the tool. --- ## Using Margins for Training and Oversight The margin calculator is a powerful training tool for sales teams. ### Training New Sales Reps New reps often underprice jobs to win customers. The margin panel provides immediate feedback. During training, have reps build practice estimates and aim for the target margin. They learn pricing discipline faster when they can see the financial impact of every decision. ### Manager Review Managers can review estimates before they are sent and check the margin. If a rep consistently produces estimates below the target margin, it signals a coaching opportunity. ### Weekly Margin Reviews Track your average margin across all sent estimates each week. A declining average margin indicates one of several issues: - Pricing defaults need adjustment. - Reps are applying excessive discounts. - Your cost structure has changed but pricing has not kept up. - You are quoting more low-margin services than usual. --- ## Tips - **Aim for a gross margin above 40%.** After accounting for overhead, insurance, fuel, and administrative costs, anything below 40% gross margin becomes tight for most cleaning businesses. - **Check margins on bundled estimates.** Package discounts reduce revenue but do not reduce your costs. Always verify the post-discount margin. - **Review margins weekly.** If your average margin is declining, investigate whether pricing defaults, discounts, or cost changes are the cause. - **Use the calculator during training.** New sales reps learn pricing discipline faster when they can see the margin impact of every decision. - **Do not chase revenue at the expense of margin.** A $2,000 job at 25% margin earns less profit ($500) than a $1,500 job at 45% margin ($675). --- ## Troubleshooting ### Margin panel is not showing Your organization does not have cost data configured. Go to **Settings > Pricing** and fill in the crew pay rate and material costs for your services. The panel appears automatically once at least one cost field is populated. ### Margin seems too high Check that your crew pay rate and material costs are realistic. If you entered zero for materials, the calculator assumes your only cost is labor. Update all cost fields to get an accurate picture. ### Margin seems too low Verify that your franchise fee percentage is correct. A franchise fee entered as 10 when you intended 1% would dramatically reduce the displayed margin. Also check that material costs per service are not inflated. ### Margin changes when I add a package discount This is expected. Package discounts reduce revenue while costs stay the same, so the margin decreases. The calculator reflects the actual margin after the discount is applied. ### Margin does not match my accounting The margin calculator shows estimated gross margin based on the cost data you configured. It does not include overhead costs such as insurance, fuel, rent, software, or administrative salaries. Your accounting margin will be lower than the calculator shows because it includes those additional expenses. --- URL: https://docs.cleanestimate.pro/estimating/proposals-and-pdfs Title: Proposals and PDFs Description: Preview, download, and send professional PDF proposals to your customers. Category: estimating Difficulty: beginner Roles: owner, sales_rep Last updated: 2026-04-27 --- # Proposals and PDFs Every estimate in CleanEstimate Pro can be turned into a professional PDF proposal. The system generates PDFs automatically when you preview or send an estimate. Customers also get a web-based proposal link where they can view, accept, or decline. --- ## PDF Preview On the review step of any estimate wizard, click **Preview** to open a PDF preview in a new tab. [SCREENSHOT: Preview button highlighted on the review step of the estimate wizard] The preview renders the full proposal exactly as the customer will see it. Use this to catch formatting issues, pricing errors, or missing information before sending. --- ## What the PDF Includes Each PDF proposal contains the following sections: | Section | Details | |---|---| | **Company header** | Your company logo, business name, address, phone number, and email | | **Customer details** | Customer name, property address, and contact information | | **Service breakdown** | Each selected service listed as a line item with quantity, unit, and price | | **Add-ons** | Any add-on items with individual pricing | | **Custom items** | Manual line items added during the estimate | | **Pricing summary** | Subtotal, discounts, taxable amount, tax, and grand total | | **Terms and conditions** | Your configured terms of service | | **E-signature area** | A designated space for the customer to sign electronically | [SCREENSHOT: Full PDF proposal showing company header, service breakdown, pricing summary, and signature area] For commercial building and fleet proposals, the default terms now come from **Admin > Commercial > Settings** whenever the proposal-level custom terms box is left blank. That keeps the office on one shared editable source instead of a hidden PDF-only fallback. ### PDF Variants CleanEstimate Pro generates different PDF layouts depending on the estimate type: - **Residential** -- standard service-based layout with property details. - **Commercial** -- includes multi-option pricing and site condition notes. - **Commercial Building** -- shows surface-level line items and building-specific details. - **Fleet** -- lists vehicle types, counts, and per-unit pricing. Seasonal fleet PDFs now break pricing into the standard cadence and alternate cadence separately, the service-plan page lists each month in the split schedule, and the cover page keeps the saved proposal date on the correct calendar day instead of shifting date-only records backward in some time zones. - **Generic Quote** -- displays manual line items in a simple table format. - **Maintenance Proposal** -- shows the visit schedule, per-visit pricing, and annual cost. --- ## Sending Proposals by Email When you click **Send Estimate** on the review step, the system attaches the PDF to the outgoing email automatically. The customer receives: 1. An email with a summary of the estimate and the PDF attached. 2. A clickable link to view the proposal online. [SCREENSHOT: Customer email showing the estimate summary, attached PDF, and proposal link] You do not need to download and attach the PDF manually. The system handles it. Residential estimates, generic quotes, holiday lights, fleet proposals, and commercial building proposals now all use the same shared review-and-send modal. Staff review the outbound email copy and outbound text message copy together, then confirm one combined send. The email carries the attachment or secure link for that estimate type, and the text message is delivered alongside it when the client phone number and SMS setup are available. Mobile reps now stay in that same send-and-close loop after the estimate exists. From mobile proposal detail, a salesperson can open the secure customer-facing estimate or proposal view that matches that quote's live delivery path, present it in person, let the customer accept and sign on the spot, and then launch either a 25% deposit link or a full-balance payment link without going back to the office UI. Estimate send actions still kick off follow-up sync work in the background, but the actual email/text delivery shown in the shared send modal is now confirmed before the office sees success. If your office sends a large burst of estimates at once, CE Pro may briefly show the delivery as **Queued** or **Processing** while the background worker drains the send backlog. When you save and send a quote from the Generic Quote Builder, the send step now reuses the customer token generated during the save response instead of regenerating it a second time. That keeps the new-quote send flow from failing on resend/retry paths and also surfaces provider misconfiguration as a real send failure instead of a false success. The manual **Send Estimate** / **Resend Estimate** flow now waits for the email delivery step to succeed before it reports success back to the office. If the send fails, CE Pro keeps the estimate retriable instead of claiming it was delivered and then blocking resend because the record is no longer in draft. If secure estimate-link signing is not configured yet, the office can still send the estimate email. In that fallback mode, the PDF still goes out, and the send dialog warns that the online estimate link is temporarily unavailable instead of blocking the entire send action. --- ## Downloading a PDF You can download a PDF at any time from the estimate detail page. 1. Open the **Manage** section in the admin sidebar, click **Estimates**, and open an estimate. 2. Click **Download PDF** on the estimate detail page. 3. The PDF downloads to your device. [SCREENSHOT: Download PDF button on the estimate detail page] This is useful when you need to print a proposal, attach it to a separate email, or save a copy for your records. --- ## Browsing the Estimates List The main **Estimates** list under **Daily work** opens as the **Estimate workbench**. The top of the page now highlights drafts to send, viewed proposals that need follow-up, unassigned estimates, and accepted estimates that still need job handoff. Those priority cards use the records currently loaded in the table and double as quick filters for the most common office follow-up paths. The list still loads the newest records first and supports filters for status, source, rep, estimate type, tags, and date range. The date control supports quick presets plus a custom start/end picker, so sales managers can jump straight to an exact window instead of relying only on fixed ranges. Each row also includes a **Next action** control beside the status. Depending on the estimate, the row can send a draft, open AI follow-up, create a job from an accepted estimate, create or copy a payment link, schedule the appointment, request a review, or open the detail page. Behind the scenes, that screen now runs on a unified indexed read model that combines residential estimates, generic quotes, holiday lights records, fleet proposals, and commercial building proposals into one fast list. Search, filters, and pagination are applied before the page returns results, so larger organizations can keep working the same way without waiting on the app to merge full estimate history in memory. Use **Load More** at the bottom of the page to fetch the next batch of records when you want to keep scrolling through older estimates. Bulk status changes from that list now report one accurate success or failure summary after the batch finishes instead of showing a false partial-failure warning when the selected estimates all updated successfully. --- ## Online Proposal Link Every sent estimate generates a unique proposal URL. The customer can open this link in any browser. ### What the Customer Sees The online proposal page displays: - A branded header with your company logo. - The full estimate breakdown with line items and pricing. - A transparent pricing summary that shows subtotal, discount, taxable amount, sales tax, and total. - Custom items inside the main estimate breakdown so they are included in the quote total the customer sees before payment options. - An expiration notice if the proposal has a validity period. - An **Accept** button that opens the e-signature capture. - A **Decline** button to reject the proposal. [SCREENSHOT: Online proposal page as seen by the customer, showing the accept and decline buttons] Generic quotes now use the same shared customer quote page under the unified quote-core path. Preview, email delivery, resend, and acceptance all point at that same persisted quote link, so the office no longer saves a generic draft through one route and opens it through a different customer-view path. The mobile proposal shell now respects that broader estimate coverage too. Generic Quote and Asphalt Maintenance launches are available from the mobile sales app through guided web handoff cards, and once those estimates are saved they appear back in mobile proposal lists with working customer-view, signature, and payment-link actions. Mobile close actions now prefer the estimate/customer view first, which keeps holiday lights, fleet, commercial building, asphalt, and generic flows on the customer page that actually exists for that quote. Residential base estimate links are now beginning to use that same shared quote-core customer page too when the saved estimate has a persisted public quote token. Multi-option proposal pages and maintenance-plan pages still keep their dedicated customer screens for now, but the base estimate preview/open flow is no longer forced to stay on the older estimate-only route. Customer-engagement alerts now distinguish between the email itself being opened and the customer document page being opened. When Resend reports that the email was opened, the outbound email row in **Messages** shows the tracked open time, total opens, and any tracked link click. When the customer then opens the quote, estimate, proposal, maintenance proposal, fleet proposal, commercial building proposal, or linked shared quote page, CE Pro raises a separate live admin alert for that page open and records the viewed event in the thread. ### E-Signature When the customer clicks **Accept**, a signature pad appears. They draw their signature using a mouse, trackpad, or finger on a touchscreen. After signing, they confirm acceptance. [SCREENSHOT: E-signature pad on the proposal acceptance page] Only customer-facing estimates that have actually been sent or viewed can be accepted, declined, or signed through the public proposal link. Drafts and expired records are blocked from those customer-action paths until the office sends a live proposal. Once signed: - The estimate status changes to **Accepted**. - You receive an in-app alert in the admin bell right away for commercial and fleet proposals. The bell now refreshes live on new signed-proposal alerts instead of waiting for the old polling interval. - Any `proposal_accepted` webhook subscriptions fire at the same time for commercial and fleet proposals. - The signature PNG is validated and saved before the acceptance completes, so the signed record keeps the captured signature instead of silently accepting without it. - Follow-up tasks like activity logging, pipeline history, and linked-estimate automation no longer turn a completed customer signature into a false failed-sign response if one of those later bookkeeping steps has a temporary issue. If the customer requests changes instead of fully accepting, the admin estimate detail page now shows a dedicated **Customer Changes Requested** card with: - The interaction status and timestamp. - The requested subtotal and accepted total. - Any customer-wide note they submitted. - The exact included and removed line items from their selection. --- ## Proposal Expiration You can configure how long proposals remain valid. After the expiration date, the online proposal page shows an expiration notice and disables the accept button. The customer must contact you for a new proposal. A cron job runs daily to expire proposals that have passed their validity date. --- ## Tips - **Always preview before sending.** A two-second check prevents embarrassing pricing errors. - **Use the online proposal link** instead of the PDF when possible. The web version is interactive and allows e-signature without printing. - **Download PDFs for in-person sales.** If you are meeting a customer on-site, pull up the PDF on a tablet or print it beforehand. - **Use mobile proposal detail for live closes.** Open the customer proposal from the phone or tablet, capture acceptance and signature, and then create a deposit or balance payment link while you are still with the customer. - **Check your company logo** in Settings. The logo appears at the top of every PDF and online proposal. --- ## Troubleshooting ### PDF is blank or missing sections Make sure the estimate has at least one service selected with pricing greater than zero. A blank estimate produces a minimal PDF. ### Customer says they cannot open the proposal link Verify the link has not expired. Check the estimate detail page for the current status. If the proposal expired, resend the estimate to generate a new link. If the office sees a warning that secure estimate links are unavailable, the email can still be delivered with the PDF attachment, but the customer will not receive the browser-based estimate link until customer-link signing is configured again. ### Company logo is not showing on the PDF Go to **Settings > Account** and upload a logo. The PDF generator uses the logo stored in your organization settings. --- URL: https://docs.cleanestimate.pro/estimating/residential Title: Residential Estimate Wizard Description: Full walkthrough of the 3-step Residential Estimate Wizard, from client details to sending. Category: estimating Difficulty: beginner Roles: owner, sales_rep Last updated: 2026-04-25 --- # Residential Estimate Wizard The Residential Estimate Wizard walks you through three steps: client and property details, services and pricing, and review and send. Most estimates take under five minutes once your pricing defaults are configured. ## Step 1 -- Client & Property Start by entering the customer and property information. [SCREENSHOT: Step 1 of the Residential Estimate Wizard showing the client and property form] ### Customer Details Fill in the following fields: - **Customer Name** (required) -- the name that appears on the proposal. - **Lead Source** -- select from the dropdown. This tracks where the lead came from (Google, referral, door hanger, etc.). - **Email** -- used to send the estimate link. - **Phone** -- used for SMS delivery. [SCREENSHOT: Customer details fields with Lead Source dropdown expanded] ### Property Address Start typing in the **Address** field. Google Places autocomplete suggests matching addresses. Select one from the dropdown. [SCREENSHOT: Address field with Google Places autocomplete suggestions visible] When you select an address, the system auto-fills **City**, **State** (2-character abbreviation), and **ZIP**. ### Property Details Enter the property characteristics manually or use the auto-fill shortcut. | Field | Description | | ----------------------- | --------------------------------------------------------------------------- | | Property Square Footage | Total livable area in square feet | | Stories | Number of floors (defaults to 1) | | Lot Size | Total lot area | | Year Built | Construction year | | Roof Sqft | Estimated from property sqft | | Gutter Linear Ft | Estimated from building footprint | | Siding Type | wood, vinyl, fiber-cement, brick, stone, stucco, aluminum, composite, other | | Roof Type | asphalt_shingle, metal, tile, slate, other | [SCREENSHOT: Property details section with all fields filled in] ### Auto-fill Property Data Click **Auto-fill Property** after entering the address and ZIP code. The system calls a property lookup API and fills in: - Square footage - Stories - Lot size - Year built - Roof square footage - Gutter linear feet This saves two to three minutes per estimate. Not all addresses have data available, especially rural properties. [SCREENSHOT: Auto-fill Property button highlighted, with fields populated after clicking] ### Assign to Sales Rep If you are creating an internal estimate, use the **Assign to Sales Rep** dropdown to assign the estimate to a team member. Internal residential estimates now autosave in the background while you work. CE Pro can save partially completed drafts during Step 1, then keep updating that same draft as you change pricing, notes, services, add-ons, or review details. The wizard header shows the save state so the office can see when changes are still pending, and the wizard also flushes pending draft changes if the office clicks away right after editing. [SCREENSHOT: Assign to Sales Rep dropdown with team member names listed] On the estimate detail page, CE Pro also shows a shared **Tags** card whenever the estimate is linked to a client. Those tags save back to the linked client so the same labels stay in sync with lead, job, and invoice filters. When the estimate is linked to a CRM client, the wizard header also includes a direct **View Client** action so the office can jump back to the customer profile without leaving the estimate workflow blind. Click **Next** to proceed to Step 2. --- ## Step 2 -- Services & Pricing Select which services to include and configure the details for each one. [SCREENSHOT: Step 2 showing the services list with toggle checkboxes and the pricing panel on the right] The Residential Estimate Wizard now loads its services, add-ons, and custom item templates through the same shared catalog bridge used by the public estimator entrypoint. In practice, that means the office and customer-facing residential estimator stay aligned to the same active catalog rows while the platform moves toward the unified price-book core. That catalog read path now stays read-only during normal page loads. Office and customer estimator screens consume the shared residential catalog snapshot (with legacy fallback when a workspace has not been bridged yet) instead of trying to repair the shared price book inline during every render. Residential catalog saves now follow that same fail-closed rule too. If the office creates, edits, or deletes a service, add-on structure, or custom item template and CE Pro cannot update the shared price-book bridge, the admin change is rolled back instead of leaving the legacy pricing table ahead of the shared quote-core catalog. Those residential catalog saves now update only the touched shared price-book rows instead of forcing a full residential catalog rebuild after every single service, add-on, or template change. That keeps org-specific custom books isolated, lowers the blast radius of each save, and still preserves the fail-closed rollback if the shared price-book write cannot complete. Residential saves also now normalize their service, add-on, and custom-item breakdown into the shared quote-core line-item model behind the scenes. The current residential wizard UI and legacy estimate fields still stay in place, but the same saved estimate now feeds the new canonical line-item layer used by the unified quote-core rollout. Behind that UI, residential create and update now run through the same shared quote-core persistence layer used by generic quotes. That means the saved estimate row, canonical line items, quote snapshots, rollback handling, and quote-event logging are all written together instead of the residential API route owning a second inline save flow. Measurement-driven property values like **Roof Sqft**, **Gutter Linear Ft**, and saved map-measure sources now persist correctly when you edit and resave a residential estimate. That same updated measurement context is written before PDF and email regeneration runs, so previews and sends stay aligned to the latest saved scope instead of a stale earlier version. ### Enabling Services Each service has a toggle checkbox. Turn on the services you want to include in the estimate. When you enable a service, its configuration fields appear below. Each enabled service now also includes a **Customer Description** field. CE Pro seeds that text from the residential service catalog when default scope copy exists, and the same description now stays visible in the office review step, the customer-facing estimate page, and the residential PDF instead of disappearing after save. Service and add-on price overrides are now directly editable text inputs. Reps can click into the amount and type the target price instead of relying on the browser's up/down number arrows. ### Service Parameters Each service has its own set of inputs. **House Wash** - Square footage (auto-filled from Step 1) - Stories - Dirtiness level **Windows** - Window count - Type: Exterior Only or Interior + Exterior - Screen removal: Yes or No **Gutters** - Linear feet (auto-filled from Step 1) - Gutter type **Roof** - Square feet - Roof type multiplier - Half roof toggle (for partial cleaning) **Driveway** - Square feet **Sidewalks** - Linear feet **Deck** - Square feet - Deck type **Patio** - Square feet - Patio type **Fence** - Linear feet - Fence type [SCREENSHOT: House Wash service expanded showing sqft, stories, and dirtiness level fields] ### Dirtiness Level Every applicable service includes a dirtiness level selector. This affects the pricing multiplier. | Level | Label | When to Use | | -------- | -------------------- | ------------------------------------- | | Light | Routine cleaning | Annual maintenance, minimal buildup | | Moderate | Some buildup | Visible dirt, mildew starting | | Heavy | Significant staining | Years of neglect, heavy mold or algae | [SCREENSHOT: Dirtiness level selector showing the three options with descriptions] ### Red Line Pricing If your workspace enables **Red Line**, CE Pro also calculates a per-service floor directly from the live suggested service price. That means the floor follows the same square-footage, size, and dirtiness inputs your team already uses instead of relying on a disconnected flat table. Red Line now follows the **assigned sales rep** on the estimate. If an owner, manager, or office teammate changes the rep while building the quote, the floor logic and save guardrails update to match that rep's Red Line access before the estimate is saved. If the estimate is still attached to an old or unavailable rep record, CE Pro now keeps Red Line hidden and falls back to standard pricing instead of borrowing the access level of the office user who opened the quote. That keeps stale assignments from changing the floor model by accident. If Red Line is not showing on a residential quote, the estimator now explains why inline. The notice tells you whether Red Line is turned off in **Pricing Manager** or the currently assigned rep is still on standard pricing, so the office does not have to guess which setting is blocking the floor. Mixed teams are supported here too. Owners, managers, and sales reps remain the default Red Line candidates, but a crew lead, technician, or other teammate with explicit **Red Line Access** now shows up as an assignable residential rep in the estimator as well. - **Suggested Price** -- the calculated service price before a manual override. - **Floor Price** -- a configurable percentage of the suggested price. - **Status** -- CE Pro marks the service as at red line, near red line, above red line, or healthy upside. - **Manual Override Guardrail** -- when manager overrides are turned off, reps still cannot save a service below the floor. Managers and owners can always review the red-line floor on eligible estimates. Whether sales reps also see the live commission number depends on the **Show commissions to reps** pricing setting. [SCREENSHOT: Residential service row showing the floor price, red-line status badge, and commission callout] If your workspace turns on **Enable manager override tracking**, the estimator also unlocks the first residential override workflow: - Reps can type a below-floor price into the service row instead of being clamped at the floor. - Step 3 shows a **Red Line manager override** card with the shortfall, affected services, and a place to explain why the quote should go out below floor. - The estimate can still save as a draft so the office has a real quote record to review, but **Send Now** stays blocked until a manager approves the request. - Owners and managers can approve or reject the pending override either from the residential review step or from the estimate detail page. - If the rep changes the below-floor pricing after requesting approval, CE Pro marks the old request as stale and requires a fresh request before sending. If your workspace also enables the **Rehash Department**, Step 3 now captures the quote outcome before the office can finish the save: - Residential quotes need a **Rehash disposition** before they can be saved or sent. - **HOT**, **PRICE**, **TIMING**, and **DEAD** require notes so the follow-up team sees the real objection or timing issue later. - Unsold quotes can auto-enroll into the staged Rehash sequence immediately after save. - Day 21 and Day 90 win-back offers still respect Red Line. If the saved service floors would be broken, CE Pro suppresses that discount message instead of sending a below-floor offer. - Once a quote is in Rehash, the estimate detail page shows a dedicated **Rehash** card with stage, notes, next touch, parent quote, and any recovered-close attribution. Sales reps building residential estimates from the mobile app now get the same Red Line guardrails. Mobile pricing review shows each service floor and status, clamps below-floor edits back to the floor, repeats the Red Line summary before delivery, and stores the Red Line snapshot with the queued mobile proposal data for later audit. Mobile residential estimates now also share the web estimator's property lookup service. When a rep starts from a live CRM client or lead, the linked customer and service address carry into the mobile builder. Once the address, city, and ZIP are present, the mobile app calls the authenticated property lookup endpoint, pre-fills square footage, stories, lot size, and year built when available, and recalculates house-wash quantity from the returned square footage. ### Add-ons Below the main services, check any applicable add-ons. Each add-on has a quantity input so you can adjust amounts. [SCREENSHOT: Add-ons section with checkboxes and quantity fields] Selected add-ons now use **Customer Description** text too. Built-in residential add-ons can start with default scope copy from the shared catalog bridge, and any edits you make there now follow the estimate through draft reopen, office review, the customer page, and the PDF export. Saved drafts now preserve add-on selections in their editable form. When you reopen a draft estimate, the selected add-ons, option pricing, and manual add-on price changes load back into Step 2 instead of duplicating or resetting. Add-on normalization is also more stable during reopen and resave now. When CE Pro rebuilds the estimate from stored add-on selections plus calculated add-on totals, it matches them by the add-on label instead of relying on raw array order. The stock residential add-ons that offices commonly reuse for detached extras now also ship with default customer-facing scope copy in the shared catalog bridge. Built-in rows such as **Shed**, **Pergola**, **Pool Deck**, **Fireplace (Exterior)**, **Play Set**, **Outdoor Furniture Set**, and **Bring Water** no longer start blank when they flow into shared quote-core line items. Template-based custom items also stay linked to the shared residential price-book bridge more reliably now. If you add a saved custom template and then reopen or resave the estimate later, CE Pro can still map that line back to the shared template definition even though the editable line item keeps its own runtime row id. ### Custom Line Items Click **+ Add Custom Item** to add a line item that is not in your standard service list. Each custom item has: - Description (free text) - Quantity - Unit Price - A delete button to remove it [SCREENSHOT: Custom line item row with description, quantity, unit price fields, and a delete button] ### Maintenance Plan Click **+ Add Maintenance Plan** to open the maintenance plan builder. This lets you create a year-by-year visit schedule with recurring service pricing. [SCREENSHOT: Maintenance plan builder showing visit schedule and yearly pricing] When a residential estimate includes a maintenance plan, the customer portal shows a clear choice between **One-Time Service** and **Maintenance Plan**. Accepting either option now completes the same acceptance workflow behind the scenes, so the estimate status, automations, and follow-up scheduling stay in sync. Accepted maintenance agreements now also seed recurring job templates automatically. CE Pro creates one recurring template per repeating seasonal visit pattern from the accepted maintenance offer, so the office can manage those future visits from **Admin > Jobs > Templates** without rebuilding the schedule manually. If the office edits that accepted maintenance estimate later, CE Pro now resyncs the linked recurring templates from the updated maintenance plan too. That keeps the future recurring schedule aligned with the latest accepted scope instead of leaving the recurring templates on the earlier agreement shape. ### Pricing Panel The right side of the screen shows a running total that updates as you make changes. The panel breaks down: - Per-service pricing - Subtotal before discounts - Package discount (triggers automatically when you select three or more services) - Add-on totals - Custom item totals - Minimum service charge, if the quote is below your configured floor - Taxable amount after discounts - Tax - **Grand Total** If you apply a manual price override to a service, that override is now carried back into the edit flow when you reopen the draft. The Residential Estimate Wizard rebuilds the quote with the saved override instead of reverting to the original calculated price. That same override path now autosaves with the rest of the draft. If you type a new service or add-on price and pause, CE Pro writes the updated amount back to the estimate automatically instead of waiting for a manual draft save from Step 3. When Red Line is enabled, the same pricing panel can also show a running **Rep Commission** block. CE Pro rolls up service commission plus add-on commission in real time, using the red-line floor for services and the configured add-on commission rate for add-ons. The public residential estimator also now merges partial pricing configs with the same default pricing structure the office uses. That keeps customer-facing estimators from dropping service rules just because an older workspace config is missing newly introduced pricing keys. Residential pricing-manager saves now keep the shared default price book in sync too. When the office saves or restores a pricing version, CE Pro mirrors that active residential pricing config into the workspace's default price book immediately so the quote-core pricing layer does not lag behind the Pricing Manager. Shared residential customer links also now preserve the correct public context when they land on the unified quote page. Standard estimate links open the estimate tab, proposal-option links keep their package-selection tracking, and maintenance-plan links keep their maintenance-agreement tracking instead of collapsing every residential customer open into one generic quote-view event. Those residential proposal-option and maintenance-plan reads also now hydrate from the shared offer mirror behind the scenes. That means the public/customer residential pages can keep rendering the correct package and maintenance data even as CE Pro moves those offer structures off the parent estimate JSON and into the shared `estimate_offer_groups` layer. That same shared offer hydration now protects customer package selection, residential send classification, and maintenance-plan PDF reads too. If the rollout has already mirrored the proposal options or maintenance plan into the shared offer layer, CE Pro can still choose the right send path, render the right customer-facing maintenance document, and process the customer’s package selection even while the legacy parent estimate JSON is being phased down. Residential package acceptance now validates against that mirrored shared offer state before it rejects the customer selection too. If the current package options already live in the shared `estimate_offer_groups` layer, customers can still accept the right package even when the older parent estimate JSON has already been trimmed back during the quote-core migration. Customer and office summary surfaces now honor that same mirrored offer layer too. The customer dashboard, customer estimate list, portal proposal lookup, and office estimate list can still classify a residential quote as a package proposal or maintenance offer even after the shared rollout moves that data off the parent estimate row. Those acceptance flows now keep the mirrored child offer quotes aligned too. When a customer accepts a package proposal or maintenance agreement, CE Pro updates the linked offer quote status along with the parent estimate so later send, PDF, recurring-template, and follow-up reads stay aligned to the accepted offer instead of only the compatibility JSON fields changing. [SCREENSHOT: Pricing panel on the right side showing per-service breakdown, package discount, tax, and total] ### Margin Calculator If your organization has cost data configured, the margin calculator appears in the pricing panel. It shows your estimated margin percentage based on your configured labor and material costs versus the quoted price. [SCREENSHOT: Margin calculator showing margin percentage and cost vs. price comparison] Click **Next** to proceed to Step 3. --- ## Step 3 -- Review & Send Review everything before sending. This step shows a read-only summary of the entire estimate. [SCREENSHOT: Step 3 review screen showing the full estimate summary] ### Summary The review screen displays: - Customer name, email, phone - Property address and details - Each selected service with its parameters - Customer-facing service and add-on descriptions exactly as they will appear on the shared estimate page and PDF - Full pricing breakdown with subtotal, visible discount lines, taxable amount, tax, and total - Custom items grouped inside the same estimate breakdown as services and add-ons - Grand Total displayed prominently at the top of the pricing section - The current autosave-backed draft record used for preview, AI review, and send actions [SCREENSHOT: Grand total prominently displayed in the pricing summary] ### Actions Four buttons appear at the bottom of the review screen: | Button | What It Does | | ----------------- | ----------------------------------- | | **Back** | Returns to Step 2 to make changes | | **Save as Draft** | Saves the estimate without sending | | **Preview** | Opens a PDF preview of the proposal | | **Send Estimate** | Opens the send modal | [SCREENSHOT: Action buttons at the bottom of the review screen -- Back, Save as Draft, Preview, Send Estimate] Because the draft autosaves during the earlier steps, Preview, AI Review, and Send now all reuse the same saved estimate record instead of creating separate parallel drafts during review. ### Sending the Estimate Click **Send Estimate** to open the shared review-and-send modal. That same module is now used across residential estimates, generic quotes, holiday lights, fleet proposals, and commercial building proposals. If the workspace is temporarily missing the secure customer-token signing secret, residential records that already have a persisted shared `/quote/[token]` link can still stay interactive. Package selection, maintenance-plan acceptance, custom estimate approval, customer-facing PDFs, and deposit actions now validate against that saved public quote token directly, so the shared quote page keeps working for customers and office previews instead of falling back to a false read-only state. Older signed estimate-only links still depend on the customer-token signing secret. Residential customer links are now converging onto the shared quote page too. When a residential estimate already has a persisted public quote token, the older `/estimate`, `/proposal`, and `/maintenance-proposal` customer links now hand off to the shared `/quote/[token]` experience so customers see the same unified estimate, package-option, and maintenance tabs from one public quote surface. The subject line, email body, and SMS body come pre-filled. You can edit them before sending. For SMS, a character counter shows how close you are to the 160-character limit. Residential sends now also flow through the shared quote-core delivery helper. The office-facing behavior is the same, but CE Pro now records residential send history in `delivery_state`, tracks the last sent customer URL, and writes quote-core `sent` events the same way the generic quote flow already does. Older workspaces that still have the pre-quote-core residential add-on table shape now stay compatible too. Residential estimate saves and residential catalog sync can fall back cleanly even if the legacy `addon_structures` rows do not expose the newer `created_at` column yet, so office users do not get blocked just opening or saving residential quotes during rollout cleanup. Customer-facing residential estimate, proposal, and maintenance pages now also record quote-core `viewed` events in addition to the existing communication and pipeline view tracking. That keeps the shared quote event stream aligned with what customers are actually opening while the public estimate UI is still being consolidated. Residential acceptance is now starting to use that same shared quote-core lifecycle too. Public signatures and accepted-status updates now run through one shared acceptance helper for the accepted event log, webhook dispatch, pipeline move to **Won**, gamification credit, and accepted-estimate automation instead of each residential route owning its own side-effect bundle. Proposal package selection now follows that same accepted-estimate path as well. When a signed customer picks one of the residential proposal options, CE Pro now runs the shared accepted follow-up flow instead of only swapping the selected package totals on the estimate row, which keeps package acceptance aligned with the rest of the quote-core lifecycle. Residential estimate previews and office/customer open actions can now also reuse the shared quote-core `/quote/[token]` page once a saved estimate has a persisted public quote token. The dedicated residential proposal-options and maintenance-plan pages still exist for those specialized offer shapes, but the base residential estimate path is now converging on the same customer quote page the generic builder already uses. Under the hood, residential proposal options and maintenance plans now also mirror into the shared quote-core offer layer as hidden child quotes plus `estimate_offer_groups` / `estimate_offer_members` records. The current proposal and maintenance customer pages still render from the legacy residential JSON for compatibility, but the saved estimate now seeds the shared offer structure needed for the full unified quote-core rollout. [SCREENSHOT: Shared send modal with editable email and SMS copy plus recipient summary] Click **Confirm & Send**. The button shows a loading state while the email and text delivery finish. After sending: - The estimate status changes from **Draft** to **Sent**. - The customer receives the email and, when a phone number is available, the matching text message in the same send action. - If the estimate includes a maintenance plan, the customer can choose either the one-time estimate or the maintenance plan from the portal without losing the acceptance workflow. [SCREENSHOT: Estimate status badge showing "Sent" after successful delivery] --- ## Tips - **Use Auto-fill Property** to save two to three minutes per estimate. Enter the address and ZIP first, then click the button. - **Enable three or more services** to trigger the automatic package discount. This shows the customer the bundled savings. - **Save as Draft** if you need to finish the estimate later. You can return to it from the estimates list. - **Preview the PDF** before sending. This catches formatting issues and pricing errors before the customer sees them. --- ## Troubleshooting ### Auto-fill did not work Make sure both the address and ZIP code are entered before clicking Auto-fill Property. Some rural or new-construction addresses may not have property data available. Enter the details manually in those cases. If CE Pro temporarily cannot verify the shared property-lookup rate limit safely, the button may return a retry-style error instead of filling partial data. Wait a moment and try again rather than assuming the address itself is invalid. ### Pricing looks wrong Check your default pricing in the Pricing Manager. The Residential Estimate Wizard pulls base rates, multipliers, and minimum charges from your pricing configuration. Go to **Settings > Pricing** to verify your defaults. ### Customer did not receive the estimate Verify the customer's email address and phone number. Check that email delivery and SMS delivery are configured correctly in **Settings > Integrations**. Look at the message log for delivery errors. --- URL: https://docs.cleanestimate.pro/getting-started/adding-your-team Title: Adding Your Team Description: Invite team members, assign roles, and control what each person can see and do. Category: getting-started Difficulty: beginner Roles: owner, manager Last updated: 2026-03-19 --- # Adding Your Team CleanEstimate Pro supports multiple users on one account. Each person gets their own login and sees only what their role allows. This guide covers inviting members, understanding roles, and managing your team. --- ## Open the Team Page Open the **Settings** section in the left sidebar, then click **Team**. The Team page shows a table of everyone on your account: their name, email, role, and status. [SCREENSHOT: Team link highlighted in the admin sidebar] [SCREENSHOT: Team page showing the member table with columns for name, email, role, and status] --- ## Invite a New Member Click the **Invite Member** button in the top right corner of the Team page. [SCREENSHOT: Invite Member button in the top right corner of the Team page] A dialog appears with two fields: 1. **Email** — The email address of the person you want to invite. 2. **Role** — A dropdown with five options: Owner, Manager, Sales Rep, Crew Lead, Technician. Fill in both fields. Click **Send Invite**. [SCREENSHOT: Invite Member dialog showing the email field and role dropdown with all five options visible] If the person already has a CleanEstimate Pro login for another workspace, use that same email address. Their access email now brings them straight into the workspace you invited them to, so they do not need to join the public waitlist or create a second account. --- ## Understanding Roles Each role controls what the person can see and do inside the app. Choose the role that matches the person's job. ### Owner Full access to everything. This includes billing, organization settings, deleting the account, and managing other owners. Use this role for business owners and partners. ### Manager Access to everything except billing management and organization deletion. Managers can invite team members, configure pricing, manage clients, and view all reports. Use this role for office managers and operations leads. ### Sales Rep Can create and manage estimates, view clients, work the sales pipeline, and send messages. Cannot access billing, organization settings, or team management. Use this role for salespeople and estimators in the field. ### Crew Lead Can view the job schedule, update job statuses, and view details for assigned jobs. Cannot create estimates or access settings. Use this role for crew supervisors who need to see the day's work. ### Technician Can view today's schedule and update job status for assigned jobs. The most limited role. Use this role for field technicians who only need to check in and out of jobs. --- ## What the Invited Person Sees After you send the invite: 1. The person receives an email from CleanEstimate Pro. 2. They click the link in the email. 3. If they are brand new, they set a password. If they already use CleanEstimate Pro somewhere else, the link signs them into the invited workspace directly. 4. They land on the dashboard for your workspace. If the direct sign-in link cannot be generated for an existing user, the invite now falls back to a recovery-style setup link automatically so the teammate can still get back into the invited workspace without a manual support step. If the teammate has never finished first-time setup and uses **Forgot password** instead of the original invite, CleanEstimate Pro now sends a fresh workspace setup link automatically so they do not get stuck on a generic reset flow that cannot activate the invited workspace. If their original invite link is already expired, the password-setup screen now routes them back to the shared **Forgot password** flow instead of trying to fire another invite directly from the expired-link page. That keeps the recovery path on the same rate-limited email flow used elsewhere in the app. If the first email opens through the short **Finishing Sign-In** handoff and that handoff still needs a retry, the **Need A New Link?** action now keeps the same workspace redirect attached. Teammates who belong to more than one org no longer lose the invited workspace context just because they had to request one more setup email. The dashboard and sidebar show only the pages their role allows. A Sales Rep, for example, sees Estimates, Clients, Pipeline, and Messages. They do not see the **Settings** section or pages like **Billing** and **Team** inside it. [SCREENSHOT: Example email invitation with the setup link] [SCREENSHOT: Sales Rep dashboard showing only the pages visible to that role] --- ## Change a Member's Role Find the person in the team table. Click the **role badge** next to their name. A dropdown appears with all five roles. Select the new role. The change takes effect immediately. The next time that person loads a page, they see updated navigation and permissions. [SCREENSHOT: Role badge clicked on the team table with the role dropdown open] --- ## Remove a Team Member Find the person in the team table. Click the **Remove** button on the right side of their row. A confirmation dialog appears. Click **Confirm** to remove them. They lose access immediately and cannot log back in. [SCREENSHOT: Remove button on a team member row] [SCREENSHOT: Confirmation dialog asking to confirm removal of the team member] Removing a member does not delete their past activity. Estimates they created, messages they sent, and jobs they worked still appear in your records. --- ## Tips - **Start with roles, not names.** Decide which roles your business needs before inviting people. Most small teams need one Owner, one Manager, and a few Sales Reps. - **Use the least access needed.** Give people only the access their job requires. You can always upgrade a role later. - **Check the team page monthly.** Remove people who left. Inactive accounts with access are a security risk. --- URL: https://docs.cleanestimate.pro/getting-started/connecting-integrations Title: Connecting Your Integrations Description: Set up lead intake, payments, messaging, and field-service sync from the integrations area. Category: getting-started Difficulty: beginner Roles: owner Last updated: 2026-04-14 --- # Connecting Your Integrations CleanEstimate Pro connects to the tools you already use. Most teams set up three systems first: - **Meta Lead Ads** for Facebook and Instagram lead forms - **Google Lead Ads** for Google lead forms - **Lead Connectors** for inbound API leads, website forms, and forwarded email lead parsing - **Stripe** for payments and invoicing - **Esendex** for shared SMS and voice - **Workiz** only if they still need legacy sync during CRM cutover --- ## Lead Connectors Lead Connectors are the new shared intake layer for outside lead sources. Use them when you want to bring leads into CE Pro from: - Zapier or Make - your website contact form - middleware or custom CRM bridges - forwarded lead emails that need parsing and review To set them up: 1. Open **Settings > Integrations**. 2. Open the **Lead Connectors** card. 3. Create a connector for the intake source you want to use. 4. Add field aliases and defaults. 5. Run a test import before switching the connector to **Active**. For full setup details, see the [Lead Connectors guide](https://docs.cleanestimate.pro/settings/lead-connectors). --- ## Meta Lead Ads Use **Meta Lead Ads** when you want the easiest path for Facebook and Instagram lead forms. The dedicated Meta page now: - starts the guided Meta login for you - lets you choose the page instead of pasting a page id - subscribes that page to the shared `leadgen` webhook automatically - keeps Meta lead intake on the same duplicate-safe connector pipeline as the rest of CE Pro To set it up: 1. Open **Settings > Integrations**. 2. Open the **Meta Lead Ads** card. 3. Click **Connect Meta**. 4. Approve the Meta login prompt. 5. If you see more than one page, choose the page you want. 6. Submit one real Meta lead form. For the full walkthrough, see [Meta Lead Ads](https://docs.cleanestimate.pro/settings/meta-lead-ads). --- ## Google Lead Ads Use **Google Lead Ads** when you want the easiest path for Google lead forms. The dedicated Google page now: - creates the native Google Ads connector for you - generates the Google verification key - shows the exact webhook URL - keeps Google lead intake on the same duplicate-safe connector pipeline as the rest of CE Pro To set it up: 1. Open **Settings > Integrations**. 2. Open the **Google Lead Ads** card. 3. Optionally add a **Form ID** if you only want one Google form connected. 4. Click **Enable Google Lead Ads**. 5. Copy the CE Pro webhook URL and Google Key into Google Ads. 6. Run Google's webhook test. 7. Submit one real lead form after the test passes. For the full walkthrough, see [Google Lead Ads](https://docs.cleanestimate.pro/settings/google-lead-ads). --- ## Stripe Stripe handles: - online estimate and invoice payments - the billing portal - payment links and invoice settlement To connect it: 1. Open **Settings > Integrations**. 2. Find the **Stripe** card. 3. Click **Connect**. 4. Complete the Stripe authorization flow. For full setup details, see the [Stripe Setup Guide](https://docs.cleanestimate.pro/settings/stripe). --- ## Esendex Esendex handles: - outbound SMS - inbound SMS replies - inbound customer call transfer to your office line - missed-call logging - call-based automation steps Esendex is configured from the **Phone / Voice** card on the main **Settings** page, not from the Integrations tab. To connect it: 1. Open **Settings**. 2. Find **Phone / Voice**. 3. Enter your shared Esendex number. 4. Add your **Esendex SMS License Key**. 5. Add your **Esendex Voice License Key**. 6. Add the forwarding number that should ring first on inbound calls. 7. Save the settings. For full setup details, see the [Esendex Setup Guide](https://docs.cleanestimate.pro/settings/esendex). --- ## Workiz Workiz remains available for teams still using legacy sync during CRM cutover. Use it only if your workspace still needs: - inbound Workiz lead mirroring - legacy estimate or job status sync - outbound Workiz push jobs during migration Open **Settings > Integrations**, then open the **Workiz** card to copy the webhook URL and key. --- ## Next Steps - [Meta Lead Ads](https://docs.cleanestimate.pro/settings/meta-lead-ads) - [Google Lead Ads](https://docs.cleanestimate.pro/settings/google-lead-ads) - [Lead Connectors](https://docs.cleanestimate.pro/settings/lead-connectors) - [Quick Start](https://docs.cleanestimate.pro/getting-started/quick-start) - [Esendex Setup Guide](https://docs.cleanestimate.pro/settings/esendex) - [Stripe Setup Guide](https://docs.cleanestimate.pro/settings/stripe) --- URL: https://docs.cleanestimate.pro/getting-started/your-first-estimate Title: Creating Your First Estimate Description: Step-by-step guide to building and sending a residential estimate to your first customer. Category: getting-started Difficulty: beginner Roles: owner, sales_rep Last updated: 2026-03-27 --- # Creating Your First Estimate This guide walks you through building a residential estimate from scratch: entering the customer, selecting services, and sending the finished proposal. The whole process takes about two minutes. --- ## Start a New Estimate Click the **New Estimate** button in the top navigation bar or the sidebar. The Residential Estimate Wizard opens. It has three steps shown as a progress bar across the top: 1. Client & Property 2. Services & Pricing 3. Review & Send [SCREENSHOT: New Estimate button in the admin navigation bar] [SCREENSHOT: Residential Estimate Wizard open on Step 1 with the three-step progress bar at the top] --- ## Step 1: Client & Property This step collects customer information and property details. ### Customer Information | Field | Required | Notes | |---|---|---| | **Customer Name** | Yes | First and last name. | | **Lead Source** | No | Dropdown: Google, Referral, Facebook, Door Knock, etc. | | **Email** | No | Needed to send the estimate by email. | | **Phone** | No | Needed to send the estimate by SMS. | [SCREENSHOT: Customer information fields at the top of Step 1] ### Property Details | Field | Notes | |---|---| | **Address** | Start typing and select from the Google Places autocomplete dropdown. | | **City, State, ZIP** | Auto-filled when you select an address from autocomplete. | | **Property Sqft** | Auto-fills from property lookup. You can override it. | | **Stories** | Select 1, 2, or 3. Affects multipliers. | | **Lot Size** | Square footage of the lot. | | **Year Built** | Helps estimate condition. | | **Roof Sqft** | Auto-fills if available. Override as needed. | | **Gutter Linear Ft** | Estimated linear feet of gutter. | | **Siding Type** | Dropdown: Vinyl, Brick, Stucco, Wood, Hardie, etc. | | **Roof Type** | Dropdown: Asphalt, Metal, Tile, Slate. Affects roof cleaning multiplier. | After entering the address, click **Auto-fill Property**. The system pulls public property records and fills in square footage, stories, year built, and roof details when available. [SCREENSHOT: Address field with Google Places autocomplete dropdown visible] [SCREENSHOT: Property details section with Auto-fill Property button highlighted] Review the auto-filled values. Adjust anything that looks off. Click **Next** to continue. [SCREENSHOT: Step 1 completed with all fields filled in and the Next button at the bottom right] If you launch **New Estimate** from a client shortcut that includes `client_id`, the wizard now preloads that client and keeps the finished estimate linked to the same CRM record instead of trying to re-create the customer during save. --- ## Step 2: Services & Pricing This step is where you build the scope of work and see the price update in real time. ### Selecting Services Each service has a toggle switch. Turn on the services the customer needs: - House Wash - Windows - Gutters - Roof Cleaning - Driveway - Sidewalks - Deck / Patio - Fence When you toggle a service on, its detail fields appear. Fill in the specifics. [SCREENSHOT: Services section with House Wash and Driveway toggled on, showing their detail fields] ### Service-Specific Fields Each service shows fields relevant to that job. Examples: - **House Wash** — Square footage, stories, dirtiness level. - **Windows** — Number of windows, interior + exterior toggle. - **Driveway** — Square footage. - **Gutters** — Linear feet. ### Dirtiness Level For applicable services, select a dirtiness level: **Light**, **Moderate**, or **Heavy**. This adjusts the price based on the extra time and materials needed. [SCREENSHOT: Dirtiness level selector showing Light, Moderate, and Heavy options] ### Add-Ons Below the main services, an **Add-Ons** section lists optional extras. Toggle any that apply. [SCREENSHOT: Add-Ons section with toggle switches] ### Custom Line Items Need something not on the list? Click **+ Add Custom Item**. Enter a Description, Quantity, and Unit Price. The item adds to the total. [SCREENSHOT: Custom Line Items section with the + Add Custom Item button and a filled-in custom row] ### Maintenance Plan Toggle the **Maintenance Plan** option to offer recurring service. The plan uses the discount percentages you set in the Pricing Manager. [SCREENSHOT: Maintenance Plan toggle and summary card] ### Running Total The right panel shows a running price breakdown as you add services. It updates instantly. [SCREENSHOT: Right panel showing the itemized running total with subtotal, tax, and total] Click **Next** when the scope and price look right. --- ## Step 3: Review & Send This step shows everything in one view so you can verify before sending. ### Review Summary You see the customer name, property address, a full list of services with prices, add-ons, custom items, subtotal, tax, and total. [SCREENSHOT: Review & Send step showing the full estimate summary] ### Your Options You have three buttons at the bottom: | Button | What It Does | |---|---| | **Save as Draft** | Saves the estimate without sending. Find it later on the Estimates page. | | **Preview** | Opens a PDF preview so you can see exactly what the customer receives. | | **Send Estimate** | Opens the send dialog. | [SCREENSHOT: Save as Draft, Preview, and Send Estimate buttons at the bottom of Step 3] Successful first-time draft saves now stay on the happy path even if the database write finishes before the API can hydrate the full saved row back into the response. In that edge case, CE Pro reloads the saved estimate summary instead of showing a false server-error toast after the draft is already stored. ### Sending the Estimate Click **Send Estimate**. A dialog opens with these options: - **Delivery Method** — Toggle between Email, SMS, or Both. - **Subject** — Pre-filled. Edit if you want. - **Message Body** — Pre-filled with a professional template. Edit to personalize. - **Send** — Sends the estimate. [SCREENSHOT: Send Estimate dialog showing delivery method toggle, subject, message body, and Send button] Click **Send**. The estimate is queued for delivery and moves to "Sent" status on your Estimates page. The estimate record moves to **Sent** immediately. PDF generation, email delivery, SMS delivery, linked maintenance proposal sends, and any connected legacy sync tasks continue in the background and may take a short moment to finish. If secure estimate links are not configured yet, CE Pro still lets the office send the email with the PDF attached. In that case the send step shows a warning that the online browser link is unavailable instead of failing the entire send action. --- ## What the Customer Receives ### By Email The customer gets an email with: - A summary of services and prices. - A PDF attachment of the full estimate. - A **View Full Estimate** button that opens the estimate in their browser. [SCREENSHOT: Example customer email showing the service breakdown, PDF attachment, and View Full Estimate button] ### By SMS The customer gets a text message with a short summary and a link to view the full estimate online. [SCREENSHOT: Example SMS message with the estimate link] --- ## After Sending Once sent, you can track the estimate from the **Estimates** page. You see its status: Draft, Sent, Viewed, Accepted, Declined, or Expired. Behind the scenes, delivery work can move through these async states: - **Queued** -- CE Pro accepted the send request and is preparing PDF, email, SMS, and sync tasks. - **Processing** -- One or more background delivery tasks are currently running. - **Sent** -- All queued delivery tasks finished successfully. - **Failed** or **Partial Failure** -- At least one delivery task needs attention. Open the estimate detail page when you are ready to collect money. The **Payments** card on the estimate lets you: - Record a deposit - Charge a keyed credit card through Stripe - Send a Stripe pay link - Record cash, check, or bank transfer - Split the balance into multiple payments The estimate detail page also includes: - **Photos** for before, during, and after image sets - **Attachments** for extra photos, PDFs, permits, contracts, and scope documents - **Assigned Rep** controls so office staff can reassign the estimate to another active workspace member - **Appointment scheduling** so owners and managers can set or reschedule an on-site estimate visit - **View Job** once the estimate has been converted - **View Invoice** once billing has been created from the estimate - **Delete Estimate** in the detail page danger zone for drafts, test records, or mistakes If attachments have not been enabled in the workspace database yet, the detail page now shows a setup notice instead of a fatal error toast. Attachment and photo reads now use the same plain-language error handling too. If uploads or estimate-detail media loads fail, the office team sees a cleaner action/setup message instead of raw storage or database text. Estimate attachments now support images, PDFs, TXT and CSV files, plus common Word, Excel, and PowerPoint documents. The upload is checked before it is saved, so renamed or mismatched files are rejected instead of quietly landing on the estimate. Estimate appointments now reject past dates and invalid time windows before they save. Estimate rep reassignment also verifies that the selected user still belongs to the active workspace, so an archived or cross-org user cannot be assigned accidentally. Owners and managers can delete any estimate. Sales reps can delete only estimates assigned to them. If an estimate has already been converted into a job, CE Pro blocks the delete until that job is removed first. [SCREENSHOT: Estimates list page showing an estimate with "Sent" status badge] --- ## Next Steps - [Setting Up Your Default Pricing](https://docs.cleanestimate.pro/getting-started/setting-up-pricing) — Fine-tune your rates. - [Adding Your Team](https://docs.cleanestimate.pro/getting-started/adding-your-team) — Let your sales reps create estimates too. --- URL: https://docs.cleanestimate.pro/getting-started/quick-start Title: Quick Start - Your First 15 Minutes Description: Set up your account, configure pricing, and send your first estimate in under 15 minutes. Category: getting-started Difficulty: beginner Roles: owner, manager Last updated: 2026-04-23 --- # Quick Start - Your First 15 Minutes This guide walks you through the eight steps to go from a fresh account to a sent estimate. Most owners finish in under 15 minutes. --- ## Step 1: Log In for the First Time Go to `/login`. Enter the email and password you used when you signed up. Click **Log In**. ![Login page showing email and password fields with the Sign In button](https://docs.cleanestimate.pro/screenshots/getting-started/login-page.png) You land on the admin dashboard at `/admin/`. This is your home base. ![Admin dashboard after first login](https://docs.cleanestimate.pro/screenshots/getting-started/admin-dashboard.png) The **Create New** menu in the Quick Start section of the sidebar gives you direct entry points for the five most common records: **Lead**, **Client**, **Estimate**, **Job**, and **Invoice**. --- ## Step 2: Set Up Your Business Profile Click **Settings** in the left sidebar. You see a **Company Information** card at the top of the page. Fill in: - **Name** - Your business name as customers see it. - **Phone** - Your main business phone number. - **Email** - The email customers reply to. - **Website** - Your business website URL. - **Address, City, State, ZIP** - Your business address. This prints on estimates and invoices. Click **Save Changes**. ![Company Information card on the Settings page](https://docs.cleanestimate.pro/screenshots/getting-started/settings-company-info.png) --- ## Step 3: Configure Default Pricing Click **Pricing** in the left sidebar to open the Pricing Manager. You see accordion sections for each service: House Wash, Windows, Driveway, and more. Expand each section and enter your rates. Every section has a Base Price, Price per unit, and Minimum Price. Do not worry about getting everything perfect. You can change rates later without affecting estimates you already sent. Click **Save & Activate** when you finish. The save flow now validates the pricing version before it goes live, so malformed percentages, negative pricing values, or invalid maintenance-plan visit counts are rejected instead of creating a broken active pricing version. ![Pricing Manager page with service accordion sections](https://docs.cleanestimate.pro/screenshots/getting-started/pricing-manager.png) For a full walkthrough, see [Setting Up Your Default Pricing](https://docs.cleanestimate.pro/getting-started/setting-up-pricing). --- ## Step 4: Set Up Services and Add-Ons Click **Services** in the left sidebar. This page lets you define which services appear in your estimator, what add-on structures are available, and which custom item templates your office can reuse. Add or edit services with a clean internal slug, category, optional crew-hours default, and the correct quantity requirements. Add-on structures and custom item templates also validate their names, prices, sort order, and units before they save. If a save fails, the page now keeps the dialog open and shows the validation or setup error instead of closing and pretending the change worked. ![Services page with service toggles and add-on section](https://docs.cleanestimate.pro/screenshots/getting-started/services-page.png) --- ## Step 5: Connect Stripe You need Stripe to accept online payments and send invoices. 1. Go to **Settings** in the sidebar. 2. Click the **Integrations** tab. 3. Find the **Stripe** card. 4. Click **Connect**. 5. Follow the Stripe prompts to link your account. ![Integrations tab with Stripe Connect button](https://docs.cleanestimate.pro/screenshots/getting-started/integrations-stripe.png) Once connected, the card shows a green "Connected" badge. --- ## Step 6: Configure Phone / Voice You need a telecom provider to send SMS estimates, receive customer replies, and route customer calls. Most new workspaces use Esendex; legacy workspaces may still use Twilio. 1. Go to **Settings** in the sidebar. 2. Open the **Phone / Voice** card. 3. Choose **Esendex** or **Twilio** in the **Telecom Provider** selector. 4. Save the workspace phone number in E.164 format, for example `+17177440798`. 5. Add the required provider credentials. 6. Click the matching provider save button. See [Connecting Esendex](https://docs.cleanestimate.pro/settings/esendex) or [Connecting Twilio](https://docs.cleanestimate.pro/settings/twilio) for provider-specific setup. --- ## Step 7: Create and Send Your First Estimate Click the **New Estimate** button in the top navigation or sidebar. The Residential Estimate Wizard opens with three steps: Client & Property, Services & Pricing, and Review & Send. Fill in your customer details, pick services, review the total, and hit **Send Estimate**. For the full walkthrough, see [Creating Your First Estimate](https://docs.cleanestimate.pro/getting-started/your-first-estimate). ![New Estimate button in the admin navigation](https://docs.cleanestimate.pro/screenshots/getting-started/new-estimate-button.png) --- ## Step 8: Invite Your First Team Member Open the **Settings** section in the left sidebar and click **Team**. Then click the **Invite Member** button in the top right corner. A dialog opens. Enter the team member's email address. Select a role from the dropdown: Owner, Manager, Sales Rep, Crew Lead, or Technician. Click **Send Invite**. They receive an email with instructions to set their password and log in. ![Invite Member dialog with email field and role dropdown](https://docs.cleanestimate.pro/screenshots/getting-started/invite-member-dialog.png) For details on roles and permissions, see [Adding Your Team](https://docs.cleanestimate.pro/getting-started/adding-your-team). --- ## What's Next That's it - you're ready to send estimates. Next: [Your First Estimate](https://docs.cleanestimate.pro/getting-started/your-first-estimate). --- URL: https://docs.cleanestimate.pro/getting-started/setting-up-pricing Title: Setting Up Your Default Pricing Description: Configure per-service rates, multipliers, package tiers, and maintenance plan discounts. Category: getting-started Difficulty: beginner Roles: owner, manager Last updated: 2026-04-21 --- # Setting Up Your Default Pricing The Pricing Manager is where you define rates for every service you offer. These rates feed into the estimator so you get consistent, accurate pricing on every job. Under the quote-core price-book rollout, CE Pro now treats pricing in two layers: one shared default price book that can serve as the baseline across every workspace, and a workspace-specific default book for any organization that needs its own custom rates or catalog changes. That means a custom pricing change made in one organization stays private to that organization. The shared default book can still be used as the starting point, but org-specific edits do not leak into another workspace's pricing. The current rollout now treats those org books as overrides on top of the shared baseline instead of forcing a full clone before every read. If one workspace customizes a service, CE Pro keeps showing that workspace's override for that one item while the rest of the untouched catalog still falls back to the shared default book. That shared fallback also stays intact during background repair and sync work. If CE Pro needs to refresh an org-specific catalog bridge, it still resolves untouched shared baseline items from the platform default book instead of temporarily hiding them from that workspace. Pricing saves now also dual-write the active residential config into the workspace's shared default price book. That keeps the quote-core price-book layer current right after **Save & Activate** or a version restore, instead of waiting for a later background repair before the shared system sees the new rates. Existing workspaces keep that same active residential pricing during the rollout too. When the shared price-book settings layer backfills onto an older org, CE Pro now preserves the saved residential pricing config under the same nested key the quote-core readers use instead of falling back to the platform defaults. The shared default price book also now carries the live asphalt maintenance catalog. That baseline includes single-coat and double-coat sealcoat items plus crack fill, line striping refresh, and patch repair add-ons. Workspaces can still override those asphalt items privately in their own default book without affecting other organizations. --- ## Opening the Pricing Manager Click **Pricing** in the left sidebar. The Pricing Manager page loads with collapsible accordion sections for each service. [SCREENSHOT: Pricing link highlighted in the admin sidebar] [SCREENSHOT: Pricing Manager page with accordion sections collapsed] --- ## Service Sections Each service has its own accordion section. Expand a section by clicking its header. Fill in the fields and move to the next one. ### House Wash | Field | What It Means | |---|---| | **Base Price** | Starting price before square footage is calculated. | | **Price per sqft** | Rate multiplied by the home's square footage. | | **Minimum Price** | The lowest price you will charge, even for small homes. | | **2-Story Multiplier** | Percentage added for two-story homes (e.g., 1.3 = 30% more). | | **3-Story Multiplier** | Percentage added for three-story homes. | [SCREENSHOT: House Wash accordion expanded showing Base Price, Price per sqft, Minimum Price, and story multiplier fields] ### Windows | Field | What It Means | |---|---| | **Per Window (Exterior)** | Price for exterior-only cleaning per window. | | **Per Window (Interior + Exterior)** | Price for full cleaning per window. | | **Screen Removal** | Add-on price per screen removed and cleaned. | | **Minimum Price** | Lowest window-cleaning charge. | [SCREENSHOT: Windows accordion expanded showing per-window pricing fields] ### Driveway | Field | What It Means | |---|---| | **Price per sqft** | Rate per square foot of driveway surface. | | **Minimum Price** | Lowest driveway charge. | [SCREENSHOT: Driveway accordion expanded] ### Sidewalks | Field | What It Means | |---|---| | **Price per linear ft** | Rate per linear foot of sidewalk. | | **Minimum Price** | Lowest sidewalk charge. | [SCREENSHOT: Sidewalks accordion expanded] ### Roof Cleaning | Field | What It Means | |---|---| | **Price per sqft** | Base rate per square foot of roof area. | | **Minimum Price** | Lowest roof cleaning charge. | | **Asphalt Multiplier** | Adjustment for asphalt shingle roofs. | | **Metal Multiplier** | Adjustment for metal roofs. | | **Tile Multiplier** | Adjustment for tile roofs. | | **Slate Multiplier** | Adjustment for slate roofs. | | **Half Roof Multiplier** | Adjustment when cleaning only half the roof. | [SCREENSHOT: Roof Cleaning accordion expanded showing material multipliers] ### Gutter Cleaning | Field | What It Means | |---|---| | **Price per linear ft** | Rate per linear foot of gutter. | | **Minimum Price** | Lowest gutter cleaning charge. | [SCREENSHOT: Gutter Cleaning accordion expanded] ### Deck, Patio, and Fence These sections follow the same pattern: price per square foot or linear foot and a minimum price. [SCREENSHOT: Deck/Patio/Fence accordion sections] --- ## Package Tiers Scroll below the service sections to find **Package Tiers**. Package tiers let you offer bundled discounts when a customer selects multiple services. Each tier has: - **Name** — A label customers see, like "Gold" or "Full Property." - **Description** — A short note about what the tier includes. - **Min Services** — The number of services a customer must select to qualify. - **Discount %** — The percentage discount applied to the total. Click **+ Add Tier** to create a new tier. Click the trash icon to remove one. [SCREENSHOT: Package Tiers section showing two tiers with name, description, min services, and discount fields, plus the + Add Tier button] --- ## Maintenance Plan Defaults Below Package Tiers you find **Maintenance Plan** settings. These apply when a customer opts into a recurring service agreement. | Field | What It Means | |---|---| | **All-Visit Discount %** | Discount applied to every visit in the plan. | | **Multi-Year Discount %** | Additional discount for multi-year commitments. | | **Default Visits/Year** | How many visits per year the plan includes by default. | [SCREENSHOT: Maintenance Plan section with discount and visit fields] --- ## Global Settings At the bottom of the page you find three global fields: - **Global Minimum Ticket** — The absolute lowest total you will charge for any estimate. - **Estimate Expiry Days** — How many days before an unsent estimate expires. - **Tax Rate %** — Default tax rate applied to estimates. [SCREENSHOT: Global Settings section with minimum ticket, expiry days, and tax rate fields] --- ## Red Line Settings If your sales team uses Red Line pricing, open the **Red Line** accordion in Pricing Manager. This section controls the floor-pricing model that sits on top of the normal residential calculator. The floor is not a separate flat-price table. CE Pro first calculates the suggested service price from the service inputs, then applies your configured floor percentage to that suggested price. Use these fields: - **Enable Red Line** -- turns the feature on or off for the workspace. - **Enable Rehash Department** -- adds the residential win-back queue, templates, and recovered-close attribution layer on top of Red Line. - **Enable Rehash template A/B testing** -- alternates the seeded Rehash templates automatically and unlocks template-variant reporting in Rehash analytics. - **Auto-enroll unsold quotes** -- starts the staged Rehash sequence automatically when an unsold residential quote is saved with an active disposition. - **Enable Day 21 auto-discount** -- allows the built-in 10% Day 21 offer when the saved Red Line floors still hold. - **Enable Day 90 final offer** -- allows the built-in 15% Day 90 final-offer message when that offer still stays above floor. - **Show commissions to reps** -- controls whether sales reps see their live commission while pricing. - **Enable manager override tracking** -- lets residential estimates save a below-floor draft, creates manager-approval requests from the estimator, and blocks sending until an override is approved. - **Allow commission exports** -- unlocks payroll-ready commission CSV exports from the Commissions dashboard, including recovered Rehash split payouts. - **Default Floor %** -- fallback floor percentage for any service without its own override. - **Per-Service Floor %** -- lets you set a different floor percentage for house wash, roof cleaning, driveway, and the other residential services. - **Service Base Commission %** -- paid on the sold price when the rep is at or below the floor. - **Service Upside Commission %** -- paid on the dollars above the floor. - **Add-On Commission %** -- paid on residential add-ons. - **Near Floor Threshold %** and **Healthy Upside Threshold %** -- drive the status labels shown in the estimator. Rehash is a residential-only bolt-on in this rollout. The queue, staged messaging, and recovered-close attribution do not apply to commercial or fleet estimates. If the Rehash page ever opens with a setup warning instead of the queue, the workspace is missing part of the latest Rehash database rollout. Apply the latest migrations, then refresh the page. [SCREENSHOT: Red Line accordion in Pricing Manager showing workspace toggles, commission settings, and per-service floor percentages] --- ## Preview Panel On the right side of the page, a blue preview card shows a sample calculation. It uses a 2,000 sqft, 2-story home with moderate dirtiness. As you change rates, the preview updates in real time. Use it to gut-check your numbers before saving. [SCREENSHOT: Blue preview card showing a sample estimate calculation for a 2,000 sqft 2-story home] --- ## Saving Your Pricing Click **Save & Activate** at the bottom of the page. Your new rates apply to all future estimates immediately. Changing rates does **not** affect estimates you already sent. Sent estimates keep the rates they were created with. The save now validates the pricing payload before it creates a new version. In practice, that means malformed percentages, negative pricing values, invalid visit counts, or incomplete package rows are rejected before a broken pricing version can go live. Under the hood, CE Pro now keeps the active pricing version mirrored into the workspace's default price book as part of that same save flow. If the shared price-book sync cannot complete, CE Pro restores the previous active pricing version instead of leaving the office pricing screen and the unified quote-core price book out of sync. [SCREENSHOT: Save & Activate button at the bottom of the Pricing Manager] --- ## Version History Below Save & Activate, the **Version History** section shows every past pricing configuration. Each entry shows the date it was saved and who saved it. Click **Restore** next to any version to roll back to those rates. The restored version becomes a new entry at the top. Restore actions only accept real saved version numbers, so stray or malformed restore requests no longer flip the active config accidentally. Restore actions now keep the shared default price book aligned too, so the unified quote-core pricing layer immediately reflects the restored version instead of lagging behind the active pricing manager entry. [SCREENSHOT: Version History section showing past versions with Restore buttons] --- ## Tips - **Start with your most common service.** Get House Wash dialed in first, then move to the others. - **Adjust after a few estimates.** Send three to five estimates and see how they land before fine-tuning. - **Use the preview panel.** It catches mistakes before your customers do. - **Set your minimums.** A low minimum erodes profit on small jobs. Make sure every truck roll is worth your time. --- URL: https://docs.cleanestimate.pro/marketing/campaigns Title: Email and SMS Marketing Campaigns Description: Create, schedule, and analyze targeted email and SMS campaigns with audience segmentation, drip sequences, and win-back templates. Category: marketing Difficulty: intermediate Last updated: 2026-03-18 --- # Email and SMS Marketing Campaigns The Campaigns module lets you send targeted email and SMS messages to segments of your customer base. You can send one-time blasts, build multi-step drip sequences, and set up triggered campaigns that fire automatically on customer events. Open **More > Marketing** from the admin sidebar to get started. > During the current tester rollout, full marketing access is limited to the approved workspace. Other workspaces can still review existing campaigns and promotions in read-only mode, but they cannot create, edit, activate, delete, or send from the Marketing area until access is enabled for that workspace. [SCREENSHOT: Marketing Campaigns page showing the campaign list with status badges] --- ## Campaign List The main Marketing page displays all campaigns in a table view. Each row shows the campaign name, status badge, channel, audience size, messages sent, and open rate (email only). | Column | Description | |--------|-------------| | **Name** | The campaign name you assigned | | **Status** | Draft, Active, Paused, or Completed | | **Channel** | Email Only, SMS Only, or Email + SMS | | **Audience** | Number of recipients matching the audience filter | | **Sent** | Total messages delivered | | **Open Rate** | Percentage of email recipients who opened the message | Click any campaign row to open its detail page for editing, sending, or reviewing performance. [SCREENSHOT: Campaign list showing three campaigns with different statuses] --- ## Creating a Campaign 1. Click the **New Campaign** button in the upper right corner. 2. Enter a **Campaign Name** -- use something descriptive like "Spring 2026 House Wash Promo." 3. Select a **Campaign Type** (see below). 4. Choose the **Channel**: Email Only, SMS Only, or Email + SMS. 5. Configure your **Audience** using the audience builder. 6. Set the **Schedule** -- send now or schedule for a future date and time. 7. Compose your message content. 8. Click **Save Draft** to save without sending, or **Send Now** to deliver immediately. Campaign draft saves now validate the request before anything is stored. If you choose **Schedule**, you must provide a send date and time, and malformed drip-step payloads are rejected instead of saving a partial draft. [SCREENSHOT: New Campaign form showing name, type selector, and channel buttons] ### Campaign Types CE Pro supports three campaign types. Select the one that matches your goal. | Type | Description | Use Case | |------|-------------|----------| | **One-Time** | Sends a single message to the selected audience | Seasonal announcements, special offers, new service launches | | **Drip** | Sends a multi-step sequence with configurable delays between steps | Win-back sequences, onboarding flows, post-service follow-ups | | **Triggered** | Sends automatically when a customer event occurs | Automated responses to proposal declines, service completions | For one-time and triggered campaigns, you compose a single email and/or SMS template. For drip campaigns, you build a full sequence of steps using the drip sequence builder. ### Channel Options | Channel | What Gets Sent | |---------|----------------| | **Email Only** | An HTML email with subject line, body, merge fields, and optional CTA button | | **SMS Only** | A plain text SMS message (160-character single segment, or multi-segment for longer messages) | | **Email + SMS** | Both an email and an SMS are sent. For one-time campaigns, each channel gets its own template | --- ## Audience Builder The audience builder determines which customers receive your campaign. Filters combine with AND logic -- a customer must match all active filters to be included. A live audience counter in the upper right corner of the Audience Targeting card updates automatically as you adjust filters. This shows you exactly how many customers will receive the campaign before you send it. [SCREENSHOT: Audience builder with filters applied showing a live count of 142 matching clients] ### Primary Audience Filter Start by selecting a primary audience type: | Primary Filter | Description | |----------------|-------------| | **All Customers** | Every customer in your CRM | | **By Service History** | Customers who have (or have not) purchased specific services | | **By Last Service Date** | Customers whose last service was more than N days ago | | **By Proposal Status** | Customers with proposals in a specific status (declined, expired, sent, viewed, accepted) within a lookback window | | **By Location (Zip Code)** | Customers in specific ZIP codes | ### Additional Filters Layer these filters on top of your primary audience to narrow the targeting further. **Services Purchased** - **Must have purchased any of** -- select one or more services (house wash, roof wash, driveway, deck wash, fence, gutter cleaning, window cleaning, holiday lights). Customers who have purchased at least one of the selected services are included. - **Must not have purchased** -- exclude customers who have purchased certain services. Useful for targeting customers who have never tried a specific offering. **Client Spend and Recency** | Filter | Description | |--------|-------------| | **No service in at least (months)** | Include customers whose last service was at least this many months ago | | **Days since service** | Legacy filter -- same concept measured in days instead of months | | **Lifetime spend at least** | Only include customers who have spent at least this dollar amount over their history | | **Lifetime spend at most** | Cap the audience to customers under a certain lifetime spend threshold | **Maintenance Plan Status** Filter by whether a customer has an active maintenance plan, an expired plan, or no plan at all. **Property Type** Filter by property type: residential, commercial, fleet, or holiday lights. **Client Health** Filter by the system-calculated health status: | Status | Meaning | |--------|---------| | **Active** | Customer has had recent service and is engaged | | **At Risk** | Customer engagement is declining | | **Dormant** | Customer has not had service in an extended period | | **New** | Recently added customer with no service history | **Lead Sources** Type a lead source name and press Enter or click **Add** to include it. Remove a source by clicking its badge. This lets you target customers who came from specific channels (Google, referrals, Angi, etc.). **Zip Codes / Service Area** Add specific ZIP codes to restrict the audience geographically. Type a ZIP code and press Enter or click **Add**. **Client Tags** Add custom tags you have applied to clients. A set of suggested tags is displayed for quick selection: VIP, Commercial, Fleet, Property Manager, Repeat Client, Referral Source, Maintenance Plan, HOA, and several more. **Estimate Status** Filter by the status of customer estimates: sent, viewed, accepted, declined, or expired. Combine with a **Proposal lookback days** value to limit to recent proposals. --- ## Scheduling For one-time and triggered campaigns, you choose when to send: - **Send Now** -- the campaign is delivered immediately when you click Send Now. - **Schedule** -- select a future date and time. The campaign is queued and sent automatically at the scheduled time. Drip campaigns do not use the schedule selector. Instead, they send automatically based on the delay configured on each step. If you switch a campaign to **Schedule**, the draft must include a valid date/time before it can be saved. This prevents "scheduled" drafts from being stored without an actual send window. Active drip campaigns are evaluated hourly in the background. Each due drip step is claimed before sending so overlapping scheduler runs do not send the same step twice. Due recipients inside the same drip campaign are now processed in parallel once their step is claimed. That helps large campaigns catch up faster after a scheduler delay without changing the duplicate-protection rules on each message record. [SCREENSHOT: Schedule card showing the Send Now and Schedule buttons with a datetime picker] --- ## Email Template Editor The email editor provides a subject line field and an HTML body field. You write templates using standard HTML and merge fields. ### Merge Fields Click any merge field badge above the editor to insert it at the cursor position. Available merge fields: | Merge Field | Inserts | Example | |-------------|---------|---------| | `{{first_name}}` | Customer's first name | John | | `{{company}}` | Your business name | Rolling Suds | | `{{last_service_date}}` | Date of the customer's most recent service | 01/15/2026 | | `{{promo_code}}` | An attached promotional code | SPRING25 | ### CTA Button Click the **+ CTA Button** link to insert a pre-styled call-to-action button into your email body. The button renders as a blue, rounded link that works across major email clients. Edit the button text and URL in the HTML after inserting it. ### Preview Mode Click **Preview** in the template editor header to toggle between edit and preview modes. Preview mode renders the HTML and replaces all merge fields with sample data so you can see exactly what customers will receive. [SCREENSHOT: Email template editor showing subject line and body with merge fields, plus the preview toggle] --- ## SMS Composer The SMS composer provides a single text field for your message. Key features: - **Character counter** -- displays current character count out of the 160-character single-segment limit. - **Segment indicator** -- if your message exceeds 160 characters, a badge shows the number of SMS segments. Multi-segment messages use 153 characters per segment and cost more. - **Merge fields** -- the same merge field badges are available. Click to insert at the end of your message. - **Live preview** -- a preview box below the editor shows the message with merge fields replaced by sample data. Keep SMS messages short and focused on a single action: reply, call, or click a link. [SCREENSHOT: SMS composer showing a short message with a merge field and the character counter] --- ## Drip Sequences When you select the **Drip** campaign type, the single template editors are replaced by the drip sequence builder. A drip sequence sends multiple messages over time, with configurable delays and optional conditions between steps. ### Visual Timeline A visual timeline at the top of the builder shows all steps as colored pills (blue for email, green for SMS) connected by lines with delay indicators. This gives you an at-a-glance view of the full customer journey. [SCREENSHOT: Drip sequence builder visual timeline showing three steps with delays] ### Adding and Configuring Steps 1. Click **+ Add Step** to add a new step to the sequence. 2. For each step, configure: | Setting | Options | |---------|---------| | **Channel** | Email or SMS | | **Delay from previous** | 1, 3, 7, 14, or 30 days (preset buttons), or enter a custom number | | **Condition** (steps 2+) | Always send, If opened previous, If NOT opened previous, If clicked previous, If NOT clicked previous | | **Subject** (email only) | The email subject line | | **Body** | The email HTML body or SMS text | 3. Reorder steps using the up/down arrows on each step card. 4. Remove a step by clicking **Remove**. Each step save is now validated as a full structured list. Invalid step numbers, invalid delay values, or malformed conditional logic are rejected before the sequence replaces the existing draft. ### Conditional Logic Starting from step 2, you can add conditions that determine whether a step sends based on the recipient's interaction with the previous step: - **Always send** -- the step sends regardless of previous engagement. - **If opened previous** -- only sends to recipients who opened the previous email. - **If NOT opened previous** -- only sends to recipients who did not open the previous email. Useful for re-sending with a different subject line. - **If clicked previous** -- only sends to recipients who clicked a link in the previous email. - **If NOT clicked previous** -- only sends to recipients who did not click. This lets you build branching sequences that adapt to customer behavior. ### Example Drip Sequence A typical declined-proposal win-back sequence: | Step | Day | Channel | Condition | Purpose | |------|-----|---------|-----------|---------| | 1 | Day 7 | Email | -- | Initial follow-up asking if they have questions | | 2 | Day 14 | SMS | Always send | Short reminder to revisit their estimate | | 3 | Day 30 | Email | If NOT opened step 1 | Final message with a different subject line | --- ## Win-Back Templates CE Pro includes four pre-built win-back templates for common re-engagement scenarios. Access them from the Marketing page. ### Available Templates | Template | Trigger | Description | |----------|---------|-------------| | **We Miss You!** | No service in 90 days | Re-engage dormant customers with a friendly check-in | | **Seasonal Reminder** | Seasonal reminder | Remind existing customers that spring or fall cleaning season has arrived | | **Declined Proposal Follow-Up** | Declined proposals | A 3-step drip sequence (7/14/30 days) for customers who declined or let proposals expire | | **Referral Request** | Post-service referral | Ask satisfied customers to refer friends after a recent service | ### Using a Template 1. On the Marketing page, scroll to the **Win-Back Templates** section. 2. Click **Preview** on any template to expand it and see the email subject, SMS text, and drip steps (if applicable). 3. Click **Activate** to create a new campaign from the template. 4. The system creates a draft campaign with the template's audience filter, channel settings, and message content pre-filled. 5. You are redirected to the campaign editor where you can customize the text, adjust the audience, and send. Each template comes with a sensible default audience. For example, the "We Miss You!" template automatically targets customers with no service in the last 90 days. Edit the audience filter if you want different criteria. [SCREENSHOT: Win-back template cards showing the four templates with Preview and Activate buttons] --- ## Campaign Lifecycle Campaigns move through the following statuses: | Status | Description | Available Actions | |--------|-------------|-------------------| | **Draft** | Campaign is saved but not sent. All fields are editable. | Save Draft, Send Now | | **Active** | Campaign is currently sending or a drip sequence is in progress. | Pause | | **Paused** | A drip sequence has been paused mid-run. No further steps are sent. | Resume | | **Completed** | All messages have been sent and the campaign is finished. | View stats | - **Pause** stops a running drip campaign. Recipients who have already received messages keep them, but no further steps are sent. - **Resume** restarts a paused drip campaign from where it left off. --- ## Campaign Analytics After a campaign is sent, the detail page displays a performance dashboard with these metrics: | Metric | Description | Good Benchmark | |--------|-------------|----------------| | **Messages Sent** | Total messages delivered across all channels | -- | | **Open Rate** | Percentage of email recipients who opened the message | Above 20% (highlighted green) | | **Click Rate** | Percentage of recipients who clicked a link in the message | Above 5% (highlighted green) | | **Conversions** | Number of recipients who booked a service after receiving the campaign | Any conversion is highlighted green | | **Conversion Rate** | Percentage of recipients who converted to a booked job | Above 2% (highlighted green) | | **Total Queued** | Total messages queued for delivery (shown for in-progress campaigns) | -- | [SCREENSHOT: Campaign performance dashboard showing five metric cards with percentages] ### Interpreting Results - **Low open rate (below 20%)** -- your subject line is not compelling enough, or your messages are landing in spam. Try a more specific, benefit-driven subject line. - **Good open rate but low click rate (below 5%)** -- customers are reading but not acting. Strengthen your call to action and make the next step clear. - **Good clicks but low conversions** -- the landing experience may need improvement, or the offer is not strong enough to close the deal. --- ## Sending a Test Before sending a campaign to your full audience: 1. Save the campaign as a draft. 2. Use the **Preview** toggle in the email template editor to verify merge fields render correctly. 3. For SMS, check the character count and preview to confirm the message reads well. 4. When ready, click **Send Now**. The system displays a confirmation dialog with the audience count before proceeding. 5. After sending, a success message shows how many messages were sent and how many failed. --- ## Best Practices - **Segment your audience.** A targeted message to 50 relevant clients outperforms a generic blast to 500. Use the audience builder filters to narrow your reach. - **Test before you send.** Always preview your messages with sample data and verify merge fields render correctly. - **Do not over-message.** Limit campaigns to one or two per month per customer to avoid unsubscribes. - **Use drip sequences for follow-ups.** A three-step sequence with escalating urgency converts better than a single message. - **Add conditions to drip steps.** Send different follow-ups to openers versus non-openers to maximize relevance. - **Track conversions, not just opens.** The real measure of a campaign is booked jobs, not vanity metrics. - **Respect opt-outs.** CE Pro automatically excludes unsubscribed customers from future campaigns. - **Keep SMS under 160 characters.** Single-segment messages are cheaper and have higher read rates than multi-segment messages. - **Write benefit-driven subject lines.** Tell customers what they gain, not what you are selling. - **Start with win-back templates.** If you are new to marketing campaigns, activate a pre-built template and customize it rather than starting from scratch. --- URL: https://docs.cleanestimate.pro/marketing/legal-pages Title: Legal Pages Description: What the public CleanEstimate Pro legal pages cover, including documented SMS consent flows in the privacy policy. Category: marketing Difficulty: beginner Roles: owner, manager, admin Last updated: 2026-04-23 --- # Legal Pages CleanEstimate Pro publishes its public legal pages on the marketing site so customers and prospects can review the current privacy and terms language before using the platform. ## Public legal routes - `cleanestimate.pro/legal/privacy` - `cleanestimate.pro/legal/terms` ## Privacy policy SMS consent documentation The privacy policy's **SMS/Text Messaging** section now documents the three ways consent can be collected before text messaging is used: 1. **Online Estimate Request** -- the customer enters a phone number through a CleanEstimate Pro-powered form and sees the SMS disclosure language before submitting. 2. **Business-Initiated Contact** -- a business operator adds a phone number gathered during a direct interaction, and the first outbound SMS includes the required disclosure and opt-out language. 3. **Verbal or In-Person Consent** -- a business operator explains that texting will be used for service communication, obtains verbal consent, and the first outbound SMS includes opt-out and help instructions. The same section also keeps the carrier-rate disclosure in place: standard message and data rates may apply depending on the recipient's mobile carrier and plan. --- URL: https://docs.cleanestimate.pro/marketing/promotions Title: Promotions and Discounts Description: Create promo codes, configure seasonal discounts, manage service-specific offers, and track promotion ROI. Category: marketing Difficulty: intermediate Last updated: 2026-03-19 --- # Promotions and Discounts The Promotions module lets you create discount codes, seasonal offers, and targeted promotions that customers can apply to estimates. Navigate to **Admin > Marketing > Promotions** to manage your promotions. [SCREENSHOT: Promotions page showing a list of active and expired promotions] --- ## Promotions List The main view displays all promotions as cards. Each card shows the promotion name, promo code, discount amount, status, validity dates, redemption count, and any service restrictions. ### Status Indicators | Status | Meaning | |--------|---------| | **Active** | The promotion is live and can be redeemed | | **Inactive** | The promotion has been manually deactivated via the toggle | | **Expired** | The current date is past the Valid Until date | | **Scheduled** | The current date is before the Valid From date | Each promotion card also displays an **Auto-apply** badge if that option is enabled, and a usage progress bar when a maximum usage limit is set. [SCREENSHOT: Promotion card showing the promo code badge, status badge, discount amount, and usage progress bar] --- ## Creating a Promotion 1. Click the **+ New Promotion** button in the upper right corner. 2. Fill in the promotion details in the form that appears. 3. Click **Create Promotion** to save. ### Required Fields | Field | Description | Tips | |-------|-------------|------| | **Promotion Name** | A descriptive name for internal reference | Use a format like "Fall 2026 -- 15% Off" for easy identification | | **Promo Code** | The code customers enter to redeem the discount | Automatically converted to uppercase. Keep it short -- SPRING25 is better than SPRING-2026-PROMO-15PCT | | **Discount Value** | The numeric discount amount | Enter 15 for 15% off, or 50 for $50 off | ### Discount Type Choose between two discount types: | Type | How It Works | Best For | |------|-------------|----------| | **Percentage (%)** | Reduces the estimate total by a percentage of the subtotal | Higher-value services where the discount should scale with the job size | | **Flat ($)** | Subtracts a fixed dollar amount from the estimate total | Consistent, predictable offers -- "$50 off your next house wash" | Select the discount type by clicking either the **Percentage (%)** or **Flat ($)** button before entering the value. [SCREENSHOT: New Promotion form showing the discount type buttons and value field] ### Validity Dates | Field | Description | Default | |-------|-------------|---------| | **Valid From** | The date and time the promotion becomes redeemable | Optional -- if omitted, the code is valid immediately | | **Valid Until** | The date and time the promotion expires | Optional -- if omitted, the code has no expiration | Both fields accept date and time input. Setting a Valid From date in the future creates a scheduled promotion that activates automatically on that date. The save form now rejects a **Valid Until** value that comes before **Valid From**, so a promotion cannot be stored with an inverted date window. ### Usage Limits | Field | Description | Default | |-------|-------------|---------| | **Max Total Uses** | The maximum number of times the code can be redeemed across all customers | Unlimited if left blank | | **Max Uses Per Customer** | The maximum number of times a single customer can use the code | 1 | When a max total usage limit is set, the promotion card displays a usage progress bar showing the percentage consumed. The bar color changes from green (under 50%) to yellow (50-89%) to red (90% and above) as the limit is approached. Promo codes are normalized to uppercase when you save them, and the admin form only accepts letters, numbers, hyphens, and underscores in the code field. ### Service Restrictions By default, a promotion applies to all services. To restrict it to specific services, click one or more service badges: - House Wash - Roof Wash - Driveway - Deck Wash - Fence Wash - Gutter Cleaning - Window Cleaning When service restrictions are set, the promo code only works on estimates that include at least one of the selected services. If a customer applies the code to an estimate with no matching services, the system returns an error. Service-restricted promos do not bypass that check when the estimate has no service selection yet. Until at least one matching service is present, validation fails instead of applying the discount optimistically. [SCREENSHOT: Service restriction badges with three services selected] ### Auto-Apply Enable the **Auto-Apply** toggle to have the promotion automatically applied when a customer requests an estimate through the portal. This is useful for site-wide promotions or seasonal specials where you want every incoming lead to see the discounted price without needing a code. When auto-apply is enabled, an **Auto-apply** badge appears on the promotion card for easy identification. --- ## Managing Promotions ### Activating and Deactivating Each promotion card has a toggle switch in the upper right corner. Switch it off to deactivate a promotion without deleting it. Switch it back on to reactivate. Deactivated promotions show an **Inactive** status badge. ### Deleting a Promotion Click the **Delete** button on a promotion card. A confirmation dialog appears before the promotion is permanently removed. Deletion is irreversible -- if you want to temporarily disable a promotion, use the toggle instead. Delete requests now fail clearly if the promotion was already removed or the id is wrong. CE Pro no longer returns a silent success for a missing promotion record. --- ## Promotion Validation When a promo code is applied to an estimate -- whether by a customer on the portal or by a sales rep in the admin panel -- the system runs five validation checks: 1. **Code exists** -- the code must match an existing promotion for your organization. 2. **Promotion is active** -- the promotion's is_active flag must be true (not toggled off). 3. **Date range is valid** -- the current date must fall within the Valid From and Valid Until range. If no dates are set, this check passes automatically. 4. **Total usage limit not reached** -- if a max total uses limit is set, the code must have remaining redemptions. 5. **Per-customer limit not reached** -- if the customer's email is known, the system checks whether they have already used the code up to the per-customer limit. 6. **Service restrictions satisfied** -- if the promotion is restricted to specific services, the estimate must include at least one of those services. If any check fails, the system returns a specific error message: | Error | Meaning | |-------|---------| | "Invalid promo code" | The code does not match any active promotion | | "Promo code is not yet active" | The Valid From date is in the future | | "Promo code has expired" | The Valid Until date has passed | | "Promo code usage limit reached" | The max total uses limit has been hit | | "You have already used this promo code" | The customer has reached their per-customer limit | | "Promo code does not apply to selected services" | The estimate does not include any of the restricted services | To slow down brute-force guessing, CE Pro now rate-limits repeated promo validation bursts per customer IP and workspace. If someone retries codes too aggressively, the validator returns a temporary retry message instead of continuing to check codes indefinitely. [SCREENSHOT: Error message when an expired promo code is entered on an estimate] --- ## Using Promotions on Estimates ### In the Estimate Wizard (Admin) When building an estimate in the admin panel, look for the **Promo Code** field. Enter the code and the system validates it in real time. If valid, the discount is applied to the estimate total and appears as a visible line item so the customer can see the savings on their proposal. ### On the Customer Portal Customers can enter a promo code when requesting an estimate through your public portal. The validation runs the same checks described above. If the code is valid, the discount is applied to the generated estimate. ### Auto-Applied Promotions If a promotion has auto-apply enabled, it is automatically included on estimates generated through the portal without the customer needing to enter a code. [SCREENSHOT: Promo code field on the estimate wizard with a discount applied and showing as a line item] --- ## Distributing Promo Codes ### Through Marketing Campaigns Include your promo code in email or SMS campaigns using the `{{promo_code}}` merge field. This inserts the code directly into the message body. See [Marketing Campaigns](https://docs.cleanestimate.pro/marketing/campaigns) for details on creating campaigns. ### Through Direct Messages Send the code to specific customers through the messaging inbox. This works well for personalized offers to high-value or at-risk clients. ### Through External Channels - **Social media** -- post the code on your business profiles with a clear expiration date. - **Print materials** -- add the code to flyers, door hangers, yard signs, or vehicle wraps. - **Google Ads or landing pages** -- include the code in ad copy or on dedicated landing pages. --- ## Seasonal Promotion Strategies ### Spring Cleaning Special Create a percentage discount (10-15%) with a Valid From date at the start of March and Valid Until at the end of April. Target dormant customers who have not had service in 6+ months using a marketing campaign with the "By Last Service Date" audience filter. ### Holiday Lights Early Bird Offer a flat dollar discount ($50-$100 off) for holiday light installations booked before October 15. Restrict the promotion to the holiday lights service. Use auto-apply so portal visitors see the discount automatically. ### Referral Reward Create a promotion code that each referring customer can share. Set the max uses per customer to 1 and the max total uses to match your budget. Distribute through the referral request win-back template. ### End-of-Season Clearance Offer a larger discount (20-25%) for the last two weeks of your busy season to fill remaining capacity. Set a tight Valid Until date to create urgency. --- ## Win-Back Promotions Win-back promotions combine a discount code with a targeted campaign to re-engage dormant customers. The recommended workflow: 1. **Create the promotion** -- set up a promo code with a reasonable discount (10-15%) and an expiration date 30 days out. 2. **Create a campaign** -- use the "We Miss You!" or "Seasonal Reminder" win-back template from the Marketing page. 3. **Link the promo code** -- include the `{{promo_code}}` merge field in your email and SMS templates. 4. **Set the audience** -- the win-back templates come pre-configured to target dormant customers, but you can adjust the filters. 5. **Send and monitor** -- track redemptions on the Promotions page and campaign conversions on the campaign detail page. --- ## Tracking Promotion ROI ### Redemption Tracking Each promotion card displays the **Redemptions** count -- the number of times the code has been applied to an estimate. If a max total uses limit is set, it shows as a fraction (e.g., 12/50) with a visual progress bar. ### Measuring Effectiveness To evaluate whether a promotion is driving profitable business: 1. **Check the redemption count** on the promotion card. This tells you how many customers used the code. 2. **Cross-reference with campaign stats** if you distributed the code via a marketing campaign. The campaign detail page shows conversions -- customers who booked a service after receiving the campaign. 3. **Calculate the discount cost.** Multiply the average discount per estimate by the number of redemptions to get your total discount spend. 4. **Compare against revenue.** Look at the total revenue from jobs that used the promo code. If revenue minus discount cost is positive, the promotion generated net-positive results. ### Key Metrics to Track | Metric | How to Calculate | What It Tells You | |--------|-----------------|-------------------| | **Redemption Rate** | Redemptions / times the code was shared | How compelling the offer is | | **Conversion Rate** | Booked jobs from promo / total redemptions | Whether the discount converts browsers to buyers | | **Cost Per Acquisition** | Total discount given / number of new customers acquired | The marketing cost of winning each new customer | | **Lifetime Value Ratio** | Average customer lifetime value / cost per acquisition | Whether the promotion pays for itself over time | --- ## Best Practices - **Set expiration dates.** Urgency drives action. A promotion with no end date does not motivate customers to act now. - **Limit total usage.** Scarcity increases perceived value. "First 20 customers" works better than "unlimited." - **Keep codes simple.** Customers type these on their phones. SPRING25 is better than SPRING-2026-PROMO-15PCT. Use uppercase letters and short numbers. - **Use service restrictions strategically.** Restrict discounts to services you want to promote or fill capacity for, rather than discounting your most profitable offerings. - **Set per-customer limits.** The default of one use per customer prevents abuse. Only increase this for loyalty-style programs. - **Track ROI.** Calculate whether the revenue from promo-driven jobs exceeds the discounts you gave. A promotion that generates $10,000 in revenue at a $1,500 discount cost is a strong return. - **Deactivate instead of deleting.** If a promotion is underperforming, toggle it off rather than deleting it. This preserves the redemption history for analysis. - **Pair promotions with campaigns.** A promo code without distribution has no impact. Always pair a new promotion with a marketing campaign or direct outreach. - **Do not stack discounts.** CE Pro applies one promo code per estimate. This prevents customers from combining multiple offers, protecting your margins. - **Test with auto-apply sparingly.** Auto-apply is powerful but reduces revenue on every portal estimate. Use it only for limited-time, high-impact promotions. --- URL: https://docs.cleanestimate.pro/marketing/public-website Title: Public Website Description: Understand the current self-serve marketing site, homepage structure, and public pricing presentation. Category: marketing Difficulty: beginner Roles: owner, manager, admin, marketing Last updated: 2026-04-24 --- # Public Website The public CleanEstimate Pro website now sends new organizations into **self-serve signup**. Visitors can browse the product story, feature pages, legal pages, blog, and pricing structure, then use the primary **Start Free Trial** CTA to create a workspace and continue into onboarding. --- ## Current homepage story The homepage now leads with the broader product truth instead of positioning CleanEstimate Pro as only an estimating tool. The current flow highlights: - admin dashboard and command-style operations surfaces - residential estimating - scheduling, dispatch, and billing workflows - analytics and reporting - AI workspace features - the native mobile app Module-specific pages still exist, but the homepage should show how those flows sit inside one connected platform. --- ## Signup behavior Public CTAs on the marketing site route to `/signup`, where the new owner enters their name, company, email, optional phone number, and password. That includes: - homepage hero actions - pricing page actions - final CTA sections - feature-page launch actions After a successful signup, CleanEstimate Pro creates the auth user, organization, owner membership, starter workspace data, and a 44-day trial, then signs the owner in and redirects to `/onboarding`. If the submitted email already belongs to an active workspace, the signup flow blocks the duplicate workspace and routes the user toward sign-in or password recovery. --- ## Public pricing page The public pricing page keeps the current plan structure and public plan prices visible. The current behavior is: - each pricing card shows the public monthly and annual pricing - plan names and feature differentiation stay visible - the card CTA routes to **Start Free Trial** - the comparison grid stays feature-based - new workspaces can choose billing before the trial ends This keeps pricing, signup, and onboarding aligned with the self-serve trial path. --- ## Messaging guardrails Keep the public website aligned with current product reality: - mobile is a live product, not a future teaser - analytics and reporting are live in the admin workspace - AI is already part of the shipped platform story - franchise support should still be described as beta or gated where appropriate If the marketing UI changes again, update this docs page before considering the website work complete. --- URL: https://docs.cleanestimate.pro/marketing/discoverability-files Title: Site Map and LLM Files Description: Understand the public discovery surfaces for CleanEstimate Pro, including the HTML site map, XML sitemap, and llms-full.txt manifest. Category: marketing Difficulty: beginner Roles: admin, marketing Last updated: 2026-03-12 --- # Site Map and LLM Files CleanEstimate Pro publishes a small set of discovery files so people, search engines, and AI tools can understand what is available without guessing through the UI. These files live on the public site: | URL | Purpose | | --- | --- | | `/site-map` | Human-readable directory of the public site, docs, and important app entry points | | `/sitemap.xml` | Machine-readable XML sitemap for search engines | | `/llms-full.txt` | Plain-text manifest for LLM and crawler-style ingestion | | `/robots.txt` | Crawler rules and sitemap pointer | ## When to use each file ### `/site-map` Use the HTML site map when you want a browseable directory of: - Public marketing pages - Module landing pages - Blog posts - Docs sections - Important app entry points like Marketing, Promotions, Automations, and Analytics This is the best place to start when a page feels buried or is hard to find from navigation alone. ### `/sitemap.xml` Use the XML sitemap when you need the canonical list of public pages for: - Search indexing - Site audits - Crawl checks - SEO validation The XML sitemap is generated from the same shared catalog as the HTML site map, so the two should stay aligned. ### `/llms-full.txt` Use `llms-full.txt` when you want a plain-text overview of the product for: - AI assistants - Internal retrieval systems - Prompt context - Automated site understanding The file includes: - A short product summary - Core public pages - Module pages - Blog articles - Important authenticated app entry points - Documentation entry points - Machine-readable discovery files ## What is included in the app section The site map and `llms-full.txt` intentionally include important app routes that are not always obvious from the main sidebar, such as: - Marketing Campaigns - Promotions - Lead Sources - Automations - Automation Analytics - Integrations These links point to `app.cleanestimate.pro` and require sign-in when appropriate. ## Best practices - Use `/site-map` for human navigation and quick audits. - Use `/sitemap.xml` for SEO and crawl tooling. - Use `/llms-full.txt` when an AI system needs the broadest possible product overview in plain text. - If you add a new public page or major app surface, update the shared discoverability catalog so all three outputs stay in sync. ## Docs site discovery The docs site also publishes its own discovery files on `docs.cleanestimate.pro`: - `https://docs.cleanestimate.pro/site-map` - `https://docs.cleanestimate.pro/sitemap.xml` - `https://docs.cleanestimate.pro/llms.txt` - `https://docs.cleanestimate.pro/llms-full.txt` See [Docs Sitemap and LLM Files](https://docs.cleanestimate.pro/developers/docs-discoverability) for the docs-specific workflow. --- URL: https://docs.cleanestimate.pro/messaging/follow-up-sequences Title: Follow-Up Sequences (Legacy) Description: Set up automated SMS and email follow-ups that run after you send an estimate. Category: messaging Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Follow-Up Sequences (Legacy) > **New: Automations Engine v2** -- Follow-up sequences have been replaced by the new [Automations](https://docs.cleanestimate.pro/automations/overview) system, which supports 27 trigger types, branching logic, auto-call, visual workflow builder, and more. Existing sequences continue to work, but we recommend [migrating to automations](https://docs.cleanestimate.pro/automations/migrating-from-sequences) for new workflows. A follow-up sequence is a series of automated messages that fire on a schedule after a trigger event. When you send an estimate, CE Pro can follow up with the customer automatically over the next several days. The system reminds them to review the estimate, answers common questions, and creates urgency -- all without you lifting a finger. --- ## How Auto-Enrollment Works You do not need to enroll customers manually. When you send an estimate, the system automatically enrolls it in your active "Estimate Follow-up" sequence. The sequence starts as soon as the estimate status changes to "sent." Every automated message that fires is logged to the customer's conversation in your inbox. You can see exactly what was sent and when. Legacy follow-up sequences are evaluated on a rolling 5-minute background cadence. If two background runs overlap, Clean Estimate Pro now claims each due enrollment before sending so customers do not receive duplicate legacy follow-up messages. [SCREENSHOT: Conversation thread showing an automated follow-up SMS that was sent 2 days after the estimate, labeled with an "Automated" tag] --- ## Sequence Types CE Pro includes three sequence types. Each one triggers at a different point in the customer lifecycle. ### Speed to Lead Fires immediately when a new lead comes in. A fast response increases your chance of winning the job. Use this sequence to send an introductory text or email within minutes of receiving a lead. [SCREENSHOT: Speed to Lead sequence card showing the sequence name, enabled toggle, and two steps] ### Estimate Follow-up Fires after an estimate is sent. This is the most important sequence. It handles the gap between sending a proposal and getting a signature. Most businesses see the biggest ROI from this one. [SCREENSHOT: Estimate Follow-up sequence card expanded to show five steps with delays and message types] ### Post-Job Fires after a job is marked as completed. Use it to request reviews, offer seasonal re-engagement deals, or thank the customer. [SCREENSHOT: Post-Job sequence card showing a review request step scheduled for 1 day after job completion] --- ## Configuring Sequences Users need **Marketing** access to work with legacy sequences. Team members with `marketing.view` can review sequence settings, while edits, deletes, and step changes require `marketing.manage`. 1. Click **Settings** in the sidebar. 2. Click **Manage Automations**. [SCREENSHOT: Settings page with the "Manage Automations" button highlighted] 3. You will see a card for each sequence type. Each card shows: - **Sequence name** -- editable, so you can rename it - **Enabled/Disabled toggle** -- turn the entire sequence on or off - **Business hours** -- start time, end time, and timezone - **Re-enrollment days** -- the cooldown period before a customer can be re-enrolled [SCREENSHOT: Sequence card header showing the name field, toggle, business hours fields, and re-enrollment days setting] 4. Click on a card to expand it and see the individual steps. --- ## Editing Sequence Steps Each step in a sequence has the following fields: - **Step number** -- determines the order of execution - **Step type** -- choose from Delay, Email, SMS, or Task - **Delay duration** -- how long to wait before this step fires (for example, "2 hours" or "3 days") - **Message template** -- the text of the email or SMS (for Email and SMS steps) - **Recipient** -- who receives the message: the customer, the sales rep, the owner, or all staff [SCREENSHOT: Step editor showing a step configured as an SMS with a 2-day delay and a message template filled in] ### Adding a Step Click **+ Add Step** at the bottom of the step list. Choose the step type, set the delay, write the message, and pick the recipient. [SCREENSHOT: Add Step button at the bottom of an expanded sequence, with the step type dropdown open] ### Editing or Removing a Step Click **Edit** on any step to change its settings. Click **Delete** to remove it. After making changes, click **Save Sequence** to apply them. Legacy sequence saves now validate the step payload before anything is replaced in the database. Event-based steps need an event trigger, system-action steps need a system action selected, and malformed saves stay on the page so you can fix them instead of partially overwriting the sequence. [SCREENSHOT: A step row with Edit and Delete buttons visible on the right side] --- ## Business Hours Automated messages only fire during the business hours you configure on each sequence. If a step is scheduled to fire at 2 AM, the system holds it until the next business-hours window -- for example, 8 AM the next morning. Set your business hours on the sequence card. Choose a start time, end time, and timezone. The save flow now validates these hours before storing the sequence. Use real time values like `08:00` and `17:00`, and keep the end time after the start time. [SCREENSHOT: Business hours fields on a sequence card showing start time 8:00 AM, end time 6:00 PM, and timezone US/Eastern] --- ## What Pauses a Sequence The system pauses a sequence automatically when the customer engages. This prevents you from nagging someone who is already talking to you. A sequence pauses when: - **The customer replies to an SMS.** Any inbound text from the customer pauses the sequence. - **The customer replies to an email.** Same behavior as SMS. - **The customer views or accepts the estimate.** If they are already looking at it, the reminders stop. A paused sequence does not resume on its own. If you want to restart it, re-send the estimate (see Re-enrollment below). --- ## What Stops a Sequence Permanently Some events end a sequence for good: - **The customer opts out of SMS.** If they text STOP, UNSUBSCRIBE, or a similar keyword, the sequence is permanently suppressed. The customer is opted out of all future SMS messages. This is required for TCPA compliance. - **The estimate is accepted.** The job is won. No more follow-ups needed. - **The estimate is declined.** The customer made a decision. The sequence completes. [SCREENSHOT: Conversation thread showing a system event that reads "Customer opted out of SMS -- sequence stopped"] --- ## Re-Enrollment If you re-send an estimate to a customer, the system checks the re-enrollment cooldown you configured on the sequence. If enough time has passed since the last enrollment, the customer is enrolled again and the sequence restarts from step one. This prevents double-messaging when you re-send an estimate quickly to fix a typo or update a price. The cooldown gives you a buffer. Set the re-enrollment period in the sequence card settings. A common default is 7 days. [SCREENSHOT: Re-enrollment days field on the sequence card set to 7] --- ## Tips - Start with the default sequences. They cover the most common follow-up patterns and are ready to use out of the box. - Keep SMS messages short and personal. Stay under 160 characters. - Send the first follow-up within 2 to 4 hours of delivering the estimate. Speed matters. - Always give the customer a way to reply or ask questions. End messages with something like "Reply to this text if you have any questions." - Check your inbox regularly. When a sequence pauses because the customer replied, you need to pick up the conversation manually. --- URL: https://docs.cleanestimate.pro/messaging/internal-notes Title: Internal Notes Description: Leave notes on customer conversations that only your team can see. Category: messaging Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-03-18 --- # Internal Notes Internal notes let you leave messages on a customer's conversation thread that are visible to your team but invisible to the customer. Use them to share context, flag special situations, or record what happened on a phone call. --- ## What Are Internal Notes? An internal note is a message attached to a customer conversation that only your team can see. The customer never sees it in SMS, email, or the customer portal. Notes appear in the conversation timeline alongside real messages and system events, but they have a distinct style so your team can tell them apart at a glance. [SCREENSHOT: Conversation thread showing an internal note with a distinct background between two SMS messages] --- ## How to Add a Note 1. Open a customer conversation in the messaging inbox. 2. Look at the compose area at the bottom of the screen. You will see tabs for **SMS**, **Email**, and **Note**. 3. Click the **Note** tab. [SCREENSHOT: Compose area with the Note tab selected, showing a plain text area and an Add Note button] 4. Type your note in the text area. 5. Click **Add Note**. 6. The note appears immediately in the conversation timeline with a "Note" label so it stands out from customer-facing messages. CE Pro now validates note drafts before saving them. Blank notes and malformed note requests are rejected immediately instead of creating an empty internal message. [SCREENSHOT: A newly added internal note in the timeline, showing the author name, timestamp, and note text] --- ## Who Can See Notes Everyone on your team who has access to the Messages section can see internal notes. There are no separate permissions for notes. If a team member can view the conversation, they can see all notes in it. Customers never see internal notes. Notes are not included in any SMS, email, notification, or customer-facing view. --- ## When to Use Notes Internal notes work well in several common situations: ### After a Phone Call Summarize what you discussed so the rest of the team knows what happened. Include any commitments you made or questions the customer asked. Example: "Spoke with John on the phone. He wants to wait until April to start. Will follow up first week of April." ### Before Handing Off a Client If you are reassigning a conversation to another rep, add a note with the context they need. Save them from having to read through the entire conversation history. Example: "Sarah is taking over this account. Customer prefers text over email. Already sent two estimates. They liked Option B but want the driveway added." ### Flagging Special Pricing or Requirements Record anything unusual about the customer or the job that your team should know. Example: "VIP customer. Always offer the 3-service bundle. Referred us three clients last year." ### Recording a Lost Reason When a customer decides not to move forward, note why. This information is valuable for spotting patterns over time. Example: "Went with a competitor. Said we were $200 higher on the house wash." [SCREENSHOT: A conversation with two internal notes visible, one summarizing a phone call and one flagging the customer as a VIP] --- ## Tips - Notes are searchable. When you search the inbox, your query checks note content too. - Add a note before reassigning a conversation. The next person on your team will have the context they need from the start. - Notes are ideal for preserving context on conversations that still need a response. Use them to explain the next step before assigning or resolving the thread. - Keep notes factual and concise. Write what happened, what was decided, and what needs to happen next. --- URL: https://docs.cleanestimate.pro/messaging/sending-messages Title: Sending SMS and Email Description: How to send manual messages to customers from the inbox, and what they receive. Category: messaging Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-04-23 --- # Sending SMS and Email You can send a text message or email to any customer directly from the messaging inbox. This page walks through both options step by step. Manual send actions follow the same role permissions as the rest of the admin app. If a teammate does not have the communications send permission, CE Pro blocks the send request even if they try to trigger it outside the normal UI. --- ## Sending a Manual SMS 1. Click **Messages** in the sidebar. 2. Find the customer in the contact list on the left. Use the search bar if needed. 3. Click on their name to open the conversation. 4. In the compose area at the bottom, make sure the toggle is set to **SMS**. [SCREENSHOT: Compose area with the SMS toggle selected and the text area empty] 5. Type your message in the text area. A character counter to the right of the field shows how many characters remain out of the 160-character limit. [SCREENSHOT: SMS compose field with a partially typed message and the character counter showing 42 remaining] 6. Check the phone number. It is auto-filled from the customer's record. Edit it if the number on file is wrong. 7. Click **Send**. 8. A success toast appears at the top of the screen. Your message shows in the thread right away as an outbound chat bubble on the right side. 9. If the active telecom provider later marks the message as failed or undelivered, that same thread entry updates with the failed status. If the draft is blank or the request payload is malformed, CE Pro blocks the send before it reaches the telecom provider and shows the validation error immediately in the UI. If CE Pro cannot hand the message to Esendex or Twilio, the send response surfaces a clear operator-facing reason instead of a generic server error or a raw provider dump. Common examples include: - The destination number is invalid. - The recipient has unsubscribed from SMS. - SMS is not configured for the current workspace. - The active telecom provider is temporarily unavailable and the send can be retried. [SCREENSHOT: Conversation thread with the newly sent SMS appearing as a right-aligned chat bubble with a timestamp] --- ## Sending a Manual Email 1. Click **Messages** in the sidebar. 2. Find and select the customer in the contact list. 3. Open their conversation. 4. In the compose area, switch the toggle to **Email**. [SCREENSHOT: Compose area with the Email toggle selected, showing the subject line field and body text area] 5. Enter a subject line. 6. Type your message in the body field. 7. Check the email address. It is auto-filled from the customer's record. 8. Click **Send**. 9. The email is sent from **"{Your Business Name}" <notifications@cleanestimate.pro>**. The customer sees your business name as the sender. 10. If inbound email routing is configured for your workspace, customer replies route back to the same contact thread automatically. 11. Delivery, open, and failure updates appear on the same thread entry when the email provider reports them back. CE Pro now validates the recipient, subject, and body before it hands the send to the email provider, so incomplete drafts fail fast instead of making a partial provider call. [SCREENSHOT: Conversation thread showing the sent email entry with subject line and preview text] --- ## Using AI Draft The AI Draft button helps you write follow-up messages faster. It works for both SMS and email. 1. Open a customer conversation and go to the compose area. 2. Click the **AI Draft** button (the Sparkles icon next to the Send button). [SCREENSHOT: AI Draft button with the Sparkles icon highlighted in the compose area] 3. The system analyzes the estimate's age, its current status, and the full conversation history. 4. A suggested message appears in the compose field. 5. Read the suggestion. Edit it to match your voice and add any details the AI missed. 6. Click **Send** when you are satisfied. AI Draft works best on estimates that are three or more days old. At that point, the system has enough context to write a relevant follow-up. AI Draft now runs through the in-app admin route instead of a separate edge-function dependency. If your workspace does not have an active AI provider configured, CE Pro still returns a safe built-in draft template so the action stays usable instead of failing outright. --- ## What Customers Receive ### SMS The customer receives a plain text message from the workspace's active telecom number. For most new workspaces this is the shared Esendex number; legacy workspaces may still send from Twilio. There is no special formatting or branding. It looks like a regular text. If CE Pro inserts an estimate, proposal, or maintenance-plan link into the SMS, that link is a signed customer link. Generic quotes are the exception: they now use the shared public quote URL, while the other estimate-family records still use signed customer-token links. If CE Pro cannot build a working secure estimate link at send time, it now avoids dropping a broken fallback URL into the text message. The SMS still goes out, but it tells the customer to contact you for a fresh secure review link instead of sending an unusable link. ### Email The customer receives an HTML-formatted email. The sender line reads as your business name with the address notifications@cleanestimate.pro. When inbound email routing is configured for your workspace, the reply-to address is set to your organization's CleanEstimate inbox address so replies route back into the same customer thread automatically. If inbound routing is not live yet, CE Pro sends without the reply-to mailbox attached and the settings area shows a setup notice instead of a fake inbox address. Estimate, proposal, and maintenance-plan emails use signed customer links so customers land on the right public page when they click through from the message. Generic quote emails now use the shared public quote URL instead, which stays stable across preview, send, and resend. Holiday-lights quote sends that originate from linked estimate-workspace actions still stay on the seasonal delivery path, so the customer receives the holiday-lights portal link instead of a generic residential estimate link. Fleet and commercial-building proposals still need to be sent from their proposal workspace rather than the shared estimate workspace, which prevents the wrong commercial template from being used by mistake. Holiday-lights quote sends now also keep the delivery event tied back to the originating estimate record, so the customer timeline and message history stay aligned when the office follows up later from the shared quote-core workspace. If CE Pro cannot build a valid customer quote link for a generic quote, the send action now fails before delivery instead of sending a broken URL. [SCREENSHOT: Example of what the customer sees in their email inbox, showing the business name as the sender] --- ## Prerequisites Before you can send messages, make sure the following are in place: ### For SMS - **A telecom provider must be configured.** Go to **Settings** and complete the **Phone / Voice** card for Esendex or Twilio. - **The SMS add-on must be active on your plan.** Go to **Settings** then **Billing** to check. [SCREENSHOT: Settings page showing the Phone / Voice card with the active telecom provider saved] ### For Email - Email sending is built into CE Pro and is configured automatically for daily use. No extra provider setup is required from reps before sending. --- ## Send Protection CE Pro now adds cooldowns to manual email, SMS, and review-request sends: - A single teammate cannot spam the same send action repeatedly in a short burst. - The same estimate cannot be emailed or texted over and over in a tight loop. - If you hit a cooldown, CE Pro returns a temporary rate-limit message instead of sending another duplicate communication. This protects customers from duplicate sends and helps prevent accidental Esendex, Twilio, Mailgun, or review-request abuse. --- ## Troubleshooting **The Send button is grayed out.** Check that the workspace has a configured telecom provider and that the SMS add-on is active on your plan. If either is missing, the SMS Send button will be disabled. [SCREENSHOT: Compose area with the Send button grayed out and a tooltip explaining that SMS is not configured] **The customer says they did not receive my SMS.** Verify the phone number format. If the carrier later rejects the message, the conversation thread updates with the failed status so you can retry or switch channels. If the send is blocked immediately, CE Pro now returns a plain-language inline reason so you know whether the issue is an invalid number, a recipient delivery block, or workspace setup. **An email reply did not show up in my inbox.** The customer must reply to the original CleanEstimate email, and inbound email routing must already be configured for your workspace. Standard replies route back into the matching contact thread only when that inbound mailbox is live. Forwarded emails or messages sent to unrelated addresses will not attach to the conversation automatically. **I need to know whether an email was opened.** Open tracking appears directly on the outbound email entry in the conversation thread when the provider reports the open event back to CleanEstimate Pro. **The email composer says "Failed to send email."** That message means CE Pro blocked the low-level provider failure details from the UI. Retry once, then confirm outbound email is configured for the workspace. If the message instead says **Email sending is not configured**, the workspace still needs email delivery setup before manual sends can succeed. --- URL: https://docs.cleanestimate.pro/messaging/inbox Title: Your Messaging Inbox Description: Find, assign, and manage all customer conversations in one shared inbox. Category: messaging Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-04-23 --- # Your Messaging Inbox The Messages page is your shared communication hub. Every SMS, email, system event, internal note, and automated follow-up lives in one place so your team can see the full customer story before responding. Call activity is part of that same record. Inbound calls, voicemail events, AI voice-agent summaries, and callback notes all land in the customer's thread so your reps do not have to switch between a dialer and the inbox to understand what happened. Go to **Messages** in the sidebar to open it. [SCREENSHOT: Messages page showing the two-panel layout with the contact list on the left and a conversation thread on the right] --- ## Page Layout The inbox uses a two-panel split view. The left panel lists your conversations. The right panel shows the full thread for whichever conversation you select. On smaller screens the inbox keeps the same two-panel content but uses mobile-safe viewport sizing so the list and thread do not overlap or overflow the screen height. ### Left Panel: Conversation List At the top of the list is a search bar. Type a name, phone number, email address, property address, or account name to filter the inbox. [SCREENSHOT: Search bar at the top of the contact list with placeholder text reading "Search accounts, contacts, properties, email, phone..."] Below the search bar you can narrow the inbox with workflow filters such as: - **Mine** to see conversations assigned to you - **Unassigned** to find threads no one owns yet - **Unread** to focus on new inbound activity - **Needs Response** to see conversations that still require follow-up Each row in the list shows: - **Customer name** in bold - **Last message preview** - a short snippet of the most recent activity - **Timestamp** - relative time like "2 hours ago" or "3 days ago" - **Unread badge** - a count of unread inbound messages, if any - **Channel icon** - a Mail icon for email or a MessageSquare icon for SMS - **Workflow badges** - indicators for assignment or response status when needed Conversations are grouped by contact, not by channel. If the same customer has both a phone number and an email address on file, their texts and emails appear in one shared row in the inbox instead of splitting into separate conversations. Conversations are sorted by most recent activity. The customer who messaged you last appears at the top. Click any row to load the conversation in the right panel. [SCREENSHOT: Contact list showing customers with unread badges, message previews, and workflow filters] ### Right Panel: Conversation Thread The top of the right panel shows a header with the customer's name in bold. Their email address and phone number appear below the name, along with channel icons. The header also shows the current assignee and whether the thread still needs a response. You can update both without leaving the conversation. [SCREENSHOT: Conversation header showing customer name, email, phone number, assignee, and response status] Below the header is a timeline of all communication in chronological order. Right above the thread you can filter the view to show **All**, **Texts**, **Emails**, **Notes**, or **System** activity for that one contact. Four types of entries appear: - **SMS messages** display as chat bubbles. Inbound messages from the customer appear on the left. Outbound messages from you appear on the right. - **Email events** show the subject line, a preview of the email body, delivery updates such as sent, delivered, opened, or failed, plus a dedicated customer-engagement panel with the latest open time, total open count, the latest tracked link click, and the clicked URL when Resend reports that activity. - **Internal notes** appear with a distinct style so your team can share context without sending anything to the customer. - **System events** still appear inline in the thread, but customer-engagement events such as quote views, proposal views, estimate views, and invoice views now render as highlighted activity cards so the office can spot them without hunting through small centered text. Phone activity also appears in the timeline as call or voicemail entries. When the AI Voice Agent handles a conversation, the thread includes the call summary, the outcome, and any internal callback task or alert created from that conversation. [SCREENSHOT: Conversation thread showing SMS, email, an internal note, and a system event] At the bottom of the thread is a **Linked Estimates** section. It lists every estimate tied to this customer. Each entry shows the estimate number, status, total amount, and date. [SCREENSHOT: Linked estimates section showing two estimates with their numbers, statuses, totals, and dates] --- ## Compose Area The compose area sits at the bottom of the right panel. Use it to send a new SMS or email directly from the conversation, or add an internal note for your team. A toggle lets you switch between **SMS**, **Email**, and **Note** mode. [SCREENSHOT: Compose area toggle showing SMS, Email, and Note options] When you switch to a different conversation, the compose area now resets to that contact before the thread reload finishes. This prevents an SMS, email subject, email body, or internal note draft from carrying over from the previous customer. **In SMS mode:** - A text area for your message - The customer's phone number, auto-filled from their record - A Send button **In Email mode:** - A subject line field - A body text area - The customer's email address, auto-filled from their record - A Send button **In Note mode:** - A plain text field for internal context - An Add Note button - Team-only visibility so the customer never sees the entry SMS and email modes also include an **AI Draft** button marked with a Sparkles icon. Click it to generate a suggested follow-up message. The system uses AI to analyze estimate age, status, and conversation history, then writes a draft for you to review before sending. If you configured [Brand Voice & AI Training](https://docs.cleanestimate.pro/ai/brand-voice), the draft also follows your saved tone, wording rules, and approved examples. [SCREENSHOT: Compose area in SMS mode with the AI Draft button highlighted] --- ## Unread Message Badge A red badge on the **Messages** link in the sidebar shows the count of unread inbound conversations. When you open a conversation, the unread count updates automatically. [SCREENSHOT: Sidebar showing the Messages link with a red unread badge] ## Real-Time Popup and Sound Alerts When a new inbound text, email reply, phone call, voicemail, or admin alert arrives, CleanEstimate Pro now raises an on-screen popup inside the admin workspace and plays a short sound cue. - **Texts, emails, calls, and voicemails** open back into the matching Messages thread. - **Customer-engagement alerts** now also pop live when Resend reports an email open or when a customer opens a quote, proposal, estimate, maintenance proposal, or invoice page. - **Operational alerts** such as stale deals or overdue follow-up items open to the related record. - If your browser allows desktop notifications, the same alert can also appear outside the tab when the app is in the background. --- ## How Messages Get Into the Inbox You do not need to manually log conversations. Messages appear in the inbox automatically from these sources: - **Estimate delivery.** When you send an estimate, the SMS and email are logged to the customer's conversation. - **Customer SMS replies.** When a customer replies to one of your text messages, the reply arrives through the active telecom provider webhook and appears in the thread. - **Customer email replies.** When a customer replies to an email, the reply is routed through your organization's email slug and logged to the thread. - **Phone calls and voicemails.** Provider-powered call activity, including Twilio AI Voice Agent summaries when that path is enabled, is logged to the same customer thread. - **Automated follow-ups.** Messages sent by follow-up sequences are logged here so you can see what your automations have sent. - **Internal notes.** Team members can leave private notes on the thread for handoffs, phone call summaries, and next steps. - **System events.** Actions like "estimate viewed," "proposal signed," and "invoice paid" appear as timeline entries in the relevant conversation, and customer-viewed estimate/proposal/invoice events now stand out as their own highlighted cards. - Customer email history now keeps the tracked open count and latest tracked click inside a dedicated engagement panel on the outbound email row, so the office can compare "email opened" versus "quote or invoice page opened" from the same thread. --- ## Tips - The inbox updates in real time, and manual sends refresh the thread immediately so you do not need to reload the page to confirm your message was logged. - The active conversation now refreshes only when that conversation changes, so background activity in other customer threads is less likely to interrupt the thread you are reading. - The conversation list now patches changed rows in place for most live updates instead of reloading the whole inbox after every new message, so busy teams should see fewer list jumps during active reply windows. - When a live contact-row patch cannot be resolved safely, the inbox now falls back to a full list refresh instead of dropping the conversation out of the sidebar mid-session. - Contact-row refreshes now normalize legacy phone and email thread keys before deciding a conversation is missing, so mixed older/newer contact-key formats are less likely to make an active thread disappear from the list. - Switching between conversations now clears the previous draft and resets the compose mode to the channels that actually belong to the newly selected contact, so you are less likely to send the right draft to the wrong customer. - A single contact thread now combines both SMS and email history, and the thread filter lets you isolate one channel without losing the unified customer view. - Use the search bar to find conversations by customer name, phone number, or email address. - Use assignment and response filters during busy periods so no conversation gets missed. - Add an internal note before handing a thread to another rep so they have the right context. - The AI Draft button works best for follow-ups on estimates that are three or more days old. - Review call summaries after AI voice-agent conversations so your team can see qualification details before calling the customer back. --- URL: https://docs.cleanestimate.pro/mobile/getting-started Title: Mobile App Setup and Usage Description: Install the Clean Estimate Pro internal beta, log in, navigate the interface, create proposals, and work assigned jobs from the field. Category: mobile Difficulty: beginner Roles: owner, manager, sales_rep, crew_lead Last updated: 2026-04-25 --- # Mobile App Setup and Usage The Clean Estimate Pro mobile app gives your field team access to proposals, clients, pipeline, and assigned jobs from a phone or tablet. This guide covers the current internal-beta install flow, login, navigation, and the common workflows you can run from the field. --- ## Installing the App ### iOS Internal Beta 1. Open the **TestFlight** invitation from your Clean Estimate Pro rollout email or message. 2. Tap **Install** for the latest **Clean Estimate Pro** preview build. 3. Wait for the beta install to finish. The app icon appears on your home screen. 4. When a newer preview build is published, update from TestFlight. [SCREENSHOT: Clean Estimate Pro TestFlight install screen with the Install button highlighted] ### Android Internal Beta 1. Open the internal beta install link shared by your Clean Estimate Pro admin. 2. Download the latest Android preview build. 3. Approve the install prompt if your device asks to allow this internal installer. 4. Wait for the install to finish. The app icon appears in your app drawer and optionally on your home screen. [SCREENSHOT: Clean Estimate Pro Android internal beta install flow with the download and install prompts highlighted] ### Requirements | Platform | Minimum Version | |---|---| | iOS | 15.0 or later | | Android | 10.0 (API level 29) or later | Make sure your device is running a supported OS version before installing. Internal beta access is managed by your Clean Estimate Pro workspace team, so you do not need to search a public app store listing. --- ## Logging In Open the app. You see the refreshed sign-in screen with a blue **CleanEstimate Pro** intro card above the login form. Current internal beta builds keep you on the auth screen until your saved session is fully ready, so the login shell should no longer flash or bounce between tabs while the app is starting. 1. Enter the same email and password you use on the web dashboard. 2. Tap **Sign In**. [SCREENSHOT: Mobile login screen showing the CleanEstimate Pro intro card, email and password fields, and the Sign In button] If you have not set up an account yet, create one on the web at the Clean Estimate Pro dashboard first. The mobile app does not support account registration. ### Forgot Password Tap the **Forgot your password?** action below the login form. The recovery screen now uses the same card layout as sign-in, so the reset flow looks and feels like the rest of the mobile app. Enter your email address and tap **Send Reset Link**. Check your inbox for a password reset email, follow the link to create a new password, then return to the app and sign in with your updated credentials. [SCREENSHOT: Forgot Password screen with the account recovery card, email field, and Send Reset Link button] ### Staying Logged In The app keeps you logged in between sessions. You only need to re-enter your credentials if you explicitly log out or if your session token expires after an extended period of inactivity. --- ## Navigating the Mobile Interface After logging in, you land on the **Home** tab. The bottom navigation bar changes slightly by role and enabled features, but the core internal-beta tabs stay focused on quoting plus crew-lite job execution. [SCREENSHOT: Bottom navigation bar showing Home, Proposals, Pipeline, Clients, Jobs, and Settings tabs] ### Bottom Navigation Tabs | Tab | What It Shows | |---|---| | **Home** | Dashboard with sync status, KPI cards, quick actions, and recent proposals | | **Proposals** | All proposals organized by status -- Draft, Sent, Viewed, Accepted, Declined, Expired | | **Pipeline** | Visual pipeline view showing deals at each stage of your sales process | | **Clients** | Searchable list of all clients with quick access to contact details and proposal history | | **Jobs** | Assigned jobs, job details, crew alerts, invoice status, and in-field payment collection when scheduling is enabled for your role | | **Settings** | Profile, organization settings, notification preferences, offline configuration, pricing references, tax references, and app information | Not every role sees every tab. Sales users stay focused on quoting, while crew-lead and technician roles see the **Jobs** tab when scheduling is enabled for their workspace. ### Pull to Refresh On any list screen, pull down from the top of the list to refresh the data. A loading indicator appears while the app fetches the latest information from the server. ### Search Most list screens include a search bar at the top. Tap it and type a customer name, address, phone number, or estimate number to filter results instantly. --- ## Home Dashboard The Home tab shows a snapshot of your business activity. [SCREENSHOT: Home dashboard showing the top summary card, KPI cards, quick actions, and recent proposals] The dashboard displays: - **Proposals This Month** -- count of proposals created in the current period. - **Pending Count** -- proposals sent but not yet accepted or declined. - **Pipeline Value** -- total dollar value of all pending proposals. - **Conversion Rate** -- percentage of sent proposals that were accepted. The top card also shows your current workspace name and a sync-status chip so field users can see whether work is fully synced before they leave the screen. Tap the sync chip to jump straight into **Settings > Offline & Storage** when you need to review queued changes. Below the KPI row, the dashboard keeps **Quick Actions** and **Recent Proposals** close together so you can jump back into quoting without leaving the mobile shell. Quick Actions now render as larger builder cards instead of a cramped single row so proposal types stay readable on a phone-sized screen, and the sales-focused shortcuts now keep **Residential** and **Holiday Lights** at the top while still exposing **Generic Quote** and **Asphalt Maintenance** through guided web handoff cards. --- ## Viewing and Managing Clients Tap the **Clients** tab to see a scrollable list of all clients in your organization. [SCREENSHOT: Clients list showing the summary header, search bar, and contact actions] ### Searching for a Client Use the search bar at the top of the Clients screen. Results filter as you type. Search matches against client name, email, phone number, and address. ### Client Detail Tap a client name to open their detail screen. The client detail view shows: - **Contact information** -- name, email, phone, address. - **Proposal history** -- a live list of estimates and mobile drafts associated with this client, with status badges and totals. - **Notes** -- any internal notes added by your team, with autosave when you pause typing or leave the field. - **Quick actions** -- call, email, edit the client, or jump into a new proposal flow. [SCREENSHOT: Client detail screen showing contact info, proposal history, notes, and quick actions] ### Quick Actions From the client detail screen, you can: - Tap the **phone number** to initiate a call. - Tap the **email address** to open your email client with a pre-filled recipient. - Tap **Edit** to update the client profile. - Tap **Create Proposal** from the proposal history empty state to jump into a new proposal. ### Address Autocomplete When creating a new lead or customer from mobile, start typing the service address and choose a Google suggestion. The app fills the street, city, state, and ZIP fields so the CRM record is ready for routing, quoting, and follow-up without retyping the property details. --- ## Creating Estimates on the Go Tap the **Proposals** tab, then tap the **+** button or **New Proposal** in the top right corner. The app opens the estimate-type selector with a field-quoting overview card, step counts, and short best-fit guidance for each builder. [SCREENSHOT: Estimate type selector showing Residential, Holiday Lights, Commercial, Fleet, Generic Quote, and Asphalt Maintenance options as cards] ### Choosing an Estimate Type Select the type of estimate you want to create: | Type | Use Case | |---|---| | **Residential** | Standard home service estimate with the five-step Residential Estimate Wizard | | **Holiday Lights** | Holiday lighting installation estimates with zone-based pricing and field-close follow-up | | **Commercial** | Commercial property estimate with multi-option and multi-service support | | **Fleet** | Vehicle fleet washing and detailing proposals | | **Generic Quote** | Flexible line-item quoting for custom scopes that use the shared quote-core web wizard | | **Asphalt Maintenance** | Pavement maintenance quoting that opens the full asphalt web wizard from mobile | Residential and Holiday Lights are the fastest path for same-day field quotes and on-the-spot closes. Commercial and Fleet include more setup because they capture extra property, scope, and scheduling detail for office follow-up. Generic Quote and Asphalt Maintenance stay available from the mobile shell through a guided web handoff so sales reps can still launch every active estimate wizard without leaving the app blind to those modules. ### Residential Estimate Walkthrough The Residential Estimate Wizard on mobile now mirrors the current beta flow with five steps. **Step 1: Address** 1. Start typing the property address and choose the matching Google suggestion. 2. Confirm the auto-filled city, state, ZIP, and property details. 3. Save the location details so the estimate can reuse them in later pricing and customer-link steps. [SCREENSHOT: Mobile residential estimate Step 1 showing address and location fields] **Step 2: Property** 1. Enter square footage, stories, lot size, and siding type. 2. The builder applies the active residential pricing defaults from the same pricing config used by the web app. 3. House Wash pricing previews update automatically as property details change. [SCREENSHOT: Mobile residential estimate Step 2 showing property details and automatic house wash pricing preview] **Step 3: Services** 1. Toggle on the services you want to include for this visit. 2. Review the current service defaults and running subtotal. 3. Add optional residential add-ons when needed. [SCREENSHOT: Mobile residential estimate Step 3 showing service toggles, add-ons, and running subtotal] **Step 4: Pricing** 1. Review the selected services and subtotals. 2. Edit pricing inline for field adjustments and custom line items. 3. Confirm the tax and total summary before moving to review. [SCREENSHOT: Mobile residential estimate Step 4 showing editable line items, tax, and total summary] **Step 5: Review and Send** 1. Review the full estimate summary including client details, property info, services, and the pricing breakdown. 2. Choose a delivery method: **Email**, **SMS**, or **Both**. 3. Edit the pre-filled subject line and message body if needed. 4. Tap **Send Estimate**. Mobile proposal sends now use the same signed customer-link flow as the web app. If you create and send a proposal from mobile before it has been synced to a linked estimate record, the delivery still uses a secure `/p/...` proposal link with a signed `token` query parameter instead of falling back to an unauthenticated URL. Those signed customer links depend on the server-side `CUSTOMER_TOKEN_SECRET` environment variable. Set that secret before sending live mobile proposal links, keep it stable across deploys, and plan for currently issued customer links to expire after the configured validity window. [SCREENSHOT: Mobile residential estimate Step 5 showing the review summary and Send Estimate button] ### Commercial, Fleet, and Holiday Lights Estimates Each estimate type follows its own Estimate Wizard tailored to that service category. The general flow is the same: enter client and property details, configure services and pricing, then review and send. Commercial estimates include multi-option builders for presenting tiered pricing. Fleet estimates include vehicle inventory configuration. Holiday lights estimates include zone-based design tools. ### Saving Drafts If you are not ready to send, tap **Save as Draft** on the review screen. The estimate saves to your Proposals list with a Draft status badge. You can reopen that draft later from mobile or web, and the mobile app now resumes it through the correct module step automatically instead of restarting the wizard. ### Proposal Detail and Close Flow Tap any proposal from the mobile list to open its detail screen. Proposal detail now shows: - **Status and created date** at the top of the page. - **Customer and total summary** for a quick read before you contact the customer. - A dedicated **Close the Deal** section with **Present and Close**, **Create 25% Deposit Link**, **Create Balance Payment Link**, and **Open Latest Payment Link** actions. - **Quick actions** for **Call**, **Email**, and **Maps** when contact or address data exists. - **Acceptance and payment state** including signature timing, signed-by name, paid-to-date amount, and balance due. - **Customer and site details** including phone, email, and service address. - **Internal notes** when the estimate includes them. [SCREENSHOT: Proposal detail screen showing the status header, Present and Close action, payment-link actions, customer info, and service address] When a rep taps **Present and Close**, the app opens the secure customer-facing estimate or proposal view that matches that estimate's live delivery path, so the customer can review, accept, and sign on the spot. If you need to collect money during that same visit, create a deposit or balance link from the proposal detail page and hand the device to the customer for checkout. --- ## Working Assigned Jobs When your workspace enables scheduling, crew-lead and technician roles see a dedicated **Jobs** tab. Owners and managers can also review scheduled work from the same tab during the internal beta. [SCREENSHOT: Jobs tab showing scheduled jobs with status badges and next visit details] ### Jobs List The Jobs list shows the jobs assigned to your crew, or the organization-wide scheduled jobs list for office roles. Each card includes: - **Job number** - **Customer name** - **Service type** - **Scheduled date and start time** - **Service address** - **Current job total** ### Job Detail Tap a job card or a job-assigned push notification to open the job detail screen. The current internal-beta job detail view includes: - **Client summary** - **Schedule and address actions** - **Invoice and balance state** - **Crew Alerts** pulled from quote line items - **Crew Notes** - **Payment collection** for card, cash, or check when an invoice is already linked Payment collection stays on the existing mobile payment endpoints and is intended for field collection only. Invoice creation still happens in the web app. --- ## Managing Pipeline from Mobile Tap the **Pipeline** tab to view your sales pipeline in a mobile-friendly kanban layout. [SCREENSHOT: Pipeline view showing deal cards organized by stage columns] ### Pipeline Stages The pipeline displays your configured stages as horizontal columns. Each deal appears as a card showing the client name, service type, value, margin badge, and time in the current stage. Swipe left or right to scroll through the stages. ### Moving Deals Between Stages Tap a deal card to open its detail view. Long-press a card or use the move action from the detail sheet to change stages. The card moves to the updated column when you return to the pipeline view. [SCREENSHOT: Deal detail view with Stage selector dropdown expanded] ### Pipeline Summary The top of the mobile pipeline keeps three quick reads visible while you move through stages: - **Deals** -- count of active deals in the pipeline. - **Pipeline Value** -- total current value across active deals. - **Needs Follow-Up** -- count of active deals that have been sitting in the same stage for a week or more. Pipeline deal cards now focus on the customer, service type, value, and time in stage. When contact data is available, the deal detail sheet also gives you working **Proposal**, **Call**, and **Email** actions instead of placeholder buttons. --- ## Settings Tap the **Settings** tab to access app configuration. [SCREENSHOT: Settings screen showing the account summary card, sync status pill, and grouped settings sections] ### Profile View and edit your name, email, and profile photo. Changes sync to the web dashboard automatically. ### Organization View your organization name and details. Organization-level settings such as company info and integrations are managed from the web dashboard. ### Notifications Configure push notification preferences. Toggle each notification type on or off: | Notification | Description | |---|---| | **New estimate requests** | A customer submits a request through the portal | | **Estimate viewed** | A customer opens your proposal link | | **Estimate signed** | A customer accepts and signs a proposal | | **New messages** | A customer replies via SMS or email | [SCREENSHOT: Notification preferences screen with toggles for each notification type] ### Offline Mode Configure offline data sync settings. The Settings landing screen also surfaces pending sync count directly in the account summary area so the field team can confirm whether local work is still queued. See [Working Offline](https://docs.cleanestimate.pro/mobile/offline-mode) for a full guide on using the app without connectivity. ### Pricing View the active residential pricing defaults that the mobile quote builder is currently using. This screen is read-only in the internal beta so the mobile app stays aligned with the active web pricing config and shared price book. ### Tax Rates View the effective residential tax fallback, your organization state, and the shared state overrides that the mobile builder applies. Manage tax policy changes from the web dashboard. ### About View the app version number, build number, and links to support and documentation. --- ## Tips - **Use Auto-fill Property** in the field to save time. Enter the address first, then tap Auto-fill to pull in property details without measuring. - **Save drafts** when you gather information on-site but want to finalize pricing back at the office. - **Enable push notifications** so you know immediately when a customer views a proposal or when a job assignment deep link lands for your crew. - **Pull to refresh** if data looks stale. The app caches data locally for performance, so a manual refresh ensures you see the latest updates. - **Create estimates from client profiles** to skip re-entering customer details. Open the client, tap New Estimate, and the form pre-fills automatically. - **Use the mobile app for on-site visits.** Creating an estimate while looking at the property reduces errors and speeds up your sales cycle. --- ## Troubleshooting ### App does not install Verify that your device meets the minimum OS version requirements listed above. Check that you have sufficient storage space on your device. On Android, make sure your device allows the approved internal beta installer your team shared with you. ### Login fails Confirm you are using the same email and password as the web dashboard. If you recently changed your password on the web, use the updated password. Tap **Forgot Password** to reset if needed. If you see an error about your account not being found, verify that your organization has an active subscription. ### Data is not showing Pull to refresh on any list screen. If data still does not appear, check your internet connection. The app requires an active connection for the initial data load after installation. See [Working Offline](https://docs.cleanestimate.pro/mobile/offline-mode) for details on using the app without connectivity. ### Push notifications are not arriving 1. Open your device settings and verify that notifications are enabled for Clean Estimate Pro. 2. In the app, go to **Settings > Notifications** and confirm your preferred notification types are toggled on. 3. Check that your device is not in Do Not Disturb mode. 4. On Android, verify that battery optimization is not preventing the app from receiving background notifications. ### Estimate totals differ from the web The mobile app uses the same active residential pricing config and tax fallback as the web dashboard. If you see a discrepancy, pull to refresh to ensure you have the latest pricing configuration. If a manager recently updated pricing defaults on the web, those changes need to sync to your device before they take effect in new estimates. --- URL: https://docs.cleanestimate.pro/mobile/sales-workspace Title: Mobile Sales Workspace Description: How the rep-first Clean Estimate Pro mobile sales app works across Today, CRM, Estimates, Messages, search, and company-line calling. Category: mobile Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-04-25 --- # Mobile Sales Workspace The Clean Estimate Pro mobile app now gives sales reps one connected loop for schedule, communication, quoting, close, and collection. Instead of splitting work across a generic dashboard, pipeline board, and separate contact list, the rep shell is organized around five tabs: - **Today** - **Estimates** - **CRM** - **Messages** - **More** This guide explains what each part of the mobile sales workspace is for and how reps should use it in the field. --- ## Today The **Today** tab is the rep home screen. It is built to answer three questions immediately: 1. Where do I need to go? 2. Who needs a reply? 3. What money still needs to be collected? The screen includes: - A top summary card with the workspace name, company line status, and counts for appointments, follow-ups, and unread conversations - A global search launcher - Today's appointment list - Unread or needs-response conversations - Payment-due cards for estimates that still need a deposit or balance payment - Active local drafts that need to be resumed - Quick Add actions for new leads, new customers, and new estimates The sync status chip on this screen now shows the real number of locally queued changes waiting to upload instead of a placeholder count, so reps can trust what still needs to sync before they leave service. [SCREENSHOT: Today screen showing appointments, unread messages, active drafts, and payment due cards] --- ## CRM The **CRM** tab combines leads and customers into one searchable list. Mobile CRM now reads and writes through the authenticated live Clean Estimate client APIs first. That means sales reps see the same live customers, lead context, service address, estimates, invoices, payments, messages, and activity that the office sees in the web app instead of depending on stale proposal-only or Workiz fallback data. Quick filters let reps narrow the list to: - **All** - **Leads** - **Customers** - **Needs Follow-Up** Every row is designed to be actionable, not just informational. Reps can jump from the list into the correct lead or customer record without digging through multiple tabs. [SCREENSHOT: CRM tab showing lead and customer filters, search, and quick-create actions] ### Lead Page Lead detail is the pre-close workspace. It surfaces: - Appointment time and address - Deposit or payment context from linked estimates - Message history preview - Estimate history - Quick actions for company-line calling, opening the message thread, and launching a new estimate If the linked customer is a business account, the lead page now uses the saved company name everywhere the mobile shell needs a display name, including message handoff and company-line call actions. ### Client Page Client detail is the customer relationship workspace. It surfaces: - Contact details and service address - Lifetime value and recent activity - Payment-due preview - Message history preview - Estimate history - Quick actions for company-line calling, messages, edit, and new estimate When a rep taps **New estimate** from a client or lead, the app carries the linked client, lead, contact details, and service address into the estimate picker. Choosing **Residential** then opens the builder with that CRM context already filled in. CRM now supports company-name-only customers cleanly. Reps can create, search, open, edit, and call business accounts from mobile even when there is no personal first-and-last contact name saved on the record yet. If the extended sales-history API is temporarily unavailable, the client page still loads the core CRM record instead of dropping the rep into a blank dead-end state. The page now keeps the contact card, call action, edit flow, estimate history, and message handoff available while the live sales timeline reconnects. Mobile-created customers now stay visible in CRM search and client detail even when they originate from the proposal-client workflow instead of the main admin client table. New customer and new lead forms also protect typed drafts if a rep hits Android Back by mistake, and modal headers respect the phone safe area on smaller screens. New lead and new customer forms now include Google address autocomplete on the address field. Reps can start typing a street address, choose a Google suggestion, and the mobile app fills the street, city, state, and ZIP fields before the record is saved. [SCREENSHOT: Client detail screen showing communication preview, payment due, and estimate history] --- ## Estimates The **Estimates** tab is the quoting and close workspace. It includes: - Search by customer or estimate number - Filters for **Drafts**, **Sent**, **Viewed**, **Signed**, **Needs Deposit**, and **Paid** - Status pills on every row - One-tap entry into the estimate close screen or back into a saved local draft [SCREENSHOT: Estimates screen showing rep-first filters and status pills] This tab is optimized for the actual field workflow: - Resume a draft - Reopen a sent quote - Follow up after a view - Reopen a signed quote - Collect the deposit Commercial building proposal steps now block incomplete handoffs before a rep reaches review. A proposal needs a client, complete property address and square-footage details, at least one service per property, positive pricing, and a selected service frequency before it can advance to final review. ### Red Line in Mobile Residential Estimates Sales reps with **Red Line Access** now see the same residential floor-pricing guidance in the mobile app that managers see in the web estimator. When the workspace has Red Line enabled in **Pricing Manager**, the mobile residential pricing step shows: - The floor for each selected service - The service status, such as below red line, at red line, near red line, above red line, or healthy upside - The rep commission when the workspace allows reps to see commission - A Red Line summary card with total service floor, sold service subtotal, and commission when visible Mobile price edits are guarded by the floor. If a rep tries to enter a service price or rate below Red Line, the app raises it back to the floor and explains why. The final review step repeats the Red Line summary and blocks **Save as Draft** or **Queue Delivery** until every service is at or above its floor. Mobile-created residential proposals also save the Red Line snapshot with the queued proposal data so the office can audit the floor, service status, and commission context after the draft syncs. ### Mobile Property Prefill Residential estimates in the mobile app now use Google address autocomplete and the same server-side property lookup used by the web estimator. Reps can start typing the property address, select the matching Google suggestion, and the builder fills the street, city, state, ZIP, and saved coordinates before Clean Estimate looks up available property data and pre-fills: - Square footage - Stories - Lot size in acres - Year built The property step marks values that came from the property API, keeps the fields editable for field verification, and recalculates the house-wash quantity from the returned square footage. --- ## Messages The **Messages** tab is the full communication workspace. It supports: - Search by customer, phone number, or thread preview - Filters for **All**, **Unread**, and **Needs Response** - Full customer thread history across SMS, email, calls, voicemail, estimate engagement, and payment activity [SCREENSHOT: Message thread showing the unified history timeline and call action] The thread view is meant to be the rep's customer history surface. Before calling or quoting, the rep can quickly see the most recent inbound message, sent quote activity, or missed call without leaving the thread. When a customer does not have live thread history yet, or the thread service is still catching up, the mobile thread screen now opens with the saved customer context and shows a reconnecting / no-messages-yet state instead of a hard failure. That means reps can still confirm they opened the right customer and place a company-line call from the thread screen even before history finishes loading. --- ## Search Search is no longer trapped inside one list. The mobile sales app includes a global search screen that can find: - Customers - Leads - Estimates - Jobs - Message threads This lets the rep jump straight to the right record from Today, CRM, Messages, or estimate detail. [SCREENSHOT: Global search screen showing mixed results for CRM, estimates, and messages] --- ## Company-Line Calling Lead pages, client pages, message threads, and estimate detail all support **Call** from the rep-side quick-action bar. When the rep taps **Call**, the app opens a call sheet with two choices: - **Call From Company Line** - **Use Device Dialer** ### Call From Company Line This option uses the workspace's configured company number. The system rings the rep's saved phone number first, then connects the rep to the customer and logs the call back to the customer history. Use this when: - The rep wants the customer to see the company number - The team wants call activity logged back into the mobile sales thread - The rep is working a lead, customer, or estimate directly from the app ### Use Device Dialer This is the fast fallback path. It opens the device dialer directly if the rep needs to place a call immediately or if company-line calling is not configured yet. [SCREENSHOT: Company-line call sheet showing company-line and device-dialer options] --- ## Recommended Rep Flow For most field visits, the best loop is: 1. Open **Today** 2. Tap the next appointment 3. Review message history on the lead or client page 4. Place a company-line call if needed 5. Launch or reopen the estimate 6. Present the quote from estimate detail 7. Hand the device to the customer for signature 8. Create a deposit or balance link when payment is needed That is the core purpose of the new mobile sales workspace: fewer disconnected lists, more direct action. --- URL: https://docs.cleanestimate.pro/mobile/offline-mode Title: Working Offline Description: How offline sync works in the mobile app, what data is available without connectivity, and how to troubleshoot sync issues. Category: mobile Difficulty: beginner Roles: owner, manager, sales_rep, crew_lead Last updated: 2026-03-15 --- # Working Offline The Clean Estimate Pro mobile app is designed to work in areas with limited or no internet connectivity. You can view client data, create estimates, and capture job details while offline. The app stores changes locally and syncs them to the server when your connection is restored. --- ## How Offline Sync Works The app uses a local database on your device to cache data and queue changes. The sync process follows three stages: 1. **Pre-cache** -- When you are online, the app downloads and stores a local copy of your most-used data: clients, pricing configuration, services, add-ons, and recent estimates. 2. **Offline queue** -- When you make changes without connectivity, the app saves each action (new estimate, client edit, note, photo) to a local queue with a timestamp. 3. **Sync on reconnect** -- When your device regains an internet connection, the app automatically processes the queue and pushes all pending changes to the server. Incoming changes from other team members are pulled down at the same time. [SCREENSHOT: Diagram showing the three sync stages -- Pre-cache, Offline Queue, and Sync on Reconnect] --- ## Sync Status Indicator A sync status indicator appears in the app header so you always know whether your data is current. It shows one of three states: | Indicator | Meaning | |---|---| | **Green checkmark** | All data is synced. You are online and up to date. | | **Orange sync icon with count** | Sync in progress or pending. The count shows how many changes are waiting to upload. | | **Gray offline icon** | You are offline. Changes are being saved locally. | Tap the indicator to see a breakdown of pending changes -- how many client edits, new estimates, photos, and other items are queued. [SCREENSHOT: App header showing the sync status indicator in each of its three states] ### Automatic vs. Manual Sync The app attempts to sync automatically whenever it detects a network connection. You can also trigger a manual sync at any time: 1. Go to **Settings > Offline**. 2. Tap **Sync Now**. This is useful when you want to confirm all changes are uploaded before switching devices, ending your work session, or heading into an area without connectivity. [SCREENSHOT: Offline settings screen with the Sync Now button highlighted] --- ## What Data Is Available Offline Not all data is cached locally. The app prioritizes the information you are most likely to need in the field. ### Always Available Offline The following data is cached automatically and accessible without connectivity: | Data | Details | |---|---| | **Client list** | Names, contact details, and addresses for all clients in your organization | | **Client profiles** | Full profiles including estimate history, notes, and communication log | | **Pricing configuration** | Your organization's base rates, multipliers, minimum charges, and package discount rules | | **Services and add-ons** | The full list of services and add-on items you have configured | | **Recent estimates** | Estimates created or modified in the last 30 days, including all line items and totals | | **Your pipeline deals** | Deals assigned to you with stage, value, and activity history | | **Custom item templates** | Saved templates for frequently used custom line items | | **Tax rates** | Your configured tax rate settings | ### Not Available Offline The following features require an active internet connection: - **Sending estimates** -- email and SMS delivery requires connectivity. You can create and save estimates as drafts offline, then send them when you are back online. - **Google Places autocomplete** -- address search and the Auto-fill Property feature require an API call. Enter addresses and property details manually when offline. - **Photo uploads** -- photos taken offline are queued locally but do not upload to the server until connectivity is restored. - **Real-time notifications** -- push notifications require a connection to the notification server. - **PDF preview and generation** -- PDF rendering happens server-side and requires an internet connection. - **AI features** -- lead scoring, pricing analysis, photo estimation, and AI-generated proposal text all require server connectivity. - **Payment processing** -- Stripe payment links, invoice creation, and payment status checks require an active connection. - **Integration syncs** -- calendar, QuickBooks, and Workiz data syncs require connectivity. If you attempt to use one of these features while offline, the app displays a message indicating that the action requires an internet connection. --- ## Creating Estimates Offline You can build a complete estimate without an internet connection. The process is nearly identical to the online workflow with a few differences. ### Step-by-Step 1. Tap the **+** button on the Proposals tab to start a new estimate. 2. Select the estimate type (Residential, Commercial, Fleet, or Holiday Lights). 3. **Client and Property** -- type the client name and details manually. If the client exists in your cached data, the app suggests matches from the local database. Google Places autocomplete is not available offline, so enter the full address, city, state, and ZIP by hand. 4. **Services and Pricing** -- select services and configure parameters as usual. Pricing calculations use your cached pricing configuration, so totals are accurate and match what the web dashboard would calculate. 5. **Review** -- review the estimate summary. The **Send Estimate** button is disabled while offline. Tap **Save as Draft** instead. [SCREENSHOT: Review screen showing the Send Estimate button disabled with an offline indicator and a prominent Save as Draft button] ### What Happens to Offline Drafts Offline drafts are stored in the local database and marked with a pending sync badge in your Proposals list. When you regain connectivity: 1. The app detects the connection and begins the sync cycle. 2. Draft estimates upload to the server. 3. The drafts appear in your estimates list on all devices -- mobile and web. 4. You can then open any draft and tap **Send Estimate** to deliver it to the customer. The pending sync badge disappears once the upload completes successfully. [SCREENSHOT: Proposals list showing a draft estimate with a pending sync badge next to the Draft status] --- ## Editing Existing Data Offline You can edit client details and estimate drafts while offline. Edits are saved locally and synced when you reconnect. ### Client Edits Open a client profile and update their contact information, address, or notes. Changes save to the local database immediately. A pending sync badge appears on the client record until the edit uploads to the server. ### Estimate Edits Open any draft estimate and modify services, pricing, client details, or add-ons. The app recalculates totals using your cached pricing data. Save the changes and they queue for sync. ### Adding Notes and Photos You can add notes to client records and job entries while offline. Photos taken with your device camera attach to the relevant record locally. Both notes and photos upload during the next sync cycle. --- ## Conflict Resolution If two team members edit the same record while one or both are offline, a conflict may occur during sync. The app handles conflicts using the following rules: ### Simple Fields For straightforward fields like client phone number, email, or address, the most recent change wins based on timestamp. If you updated a phone number at 2:00 PM and a colleague updated the same phone number at 2:15 PM, your colleague's change takes precedence. ### Notes Notes from both edits are preserved and merged chronologically. Neither person's notes are lost. ### Estimates If two team members edit the same estimate while one or both are offline, the app flags the conflict during sync. A conflict resolution dialog appears prompting you to review both versions side by side and choose which to keep. [SCREENSHOT: Conflict resolution dialog showing two versions of an estimate with options to keep either version or merge] ### Conflict Frequency In practice, conflicts are uncommon. Most offline usage involves working on different client records or creating new estimates rather than editing the same data simultaneously. --- ## Configuring Offline Settings Go to **Settings > Offline** to manage how the app handles local data. [SCREENSHOT: Offline settings screen showing the offline mode toggle, cached data size, Sync Now button, and Clear Cache button] ### Offline Mode Toggle Offline mode is enabled by default. The toggle controls whether the app maintains a local data cache. Leave this on unless you have a specific reason to disable it. ### Data Cache Size The settings screen shows how much device storage the app is using for cached data. Typical usage ranges from 50 MB to 200 MB depending on the size of your client list and the number of recent estimates. ### Sync Now Tap this button to manually trigger a full sync cycle. The app uploads any pending local changes and downloads the latest data from the server. ### Clear Cache Tap this to remove all locally cached data and force a full re-download on the next sync. Use this only if you suspect corrupted local data or need to reclaim device storage. > **Warning:** Do not clear the cache while you have unsynced changes. Verify that the sync status indicator shows a green checkmark before clearing. If you clear the cache with pending changes, those changes are lost permanently. --- ## Preparing for Offline Work Before heading into an area with limited connectivity, take these steps to ensure you have the data you need: 1. **Open the app while online.** This triggers a background sync that downloads the latest client and pricing data. 2. **Tap Sync Now** in **Settings > Offline** to force a complete sync cycle. 3. **Verify the sync indicator** in the app header shows a green checkmark, confirming all data is up to date. 4. **Browse the clients and estimates** you plan to work with during your offline period. Accessing a record ensures it is fully cached in the local database. 5. **Check your pricing configuration** by viewing the Pricing section in Settings. Confirm your rates are current before creating estimates offline. --- ## Syncing When Back Online When your device reconnects to the internet, the sync process starts automatically within a few seconds. Here is what to expect. ### Sync Order The app processes queued changes in a specific order to maintain data integrity: 1. New client records upload first so that estimates can reference them. 2. Client edits sync next. 3. New estimate drafts upload. 4. Estimate edits sync. 5. Notes and other metadata sync. 6. Photo uploads begin last. These may take longer depending on file sizes and connection speed. ### Sync Progress A progress indicator appears showing the number of pending items and the current upload status. For example: "Syncing 3 of 7 items." [SCREENSHOT: Sync progress indicator showing "Syncing 3 of 7 items" with a progress bar] ### Completion When sync finishes, the indicator returns to the green checkmark state. All your offline work is now visible on the web dashboard and accessible to other team members. Queued proposal deliveries also finish at this point. If a proposal was created directly on mobile and does not yet have a linked estimate record, Clean Estimate Pro now sends a signed proposal-view link with a `token` query parameter instead of dropping the SMS send or requiring an older unauthenticated fallback URL. That signed-link flow depends on the server-side `CUSTOMER_TOKEN_SECRET` environment variable. Keep that secret configured and stable across deploys, and expect customer delivery links to expire after their configured lifetime rather than staying valid forever. --- ## Troubleshooting Sync Issues ### Changes are not syncing 1. Verify your internet connection by opening a browser and loading a web page. 2. Go to **Settings > Offline** and tap **Sync Now** to trigger a manual sync. 3. If the sync fails, read the error message displayed below the Sync Now button. Common causes include expired authentication tokens and temporary server issues. 4. If the error mentions authentication, log out and log back in to refresh your session. Pending offline changes are preserved through the logout and login cycle. ### Duplicate records after sync This can happen if you create a new client offline that another team member also created while you were disconnected. The app detects potential duplicates based on matching email address or phone number. When detected, a merge prompt appears asking you to combine the records or keep them separate. [SCREENSHOT: Duplicate client detection dialog with Merge and Keep Separate options] ### Sync takes too long Large photo uploads are the most common cause of slow syncs. If you have many queued photos: 1. Connect to a Wi-Fi network for faster upload speeds. 2. Keep the app open and in the foreground during the sync. Mobile operating systems may throttle background data transfers. 3. Wait for the sync to complete before closing the app. Interrupting a sync mid-transfer can cause it to restart from the beginning on the next attempt. ### Cached data seems outdated Pull to refresh on any list screen first. If data still appears stale: 1. Go to **Settings > Offline**. 2. Tap **Sync Now** and wait for it to complete. 3. If data remains outdated, tap **Clear Cache** (after confirming you have no pending changes) to force a full re-download of all data. ### Estimate pricing differs from web This typically means your cached pricing configuration is out of date. A manager may have updated pricing defaults on the web since your last sync. Tap **Sync Now** to pull the latest pricing data, then open the estimate and verify the totals update accordingly. ### Error: "Session expired" Your authentication token has expired after an extended offline period. Log out via **Settings > Profile > Log Out**, then log back in with your credentials. The app preserves all pending offline changes and uploads them after you re-authenticate. --- ## Tips - **Sync before you leave the office.** A quick tap on Sync Now ensures your local data is current before heading into the field. - **Save estimates as drafts when offline.** Finalize and send them as soon as you reconnect -- it takes only a few seconds. - **Monitor the sync indicator.** The icon in the header tells you at a glance whether your data is current or has pending uploads. - **Use Wi-Fi for the initial sync.** The first sync after installing the app downloads your full client list and pricing data. A Wi-Fi connection avoids consuming mobile data. - **Do not clear the cache unnecessarily.** Clearing forces a full re-download of all data. Only use it when troubleshooting persistent issues. - **Take photos on-site even without signal.** They attach to the relevant record locally and upload automatically during the next sync. - **Check the sync status before switching devices.** If you create estimates on mobile and want to continue on the web, make sure the green checkmark is showing first. --- URL: https://docs.cleanestimate.pro/operations/holiday-lights-inventory Title: Holiday Lights Inventory Management Description: Track light strands, accessories, and seasonal supplies with purchase orders, equipment testing, and end-of-season workflows. Category: operations Difficulty: intermediate --- # Holiday Lights Inventory Management Holiday lighting services require specialized inventory tracking that goes beyond standard cleaning supplies. Light strands, clips, extension cords, timers, and mounting hardware must be tracked by type, length, color, and condition. CleanEstimate Pro provides a dedicated inventory system for seasonal lighting supplies, separate from your general operations inventory. Navigate to **Admin > Holiday Lights > Inventory** to manage your holiday lights inventory. [SCREENSHOT: Holiday lights inventory page showing light strands categorized by type with quantity, condition, and location columns] --- ## Why Separate Inventory Tracking Holiday lighting inventory has characteristics that make it unsuitable for general inventory tracking: - **Seasonal usage.** Supplies are purchased, deployed, retrieved, and stored on a yearly cycle. They sit idle for months between seasons. - **Condition tracking.** Light strands degrade over time and must be tested before each season. General inventory items do not need condition assessments. - **Customer allocation.** Strands and hardware are often allocated to specific customer installations and must be tracked at that level. - **Reusability.** Unlike cleaning chemicals that are consumed, lighting supplies are reused across multiple seasons, making asset tracking essential. The dedicated holiday lights inventory system handles all of these requirements. --- ## Inventory Categories The holiday lights inventory organizes items into categories that reflect the types of supplies used in lighting installations. ### Light Strands Light strands are the core product. Track them by: | Attribute | Description | |---|---| | **Strand type** | LED mini lights, C9 bulbs, C7 bulbs, icicle lights, net lights, rope lights, etc. | | **Length** | Strand length in feet (e.g., 25 ft, 50 ft, 100 ft). | | **Color** | Warm white, cool white, multi-color, single color (red, green, blue, etc.). | | **Quantity** | Number of strands in stock. | | **Condition** | New, Tested Good, Needs Repair, Damaged, Retired. | | **Location** | Storage warehouse, assigned to customer, or deployed on-site. | [SCREENSHOT: Light strand inventory list showing type, length, color, quantity, condition, and location for each entry] ### Clips and Mounting Hardware Track the clips, hooks, and fasteners used to attach lights to rooflines, gutters, and architectural features. | Item Type | Common Variants | |---|---| | **Gutter clips** | Standard, all-in-one, shingle tab | | **Roof clips** | Adhesive, magnetic, screw-mount | | **Tree wrapping clips** | Spiral clips, trunk wraps | | **Hooks and hangers** | S-hooks, command hooks, wreath hangers | | **Cable ties** | Standard zip ties, reusable ties | ### Electrical Supplies | Item Type | Description | |---|---| | **Extension cords** | Outdoor-rated cords by length (25 ft, 50 ft, 100 ft). | | **Timers** | Mechanical and digital timers for automated on/off scheduling. | | **Power splitters** | Multi-outlet adapters and power strips rated for outdoor use. | | **GFCI adapters** | Ground fault circuit interrupter adapters for safety compliance. | | **Replacement bulbs** | Individual bulbs for each strand type, tracked by color and style. | ### Storage Supplies | Item Type | Description | |---|---| | **Storage bins** | Labeled bins for organizing strands by type and color. | | **Cord reels** | Reels for wrapping strands to prevent tangling. | | **Labels and tags** | For marking bins with customer names, strand types, and conditions. | --- ## Adding Inventory Items ### Adding a Single Item 1. Navigate to **Admin > Holiday Lights > Inventory**. 2. Click **+ Add Item**. 3. Fill in the item details: - **Item name** -- A descriptive name (e.g., "C9 LED Warm White - 50 ft"). - **Category** -- Select from Light Strands, Clips, Electrical, or Storage. - **Type / Variant** -- The specific product type. - **Quantity** -- Number of units on hand. - **Unit cost** -- Cost per unit for tracking investment. - **Condition** -- New, Tested Good, Needs Repair, Damaged, or Retired. - **Storage location** -- The warehouse or storage site where the item is kept. - **Reorder point** -- The quantity threshold that triggers a low-stock alert. 4. Click **Save**. [SCREENSHOT: Add inventory item form with fields for name, category, type, quantity, unit cost, condition, location, and reorder point] ### Bulk Entry For large initial inventories, use the batch entry mode on the inventory page. This lets you add multiple rows at once without navigating back to the form for each item. --- ## Purchase Orders Purchase orders track orders placed with suppliers for new lighting supplies. They help you plan seasonal purchasing, track costs, and manage receiving. ### Creating a Purchase Order 1. Navigate to **Admin > Holiday Lights > Inventory > Purchase Orders**. 2. Click **+ New Purchase Order**. 3. Enter the supplier information: - Supplier name - Contact information - Expected delivery date 4. Add line items: - Select or enter the product name. - Specify the quantity ordered. - Enter the unit cost. - The line total calculates automatically. 5. Review the purchase order total. 6. Click **Save**. [SCREENSHOT: Purchase order creation form showing supplier details, line items with product, quantity, unit cost, and line total] ### Purchase Order Statuses Each purchase order moves through a lifecycle: | Status | Description | |---|---| | **Draft** | Created but not yet submitted to the supplier. | | **Ordered** | Submitted to the supplier. Awaiting delivery. | | **Partially Received** | Some items have arrived. Remaining items are still expected. | | **Received** | All items have arrived. Inventory quantities updated. | | **Cancelled** | The order was cancelled before completion. | ### Receiving a Purchase Order When a shipment arrives: 1. Open the purchase order. 2. Click **Receive**. 3. Enter the quantities received for each line item. If the full quantity arrived, click **Receive All**. 4. Click **Confirm**. The system updates your inventory quantities automatically. If only a partial shipment arrived, mark the received quantities and the PO status changes to "Partially Received." [SCREENSHOT: Purchase order receiving screen showing ordered quantities, received quantities, and remaining quantities] ### Pre-Season Purchasing Workflow Most holiday lighting businesses follow a purchasing calendar: | Month | Action | |---|---| | **July - August** | Review prior year usage. Identify items that need replacement. Create purchase orders for new stock. | | **September** | Receive shipments. Add new inventory. Begin pre-season testing. | | **October** | Finalize inventory counts. Place supplemental orders for any shortfalls. | | **November - December** | Deploy inventory to customer installations. Track allocations. | | **January** | Retrieve installed lights. Return to storage. | | **February - March** | Post-season inventory audit. Update conditions. Retire damaged items. | --- ## Testing Equipment Pre-season testing ensures that reusable light strands are functional before deployment. CleanEstimate Pro includes a testing log at **Admin > Holiday Lights > Inventory > Testing**. ### Testing Workflow 1. Navigate to **Admin > Holiday Lights > Inventory > Testing**. 2. Select the items to test from your inventory. 3. For each item, record the test result: - **Pass** -- The strand is fully functional. Condition updates to "Tested Good." - **Needs Repair** -- The strand has minor issues (e.g., a few dead bulbs). Condition updates to "Needs Repair." - **Fail** -- The strand is not functional and cannot be economically repaired. Condition updates to "Damaged" or "Retired." 4. Add optional notes for items that need repair (e.g., "3 dead bulbs at positions 12, 23, 45"). 5. Click **Save Results**. [SCREENSHOT: Testing log showing a list of light strands with Pass, Needs Repair, and Fail radio buttons and a notes field] ### Why Test Equipment Holiday light strands degrade over time from weather exposure, handling, and storage. Testing before the season starts prevents costly problems: - **Installation delays.** Dead strands discovered on a rooftop require a crew to climb down, return to the warehouse, and come back. This can turn a 2-hour job into a 4-hour job. - **Customer callbacks.** Burnt-out sections discovered after installation require a return visit at your expense. - **Safety hazards.** Damaged wiring can cause electrical shorts, tripped breakers, or fire hazards. A systematic testing process catches failures in the warehouse where they are cheap to address, not on the roof where they are expensive. ### Test Metrics The testing page displays summary metrics: | Metric | Description | |---|---| | **Total tested** | Number of items that have been tested this season. | | **Pass rate** | Percentage of items that passed testing. | | **Needs repair** | Number of items requiring repair before deployment. | | **Failed / retired** | Number of items that cannot be reused. | | **Untested** | Number of items still awaiting testing. | [SCREENSHOT: Testing summary metrics showing pass rate, repair count, failed count, and untested count] ### Repair Tracking Items marked "Needs Repair" should be repaired and retested before deployment. After repairing a strand: 1. Return to the testing page. 2. Find the repaired item. 3. Retest and update the result to Pass or Fail. This ensures no damaged strands are sent to customer installations. Strands that fail testing twice should generally be retired rather than repaired again -- the labor cost of repeated repairs typically exceeds the replacement cost. --- ## Seasonal Inventory Workflows Holiday lighting inventory follows a distinct seasonal cycle. Each phase has specific inventory management tasks. ### Pre-Season (August - October) 1. **Audit existing inventory.** Count all items in storage. Update quantities in the system to match physical counts. 2. **Test reusable strands.** Run every strand through the testing process. Retire damaged items. 3. **Calculate needs.** Review signed contracts and proposals to determine how many strands, clips, and accessories you will need for the upcoming season. 4. **Place purchase orders.** Order new stock to fill gaps between existing inventory and projected needs. Order early -- suppliers often run low on popular items by October. 5. **Receive and organize.** When orders arrive, receive them in the system, label them, and organize them in storage by type and color. ### Installation Season (October - December) 1. **Allocate inventory to jobs.** When a job is scheduled, allocate the required strands and hardware to that customer. Update the item location from the warehouse to the customer name or address. 2. **Track deployments.** As crews install lights, record which items went to which property. This is critical for retrieval and for knowing what the customer had last year. 3. **Monitor stock levels.** Watch for low-stock alerts on clips, extension cords, and frequently used strand types. Place supplemental orders as needed. 4. **Handle field issues.** When a strand fails during installation, log it as damaged in the system and pull a replacement from stock. ### Retrieval Season (January - February) 1. **Retrieve installed lights.** As crews take down installations, record the returned items. 2. **Inspect returned items.** Note the condition of each returned strand. Mark items that need repair or retirement. 3. **Return to storage.** Update item locations back to the warehouse. Organize by type and condition. 4. **Reconcile.** Compare the items returned from each customer against what was deployed. Identify any losses. ### Off-Season (March - July) 1. **Post-season audit.** Conduct a full inventory count and reconcile with the system. 2. **Retire damaged items.** Remove items that are beyond repair from active inventory. 3. **Analyze usage.** Review which strand types and colors were most popular. Identify items with high failure rates. Use this data to inform next season's purchasing decisions. 4. **Plan early purchases.** Some suppliers offer pre-season discounts for orders placed in the spring. Identify your needs early and lock in pricing. --- ## Low-Stock Alerts Items with a quantity at or below their configured reorder point are flagged with a low-stock warning. These alerts appear: - On the holiday lights inventory page as a highlighted row with a warning badge. - In the low-stock alert banner at the top of the inventory page. - On the admin dashboard as a notification. Set reorder points based on your peak weekly installation volume, not your average. Running out of C9 warm white strands during the busiest week of the season causes installation delays and lost revenue. | Item | Example Reorder Point | Rationale | |---|---|---| | C9 LED strands | 50 strands | High usage item; supplier lead time is 2 weeks. | | Gutter clips | 500 clips | Cheap, high-volume; running out halts installations. | | Extension cords (50 ft) | 20 cords | Moderate usage; replacements are easy to source locally. | | Timers | 10 units | Low usage per job; small buffer is sufficient. | [SCREENSHOT: Low-stock alert banner showing items below reorder threshold with quantities and reorder points] --- ## Storage Location Tracking If you operate from multiple warehouses or storage facilities, track which items are stored where. Each inventory item has a location field that can be set to: - A specific warehouse or storage facility name. - A customer name or address (for items currently deployed at a customer's property). - "In Transit" for items being moved between locations. This helps crews find what they need without searching every storage location. During the busy season, knowing that the warm white C9 strands are in Warehouse B, Bay 3, saves significant time. --- ## Cost Tracking Purchase order data feeds into your holiday lighting profitability analysis. By tracking the cost of every strand, clip, and accessory, you can: - Calculate the true cost of each installation (materials plus labor). - Determine which strand types offer the best margins. - Identify whether reusing strands across seasons is cost-effective versus buying new each year. - Set accurate pricing for your holiday lighting proposals. Review your cost data at the end of each season to refine next year's pricing. --- ## Tips - **Label everything.** Physical labels on storage bins that match your digital inventory categories save enormous time during the busy season. - **Test early.** Begin pre-season testing in August or September. Waiting until October leaves too little time to order replacements for failed strands. - **Track by customer.** Recording which strands went to which property makes retrieval faster and helps you plan repeat installations with the same setup. - **Set aggressive reorder points for clips.** Clips are inexpensive and used in high volume. Running out mid-season delays installations and frustrates crews. - **Retire aggressively.** Strands that fail testing twice should be retired. The labor cost of repeated repairs exceeds the replacement cost. - **Reconcile after every season.** Physical counts after retrieval season catch discrepancies before they compound year over year. - **Order popular colors early.** Warm white and multi-color strands sell out at suppliers first. Place orders by August for guaranteed availability. - **Track cost per installation.** Use purchase order data to calculate your material cost per job. This informs future pricing and margin targets. --- ## Troubleshooting ### Stock levels do not match physical counts Conduct a manual count and update the system. Discrepancies usually arise from items deployed to customer sites without updating the location field, items damaged in the field without being recorded, or items moved between storage locations without logging the transfer. ### Purchase order did not update inventory quantities Make sure you clicked **Receive** on the purchase order and confirmed the received quantities. Simply changing the PO status manually does not trigger the inventory update. You must go through the receiving workflow. ### Testing page shows no items The testing page pulls from your holiday lights inventory. If the page is empty, you have not added any items to the holiday lights inventory yet. Add items at **Admin > Holiday Lights > Inventory** first, then return to the testing page. ### Low-stock alerts are not appearing Verify that reorder points are configured on your inventory items. Items without a reorder point will never trigger a low-stock alert. Open each item and set an appropriate threshold. ### Items showing wrong condition after testing Test results update the condition field automatically. If the condition does not match the test result, check that the test was saved successfully. Re-run the test and save again if needed. --- URL: https://docs.cleanestimate.pro/operations/inventory Title: Inventory Management Description: Track equipment, chemicals, and supplies with low-stock alerts and purchase orders. Category: operations Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Inventory Management Keep track of everything your business uses. CleanEstimate Pro tracks quantities, alerts you when stock runs low, and lets you create purchase orders to restock. Navigate to **Admin > Operations > Inventory** to open the inventory table. [SCREENSHOT: Inventory table showing columns for item name, category, quantity, reorder point, location, and last updated date] ## Inventory Table The inventory table lists every tracked item. Each row shows: | Column | Description | |---|---| | Item Name | The name of the supply or piece of equipment. | | Category | Grouping such as Chemicals, Hardware, Safety, or Lights. | | Quantity on Hand | Current stock count. | | Reorder Point | The quantity that triggers a low-stock alert. | | Location | The warehouse or storage site where the item is kept. | | Last Updated | The date the quantity was last changed. | Click any row to edit the item details. ## Low-Stock Alerts Items with a quantity at or below their reorder point are highlighted in the table. A warning badge appears next to the item name. Check the inventory page regularly or look for the low-stock alert banner at the top of the page. [SCREENSHOT: Inventory table with two items highlighted in yellow showing low-stock warning badges] ## Adding an Inventory Item 1. Click **+ Add Item** at the top of the inventory page. 2. Fill in the following fields: - **Item Name**: A descriptive name (e.g., "Window Cleaning Solution - 1 Gallon"). - **Category**: Select Chemical, Supply, Safety, or Other. - **Unit**: Choose how you count the item, such as each, gallon, or case. - **Quantity**: Current quantity on hand. - **Unit Cost**: Cost per unit for tracking expenses. - **Reorder Point**: Set the threshold for low-stock alerts. - **Supplier**: Optional vendor name for reorder tracking. - **Storage Location**: Select the warehouse or storage site. - **Last Reorder Date**: Optional date of the most recent restock. 3. Click **Save**. [SCREENSHOT: Add inventory item form with fields for name, SKU, category, quantity, unit cost, reorder point, and location] Inventory saves now reject malformed category, quantity, unit-cost, reorder, and date payloads before they are written. That keeps low-stock alerts and cost rollups from drifting because of half-valid item edits. ## Editing and Updating Quantities Open any item to update its details. Use the quantity field to adjust stock after receiving a shipment or using supplies on a job. All quantity changes are logged with a timestamp so you can track usage over time. ## Purchase Orders Purchase orders help you track orders placed with suppliers. ### Creating a Purchase Order 1. Navigate to **Admin > Operations > Inventory**. 2. Click **Purchase Orders** in the sub-navigation. 3. Click **+ New Purchase Order**. 4. Select a supplier or enter supplier details. 5. Add line items with the items you need, quantities, and unit costs. 6. Click **Save**. ### Tracking Purchase Orders Each purchase order shows its status: Draft, Ordered, Received, or Cancelled. When a shipment arrives, mark the PO as Received to update your inventory quantities. [SCREENSHOT: Purchase order detail page showing supplier info, line items, totals, and a status dropdown] ## Holiday Lights Inventory If you offer holiday lighting services, CleanEstimate Pro provides a separate inventory section for seasonal supplies. Navigate to **Admin > Holiday Lights > Inventory** to manage: - Light strands (by type, length, and color) - Clips, hooks, and mounting hardware - Extension cords and timers - Storage bins and labels This inventory is separate from your general supplies so seasonal items do not clutter your everyday tracking. The holiday lights inventory also includes a **Testing** page at **Admin > Holiday Lights > Inventory > Testing** where you can log the results of pre-season light strand testing. [SCREENSHOT: Holiday lights inventory page showing light strands categorized by type with quantity and condition columns] ## Next Steps - Set up [storage locations](https://docs.cleanestimate.pro/operations/locations) to organize where inventory is kept. - Return to the [Operations Overview](https://docs.cleanestimate.pro/operations/overview) to explore other features. --- URL: https://docs.cleanestimate.pro/operations/invoices Title: Invoices and Payments Description: Create invoices, send pay links, and collect split payments with a shared payment ledger. Category: operations Difficulty: beginner Roles: owner, manager, sales_rep, crew_lead Last updated: 2026-04-18 --- # Invoices and Payments CleanEstimate Pro handles invoicing from creation through collection. You can send Stripe pay links, charge a card from the office, or record offline tender like cash, check, and bank transfer without leaving the invoice workflow. Navigate to **Admin > Invoices** to view all invoices. [SCREENSHOT: Invoices list page showing invoice number, customer, total, balance due, status, and actions] ## Invoice List The invoice list shows both the original invoice total and the remaining balance. This makes partial and split payments visible at a glance. | Status | Meaning | |---|---| | Draft | Invoice exists but has not been sent yet. | | Sent | Invoice was sent to the customer. | | Viewed | Customer opened the invoice or payment page. | | Partial | Some money has been collected, but a balance remains. | | Paid | The balance is fully collected. | | Overdue | The due date passed and money is still owed. | | Void | The invoice was closed without collection. | Use **Collect** from the list for fast payment entry, or click the invoice number to open the full invoice page. The invoice list also supports the shared **Filter by tag** dropdown used in leads, jobs, and estimates. Tags are color coded and can be created from the dropdown so the same tag set stays consistent across the office views. That tag filter now resolves against the linked client tags inside the invoice list query itself, so larger workspaces do not need to load every matching client id into the app server before the filtered list can render. The list now includes the same shared date-range control as the rest of the admin workspace. You can keep a quick preset like **Last 30 days** or open the custom picker to isolate invoices created inside an exact date window. Invoice detail loads now fail less often on older workspaces too. CE Pro no longer depends on a removed invoice customer-phone column just to open the page, so existing invoice records keep opening normally and the payment drawer stays reachable. ## Invoice Detail Page Each invoice has its own detail page with: - Invoice status, total, paid amount, and remaining balance - Customer information - A direct **View Client** action when the invoice is linked to a CRM client - Assigned sales rep with an editable selector on the invoice detail page - Stored line items - Office notes - A customer-facing invoice page you can open before sending - Invoice attachments for photos, PDFs, permits, and supporting files - A full payment ledger [SCREENSHOT: Invoice detail page showing totals on top, line items in the center, and the payments card on the right] ## Collecting Payments You can collect money directly on the invoice, or from the linked job, estimate, or lead. All of those entry points write to the same ledger and keep balances in sync. When you create an invoice from a job that already has a deposit or split payment on file, the invoice now carries that collected amount forward automatically. The invoice balance starts at the true remaining amount due instead of resetting to the full job total. Supported collection methods include: - Credit card keyed in through Stripe - Stripe pay link for online payment - Tap to pay / reader payments recorded by the office - Cash - Check - Bank transfer / ACH - External card processor entries - Other custom payment types ### Split Payments Split payments are supported automatically. Example: - Invoice total: `$800` - First payment: `$600` credit card - Second payment: `$200` cash After the first payment, the invoice moves to **Partial** and shows a `$200` balance. After the second payment, the invoice moves to **Paid**. The collection dialog is designed for this flow. Enter any portion of the balance, save it, and keep adding payments until the balance reaches `$0.00`. The payment modal now uses a wider office layout with: - totals across the top - a full-width method picker that stays readable - a wider dialog frame tuned for laptop screens instead of a cramped narrow popup - a fixed modal frame with an internal scroll area so no payment content bleeds outside the window - payment history visible in the same workflow while you collect money, with the payment setup on the left and the running ledger on the right on desktop and larger laptop layouts - clearer section headers for setup, collection method, and ledger review - credit-card sub-method warnings render below the button grid with clear spacing instead of overlapping the controls - keyed-card entry stays mounted after it is prepared; if the amount changes, the office gets a clear **Refresh Card Amount** prompt instead of losing the entered card data - invoice detail now gives the sales-rep and billing-owner block enough width so the payment workspace is not squeezed by a tiny side panel - long invoice labels, customer names, and receipt emails now wrap inside the modal instead of pushing content outside the dialog frame - long customer names and emails now also wrap safely on the invoice detail page itself, so the customer header does not break the side-by-side billing-owner layout - invoice **Collect Payment** now keeps the keyed-card action stable while the dialog refreshes payment data, which removes the intermittent office-side crash some staff saw when opening the payment workspace on invoice detail - invoice collect-payment and pay-link actions now reuse the stored invoice link when one already exists, so older invoices can still open or retry payment flows without forcing a fresh customer-token setup path ## Payment History Every invoice keeps a payment history showing: - Amount - Method - Status - Date and time - Reference number - Notes - Stripe link or charge details when applicable This history is the source of truth for invoice payment reporting. CleanEstimate Pro does not rely on a manual "mark paid" shortcut for partial or full payment collection. Refund actions now create the internal adjustment record before Stripe is asked to move money. If a follow-up save or sync step needs to retry, the office ledger still has a durable refund trail instead of leaving the invoice with no matching record, and failed Stripe refunds now mark that pending adjustment as failed instead of leaving it stuck in limbo. ## Sending an Invoice Invoices can be sent from the invoice page or the job page. 1. Open the invoice. 2. Click **Send Invoice**. 3. Review the recipient, subject, and email message in the send dialog. 4. CleanEstimate Pro emails the customer a direct invoice link and moves it to **Sent**. The send dialog also shows the customer-facing invoice page and any available pay link so the office can preview or copy them before sending. If a Stripe payment link is available, the email includes that payment path automatically. If not, the customer can still open the hosted invoice page and review the billed work. If secure invoice-link signing is not configured yet, the invoice detail page still opens and the office can keep reviewing billing details. In that state, **Create Pay Link** still returns a clear setup message instead of a generic server error unless the invoice already has a stored link that can be reused. **Send Invoice** now still delivers the invoice email, but it omits the online pay button when a fresh secure link cannot be generated yet. When the customer opens the invoice email, Resend now feeds that email-open activity back into the outbound email row inside **Messages** with the tracked open time, total opens, and latest tracked link click. When the customer opens the hosted invoice page itself, CleanEstimate Pro logs a separate `Invoice viewed` system event and raises a live admin popup plus bell alert that links back to the invoice record. ## Sales Rep Tracking Invoices inherit the assigned sales rep from the linked job whenever one exists. If you create an invoice directly from an estimate, the estimate's sales rep also carries forward. Office staff can change the rep from the invoice detail page at any time without affecting the payment ledger. The same invoice header now exposes **View Client**, **View Estimate**, and **View Job** actions together when those linked records exist, so billing staff can move between the customer, sales, and production records without backing out to list pages first. [SCREENSHOT: Invoice action bar showing Send Invoice, Open Pay Link, and linked job/estimate actions] ## Bulk Invoices From Bulk-Scheduled Jobs Jobs created through **Bulk Schedule** are invoice-ready from the moment they are created. Each job stores: - line items - subtotal - tax amount - total Because the billing fields live on the job, you can create draft invoices for the newly created batch directly from the bulk scheduler without opening each job one by one. The bulk invoice action lets you: - choose which created jobs to invoice - generate draft invoices in one step - skip jobs that already have an invoice instead of duplicating billing ## Attachments Invoices now support a shared **Attachments** section on the detail page. Use it to store: - Jobsite photos tied to billing questions - Signed approvals or change orders - Purchase orders - Permit documents - Supporting PDFs and office files Attachments stay on the invoice record so the office can review the full billing package in one place. Supported attachment types are images, PDFs, TXT and CSV files, plus common Word, Excel, and PowerPoint documents. CleanEstimate Pro now verifies the uploaded file before saving it. If the extension or real file type does not match, the upload is rejected with a plain-language message instead of being stored anyway. ## Stripe Payments When a customer pays through Stripe: - The payment lands in the ledger automatically - The invoice balance updates - The invoice status changes to **Partial** or **Paid** - The linked job stays in sync If a payment fails or remains pending, the ledger reflects that status instead of falsely settling the invoice. Every successful office-collected payment can also send a receipt email to the customer using the receipt email field in the collection dialog. Keyed-card preparation no longer creates a pending payment row by itself. The ledger records the payment only after Stripe confirms the charge and CE Pro syncs the intent, which keeps payment history cleaner when staff changes their mind mid-entry. ## Offline Payments Use the payment dialog to record offline tender the moment you receive it. This keeps the invoice, job, estimate, and lead records aligned without having to reconcile them later. Recommended uses: - Cash collected by the crew on site - Check received by the office - ACH or bank transfer confirmed by accounting - Card run through an external terminal or another processor ## Next Steps - Learn how [jobs](https://docs.cleanestimate.pro/operations/jobs) connect to invoice collection. - Connect Stripe in [Settings > Stripe](https://docs.cleanestimate.pro/settings/stripe) for keyed cards and hosted pay links. --- URL: https://docs.cleanestimate.pro/operations/locations Title: Locations Description: Manage your warehouses, offices, and storage locations. Category: operations Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Locations Locations represent the physical sites where your business stores equipment and supplies. Track your warehouses, offices, and storage units in one place. Navigate to **Admin > Operations > Locations** to view all locations. [SCREENSHOT: Locations list page showing three locations with name, address, type, and inventory count columns] ## Location List The Locations page shows all your sites in a table. Each row displays: | Column | Description | |---|---| | Name | The name you gave the location (e.g., "Main Warehouse"). | | Address | Street address of the location. | | Type | Warehouse, Office, or Storage. | | Inventory Count | The number of distinct inventory items stored at this location. | Click any location to view its detail page. ## Adding a Location 1. Click **+ Add Location** at the top of the page. 2. Fill in the following fields: - **Name**: A descriptive name for the location. - **Address**: The full street address. - **Type**: Select Warehouse, Office, or Storage. - **Notes**: Any additional details about the location (access hours, gate codes, etc.). 3. Click **Save**. The new location appears in the list and is available as a storage option when adding inventory items. CE Pro now validates location saves more strictly before writing them. Name stays required, and service-area ZIP lists reject malformed entries so dispatch and inventory filters do not inherit broken location data. [SCREENSHOT: Add location form with fields for name, address, type dropdown, and notes] ## Location Detail Page Open a location to see everything stored there. The detail page at `/admin/operations/locations/[id]` shows: ### Inventory at This Location A filtered view of your inventory table showing only items assigned to this location. You can see quantities, reorder points, and low-stock alerts for this site. [SCREENSHOT: Location detail page showing the location name and address at the top, followed by an inventory table filtered to that location] ### Equipment Assignments Any equipment assigned to this location appears here. This helps you track which tools and machines are stored at each site. ## Tips for Using Locations - **Create a location for each storage site.** Even if you only have one warehouse, adding it as a location lets you assign inventory to a specific place. - **Use the type field consistently.** Filtering by type helps when you have many locations. - **Add notes for access details.** Gate codes, operating hours, and contact info for the site manager are useful for crew leads picking up supplies. ## Next Steps - Learn how to [track inventory](https://docs.cleanestimate.pro/operations/inventory) at each location. - Return to the [Operations Overview](https://docs.cleanestimate.pro/operations/overview) for the full list of operations features. --- URL: https://docs.cleanestimate.pro/operations/jobs Title: Managing Jobs Description: Track jobs from scheduling through completion, then collect or record payments from the job record. Category: operations Difficulty: beginner Roles: owner, manager, crew_lead Last updated: 2026-04-18 --- # Managing Jobs A job represents a unit of work to be performed at a customer's property. Jobs flow through a series of statuses from scheduling to completion. Navigate to **Admin > Jobs** to view all jobs. [SCREENSHOT: Jobs list page showing a table of jobs with columns for customer, date, status, crew, and services] ## Job List The Jobs page shows all jobs in a filterable table. Each row displays: - Customer name - Service address - Scheduled date and time - Status - Assigned crew - Services ### Filtering Jobs Use the filters at the top to narrow the list: - **Status**: Scheduled, In Progress, Completed, Cancelled - **Date range**: Use quick presets or open the custom range picker to show only work scheduled between exact start and end dates - **Crew**: Show jobs for one crew only - **Tags**: Filter by custom tags you have applied The **Filter by tag** control is a searchable dropdown. It shows color-coded tags and lets office staff create a new shared tag definition directly from the picker when needed. The Jobs list now loads cleanly again in workspaces where the legacy job-level tag column is absent. Tag filters still work, but they are resolved from the linked client tags instead of depending on a separate `jobs.tags` field. Tag-filtered job searches now apply that client-tag match directly in the database query instead of loading every tagged client id into the app first. Larger workspaces should see more consistent tagged results without the older list-cap edge cases. [SCREENSHOT: Filter bar above the jobs table with status, date range, crew, and tag dropdowns] ## Job Statuses Every job moves through these statuses: | Status | Meaning | |---|---| | Scheduled | The job is on the calendar. Work has not started. | | En Route | The crew is traveling to the job site. | | In Progress | The crew is actively working on the job. | | Completed | The work is finished. | | Invoiced | Work is complete and billing is active. | | Cancelled | The job was cancelled before completion. | | Skipped | A recurring-template visit was intentionally skipped. | Status updates can be made from the admin dashboard or by crew leads using the mobile app. ## How Jobs Are Created Jobs are created in two ways: ### Automatically from Accepted Estimates When a customer signs a proposal or an estimate is marked as "Won" in the pipeline, CleanEstimate Pro creates a job automatically. The job inherits the customer info, services, and pricing from the estimate. ### Manually You can create a job manually from the Schedule page or the Jobs page. Click **+ Create Job**, set both the start date and end date, book the truck if needed, assign the crew, choose the sales rep if needed, then save. For single-day work, use the same date in both fields. See the [Schedule guide](https://docs.cleanestimate.pro/operations/schedule) for step-by-step instructions. ### Bulk Multi-Property Scheduling Use **Bulk Schedule** from **Admin > Jobs** when one contract covers many saved properties at once. This workflow is built for situations like one commercial account adding dozens of locations in a single sale. 1. Choose one source account or one standalone client. 2. Select multiple saved properties from that source. 3. Apply batch defaults for service type, dates, times, truck, crew, notes, tax, and line items. 4. Override any row that needs different pricing, notes, truck, or timing. 5. Create the batch in one submission. Each created job is invoice-ready immediately. CleanEstimate Pro stores the job's line items, subtotal, tax amount, and total on the job record, so you do not need to open every job just to prepare billing later. Bulk Schedule jobs now also write the same live environment marker that the Jobs list expects, so newly created rows appear immediately in **Admin > Jobs** after the batch completes. You can optionally load pricing and notes from an estimate or proposal template source. That source does **not** need to be won first. It simply seeds the batch defaults so the office can review and adjust them before creation. After the batch is created, use **Create Draft Invoices** to generate invoices for the created jobs in bulk without leaving the workspace. In v1, the bulk scheduler only uses saved properties from the address book. If a location is missing, add it to the client's saved addresses first. ### From Recurring Templates Recurring templates create jobs automatically as each scheduled visit approaches the lead window. Generated jobs stay linked to the template and occurrence number so you can reschedule or skip one visit without changing the full series. See [Recurring Job Templates](https://docs.cleanestimate.pro/operations/recurring-templates). ## Job Detail Page Click any job in the list to open its detail page at `/admin/jobs/[id]`. The detail page includes: The top action bar now also includes a dedicated **View Client** shortcut whenever the job is linked to a CRM client. That makes it easier to jump back to the customer profile from dispatch, scheduling, and payment work. ### Customer Information Name, phone, email, and service address. The job detail page now lets office staff edit those customer snapshot fields directly on the job without mutating the linked client record behind the scenes. ### Services The list of services to be performed, with quantities and pricing. Service lines are now job-scoped and fully editable on the detail page: - add or remove line items - change descriptions and notes - change quantity and unit price - recalculate subtotal, tax, and total live before saving If the job does not have direct line items yet, CleanEstimate Pro seeds the editor from the linked estimate so the office can make job-only pricing adjustments without recreating the work from scratch. That seeded baseline now stays stable after the page loads, so the Save button and unsaved-changes guard only turn on when someone actually edits the job. Jobs created from generic quotes and commercial building proposals now also surface saved **Crew Alerts** in the job detail workspace. The office and crew can review those internal instructions above the line-item editor and on the individual service rows, and crew leads now see the same callouts in the mobile job detail screen too. That keeps field-only guidance attached to the work without exposing it to the customer-facing quote or proposal. ### Truck Assignment The truck booked to this job comes from your dispatch vehicle list. CleanEstimate Pro accepts both dedicated truck records and legacy vehicle records from **Operations -> Vehicles**, then saves the correct dispatch truck behind the scenes. Assign the truck first when the equipment package matters for the work. ### Crew Assignment The crew or crew lead assigned to this job. After the truck is booked, you can assign the crew running that truck from this page. Existing crews created before the active/inactive toggle was added still appear in the selector, so older crew records with a blank active flag remain assignable until you intentionally archive them. Any active teammate with the **Crew Lead** or **Technician** role also appears in the crew selector automatically, even if you never created a manual crew record for them yet. That means field staff can be booked to jobs right away from Team settings. The job totals card also shows a **modeled crew pay** preview. That preview uses each assigned crew member's pay settings from **Team**: - Commission teammates are paid on the commissionable work subtotal only - Sales tax is excluded - Lift, equipment, and access adders are excluded - Subcontractor scope is excluded - Hourly teammates use the job's actual or scheduled time window ### Sales Rep Assignment Jobs now include a **Sales Rep** slot on the detail page and in the scheduling dialogs. - Standalone jobs can assign a rep while booking the work - Jobs created from estimates carry the estimate's assigned rep forward automatically - Office staff can reassign the rep later from the job detail page without recreating the job ### Shared Tags Job detail includes a **Tags** card when the job is linked to a client. Saving tags there updates the shared client tag set so those labels keep working across leads, estimates, jobs, and invoices. ### Subcontractor Payouts When a subcontractor is assigned, the **Subcontractor Payouts** section appears so you can record payout amount, status, and payment details. If no subcontractor is selected for the job, this section is hidden by default. ### Notes Internal notes for the crew. Add instructions, access codes, or special requests. ### Photos Before and after photos uploaded by the crew. Photos are attached to the job for quality tracking and customer records. Supported upload formats are JPEG, PNG, and WebP. For security, renamed or unsupported files are rejected instead of being stored. ### Status Updates A timeline of status changes with timestamps. See exactly when the crew went en route, started work, and finished. ### Deleting Jobs Owners and managers can permanently delete a job from the **Delete Job** link at the bottom of the detail page. CE Pro always asks for confirmation before deleting. When you confirm, the job is removed and you return to the Jobs list with a success message. ### Payments The job detail page includes a **Collect Payment** modal in the Payments card. On desktop and larger laptop screens, the modal now uses a split layout: payment setup and card entry stay on the left while the live payment summary and history stay visible on the right. The header and action button remain fixed so office staff can still see the balance due while entering payments. If the job already has an invoice, the modal collects against that invoice balance. If the invoice has not been sent yet, the same modal can still record payments or generate a Stripe pay link. Deposits and partial payments collected before the invoice exists still count. When you generate the invoice later, CleanEstimate Pro carries those payments forward so the job and invoice both show the correct remaining balance. The payment modal includes: - **Payment Setup** for amount, receipt email, and internal notes - **Apply As** toggle for payment versus deposit - **Collection Method** buttons for Credit Card, Cash, Check, Bank Transfer / ACH, and Other - **Credit Collection** options for Keyed Card, Pay Online Link, Tap to Pay / Reader, and External Processor - **Payment History** with prior successful payments, notes, status badges, and eligible refund / void actions Supported job-side payment actions include: - Record cash, check, bank transfer, and other offline payments - Charge a keyed credit card through Stripe's secure embedded payment form - Record tap to pay / reader collections - Record external processor card charges - Create and copy a Stripe pay link - Refund or void eligible payments directly from Payment History - Take split payments across multiple tender types - Refresh the prepared keyed-card amount if the office changes the charge after secure card entry is loaded [SCREENSHOT: Job detail page showing customer info, services list, assigned crew, notes, and a status timeline] ## Completing a Job When work is finished: 1. Update the job status to **Completed**. 2. Add any final notes about the work performed. 3. Upload after photos if required. When a job is marked as Completed, CleanEstimate Pro can automatically: - **Generate an invoice** for the work performed. - **Send a review request** to the customer asking for a Google review. After the invoice exists, you can stay on the job page to collect payment, record partials, or open the invoice detail screen. See [Invoices and Payments](https://docs.cleanestimate.pro/operations/invoices) for the full billing workflow. [SCREENSHOT: Job completion screen showing the status dropdown set to Completed, a notes field, and a photo upload area] ## Converting Estimates to Jobs From the Estimates section, you can convert an accepted estimate into a job: 1. Open the estimate detail page. 2. Click **Convert to Job**. 3. Set the scheduled start date and end date, then assign a crew. 4. Click **Create Job**. This creates the job and links it to the original estimate. The convert flow now validates the schedule payload more strictly before it creates the job. Start date and end date are both required, the end date cannot be earlier than the start date, and any optional time window must stay in chronological order. Owners and managers can also force the conversion when the estimate has not been marked `accepted` or `signed` yet, as long as they use the override flow in the convert dialog. [SCREENSHOT: Convert to Job dialog on an estimate page with date picker and crew assignment fields] ## Next Steps - Learn how to [create and send invoices](https://docs.cleanestimate.pro/operations/invoices) after completing jobs. - Set up [quality control checklists](https://docs.cleanestimate.pro/operations/quality-control) for your crews. --- URL: https://docs.cleanestimate.pro/operations/overview Title: Operations Overview Description: Manage your daily operations — schedule, dispatch, jobs, and invoicing. Category: operations Difficulty: beginner Roles: owner, manager Last updated: 2026-03-10 --- # Operations Overview The Operations section gives you everything you need to run your business day to day. From scheduling crews to collecting payment, it all lives here. Open **More > Operations** in the admin sidebar to jump in. CleanEstimate Pro lands you on **Locations** first, and the tabs across the top let you switch between Locations, Inventory & Equipment, Vehicles, and Quality Control. [SCREENSHOT: Operations section in the admin sidebar showing Schedule, Jobs, Invoices, and other sub-menu items] ## What Operations Covers ### Schedule and Dispatch View your daily job calendar. Assign crews to jobs. Send ETA notifications to customers. Toggle between day and week views to plan ahead. [Learn more about Schedule and Dispatch.](https://docs.cleanestimate.pro/operations/schedule) ### Route Management Optimize the order of jobs for each crew. Minimize drive time. See routes on a map. [Learn more about Route Management.](https://docs.cleanestimate.pro/operations/routes) ### Jobs Track every job from the moment it is scheduled through completion. Update statuses, add notes, and attach photos. [Learn more about Managing Jobs.](https://docs.cleanestimate.pro/operations/jobs) ### Recurring Templates Build repeat service contracts that automatically generate future jobs. Use these for quarterly, monthly, or seasonal work that should stay on a schedule without being recreated every time. [Learn more about Recurring Job Templates.](https://docs.cleanestimate.pro/operations/recurring-templates) ### Invoices and Payments Create invoices, send them by email or SMS, and accept online payments through Stripe. Track which invoices are paid, pending, or overdue. [Learn more about Invoices and Payments.](https://docs.cleanestimate.pro/operations/invoices) ### Inventory Track your equipment, chemicals, and supplies. Get alerts when stock runs low. Create purchase orders to restock. [Learn more about Inventory Management.](https://docs.cleanestimate.pro/operations/inventory) ### Locations Manage your warehouses, offices, and storage locations. See what inventory is stored at each site. [Learn more about Locations.](https://docs.cleanestimate.pro/operations/locations) ### Quality Control Build inspection checklists for your crews. Review quality reports after each job. Track callbacks and rework. [Learn more about Quality Control.](https://docs.cleanestimate.pro/operations/quality-control) ### Vehicles Track your fleet of trucks and vans. Log maintenance and assign vehicles to crews. Vehicle management is handled within the Operations section at **Operations > Vehicles**. ## Getting Started Most operations workflows start with an accepted estimate. When a customer signs a proposal, CleanEstimate Pro automatically creates a job. From there you schedule it, assign a crew, complete the work, and send an invoice. 1. A customer accepts an estimate. 2. A job is created automatically. 3. You schedule the job and assign a crew. 4. The crew completes the work and updates the status. 5. An invoice is generated and sent to the customer. 6. The customer pays online through Stripe. [SCREENSHOT: Flowchart showing the path from accepted estimate to paid invoice] ## Who Uses Operations - **Owners** and **Managers** have full access to all operations features. - **Crew Leads** can view their assigned jobs, update statuses, and submit quality reports. - **Sales Reps** can view job statuses but cannot modify schedules or invoices. ## Next Steps Start with the [Schedule and Dispatch](https://docs.cleanestimate.pro/operations/schedule) guide to learn how to manage your daily calendar. --- URL: https://docs.cleanestimate.pro/operations/quality-control Title: Quality Control Description: Create inspection checklists and track quality reports for every job. Category: operations Difficulty: intermediate Roles: owner, manager, crew_lead Last updated: 2026-03-18 --- # Quality Control Quality control helps you maintain consistent service across every job. Build checklists your crews follow on site. Review reports to catch issues early. Navigate to **Admin > Operations > Quality** to access QC features. [SCREENSHOT: Quality control landing page with two sections: Checklists and Reports] ## QC Checklists Checklists define the steps your crew must complete before or after a job. You create them once, then assign them to job types. ### Viewing Checklists Navigate to **Admin > Operations > Quality > Checklists** to see all checklists. Each checklist shows its name, linked service type, item count, and whether the template is active. [SCREENSHOT: Checklists page showing a list of checklists with name, item count, and type columns] ### Creating a Checklist 1. Click **+ New Checklist**. 2. Enter a name (e.g., "Post-Job Window Cleaning Inspection"). 3. Optionally enter the service type this checklist is meant to support. 4. Add checklist items. For each item, set: - **Description**: What the crew member needs to check (e.g., "All windows are streak-free"). - **Photo Required**: Whether the crew member must upload a photo for this item. 5. Click **Save**. [SCREENSHOT: Checklist editor with a name field, type toggle, and a list of checklist items each with description, required toggle, and photo required toggle] Checklist saves now reject malformed item payloads before they are written. In practice, every item needs a stable id, a label, and a valid photo-required flag, so the report builder always has a clean template to render. Editing an existing checklist now only changes the fields you actually save. Updating the name or item list no longer flips an inactive checklist back on unless you explicitly reactivate it. ### Checklist Item Examples Here are some common checklist items for cleaning businesses: **Pre-Job Checklist** - Verify correct customer address. - Check that all required equipment is loaded. - Confirm access instructions with the customer. **Post-Job Checklist** - All service areas are clean and inspected. - No equipment or supplies left on site. - Before and after photos uploaded. - Customer walkthrough completed (if applicable). ## QC Reports When a crew completes a checklist on site, the results are submitted as a QC report. Reports give managers visibility into the quality of every job. ### Viewing Reports Navigate to **Admin > Operations > Quality** to see submitted reports. Each report shows: | Field | Description | |---|---| | Job Reference | The job this report belongs to. Links to the job detail page. | | Checklist | The checklist that was completed. | | Completion | How many items were checked off out of the total. | | Photos | Photos uploaded as part of the checklist. | | Notes | Any notes the crew added during the inspection. | | Result | Pass or Fail based on whether all required items were completed. | [SCREENSHOT: QC report detail showing a completed post-job checklist with checkmarks, two uploaded photos, and a Pass result badge] ### Pass and Fail A report score is calculated from the checklist items marked **Pass**, **Fail**, or **N/A**. Items marked **N/A** are excluded from the score, and failed items are highlighted so managers can review them quickly. Failed reports are highlighted in the report list so managers can follow up quickly. QC report submissions now validate the full nested results payload before saving. That means broken item ids, invalid pass/fail states, and malformed score values are rejected up front instead of creating unusable report history. ## Tracking Callbacks and Rework Use QC reports to identify patterns that lead to callbacks. If a crew consistently fails a specific checklist item, it may indicate a training gap. To track rework: 1. Filter QC reports by **Fail** status. 2. Look for repeated failures on the same checklist item. 3. Review the associated jobs to see if customers reported issues. 4. Address the root cause with additional training or updated procedures. Over time, tracking QC data helps you reduce callbacks and improve customer satisfaction. [SCREENSHOT: Filtered QC report list showing only failed reports with the failed checklist items highlighted] ## Who Can Use QC Features - **Owners** and **Managers** can create and edit checklists and review all reports. - **Crew Leads** can complete checklists on site and submit reports through the mobile app. ## Next Steps - Set up checklists for your most common job types to start collecting QC data. - Learn about [managing jobs](https://docs.cleanestimate.pro/operations/jobs) to see how QC fits into the job lifecycle. - Return to the [Operations Overview](https://docs.cleanestimate.pro/operations/overview) for the full list of operations features. --- URL: https://docs.cleanestimate.pro/operations/recurring-templates Title: Recurring Job Templates Description: Create reusable service contracts that auto-generate future jobs for recurring commercial, fleet, residential, or holiday-light work. Category: operations Difficulty: intermediate Roles: owner, manager, sales_rep Last updated: 2026-03-29 --- # Recurring Job Templates Recurring templates let you define a standing service agreement once, then generate future jobs from that template on a schedule. Navigate to **Admin > Jobs > Templates** to open the recurring template library. [SCREENSHOT: Recurring template library showing template name, client, frequency, per-visit total, annual value, next job, and status] The template library and template detail page both calculate contract value from the actual recurring visit total. If maintenance pricing is enabled, the per-visit and annual values reflect the maintenance multiplier instead of the original one-time estimate total. Template load, save, generate, and occurrence actions now show plain-language admin errors instead of raw database text, while the detailed failure context still goes to server logs. ## What A Template Stores Each recurring template includes: - Template name and service type - Linked client and service property - Reusable line items and per-visit pricing - Optional maintenance pricing multiplier - Frequency, preferred day, and preferred time window, including weekends and after-hours windows - Skip months for seasonal contracts - Contract start date and optional end date or visit count - Default crew and truck assignments - Lead time for when future jobs should be generated Templates are ideal for quarterly building washes, monthly fleet work, biweekly storefront cleaning, and similar standing service agreements. ## Creating A Template 1. Open **Admin > Jobs > Templates**. 2. Click **New Template**. 3. Enter the template identity and select the service type. 4. Search for the client, then choose an existing property or enter one manually. 5. Add the recurring line items and confirm the per-visit total. 6. Set frequency, preferred day, time window, skip months, and contract term. 7. Choose default crew and truck assignments if you want dispatch defaults. Template truck defaults now use the same dispatch truck records as job scheduling. 8. Save the template. The template detail page opens after save so you can review projected occurrences and generate the next job immediately if needed. [SCREENSHOT: New recurring template form showing identity, client and property, line items, schedule, and auto-scheduling defaults] ## Creating A Template From An Accepted Estimate On accepted **Commercial Building** and **Fleet** estimates, the estimate detail page includes **Create Recurring Template**. That shortcut pre-fills: - Client record - Property address - Service type - Line items from the accepted estimate - Maintenance pricing enabled by default for follow-on contract work When the accepted estimate already has canonical quote-core line items, that shortcut now prefers those normalized rows over the older compatibility JSON snapshot. The new template also keeps the source estimate id attached behind the scenes so later recurring-template automation and reporting can trace the template back to the quote it came from. Recurring templates created from accepted estimates now also show that source quote link on the template list and template detail page, so the office can jump back to the originating quote without hunting through the estimates workspace first. You only need to finish the schedule and contract settings before saving. Residential maintenance agreements now create their recurring template series automatically when the customer accepts the maintenance offer. CE Pro stores one linked recurring template per repeating seasonal visit pattern in the maintenance agreement, which lets the office review, pause, or retime those future visits from the same recurring-template library without recreating the seasonal service mix by hand. When that maintenance agreement is resynced later, CE Pro now only ends the recurring templates that are still active and no longer belong to the current agreement shape. Historical templates that were already ended keep their original ended timestamps instead of being re-ended on every later agreement sync. Accepted maintenance agreements now stay in sync after office edits too. If the team updates the services, visit mix, or other maintenance-plan details on an already accepted estimate, CE Pro resyncs the linked recurring templates from the updated canonical quote data instead of leaving the recurring schedule on the older agreement shape. ## Template Detail Page The template detail page has two main areas: - **Configuration panel**: Edit the template settings, pricing, schedule, and default dispatch assignments. - **Occurrence schedule**: View every projected visit in the series, not just the jobs that have already been generated. This matters because jobs are only written to the jobs table when the occurrence enters the lead window. Future visits still appear in the occurrence table as projected rows so you can manage the full series from day one. [SCREENSHOT: Template detail page with editable configuration on the left and projected occurrence table on the right] ## Occurrence Statuses | Status | Meaning | |---|---| | Projected | Future occurrence that has not generated a job yet | | Scheduled | Job exists and is on the calendar | | In Progress | Crew is en route, on site, or actively working | | Complete | Generated job has been completed | | Skipped | The occurrence was skipped before or after job generation | | Rescheduled | The generated job date was changed for that occurrence only | | Cancelled | The generated job was cancelled | ## Skipping One Occurrence Use **Skip** from the occurrence row when you want to remove one visit without ending the full contract. - If the job has already been generated, the job status becomes **Skipped**. - If the occurrence is still projected, CleanEstimate Pro stores a skip record and the generator ignores that date later. - The overall series continues normally after the skipped visit. - Manual skips still count toward a visit-based contract cap. Seasonal **skip months** do not count toward the visit cap because they are part of the schedule definition, not an ad-hoc skipped visit. ## Deleting One Occurrence Use **Delete** from the occurrence row when you want to remove that visit from the series entirely. - Projected occurrences are removed from future generation. - Generated future occurrences are removed from the schedule and excluded from regeneration. - Completed or invoiced visits stay in history and cannot be deleted from the template page. ## Rescheduling One Occurrence Use **Reschedule** on a generated occurrence to move only that one job. - The underlying recurring series does not shift. - The job keeps its template linkage and occurrence number. - The occurrence row shows the moved date and keeps the original date for reference. ## How Auto-Generation Works Templates use a lead window to decide when to create the next job. For example: - A quarterly template with **14 lead days** creates the next job two weeks before service. - A template with **auto-generate off** stays in the library until someone clicks **Generate Now**. When a job is generated, CleanEstimate Pro: - Copies the template line items - Applies the maintenance multiplier if enabled - Assigns the default crew and truck when set - Links the new job back to the template and occurrence number ## Pausing And Ending Templates - **Pause** stops future generation without deleting projected history. - **Resume** restarts the template from its current next scheduled date. - **End** closes the template and cancels future generated jobs that have not been completed yet. ## Deleting A Template Use **Delete Template** when the recurring agreement should be removed completely. - Future generated jobs tied only to that template are removed. - Completed history stays attached to the client and job records. - If you only want generation to stop, use **Pause** or **End** instead. Templates with a visit-count end condition stop exactly at the configured visit cap. Generated visits, manually skipped visits, and already-generated occurrences that the template is catching up to all count toward that cap; built-in skip months do not. ## Next Steps - Review the [Jobs guide](https://docs.cleanestimate.pro/operations/jobs) to see how generated jobs appear in the job list and job detail views. - Use the [Schedule guide](https://docs.cleanestimate.pro/operations/schedule) to manage dispatch once recurring jobs land on the calendar. --- URL: https://docs.cleanestimate.pro/operations/routes Title: Route Management Description: Use the dispatch board to order stops, review drive gaps, and rebalance truck routes. Category: operations Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Route Management CleanEstimate Pro now treats route management as part of the main **Admin > Schedule** experience. The daily Ops board is where you review stop order, drive time, map coverage, and crew-by-truck assignment together. [SCREENSHOT: Ops day board with the selected truck stop list and route map side by side] ## What Counts as a Route A route is the ordered list of jobs for one truck on one date. For each stop, CE Pro shows: - Stop number - Customer and address - Job value - Time window - Estimated arrival - Estimated crew hours - Drive minutes and miles from the previous stop - Notes and special instructions when they exist on the job The system uses the saved truck stop order first. If the truck does not have a saved order yet, it falls back to the built-in dispatch heuristic that groups jobs by time window and then keeps nearby work together. ## Reviewing a Route 1. Open **Admin > Schedule**. 2. Stay on the **Ops** scope. 3. Choose **Day**. 4. Click the truck you want to review. The selected truck becomes the active route panel. The map on the right now uses the live Google Maps surface with numbered pins, route polylines, and saved stop timing for that truck-day. ## Reordering Stops You can reorder a route in three ways: 1. Drag a stop card higher or lower in the selected truck's stop list. 2. Use the up/down controls on the stop card for small adjustments. 3. Click **Optimize Route** to rebuild the order from the current truck-day jobs. When the day board finds a likely improvement, it shows a **Routing Suggestions** card. Accepting a suggestion moves the job to the proposed truck and then re-saves the affected route timing. When a route does not have a saved shop origin yet, optimization now keeps the first visible stop fixed and reorders the remaining stops around it. That avoids route jumps where the dispatcher's starting stop unexpectedly changes just because the yard location is still blank. ## Bulk-Created Routes The **Bulk Schedule** workspace can create route stops at the same time it creates jobs. Choose **Jobs + Route Stops** when: - every selected row belongs on a truck now - every routed row is a single-day job - you want the initial stop order to match the batch grid order CleanEstimate Pro groups those new jobs by `scheduled date + truck`, appends the new stops after any existing saved route positions for that truck-day, and keeps the sequence from the bulk review grid. Use this when a new commercial contract adds many same-day properties to one truck and you need a starting route immediately. ## Unassigned Work The **Unassigned Jobs** panel is route-aware. It helps dispatchers: - See estimated hours before assigning the job - Open the job detail sheet for more context - Send the job directly to the best-fit truck from the daily board ## Crew Notes and Solo Days Use **Edit Crew** from the selected truck to set: - Crew lead - Technician - Solo route toggle - Day-specific notes These details show up in both the daily route panel and the weekly planning grid. ## Warnings Route warnings surface directly on the stop list and truck summary cards. Common warnings include: - Late arrival risk - Drive-heavy routing - Capacity pressure - Trucks with no assigned crew - Solo-day load pressure ## Related Guides - Read [Schedule and Dispatch](https://docs.cleanestimate.pro/operations/schedule) for the full board overview. - Configure shop address, truck capacity, and route defaults in [Schedule & Dispatch Settings](https://docs.cleanestimate.pro/settings/schedule-dispatch). --- URL: https://docs.cleanestimate.pro/operations/schedule Title: Schedule and Dispatch Description: Run ops, sales, and combined planning from one schedule board with truck routes, crew assignments, and daily stop order. Category: operations Difficulty: beginner Roles: owner, manager, sales_rep, crew_lead, technician Last updated: 2026-03-20 --- # Schedule and Dispatch Open **Admin > Schedule** to manage the full workboard for operations and sales. The refreshed landing view keeps the same workflows and scopes, but now opens inside the branded admin shell with a summary header and dispatch-readiness cards above the calendar. The page still has three scopes: - **Ops** for truck dispatch, route order, unassigned jobs, and crew coverage. - **Sales** for appointments and same-day follow-up work. - **Combined** to stack both sections in one date range. [SCREENSHOT: Schedule board showing truck cards, ordered stops, route map, and the sales panel stacked below] The summary strip above the board calls out active crews, dispatch assets, service defaults, and automation status so dispatchers can check readiness before opening the day grid. The toolbar now also includes a **Jump to** date picker. Use it when you need to move straight to a specific service date without stepping forward or backward one day at a time. ## Ops Day View The **Day** view is the daily dispatch board. Each truck card shows: - Truck name - Assigned crew for that truck and date - Stop count - Revenue - Scheduled hours - Warning indicator when the route is tight or overloaded - Solo coverage and crew-note callouts when a truck-day changed When you select a truck, the main panel shows that truck's ordered stop list with: - Stop number - Customer and address - Service type - Job value - Arrival estimate - Drive time and distance from the previous stop - Estimated crew hours - Job notes, access notes, and special instructions when present - Crew pay per stop when the crew pay toggle is enabled - Quick actions for **Navigate**, **Start**, and **Skip** The **Map** toggle opens the live Google route map panel on the right. Numbered pins match the stop list, truck polylines render on top of the map tiles, and unassigned jobs appear with a `?` marker when they already have coordinates. The day board now also writes the current stop order, drive minutes, drive miles, and arrival estimates back into the dispatch tables so the next load keeps the same route timing. That route-sync save now validates the full payload before it writes and batches the coordinate updates in parallel, so malformed dates, stop ids, or invalid latitude/longitude values are rejected cleanly and larger syncs should finish faster. ## Crew Assignments By Day Click **Edit Crew** inside the selected truck's day board to assign the crew lead and technician for that specific truck-day. Use this when: - A technician calls out - A lead swaps trucks for the day - One truck runs solo - You need to leave notes for the dispatcher These day-specific assignments show on the truck cards and in the weekly grid. CE Pro now validates those day-assignment saves before they overwrite dispatch data. Invalid truck ids, malformed dates, or broken crew-member ids are rejected with a readable error instead of partially writing a bad truck-day record. ## Route Ordering The board automatically uses the saved stop order when a truck already has one. If no saved order exists, CE Pro uses a dispatch heuristic that groups stops by time window and then orders nearby jobs together. You can change the order by: 1. Dragging a stop within the selected truck's list. 2. Using the up/down controls on a stop card. 3. Clicking **Optimize Route** to rebuild the day's order from the current jobs on that truck. Route optimization now rebuilds the full stop order instead of pinning the previous last stop in place. In practice that means short routes can still improve when the best final stop changes after you add, remove, or swap jobs. When the system finds a likely improvement, it shows a **Routing Suggestions** card at the top of the day view with the proposed truck move, rationale, and estimated time or distance savings. The reorder controls now degrade gracefully when the optional dispatch sync tables are unavailable or a stored truck assignment is stale. In practice, that means dragging a stop or using the up/down controls should still persist the visible route order instead of kicking back a board-level 500. ## Unassigned Jobs Jobs without a truck stay in the **Unassigned Jobs** panel. From there you can: - See the estimated hours for the job - Open the job detail sheet - Assign the job to the best-fit truck from the current board ## Week View The **Week** view now uses a compact Gantt layout instead of separate cards in every cell. Each truck row shows: - Continuous multi-day bars for jobs that span across several dates - Dense single-day cards with customer, address, time window, and value - A crew strip below the bars for each truck-day - Amber highlighting when a day is solo or has a swap note - A tighter footer with daily revenue, job count, scheduled hours, and optional crew pay/gross This view is best for spotting trucks tied up for multiple days, overloaded lanes, empty capacity, and crew swaps later in the week. ## Month View The **Month** view rolls the schedule into a revenue calendar. Click a day to jump into that day's dispatch board. Each day tile shows: - Daily revenue - Up to three scheduled jobs - Overflow count when more jobs exist than the tile can show ## Sales and Combined The **Sales** scope separates work into two sections: - **Appointments** grouped by rep - **Follow-Ups Due** with owner, type, pipeline value, and age In the daily Sales view, you can switch reps, open the map split panel, and review **Nearby follow-ups while you're here** between appointments for the active rep. In **Week** view, reps become rows and the calendar becomes a rep-by-day grid with denser appointment cards and follow-up badges that include pipeline value. In **Month** view, appointment and follow-up counts roll up into a monthly calendar. The **Combined** scope stacks the operations board above the sales board for the same date range. Both map panels now share the same Google Maps loader configuration behind the scenes, so switching between Ops, Sales, and Combined views no longer trips the schedule board into a client-side loader crash. ## Creating Jobs Use **Create Job** from the top-right corner of the schedule when you need to add work directly from dispatch. The dialog lets you set: - Customer details - Service type - Date range - Start and end time - Truck - Crew - Estimated crew hours - Notes and quoted total Use the single-job dialog when dispatch is booking one location at a time. For multi-location contracts, start from **Admin > Jobs > Bulk Schedule** instead. The bulk scheduler is better when you need to create many separate property jobs in one pass, reuse shared pricing defaults, and keep every job invoice-ready without opening each detail screen. ### Bulk Schedule And Route Mode Bulk Schedule supports two submit modes: - **Jobs Only** creates one job per selected property. - **Jobs + Route Stops** creates one job per selected property and then appends route stop positions by truck and service date using the row order from the batch grid. Behind the scenes, truck-id resolution and route-stop appends now run in parallel per batch, so larger same-day route imports should finish faster before the new jobs appear on the board. Route mode only works when every routed row has: - one truck assignment - a single service date instead of a multi-day range If you need multi-day work, create those rows in **Jobs Only** mode and place them on the board manually afterward. ## Related Guides - Use [Route Management](https://docs.cleanestimate.pro/operations/routes) for route-specific workflow details. - Use [Schedule & Dispatch Settings](https://docs.cleanestimate.pro/settings/schedule-dispatch) to set the shop address, truck capacity, and crew pay visibility. --- URL: https://docs.cleanestimate.pro/settings/account Title: Account Settings Description: Update your personal login, company details, and general account configuration. Category: settings Difficulty: beginner Roles: owner Last updated: 2026-04-27 --- # Account Settings The Settings page is your central hub for managing your business profile, integrations, and account configuration. Go to **Settings** in the sidebar to get started. The same **Settings** section also contains related admin pages like **Team** and **Billing**. The Workspace shortcuts on that page now also include direct links into module hubs like **Residential** and **Holiday Lights**, so important pages stay discoverable without adding more items to the left sidebar. If you collapse the admin sidebar, every page you can access stays available in the icon rail. Click the chevron at the top of the rail to expand the full sidebar again. The main admin chrome now splits responsibilities more cleanly. The page-level header keeps the compact global search trigger across the top of the workspace, and on desktop it also keeps **Help** plus **Alerts** on the right. On mobile, those two actions stay in the fixed top bar instead of being duplicated inside the page content. XP now lives in the left sidebar between the workspace section and **Quick Start**, so the same leaderboard shortcut stays available from every admin page without taking up room in the page header. [SCREENSHOT: Settings page showing the full layout with Company Information, Estimator URL, AI Settings, and integration cards] --- ## Personal Account CleanEstimate Pro now includes a dedicated **Settings -> Account** page for the signed-in user. Use it to update your own: - Name - Login email - Phone number - Job title You can also send yourself a password reset email from that page if you want to rotate your password without logging out first. Your workspace plan and subscription status now appear as a compact badge row in both **Settings** and **Settings -> Account**, instead of living in the left sidebar card. The old sidebar role/focus/mode callout has also been removed so the left rail stays focused on navigation and org switching. The left-rail quick action has been simplified too. **Quick Start** is now a single dropdown bubble for creating common records quickly, without the larger launchpad promo card around it. Franchise and multi-location operators also now get a darker, higher-contrast workspace switcher card so the current org is readable in the left rail. The left sidebar now groups the highest-traffic office pages under **Daily work**. **Command Center**, **Inbox**, **Estimates**, **Schedule**, and **Jobs** stay pinned at the top of the rail, while **Pipeline**, **AI Hub**, analytics, marketing, automations, and back-office settings sit in the lower grouped sections. The main dashboard no longer uses the oversized **Operations Command** hero. Instead, it opens as the **Command Center** with a tighter office signal summary followed immediately by the **Daily admin queue**. Report links still stay close by as **Top reads**, but they sit below the first action queue so the dashboard starts with follow-ups, replies, and handoffs before analytics. Dashboard summary cards also handle empty-state metrics more cleanly now. Commercial gross-margin cards stay on a plain dash until you actually have modeled commercial revenue, and the sales-rep pace card explicitly tracks new estimates created so far this month instead of implying a rolling weekly total. [SCREENSHOT: Account settings page showing personal profile fields and the password reset action] --- ## Company Information The Company Information card stores the details that appear on every estimate, invoice, and email your business sends. [SCREENSHOT: Company Information card with fields for Name, Phone, Email, Website, Address, City, State, and ZIP] Fill in the following fields: - **Name** - Your business name as you want it to appear on customer-facing documents. - **Phone** - Your main business phone number. - **Email** - Your primary business email address. - **Website** - Your business website URL. - **Address, City, State, ZIP** - Your business mailing address. Click **Save Changes** when you are done. > **Tip:** Your company name appears on all estimates, emails, and invoices. Double-check it for typos before saving. --- ## Estimator URL The Estimator URL card displays your unique public booking link. It looks like this: ```text app.cleanestimate.pro/e/your-slug ``` [SCREENSHOT: Estimator URL card showing the read-only URL with a copy button] This URL is read-only. You cannot change it directly. Share this link with customers to let them request estimates online. Post it on your website, social media profiles, Google Business listing, or printed materials. > **Tip:** The estimator URL is how customers access your online booking form. Keep it handy and share it everywhere you advertise. --- ## AI Settings The AI Settings panel controls how CE Pro uses AI features across your account. [SCREENSHOT: AI Settings panel showing the enabled toggle, tone dropdown, credits usage bar, and usage limit action dropdown] - **AI Enabled/Disabled toggle** - Turn AI features on or off for your entire account. - **Default Tone** - Choose the tone for AI-generated text. Options: Professional, Friendly, Casual, Technical. - **Monthly AI Credits** - A usage bar showing how many AI credits you have used this billing cycle. - **Usage Limit Action** - Choose what happens when you hit your monthly credit limit: - **Warn** - You see a warning but can keep using AI. - **Block** - AI features are disabled until the next billing cycle. - **Overage** - AI features stay on and you are billed for extra usage. The **Internal Assistant Tone** setting affects the Business Assistant in the AI Hub. Customer-facing AI tone and training now live in the **Brand Voice** panel below the AI Settings card, where you can teach drafts, website chat, and the AI Voice Agent how to represent your business. If the AI Settings save fails, CE Pro now returns a plain-language admin error instead of exposing raw provider or database text. Support can still see the detailed diagnostics in server logs when deeper investigation is needed. --- ## Integrations The Integrations card links to the full integrations management page. [SCREENSHOT: Integrations card with a "Manage Integrations" button] Click **Manage Integrations** to connect or configure: - **Stripe** - Accept online payments, send invoices, and enable tap-to-pay. - **Phone / Voice** - Configure Esendex or Twilio for SMS replies and call routing. - **Calendar** - Sync appointments with Google Calendar. - **QuickBooks** - Sync invoices and payments with QuickBooks Online. - **Webhooks** - Send event data to external systems. Each integration has its own setup guide. See the related articles below for details. --- ## Platform Analytics CleanEstimate Pro also runs first-party platform analytics in production so the team can monitor real-world usage and release health across the app shell and marketing experience. This tracking is automatic at the platform level. It does not require an extra setup step inside your account settings, but it works alongside your configured business integrations and site tracking. --- ## Automations The Automations card links to your follow-up sequence configuration. [SCREENSHOT: Automations card with a "Manage Automations" button] Click **Manage Automations** to create and edit follow-up sequences. These sequences automatically send emails and texts to customers after you send an estimate, complete a job, or at other trigger points. --- ## Brands The Brands card lets you configure separate brands for different service lines. [SCREENSHOT: Brands card showing a list of configured brands with an "Add Brand" button] Use brands when you operate under different names for different services. For example, you might run your power washing business under one name and your holiday lights installation under another. Each brand can have its own: - Logo - Company name - Contact information - Color scheme Assign brands to estimates and proposals so customers see the correct branding. --- ## Email Reply Routing The **Email Reply-To Slug** setting saves the mailbox local-part CleanEstimate Pro will use once inbound email routing is configured for your environment. If you set a custom slug, that saved slug is used. If you leave the slug blank, CleanEstimate generates a default slug from your organization. When inbound email routing is live, the Settings page shows the full reply-to address. If the environment is not configured yet, CE Pro shows the saved slug and a setup-required notice instead of advertising an address that cannot receive mail yet. Custom slugs must use lowercase letters, numbers, and underscores only. Saving a blank slug clears the custom reply-to and returns the inbox to the generated default. [SCREENSHOT: Email reply routing setting showing the reply-to preview address] --- ## Reviews The **Reviews** card stores the Google review link used by CE Pro when it redirects happy customers to your public Google review form. Use the direct Google review URL from your Business Profile. CE Pro only accepts valid HTTPS Google review links here, and leaving the field blank removes the redirect without breaking internal review collection. [SCREENSHOT: Reviews card showing the Google Review URL field and save button] --- ## Subcontractors The Subcontractors card lets you manage your subcontractor roster. [SCREENSHOT: Subcontractors card showing a list of subcontractors with name, phone, and specialty columns] Add subcontractors you use for installs or overflow work. Each subcontractor record includes their name, contact information, and specialty. You can assign subcontractors to jobs from the Schedule page. --- ## Tips - Keep your phone and email current. They appear on every customer-facing document. - Your company name prints on all estimates, emails, and invoices. Make sure it matches your legal business name. - The estimator URL is the fastest way to get customers into your pipeline. Share it widely. --- URL: https://docs.cleanestimate.pro/settings/billing Title: Billing and Subscription Description: Manage your CE Pro subscription, plans, SMS credits, payment methods, and invoice history. Category: settings Difficulty: intermediate Last updated: 2026-03-26 --- # Billing and Subscription The Billing page is where you manage your CE Pro subscription, monitor add-on usage, track referral credits, and view invoice history. Open the **Settings** section in the sidebar, then click **Billing**. The billing workspace now loads its major cards independently. If invoice history, referral totals, or AI-usage data is temporarily unavailable, the rest of the page still opens so you can keep working on subscription and payment-method tasks. [SCREENSHOT: Billing page showing the Subscription card, SMS Add-on card, Referral card, AI Usage card, and Invoice History table] --- ## Plans and Pricing Tiers CE Pro offers tiered subscription plans designed for different business sizes and needs. Each tier unlocks additional features and higher usage limits. ### Plan Comparison | Feature | Starter | Professional | Enterprise | |---|---|---|---| | Estimates per month | 50 | Unlimited | Unlimited | | Team members | 2 | 10 | Unlimited | | SMS messaging | Add-on | Included | Included | | AI features | Basic | Full | Full + priority | | Commercial module | -- | Included | Included | | Holiday Lights module | -- | Add-on | Included | | Fleet module | -- | -- | Included | | Customer portal | Basic | Full | Full + custom domain | | Analytics | Basic | Advanced | Advanced + exports | | API and webhooks | -- | Included | Included | | Dedicated support | -- | -- | Included | ### Billing Frequency All plans are available on monthly or annual billing. Annual billing provides a discount compared to the month-to-month rate. Your billing frequency is shown on the Subscription card. --- ## Subscription Card The Subscription card displays your current plan details at a glance: - **Plan Name** -- Your current subscription tier. - **Status Badge** -- Active, Invite Only, Past Due, or Cancelled. - **Billing Period** -- Monthly or Annual, with the next billing date. - **Access Info** -- If your organization is in prelaunch access, the card may show onboarding or billing status details. [SCREENSHOT: Subscription card showing plan name, active status badge, billing period, and Manage Subscription button] > **Tip:** If your status shows Past Due, update your payment method immediately through the Stripe portal to avoid service interruption. --- ## Upgrading Your Plan 1. Open the **Settings** section in the sidebar and click **Billing**. 2. Click **Manage Subscription** on the Subscription card. 3. The Stripe customer portal opens in a new tab. 4. Select the plan you want to upgrade to. 5. Confirm the change. When you upgrade mid-cycle, Stripe prorates the charges. You are credited for the unused portion of your current plan and charged the prorated amount for the new plan. The change takes effect immediately. ### What Happens After Upgrading - New features unlock instantly. - Higher usage limits apply immediately. - Your next invoice reflects the new plan price. - Your billing date does not change. --- ## Downgrading Your Plan 1. Open the **Settings** section in the sidebar and click **Billing**. 2. Click **Manage Subscription**. 3. In the Stripe portal, select a lower-tier plan. 4. Confirm the change. Downgrades take effect at the end of your current billing cycle. You retain access to all features of your current plan until the cycle ends. ### What to Check Before Downgrading - **Team members** -- If your current team size exceeds the lower plan's limit, you need to remove team members first. - **Active modules** -- Modules not included in the lower plan will be disabled at the end of the cycle. Export any data you need beforehand. - **Webhook and API access** -- If moving to a plan without API access, active webhooks will stop firing. --- ## SMS Add-On Credits The SMS Add-on card shows the status of your text messaging capability: - **Status** -- Active or Inactive. Active means you can send SMS messages from CE Pro. - **Messages Used This Month** -- A count of SMS messages sent during the current billing cycle. - **Credit Balance** -- If your plan uses SMS credits, this shows your remaining balance. ### How SMS Credits Work SMS credits are consumed each time CE Pro sends a text message. Each outbound message costs one credit. Inbound messages (customer replies) do not consume credits. If your plan includes SMS, credits replenish at the start of each billing cycle. If SMS is an add-on for your plan tier, you purchase credit bundles through the Stripe portal. ### Purchasing Additional SMS Credits 1. Click **Manage Subscription** on the Subscription card. 2. In the Stripe portal, find the SMS add-on section. 3. Select a credit bundle. 4. Complete the purchase. Credits are added to your account immediately. [SCREENSHOT: SMS Add-on card showing Active status, messages used, and credit balance] > **Tip:** Monitor your SMS usage throughout the month. If you run automated follow-up sequences, usage can increase quickly during busy seasons. --- ## AI Usage Card The AI Usage card summarizes your AI consumption for the current billing cycle: - **Input Tokens** -- The number of tokens sent to AI models. - **Output Tokens** -- The number of tokens generated by AI models. - **Images** -- The number of AI image operations (photo estimates, mockups). - **Credits** -- Your total AI credit usage and remaining balance. [SCREENSHOT: AI Usage card showing input tokens, output tokens, images processed, and credits used versus available] If you are approaching your credit limit, the behavior depends on your Usage Limit Action setting in Account Settings. See the [Account Settings](https://docs.cleanestimate.pro/docs/settings/account) article for details on configuring Warn, Block, or Overage modes. --- ## Referral Program The Referral card displays your referral program details: - **Referral Code** -- Your unique code. Share it with other service business owners. - **Referral Link** -- A shareable URL that includes your code. - **Total Referrals** -- The number of businesses that signed up using your code. - **Credited** -- Referrals that have been confirmed and applied as account credits. - **Pending** -- Referrals that signed up but have not yet qualified. - **Earned** -- The total dollar amount you have earned through referrals. [SCREENSHOT: Referral card showing the referral code, link, and stats for total, credited, pending, and earned] Referral credits are applied as discounts on future invoices. They do not expire as long as your account remains active. > **Tip:** Share your referral link with other service business owners at trade shows, in online communities, or through industry groups. --- ## Viewing Invoices The Invoice History table shows all past billing invoices from CE Pro. Each row includes: - **Invoice Number** -- The unique identifier. - **Amount** -- The dollar amount charged. - **Status** -- Paid, Open, or Failed. - **Date** -- The date the invoice was issued. - **Download** -- A link to download the invoice as a PDF. [SCREENSHOT: Invoice History table showing recent invoices with number, amount, paid status, date, and download PDF links] Click the **Download** link on any row to save a PDF copy for your records or accountant. ### Failed Invoices If an invoice shows a Failed status, it means the charge was declined. Common causes: - Expired credit card. - Insufficient funds. - Bank-level fraud block. Update your payment method through the Stripe portal to resolve failed charges. CE Pro retries failed charges automatically for up to 7 days. --- ## Managing Payment Methods All payment method management is handled through the Stripe customer portal. ### Office Payment Collection Once Stripe is connected, the **Collect Payment** modal on jobs, estimates, invoices, and leads can open Stripe's embedded payment form for keyed card entry. Office staff can also switch that same modal to send a pay link, record tap to pay / reader activity, or log an external processor reference without leaving the record. The modal also keeps payment notes and shows inline refund / void actions for eligible history entries. Estimate-side payment collection now authorizes through the same estimate-friendly permission path as the rest of the estimating workspace, so office users with estimate access can open the modal without hitting a `403`. ### Updating Your Payment Method 1. Open the **Settings** section in the sidebar and click **Billing**. 2. Click **Manage Subscription**. 3. In the Stripe portal, click **Payment Methods**. 4. Add a new card or bank account. 5. Set it as your default payment method. 6. Remove outdated payment methods if desired. The **Manage Billing** button now opens the Stripe portal using the current site origin, so a stale app URL setting is less likely to block the return link. ### Accepted Payment Methods CE Pro accepts the following through Stripe: - Credit cards (Visa, Mastercard, American Express, Discover). - Debit cards. - ACH bank transfers (where available). ### Stripe Portal Access The Stripe customer portal is a secure, hosted page provided by Stripe. It handles all sensitive payment information. CE Pro never stores your full credit card number or bank account details. From the Stripe portal you can: - View and update payment methods. - Change your subscription plan. - View and download invoices. - Cancel your subscription. - Update your billing address. If the portal is temporarily unavailable, the Billing page now returns a setup or availability message instead of a generic failure. The most common causes are: - Stripe is not configured for the environment yet. - The workspace does not have a Stripe customer id yet. - Stripe Billing Portal configuration is missing or still being updated. The page now distinguishes between the most common Stripe portal problems: - **Missing billing customer** -- the workspace's Stripe customer id no longer exists in Stripe. - **Portal configuration issue** -- the Stripe Billing Portal has not been configured for the account yet. - **Invalid return URL** -- the app URL configuration is malformed, so Stripe cannot redirect back to CE Pro after portal actions. --- ## Self-Serve Trial and Early Access CleanEstimate Pro now supports direct self-serve workspace creation from `/signup`, while support can still provision selected organizations through early-access workflows when needed. For self-serve organizations: - The signup flow creates the owner account, organization, owner membership, starter setup data, and a 44-day trial. - The owner is signed in and sent to `/onboarding` to finish company info, services, and pricing setup. - Billing details and plan selection can be completed before the trial ends. For support-provisioned organizations: - Early access invitations may still be issued manually for selected accounts. - CleanEstimate Pro provisions the organization first and then emails the account owner an invite link. - If that invite link expires or gets used already, the recovery flow now keeps you on the workspace-activation path. Use the same invited email address to send yourself a fresh setup link instead of joining the waitlist again. - Newly provisioned trial workspaces currently default to a 44-day trial window unless CE Pro support assigns a different onboarding length manually. - Access and feature availability may vary while the platform is still rolling out. --- ## Tips - Check the Billing page after onboarding to confirm your subscription status and payment method details. - Download invoice PDFs at the end of each month for your accounting records. - Monitor AI usage if you use features like the photo estimator, AI lead scoring, or AI-generated proposal text. Heavy usage can consume credits quickly. - If CE Pro support provisions your workspace manually, watch for your onboarding email. Once your workspace is provisioned, the invite email is your path into the account. - If you refer other businesses, check the Referral card periodically to track your earned credits. --- URL: https://docs.cleanestimate.pro/settings/commissions Title: Commissions Description: Track and calculate sales rep commissions based on accepted estimates. Category: settings Difficulty: intermediate Roles: owner, manager Last updated: 2026-04-21 --- # Commissions The Commissions page tracks what your sales reps earn on accepted estimates. CE Pro calculates commissions automatically based on lead source. Open **More > Commissions** in the admin sidebar to view the dashboard. [SCREENSHOT: Commissions dashboard showing summary cards for MTD and YTD totals, and a table of individual commission entries] --- ## Commission Rates CE Pro uses two commission rates based on how the lead was generated: - **Company-Generated Leads** — 5% commission. These are leads that came through your marketing, website portal, integrations, or other company channels. - **Self-Generated Leads** — 10% commission. These are leads the sales rep found on their own, through personal networking, door knocking, or referrals they sourced. The lead source on each estimate determines which rate applies. Make sure reps tag their leads correctly to get the right commission. [SCREENSHOT: Commission rate cards showing 5% for company-generated and 10% for self-generated leads] --- ## Red Line Commissions When your workspace enables **Red Line**, CE Pro stores the commission snapshot on the estimate itself instead of falling back to the lead-source percentage. For Red Line estimates: - **Service commission** uses the configured base rate at or below the floor. - **Upside commission** uses the configured upside rate on dollars above the floor. - **Add-on commission** uses the configured add-on rate. - The Commissions dashboard shows a **Red Line** badge only when the saved Red Line snapshot is actually present on the estimate, so managers can distinguish true Red Line payouts from the standard 5% / 10% lead-source model. This lets the estimator, saved estimate, and commission dashboard all agree on the same payout number. If CE Pro ever encounters a stored commission amount without a matching Red Line snapshot, the dashboard now labels that row as **Stored** instead of incorrectly calling it Red Line. Below-floor residential drafts do not need manager approval just to be saved anymore when **Enable manager override tracking** is on, but the quote still cannot be sent until the Red Line override is approved. That keeps the saved commission snapshot, manager approval record, and send workflow aligned to the same final pricing decision. Recovered Rehash closes now also save the split attribution on the estimate itself. That keeps the original-rep share, closer share, total commission, and timing band together so managers can review the recovered payout from the estimate detail page or the Rehash analytics report instead of rebuilding it by hand. If **Allow commission exports** is enabled in Pricing Manager, the Commissions dashboard also unlocks export options for: - the filtered estimate summary - a standard payroll payout CSV - a Gusto-friendly payroll CSV - a QuickBooks-friendly payroll CSV Payroll exports only include earned payouts. Recovered Rehash closes expand into separate rows for the original rep and the closer so payroll can follow the saved split without a manual spreadsheet rebuild. Legacy accepted estimates still export correctly too. If an older lead-source estimate never saved a commission snapshot, CE Pro calculates the earned payroll row from the saved lead-source commission rate instead of dropping that payout from the CSV. [SCREENSHOT: Commissions table showing a Red Line badge and explicit commission amount] --- ## Commission Per Estimate Each accepted estimate generates a commission entry. The entry shows: - **Estimate Number** — The estimate ID. - **Client Name** — The customer name. - **Sales Rep** — The team member who created the estimate. - **Lead Source** — Company-generated or self-generated. - **Estimate Total** — The full dollar amount of the accepted estimate. - **Commission Rate** — 5% or 10%. - **Commission Amount** — The dollar amount earned. - **Status** — Pending or Approved. [SCREENSHOT: Commission table showing individual entries with all columns visible] --- ## MTD and YTD Totals Two summary cards sit at the top of the page: - **Month-to-Date (MTD)** — Total commissions earned so far this month across all reps. - **Year-to-Date (YTD)** — Total commissions earned so far this year across all reps. Click on a rep's name to filter the table and see their individual MTD and YTD totals. [SCREENSHOT: MTD and YTD summary cards at the top of the Commissions page] --- ## Approval Workflow Commissions start with a **Pending** status. An Owner or Manager must approve each commission before it counts toward payout. 1. Find the commission entry in the table. 2. Review the estimate details, lead source, and calculated amount. 3. Click **Approve** to confirm the commission. Approved commissions move to the Approved status. You can filter the table by status to see only pending items that need your review. [SCREENSHOT: Commission entry with the Approve button highlighted and status showing Pending] > **Tip:** Set a weekly or bi-weekly review cadence for commission approvals. Reps stay motivated when they see commissions approved promptly. --- ## Filtering and Sorting Use the filters at the top of the table to narrow results: - **Team Member** — Show commissions for a specific rep. - **Date Range** — Filter by date. - **Status** — Show only Pending or Approved entries. Click any column header to sort the table. --- ## Tips - Train reps to tag lead sources correctly when creating estimates. The wrong tag means the wrong commission rate. - Review pending commissions regularly. A backlog of unapproved commissions can frustrate your sales team. - Use the YTD total in compensation reviews and annual planning. - Commissions are calculated on the accepted estimate total, not on collected payments. If you need to track against collections, export the data and reconcile manually. --- URL: https://docs.cleanestimate.pro/settings/esendex Title: Connecting Esendex Description: Set up Esendex for shared SMS, inbound call transfer, missed-call alerts, and phone automations. Category: settings Difficulty: beginner Roles: owner Last updated: 2026-04-23 --- # Connecting Esendex Esendex powers the shared business phone number for workspaces whose **Telecom Provider** is set to **Esendex**. That shared number can: - send customer SMS messages - receive customer SMS replies - receive inbound customer calls and transfer them to your office line - log missed calls into **Messages** and alerts - power automation steps like **Make Call** and **Voicemail Drop** Phase 1 does **not** include the AI Voice Agent or inbound voicemail recording playback. --- ## What You Need Before you start, gather: 1. An Esendex SMS license key 2. An Esendex Voice license key 3. A shared Esendex phone number in E.164 format, for example `+17177440798` 4. The real phone number that should receive transferred inbound calls --- ## Where To Configure It Go to **Settings** in the admin app and open the **Phone / Voice** card. 1. Choose **Esendex** in the **Telecom Provider** selector. 2. Enter the **Shared Esendex Number**. 3. Enter **Forward Calls To** for the office or cell number that should ring first. 4. Enter the **Esendex SMS License Key**. 5. Enter the **Esendex Voice License Key**. 6. Turn on **Voice Enabled** when the number, forwarding destination, and voice license key are ready. 7. Click **Save Esendex Settings**. The card shows a voice-readiness panel so you can confirm the number and forwarding destination are valid before live calls depend on them. Switching a workspace from Twilio to Esendex may turn **Voice Enabled** off until the Esendex number, forwarding destination, and voice license key are ready. This prevents live calls from routing through a half-configured provider. If your workspace should stay on the legacy Twilio path instead, use the [Twilio setup guide](https://docs.cleanestimate.pro/settings/twilio) and switch the provider to **Twilio** before saving. --- ## Callback URLs Configure the exact callback URLs shown on the **Phone / Voice** card in Esendex. - **SMS inbound** - **SMS status** - **Voice status** Production environments require `ESENDEX_POSTBACK_TOKEN` before Esendex postbacks are accepted. The URL shown in Settings already includes the tokenized callback form that CE Pro expects when the environment variable is configured. --- ## Voice Behavior When voice is enabled: 1. A customer calls your shared Esendex number. 2. Clean Estimate Pro logs the inbound call. 3. CE Pro plays a short text-to-speech greeting. 4. CE Pro transfers the caller to the forwarding number you saved. 5. If nobody answers, the call is logged as a missed call and missed-call workflows can run. Outbound automations use the same number for **Make Call** and **Voicemail Drop** steps. Phase 1 uses text-to-speech greetings only. Custom uploaded audio greetings, inbound voicemail recordings, voicemail transcripts, browser softphone calling, and AI call handling are not live in this release. --- ## Testing Checklist After setup, test all three paths: 1. Send an outbound SMS and confirm the thread shows the provider status update. 2. Reply from a real phone and confirm the inbound message lands in **Messages**. 3. Call the shared number and confirm the office line rings and missed calls log correctly when unanswered. 4. Run one workflow test for **Make Call** and one for **Voicemail Drop** so automation callbacks are reaching CE Pro. --- ## Troubleshooting ### SMS sends are skipped - Confirm the workspace has an active SMS add-on. - Confirm the Esendex SMS license key is saved. - Confirm the shared number is present on the **Phone / Voice** card. ### Customer replies do not appear - Confirm the inbound SMS callback URL points to `/api/webhooks/esendex/sms/inbound`. - Confirm the postback token matches your app environment. Production Esendex callbacks are rejected when `ESENDEX_POSTBACK_TOKEN` is missing or does not match the callback URL. - Confirm the customer replied to the exact shared Esendex number shown in Settings. ### Inbound calls do not ring the office - Confirm **Voice Enabled** is on. - Confirm the **Forward Calls To** number is valid and can accept calls. - Confirm the Esendex Voice license key is saved. - Confirm the voice status callback URL points to `/api/webhooks/esendex/voice/status`. ### Voice is saved but not fully synced If the settings card shows a sync warning, CE Pro saved your workspace settings but Esendex did not confirm the incoming-number assignment or call-script update yet. Retry the save once, then contact support if the warning remains. --- URL: https://docs.cleanestimate.pro/settings/stripe Title: Connecting Stripe Description: Set up Stripe for pay links, keyed card entry, hosted tip collection, and automatic payment syncing in CE Pro. Category: settings Difficulty: beginner Roles: owner Last updated: 2026-03-29 --- # Connecting Stripe Stripe powers the hosted and direct card-payment flows in CleanEstimate Pro. Once connected, your team can send pay links, open the embedded Collect Payment modal, take keyed card payments, present customer tip options, and let invoice and estimate balances update automatically after Stripe confirms success. ## What Stripe Handles - Estimate and invoice pay links - Hosted online checkout for customers - Hosted crew tip selection on invoice payment pages - Keyed credit card entry from the Collect Payment modal - Automatic invoice and estimate payment status updates - Ledger entries for successful, pending, and failed Stripe collections ## How to Connect 1. Go to **Settings**. 2. Open **Integrations**. 3. Find **Stripe** and click **Connect**. 4. Complete the Stripe authorization flow. 5. Return to CleanEstimate Pro and confirm the Stripe card shows **Connected**. [SCREENSHOT: Integrations page showing the Stripe card connected] ## What Becomes Available After Setup After Stripe is connected, the payment tools on leads, estimates, jobs, and invoices can: - Generate Stripe pay links - Open hosted checkout for customers with optional crew tipping on invoice payments - Charge a keyed card from the office with Stripe's embedded payment form - Let field crews open a card checkout flow from the mobile app when they collect payment in person - Show alternate card collection flows for pay link, tap to pay / reader, and external processor recording - Sync partial and full card payments back into the shared ledger - Show payment-history status updates plus eligible refund / void actions for collected card payments Offline methods like cash, check, and bank transfer are still recorded in CleanEstimate Pro, but they do not require Stripe. The shared office **Collect Payment** modal now also keeps its intended wide desktop frame on estimate, invoice, job, and lead detail pages instead of falling back to the small default dialog width on some screens. That keeps the payment setup and history panes readable when staff opens billing from a record detail page. ## Customer Payment Experience When a customer opens an estimate or invoice pay link: 1. Estimate links can go straight to Stripe checkout. 2. Invoice links first land on the CE Pro hosted invoice payment page. 3. On invoice payments, the customer can choose **10%**, **15%**, **20%**, **Custom**, or **No Tip** based on the invoice taxable amount. 4. CE Pro opens Stripe checkout with the selected payment amount plus any tip. 5. Stripe confirms the payment. 6. CleanEstimate Pro updates the related estimate or invoice to **Partial** or **Paid** based on the remaining balance. When a crew member collects a card payment from the mobile app: 1. They open the job's invoice payment section. 2. They choose card, cash, or check. 3. For card payments, they can present the same **10%**, **15%**, **20%**, **Custom**, or **No Tip** options to the customer. 4. CE Pro opens Stripe checkout for the balance due plus any selected tip. When the pay link started from an estimate, CE Pro now sends the customer back to the same signed estimate experience after success or cancel. Customers are no longer dropped onto an admin-only page after checkout. Estimate payment links and estimate payment status now stay mirrored onto the shared quote-core record too. When the office generates a Stripe pay link or records a payment against an estimate, CE Pro updates the quote's shared delivery and payment state so the public quote page, office follow-up history, and quote-core automation stay aligned across both Stripe and manually recorded collections. That shared payment sync now also merges against the latest saved quote delivery state before it writes. If the office resends a quote or creates a pay link right before a payment posts, CE Pro preserves the newer shared quote-link history instead of letting the balance update overwrite it with an older snapshot. Customer-facing estimate and quote pages, plus the office estimate list, now also read estimate payment status and pay-link state back from that shared quote-core delivery state when needed. If a payment posts before an older flat estimate column catches up, the pay badge and pay-link CTA still reflect the latest shared quote payment state. The estimate-list projection now keeps that shared delivery-state payload as structured JSON too, which prevents projection refreshes from flattening the quote payment metadata back into an unreadable string on the office list surfaces. Shared manual-quote sends now also fall back to a neutral sender label if the workspace name cannot be loaded, so customer-facing estimate, quote, and asphalt-maintenance messages never default to another provider's brand name during delivery. ## Troubleshooting ### A Stripe payment does not appear right away - Refresh the invoice, estimate, or job page. - Check whether the ledger entry is still **Pending**. - Confirm the charge succeeded in Stripe. - If a delayed payment method was used, wait for Stripe's final success event before expecting a paid status. If a payment attempt fails during office collection, mobile collection, public invoice checkout, or billing-portal launch, CleanEstimate Pro now shows a plain-language action or setup message instead of raw Stripe or provider error text. Use those messages to confirm whether the issue is a balance rule, missing record, or Stripe setup/configuration problem. ### The keyed card option is unavailable - Confirm Stripe is connected. - Confirm the app has a valid Stripe public key configured. CleanEstimate Pro loads the public key from the billing config endpoint before it opens the embedded payment form. - If the modal shows **Stripe not connected**, go to **Settings -> Billing** and finish the Stripe setup there. - Reload the page after any Stripe settings changes. ### The keyed card form asks to refresh after I changed the payment - If you change the amount or tip after secure card entry has already loaded, CleanEstimate Pro keeps the current card form on screen but pauses submission until you click **Refresh Card Entry**. - Use that refresh step any time you adjust the amount or tip so the Stripe intent matches the final payment total before you charge the card. ### The customer cannot use a pay link - Make sure the balance due is greater than `$0.00`. - Confirm the invoice or estimate is not voided. - Generate a fresh pay link if needed. If the customer finishes checkout successfully but still reports an access issue, resend the latest estimate or payment link. CE Pro now preserves the signed customer context across Stripe return URLs, so a fresh link should bring them back to the correct public page. --- URL: https://docs.cleanestimate.pro/settings/twilio Title: Connecting Twilio Description: Set up Twilio for legacy or Rolling Suds workspaces that should stay on the Twilio phone stack. Category: settings Difficulty: beginner Roles: owner Last updated: 2026-04-23 --- # Connecting Twilio Twilio is still supported for workspaces whose **Telecom Provider** is set to **Twilio**. Use this path for legacy Twilio workspaces, including Rolling Suds orgs that should stay on the Twilio phone stack. If your workspace should use the newer default provider, follow the [Esendex setup guide](https://docs.cleanestimate.pro/settings/esendex) instead. When Twilio is the active provider, the shared number can: - send outbound SMS - receive customer SMS replies - receive inbound customer calls and forward them to your office line - record voicemail when voicemail is enabled - log missed calls and voicemail into **Messages** - power automation steps like **Make Call** and **Voicemail Drop** --- ## Where To Configure It Go to **Settings** in the admin app and open the **Phone / Voice** card. 1. Set **Telecom Provider** to **Twilio**. 2. Enter your **Shared Twilio Number**. 3. Enter **Forward Calls To** for the office or mobile line that should ring first. 4. Turn on **Voice Enabled** if the workspace should receive inbound calls. 5. Save the settings. If you want voicemail recording and custom audio greetings, keep **Voicemail Enabled** on and choose either **Text to speech** or **Custom audio file** for the greeting type. When you choose **Custom audio file**, upload or select the greeting audio before saving. CE Pro blocks the save if custom-audio mode is selected without an audio file. Switching a workspace from Esendex to Twilio may turn **Voice Enabled** off until the Twilio number and forwarding destination are ready. This keeps the workspace from receiving calls through an incomplete provider setup. --- ## Required Server Settings Twilio workspaces still need the Twilio server environment variables in the active app deployment: - `TWILIO_ACCOUNT_SID` - `TWILIO_AUTH_TOKEN` - `TWILIO_PHONE_NUMBER` If those values are missing, Twilio SMS, outbound calls, and webhook-driven call handling cannot run even if the workspace settings are saved correctly. --- ## Callback URLs Configure the exact callback URLs shown on the **Phone / Voice** card in Twilio. - **Voice inbound:** `/api/webhooks/twilio/voice/inbound` - **Recording callback:** `/api/webhooks/twilio/voice/recording` - **Transcription callback:** `/api/webhooks/twilio/voice/transcription` - **SMS inbound:** `/api/webhooks/twilio` - **SMS status:** `/api/webhooks/twilio/status` The settings card shows full URLs for the current environment so you do not have to compose them by hand. --- ## Voice Settings The **Phone / Voice** card includes voice-specific controls: - **Voice Enabled** turns inbound call routing on for the workspace. - **Forward Calls To** controls the office or cell number that should ring first. - **Voicemail Enabled** records voicemail when no one answers. - **Greeting Mode** supports text-to-speech or uploaded custom greeting audio. - **Call Recording** stores call recordings when Twilio returns them. - **Missed Call Alerts** raises internal notifications for missed calls and voicemail. The readiness panel will not mark voice ready until a Twilio number and forwarding destination are present. --- ## Testing Checklist After setup, test: 1. Send a manual SMS from **Messages**. 2. Reply from a real phone and confirm the inbound reply lands in the thread. 3. Call the Twilio number and confirm it forwards to the saved office number. 4. Let a call go unanswered and confirm missed-call or voicemail behavior. 5. Run one workflow test for **Make Call** and one for **Voicemail Drop**. --- ## Troubleshooting ### SMS not sending - Verify the workspace **Telecom Provider** is set to **Twilio**. - Verify your Twilio credentials are present in the app environment. - Confirm the SMS add-on is active on the workspace plan. - Check your Twilio console for account suspension, balance, carrier, or compliance issues. ### Customer replies do not appear - Confirm the Twilio messaging webhook points to `/api/webhooks/twilio`. - Look for the message in Twilio under **Messaging > Logs**. - Confirm the customer replied to the exact Twilio number shown in Settings. ### Voice calls are not ringing your office - Verify **Voice Enabled** is on. - Verify the incoming voice webhook points to `/api/webhooks/twilio/voice/inbound`. - Verify the forwarding number is saved in E.164 format. - Make sure your Twilio number supports voice, not just messaging. ### Wrong phone number appearing - Verify the number format in the customer record. - Verify the workspace Twilio number is saved in E.164 format with the leading `+` and country code. - If a customer has multiple phone numbers, make sure the primary number is correct. --- URL: https://docs.cleanestimate.pro/settings/crew-pay Title: Crew Pay Description: Configure versioned crew pay policies, crew splits, job-level compensation overrides, and crew tip visibility. Category: settings Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-15 --- # Crew Pay Crew Pay now uses **versioned policies** instead of hardcoded percentages. That means you can change pool percentages, daily caps, overtime rules, solo rates, and pay periods without rewriting old payroll history. Open: - **Settings > Crew Pay** to schedule a new policy version - **Team > Crew Pay** to review modeled payouts and edit crew split defaults - **Jobs > Job Detail** to override compensation for one job - **Schedule > Day Route View** to mark a truck day as hourly-only --- ## What Is Editable Each crew pay policy version stores: - Standard pool percentage - Elite pool percentage - Callback threshold percentage - Daily revenue cap - Solo rate - Leader max share - Pay period cadence - Pay period start day - Overtime threshold hours - Overtime multiplier - Default minimum wage - State minimum wage overrides - Callback source label - Commission exclusion keywords When you save a new version, CE Pro applies it **prospectively** from the effective date forward. --- ## How Payouts Work Crew payouts are now built in layers: 1. CE Pro finds the policy version that matches the job's service date, unless the job has a saved policy override. 2. CE Pro calculates **commissionable revenue** by removing: - Sales tax - Equipment and rental line items - Lift and access-equipment line items - Subcontractor scope - Subcontractor payouts 3. CE Pro applies the crew's split template and any job-level participant overrides. 4. If the truck day or job is marked **hourly-only**, hourly pay is used instead of the commission pool. 5. Daily revenue caps are applied at the crew/day level before the commission pool is split, and linked callback-origin jobs do not consume cap room for the rest of that crew-day. 6. Commission participants earn a **minimum-wage base** plus a top-up only when their earned commission falls short of that floor. 7. Hourly-only participants earn hourly pay with overtime based on the active policy, and overtime thresholds only count hourly-only hours. Unused split shares are **not redistributed**. If a split slot is assigned to an hourly-only or salary-like participant, that portion stays with the company. --- ## Crew Defaults Each crew can now store a default split template. This is the normal starting point for that crew's jobs. Use the **Team > Crew Pay** page to: - Set or change the crew leader - Adjust split percentages - Save a different mix for a specific crew Example: - Crew Lead: 57% - Technician: 43% You can change those percentages any time. CE Pro validates that: - The total split equals 100% - The leader share does not exceed the policy's leader max share --- ## Team Member Defaults Team records still store default compensation behavior for each person: - **Commission eligible** by default - **Hourly default** with that person's hourly rate These are defaults only. Actual payout can still change because of: - Crew split templates - Job-level compensation overrides - Route-day hourly-only settings This is useful for weekend crews, overnight crews, and salary-like field support people who should always stay hourly in CE Pro. --- ## Job-Level Overrides Open any job and use the **Crew compensation** section to: - Pick the policy version used on that job - Mark the job as hourly-only - Mark the job as callback / rework - Link a callback to the original job - Override the participant list - Override each participant's pay mode - Override hourly rates - Override split percentages for that job only Use this when: - A weekend crew should stay hourly - A manager works the route but should not receive commission - A helper should keep their commission share while the lead stays hourly - One job needs a different split than the crew default --- ## Route-Day Hourly Override In **Schedule > Day Route View**, each truck day can be marked **Hourly only**. This is the fastest way to handle: - Overnight crews - Weekend crews - Training days - Salary support days - Non-standard work that should not use commission When a route day is hourly-only, commission previews are hidden for that truck/day and job overrides can still refine the participant mix if needed. --- ## Callbacks And Elite Rate Callback and rework jobs are explicit payroll flags now. They are not inferred from notes. When a job is marked as callback / rework: - It can use the configured callback source label, such as `touch up` - It counts toward callback rate tracking - It can be linked to an original job - The original job's commission pool can be forfeited when linked Elite rate eligibility is calculated per crew using the policy's configured threshold and measurement period. --- ## Crew Pay Dashboard The Crew Pay dashboard now shows: - Active policy version - Commissionable revenue after exclusions and caps - Total crew pay - Retained split share - Base wage totals - Commission top-up totals - Hourly totals - Crew tip totals with cash, check, and card method visibility - Recent jobs with the applied policy version This gives payroll and ops a cleaner read on what changed and why. --- ## Crew Tips Customer tips are tracked separately from crew pay. They do not change the commission pool or the hourly / commission payout math. CE Pro now supports tips in three places: - The hosted invoice payment page - Mobile payment collection when the crew collects payment in the field - Manual cash or check payment logging in the payment collection flow Tip suggestions are always calculated from the **taxable amount** using: - 10% - 15% - 20% - Custom amount - No tip When a tip is collected: - Card tips are added during checkout before Stripe payment submission - Cash and check tips can be recorded alongside the collected payment - The Crew Pay dashboard shows total tips for the selected period - Tip totals are broken out by payment method so payroll and ops can see where the money came from - Individual crew member rows show allocated tip visibility alongside base, top-up, and hourly pay - Start with a policy version that mirrors your current agreement, then schedule future versions as you learn from production. - Use crew split templates for the normal case and job overrides only for exceptions. - Mark overnight and weekend routes hourly-only at the route-day level first. - Keep state minimum wage overrides current if crews cross state lines. - Review retained share totals regularly so managers understand when hourly-only participants occupied commission slots. - If your org is still finishing a crew-pay schema rollout, CE Pro falls back to default crew behavior until the newest split-template and compensation columns are available. --- URL: https://docs.cleanestimate.pro/settings/customer-portal Title: Customer Portal Description: How customers access their portal to view estimates, make payments, leave reviews, and share referral links. Category: settings Difficulty: beginner Last updated: 2026-04-23 --- # Customer Portal The customer portal is a public-facing page where your customers interact with your business online. It gives them self-service access to view proposals, request estimates, pay invoices, leave reviews, and share referral links -- all without calling your office. The portal is branded with your company identity and accessible at a permanent URL that you share on your website, social media, business cards, and marketing materials. [SCREENSHOT: Customer portal landing page showing branded header, navigation tabs, and welcome message] --- ## Portal URL Your portal is available at: ``` app.cleanestimate.pro/portal/your-slug ``` The slug is your unique business identifier, set during onboarding. It appears in all portal links shared with customers. For example, if your company is "Sparkle Clean Pros" and your slug is `sparkle-clean`, your portal URL would be: ``` app.cleanestimate.pro/portal/sparkle-clean ``` The slug cannot be changed after initial setup. Choose a short, recognizable slug that matches your business name or brand. [SCREENSHOT: Portal URL displayed in the settings page with a copy-to-clipboard button] --- ## How Customers Access the Portal Customers reach your portal through several channels. No account creation or password is required for most features -- customers identify themselves by entering their email address or phone number. | Channel | How It Works | |---|---| | **Direct link** | Share the portal URL on your website, in email signatures, or on social media profiles. | | **QR code** | Generate a QR code for the portal URL. Print it on business cards, door hangers, vehicle wraps, or yard signs. | | **Estimate emails** | When you send an estimate, the email includes a link to the portal where the customer can view their proposal. | | **Invoice emails** | Invoice notifications include a portal link for online payment. | | **SMS messages** | Text messages sent through the platform can include the portal link. | | **Post-job follow-ups** | After completing a job, send a follow-up message with a portal link for reviews and referrals. | The low-friction access model (no login required for lookups) means customers can interact with the portal immediately without setting up credentials. This dramatically increases usage compared to systems that require account creation. Portal, estimate, and invoice links open as normal browser pages. CleanEstimate Pro no longer prompts customers to install the site as a Chrome app/PWA. The dedicated customer login page at `app.cleanestimate.pro/customer/login` now renders outside the authenticated customer portal shell. That keeps magic-link sign-in available to signed-out customers instead of redirecting the login route back to itself. Direct estimate, proposal, maintenance-plan, and payment links are signed automatically. Generic quotes plus the shared quote-core linked-estimate pages for residential, fleet, commercial building, and holiday-lights records now use the shared public quote URL instead of the older signed estimate-only route whenever that saved quote has a persisted public quote token. When a customer opens a link from email or SMS, CE Pro still routes them to the correct public page without requiring an office login. Commercial linked-estimate sends now preserve that saved shared quote token more reliably too. When a fleet or commercial building proposal already has a persisted public quote token on its linked estimate, resend and preview flows keep reusing that same `/quote/[token]` link instead of silently downgrading to a temporary signed estimate URL. Holiday-lights sends now follow that same rule. If the linked holiday-lights estimate already has a persisted public quote token, CE Pro delivers the shared `/quote/[token]` link to the customer first and only falls back to the older seasonal portal URL when the shared quote link is not available yet. Those signed estimate, proposal, maintenance-plan, and payment links still depend on the server-side `CUSTOMER_TOKEN_SECRET` environment variable. Set that secret before you send live customer links, keep it stable across deploys, and rotate it only when you are prepared for previously sent signed links to stop working. Customer delivery tokens now include an expiry window, so older links will age out instead of remaining valid forever. Shared quote-core public links are stored separately on the quote record and do not use that same customer-token URL format for the base page itself. Customer sends now also fall back to the workspace's configured public site URL when the older dedicated app URL setting is blank. That means quote, proposal, maintenance-plan, shared quote, and holiday-lights portal links can still be generated during normal deploy or config transitions instead of failing the send with a temporary secure-link error. Office-side send failures are now categorized more accurately too. If customer-link setup is the real issue, CE Pro still shows the secure-link setup warning. But if the draft is missing proposal options, missing a maintenance plan, or the email provider itself is unavailable, the send flow now surfaces that specific delivery problem instead of incorrectly blaming secure estimate links. Estimate sends are also now resilient to live schema drift in the estimate pricing columns. The delivery helper no longer depends on newer optional estimate columns being present on every production workspace before a quote email can be generated, so sends keep working during rollout windows where one workspace still has an older `estimates` table shape. Shared `/quote/[token]` pages now keep their online actions interactive even if that signing secret is temporarily unavailable. Quote acceptance, proposal package selection, maintenance-plan acceptance, customer-facing PDFs, and deposit actions can validate directly against the saved public quote token on the linked estimate, so a customer or office preview opened through the shared quote link no longer falls back to a misleading read-only "approval unavailable" state just because the customer-token secret is missing. That same shared-quote fallback now also keeps office send messaging aligned with reality. When a generic, asphalt, residential, fleet, commercial building, or holiday-lights quote already has a persisted public quote token, CE Pro no longer warns the office that the delivered link is "view-only" or that secure quote setup is incomplete just because `CUSTOMER_TOKEN_SECRET` is temporarily missing. The email still sends, and the shared quote page keeps using the saved public token path. Residential proposal-option and maintenance-plan links also keep their own public-view context when they hand off to the shared quote page. That means package-option opens still count as proposal views, maintenance-plan opens still count as maintenance-proposal views, and the customer sees the same specialized tab first instead of everything being treated as one generic quote open. Portal proposal lookup and customer estimate lists now classify those mirrored residential package and maintenance offers from the shared quote-core offer layer too. Even after CE Pro moves proposal-option or maintenance-plan data off the parent estimate JSON, customers still land on the right public page from the portal instead of seeing a plain estimate link. That same shared offer classification now also drives the customer dashboard and customer estimate list links directly. If a residential record is really a package proposal or maintenance offer, those summary cards now open the matching proposal or maintenance view instead of always defaulting to the base estimate link. --- ## Viewing Estimates and Proposals Customers can look up their proposals through the portal's Proposals tab. ### How It Works 1. The customer navigates to your portal URL. 2. They select the **Proposals** tab. 3. They enter the email address used on their estimate or proposal. 4. CE Pro checks for matching live proposals and estimates in that workspace, then emails secure links instead of rendering proposal data directly in the browser. [SCREENSHOT: Proposal lookup form with an email input field and a "Find My Proposals" button] ### What the Customer Sees After they submit the form, the portal shows a confirmation state: - If matching live records are found and email delivery is available, the customer receives secure links in their inbox. - If no matching live records are found, the portal keeps the response generic instead of exposing whether that email belongs to a customer. - If email delivery is temporarily unavailable, the portal asks the customer to retry instead of falsely claiming links were sent. Opening a secure link from that email takes the customer to the full proposal or estimate view, which includes: - Detailed service descriptions with scope of work. - Line-item pricing breakdown. - Multi-option selections if the proposal includes tiered pricing (e.g., Basic, Standard, Premium). - Package discount details if applicable. - Terms and conditions. - An **Accept** button with e-signature capture. - A **Download PDF** option for the customer's records. [SCREENSHOT: Customer viewing a detailed proposal with service breakdown, pricing, multi-option selector, and an Accept button] ### Accepting a Proposal When the customer clicks **Accept**, a signature pad appears. The customer signs using their mouse, trackpad, or finger (on mobile devices). After signing: 1. The proposal status changes to "Accepted." 2. You receive a notification that the proposal was accepted. 3. The customer sees a confirmation screen. 4. A job record is created in your system automatically. Office staff can also use the admin-side **View Public Page** preview to walk through the same signature flow while signed in. CE Pro now honors that authenticated office preview path instead of requiring a separate customer token just to verify the acceptance experience from admin. Shared quote-core public pages now inherit the workspace organization name in the header too, so customers see the office brand instead of a hardcoded product label when they open a shared estimate or quote link. That office preview path now resolves through the same valid customer-link contract across residential estimates, package proposals, maintenance plans, fleet proposals, commercial building proposals, holiday-lights linked estimates, generic quotes, and asphalt quotes. If an internal teammate opens an older raw public route while signed in, CE Pro now hydrates the same interactive approval token the delivered link would have used instead of falling back to a read-only "approval unavailable" state. Signature capture is now hardened across all three public acceptance pipelines too: shared estimate and quote links sign through the shared estimate-sign route, fleet and commercial building proposal pages self-heal missing signature-storage buckets before retrying the upload, and holiday-lights contract signing keeps using the inline contract signature fields. That keeps online approval reliable across estimate, proposal, maintenance-plan, and holiday contract flows instead of each module depending on a separate fragile signature setup. If the customer adds notes or requests changes before signing, those comments are saved on the estimate record so your team can review them in the admin estimate detail view. This eliminates the back-and-forth of emailing signed documents and accelerates the time from proposal to scheduled job. --- ## Requesting an Estimate The estimate request form turns your portal into a lead generation tool that operates around the clock. ### The Request Form Customers fill out a form with: - **Contact information** -- Name, email address, and phone number. - **Property address** -- With optional autocomplete for faster entry. - **Services of interest** -- Checkboxes for the service types you offer (house wash, gutter cleaning, window cleaning, etc.). - **Additional notes** -- A free-text field where the customer can describe their specific needs, timeline, or concerns. [SCREENSHOT: Estimate request form showing fields for name, email, phone, address, service checkboxes, and a notes area] ### What Happens After Submission When a customer submits an estimate request: 1. A new lead is created in your pipeline automatically. 2. The lead source is tagged as "Portal" so you can track portal-generated leads separately. 3. You receive a notification (email or in-app, depending on your notification settings). 4. The customer sees a confirmation message thanking them for their request. This means a homeowner who visits your website at 10 PM on a Saturday can submit their request immediately. Without the portal, that lead might forget to call on Monday morning. ### Response Time Portal estimate requests are warm leads -- the customer actively sought you out and took the time to fill out a form. Respond within one hour during business hours for the best conversion rates. Configure notifications to alert you immediately when a new portal request arrives. --- ## Making Payments Customers can pay outstanding invoices directly through the portal. Payments are processed through Stripe, so your Stripe integration must be connected before enabling this feature. ### Payment Workflow 1. The customer navigates to the **Pay** tab on your portal. 2. They enter their email address or invoice number. 3. The portal displays their outstanding invoices with amounts and due dates. 4. The customer selects an invoice and clicks **Pay Now**. 5. A Stripe-hosted checkout page opens for secure card entry. 6. After successful payment, the invoice status updates to "Paid" automatically. 7. Both the customer and your team receive a payment confirmation email. [SCREENSHOT: Outstanding invoice list showing invoice number, date, amount due, and a Pay Now button for each] ### Benefits of Portal Payments - **Faster collection.** Customers pay immediately without writing a check or calling to read a card number over the phone. - **Reduced friction.** The fewer steps between "customer wants to pay" and "payment received," the faster your cash flow. - **Automatic reconciliation.** Payments update your invoice records automatically. No manual data entry. - **Security.** Stripe handles all card data. You never see or store credit card numbers. ### Payment Methods Stripe supports credit cards, debit cards, and (depending on your Stripe configuration) ACH bank transfers and digital wallets like Apple Pay and Google Pay. The available payment methods are determined by your Stripe account settings. --- ## Leaving Reviews After a completed job, customers can leave feedback through the portal's Review tab. ### Review Flow 1. The customer navigates to the **Review** tab. 2. They select a star rating from 1 to 5. 3. They write optional feedback in a text area. 4. They submit the review. [SCREENSHOT: Review submission form showing a 5-star rating selector and a text area for written feedback] ### Google Review Redirect If you have configured a Google Review URL in **Settings > Account**, the portal implements a smart redirect: - **High ratings (4-5 stars):** After submitting through the portal, the customer is encouraged to also post their review on Google. A button links directly to your Google Business Profile review page. - **Lower ratings (1-3 stars):** The customer's feedback is captured privately through the portal. They are not redirected to Google. This gives you an opportunity to address the concern before it becomes a public negative review. [SCREENSHOT: Post-review screen for a 5-star rating showing a "Leave a Google Review" button and a thank-you message] This approach protects your public reputation while still giving you honest feedback from every customer. ### Using Reviews Effectively - Send a follow-up message with a portal review link within 24 hours of completing a job, while the experience is fresh. - Respond to all feedback, positive or negative. Customers who leave low ratings through the portal are giving you a chance to fix the problem. - Track your average rating over time. A declining trend signals a service quality issue. --- ## Sharing Referral Links Referrals are one of the highest-converting lead sources for exterior cleaning businesses. The portal makes it easy for happy customers to refer friends and family. ### Referral Lookup The **Refer** tab is available only to existing customers. CE Pro uses the customer's email address to protect referral credit and keep the portal from turning into an open public lead form. - If the customer already has a referral code, the portal shows their existing share link and stats immediately. - If the customer is known to your workspace but has never used referrals before, the portal asks for their name once and then creates a shareable referral code. - If the email is not tied to an existing customer record, CE Pro blocks the request instead of letting an unknown visitor create a referral code. [SCREENSHOT: Referral card showing the customer email lookup, referral code, and shareable portal link] ### What Happens After Submission 1. The customer copies or shares their personal referral link. 2. A referred prospect opens that link and starts an estimate request with the referral code attached. 3. The new lead or estimate is tagged back to the referring customer for attribution. 4. The referring customer can return to the portal later to reuse the same link and review their referral totals. ### Tracking Referral Performance Because the referring customer and code stay attached to the referral link, you can: - Identify your top referral sources (which customers refer the most). - Calculate the lifetime value of referral leads versus other lead sources. - Implement referral incentive programs and track redemption. --- ## Holiday Lights Portal Tab If your account has the Holiday Lights module enabled, the portal automatically includes an additional tab for holiday lighting. Customers can: - View their holiday lighting proposal with design details. - See mockups showing how their property will look with lights installed. - Review zone configurations and light specifications. - Accept the holiday lighting proposal with an e-signature. This tab appears only when the Holiday Lights module is active. It is visible to customers who have an active or pending holiday lighting proposal. [SCREENSHOT: Portal with the Holiday Lights tab showing a customer's lighting design mockup and proposal summary] --- ## Portal Branding The portal displays your company branding to create a professional, consistent customer experience. ### Branding Elements - **Company logo** -- Displayed in the portal header. - **Brand colors** -- Applied to buttons, headings, links, and accent elements. - **Company name** -- Shown in the page header and footer. If you have multiple brands configured in **Settings > Brands**, the portal uses your default brand. The branding ensures the portal looks like an extension of your company's website, not a generic third-party tool. [SCREENSHOT: Portal with custom branding showing company logo, brand-colored navigation and buttons, and company name] --- ## Configuring Portal Features Go to **Settings > Portal** to control which features are available on your portal. Each feature has an on/off toggle. | Feature | What It Controls | Prerequisite | |---|---|---| | **Proposals** | Show or hide the proposal lookup tab. | None | | **Estimate Requests** | Show or hide the estimate request form. | At least one service configured in pricing settings. | | **Invoice Payments** | Show or hide the payment tab. | Stripe integration connected. | | **Reviews** | Show or hide the review submission form. | Google Review URL configured (optional but recommended). | | **Referrals** | Show or hide the referral form. | None | Changes save automatically when you toggle a feature. For detailed portal configuration instructions, see the [Portal Settings](https://docs.cleanestimate.pro/settings/portal-settings) guide. [SCREENSHOT: Portal settings page showing the five feature toggles with their on/off states] --- ## Sharing the Portal Effectively The portal only provides value if customers know about it. Integrate the portal URL into every customer touchpoint. ### Website Add a prominent "Customer Portal" or "Pay Online" button to your website navigation. Place it in the header, footer, or on a dedicated customer resources page. ### Print Materials Include a QR code for the portal URL on: - Business cards - Door hangers left after estimates or jobs - Yard signs placed during active jobs - Vehicle wraps and magnets - Flyers, brochures, and direct mail pieces ### Email Communications - Add the portal URL to your team's email signatures. - Include portal links in estimate emails, invoice emails, and follow-up messages. - Create a post-job email template that links to the review and referral sections of the portal. ### Post-Job Follow-Up After completing a job, send a single follow-up message that includes links to: - The **Review** tab for leaving feedback. - The **Pay** tab if there is an outstanding invoice. - The **Refer** tab for recommending friends. This one message can drive reviews, accelerate payment collection, and generate new leads simultaneously. --- ## Tips - **Enable only relevant features.** If you do not offer online payments through Stripe yet, do not enable the Pay tab. Empty or broken features erode customer trust. - **Test the portal from a customer's perspective.** Open the URL in a private browser window and walk through each feature. Make sure everything works and looks professional. - **Mention the portal to customers.** Technology only helps if people use it. Train your team to mention the portal during job completion and follow-up calls. - **Use the referral feature actively.** Ask satisfied customers to refer a friend through the portal right after completing their job, while their satisfaction is highest. - **Respond to portal estimate requests quickly.** These are warm leads. Aim for a response within one hour during business hours. - **Keep your Google Review URL current.** If you change your Google Business Profile, update the URL in settings immediately. - **Track portal metrics.** Monitor how many estimate requests, payments, reviews, and referrals come through the portal each month. This data justifies the effort of promoting it. --- ## Troubleshooting ### Portal page shows a 404 or "not found" error Verify your portal slug at **Settings > Portal**. The URL must match exactly, including case. If the account was recently created, the portal may take a few minutes to become active. ### Customer cannot find their proposal The proposal lookup matches by email or phone number. The customer must enter the same email or phone number that was used when the estimate was created. If they use a different email, no results appear. Check the estimate record to confirm the correct contact information was entered. ### Pay Now button is not showing on invoices Ensure your Stripe integration is connected and active at **Settings > Billing**. If Stripe is connected but the button still does not appear, check that the invoice status is "Sent" or "Outstanding." Draft invoices are not available for payment through the portal. ### Google Review redirect is not working Verify that the Google Review URL is configured at **Settings > Account**. The URL must be the direct review link for your Google Business Profile, not your general business listing URL. You can find this link in your Google Business Profile dashboard under "Get more reviews." ### Referral form submissions are not creating leads Check that the Referrals toggle is enabled at **Settings > Portal**. If the toggle is on but leads are not appearing in your pipeline, check the leads list with the source filter set to "Portal" or "Referral." The leads may be created but filtered out of your default view. ### Portal looks unbranded or uses default styling Verify that your company logo and brand colors are configured at **Settings > Brands**. The portal pulls branding from your default brand. If no brand is configured, the portal uses generic default styling. --- URL: https://docs.cleanestimate.pro/settings/portal-settings Title: Customer Portal Settings Description: Configure the customer-facing portal with branding, feature toggles, booking widget, and review requests. Category: settings Difficulty: intermediate Last updated: 2026-03-20 --- # Customer Portal Settings The customer portal is a public-facing page where your customers interact with your business online. They can view proposals, request estimates, pay invoices, leave reviews, refer friends, and book services. Go to **Settings --> Portal** to configure it. [SCREENSHOT: Portal Settings page showing the portal URL, feature toggles, branding options, and booking widget configuration] --- ## Enabling the Portal The customer portal is enabled by default when you create your CE Pro account. Your portal URL is: ``` app.cleanestimate.pro/portal/your-slug ``` The slug is your unique business identifier, set during onboarding. It appears in all portal links. To disable the portal entirely: 1. Go to **Settings --> Portal**. 2. Toggle the **Portal Active** switch to off. 3. The portal URL returns a "not available" message to anyone who visits it. To re-enable, toggle the switch back on. Your configuration and branding are preserved. > **Tip:** The portal slug cannot be changed after initial setup. Choose a short, recognizable slug that matches your business name or abbreviation. --- ## Customizing Portal Branding The portal uses your default company branding. If you have multiple brands configured, you can select which brand appears on the portal. ### What Branding Controls - **Logo** -- Displayed in the portal header and on all portal pages. - **Company Name** -- Appears in the page title and header. - **Accent Colors** -- Applied to buttons, links, headings, and interactive elements. - **Contact Information** -- Shown in the portal footer and contact sections. ### Changing the Portal Brand 1. Go to **Settings --> Portal**. 2. In the **Branding** section, select a brand from the dropdown. 3. The preview updates to reflect the selected brand. 4. Changes save automatically. [SCREENSHOT: Portal branding section with brand selector dropdown and live preview] If you need to create a new brand first, go to **Settings --> Brands** and add it there. See the [Managing Brands](https://docs.cleanestimate.pro/docs/settings/brands) article for details. --- ## Configuring Portal Features The portal offers five customer-facing features. Each can be independently toggled on or off. ### Proposals When enabled, customers can request secure proposal and estimate links by entering the email address tied to their record. CE Pro emails matching live links for that workspace instead of rendering the customer record directly in the portal response. Proposal lookups stay scoped to the matching provider workspace and only reuse live customer records for that portal. If a secure proposal or estimate link is temporarily unavailable because customer-link signing is not configured yet, the email still includes a fallback support note for that item. If email delivery itself is temporarily unavailable, the portal now shows a retry message instead of claiming secure links were sent. ### Estimate Requests When enabled, a form is available where customers enter their contact information, property details, and service needs. Submitted requests create a new lead in your pipeline with the source tagged as "Portal." ### Invoice Payments When enabled, customers can look up and pay outstanding invoices by entering their email or invoice number. Payments are processed through your connected Stripe account. > **Note:** Stripe must be connected before enabling invoice payments. See the [Stripe Settings](https://docs.cleanestimate.pro/docs/settings/stripe) article for setup instructions. ### Reviews When enabled, customers can leave a star rating and written review after a completed job. If you have configured a Google Review URL in your account settings, CE Pro redirects customers with high ratings (4 or 5 stars) to leave a public Google review. ### Referrals When enabled, existing customers can look up their personal referral link from the portal and share it. Unknown emails are blocked, and known customers who have never used referrals before are prompted once to create their shareable code. ### Toggling Features 1. Go to **Settings --> Portal**. 2. Each feature has a toggle switch. 3. Turn features on or off as needed. 4. Changes save automatically. [SCREENSHOT: Feature toggles on the Portal Settings page showing Proposals, Estimate Requests, Invoice Payments, Reviews, and Referrals with toggle switches] --- ## Booking Widget The booking widget is an embeddable estimate request form that you can add to your own website. It provides the same functionality as the portal's estimate request form but runs directly on your site. ### Enabling the Booking Widget 1. Go to **Settings --> Portal**. 2. Scroll to the **Booking Widget** section. 3. Toggle the widget to **Active**. 4. Copy the embed code snippet. ### Embedding on Your Website Paste the provided code snippet into your website's HTML where you want the booking form to appear: ```html ``` The widget adapts to the width of its container. It uses your portal branding for a consistent look. ### Widget Behavior - Customers fill out their name, contact information, property address, and service needs. - On submission, a new lead is created in your pipeline with the source tagged as "Booking Widget." - The customer sees a confirmation message. - You receive a notification (email and/or SMS, depending on your notification settings). [SCREENSHOT: Booking widget embedded on an example website showing the estimate request form with branding] --- ## Review Requests Review requests are automated messages that encourage customers to leave a review after a job is completed. ### How Review Requests Work 1. A job is marked as complete in CE Pro. 2. CE Pro sends an automated email or SMS (based on your automation settings) with a link to your portal's review page. 3. The customer clicks the link and submits a review. 4. If the customer gives a rating of 4 or 5 stars and you have a Google Review URL configured, they are prompted to post the review on Google. ### Configuring the Google Review URL 1. Go to **Settings** (main settings page). 2. Find the **Google Review URL** field. 3. Paste the direct HTTPS Google review link for your Business Profile. 4. Click **Save**. To find your Google review link: 1. Search for your business on Google Maps. 2. Click your business listing. 3. Click the "Write a Review" button. 4. Copy the URL from your browser's address bar. Only Google-owned review links are accepted here. Non-Google or non-HTTPS URLs are ignored for safety, and the portal still captures the internal CE Pro review even if the public Google link is unavailable. ### Review Request Timing Review requests are tied to your follow-up automation sequences. You can configure the delay and number of review request messages in **Settings --> Automations**. A typical setup sends the first request 24 hours after job completion, with a follow-up reminder 3 days later if no review has been submitted. --- ## How Customers Access the Portal Direct customers to your portal through any of these channels: - **Direct link** -- Share the portal URL on your website, social media profiles, or Google Business listing. - **QR code** -- Generate a QR code for the portal URL and print it on business cards, door hangers, yard signs, or vehicle wraps. - **Estimate and invoice emails** -- Links to the portal are automatically included in estimate, proposal, and invoice emails sent from CE Pro. - **SMS messages** -- Include the portal link in text messages to customers. - **Website embed** -- Use the booking widget to embed the estimate request form directly on your website. If the same email address exists under more than one provider, CE Pro hides the shared customer dashboard, estimate list, and message history until the customer opens a direct signed link from the correct provider. That prevents account history from being mixed across different companies. --- ## Holiday Lights Portal Tab If your account has the Holiday Lights module enabled, the portal includes an additional tab where customers can view their holiday lighting proposals and designs. This tab appears automatically when the module is active. No additional configuration is needed. [SCREENSHOT: Customer portal with the Holiday Lights tab visible in the navigation] --- ## Tips - Enable only the features your customers will actually use. A simpler portal is easier for customers to navigate. - Test your portal from a customer's perspective. Open the URL in a private browser window and verify the layout, branding, and forms. - If you use the referral feature, mention it to satisfied customers after completing a job. Referrals convert at higher rates than cold leads. - Make sure your Stripe integration is connected before enabling invoice payments on the portal. - Set up your Google Review URL before enabling the review feature. Without it, reviews stay internal to CE Pro and are not posted publicly. - Embed the booking widget on every page of your website, not just the contact page. More visibility means more leads. --- URL: https://docs.cleanestimate.pro/settings/franchise-hierarchy Title: Franchise Hierarchy Description: Beta support for parent-child organizations, scoped multi-org access, active workspace switching, summary refresh, audit logging, and the new franchise admin workspace. Category: settings Difficulty: advanced Roles: owner, manager Last updated: 2026-03-16 --- # Franchise Hierarchy CleanEstimate Pro now has the Phase 1 through Phase 4 franchise beta workflow for parent-child organization management. This is still a beta workflow. The current build now supports: - parent and child organizations - franchisor, operator, location, HQ, and branch org types - scoped multi-org memberships - active workspace switching - a sidebar workspace switcher for eligible multi-org users - a dedicated **Franchise** admin area for viewing and managing descendant orgs - 15-minute franchise summary refreshes for beta rollups - franchise audit logging for org switching and cross-org franchise access The workflow is still intentionally constrained for beta rollout, but parent-org admins no longer need to rely only on raw APIs or internal setup tools. --- ## What Exists Today The current build includes: - hierarchy metadata on organizations - relationship records between parent and child orgs - descendant and ancestor traversal helpers in the database - scoped membership access for org-only, org-and-children, and assigned-children access - active org switching through the authenticated admin API - franchise admin APIs for overview, child-org management, child-org user listing, and child-org invites - continued parent-org visibility into inactive descendant workspaces so beta admins can review and reactivate child orgs without losing the hierarchy tree - a normal admin-sidebar entry at **Admin --> Franchise** for eligible parent workspaces - a workspace switcher in the admin shell when a user can access more than one readable org - franchise overview, workspace roster, child-workspace detail, child-workspace users, reports, and settings pages - a materialized franchise summary snapshot (`mv_org_summary`) refreshed every 15 minutes for beta reports and workspace-level rollups - franchise audit logs for org switching and franchise page/API access - descendant-read RLS helper coverage on the core org-scoped workflow tables used in the beta - descendant-read RLS intentionally excludes inactive child-workspace data on authenticated paths, while the franchise admin APIs still keep inactive workspaces visible for management via service-role reads The current build still does **not** include public franchise APIs or full cross-org analytics beyond the operational rollups in the beta admin area. --- ## Supported Org Types The hierarchy model supports these org types: - `standalone` - `franchisor` - `operator` - `location` - `hq` - `branch` Current parent-child expectations: - `franchisor` can manage `operator` and `location` descendants - `operator` can manage `location` descendants - `hq` can manage `branch` descendants --- ## Access Model Phase 2 keeps access explicit. A user can only switch into an org when their membership or membership scope allows it. Supported membership scopes: - `own_org` - `org_and_children` - `assigned_children` This is intentional. CE Pro does not silently grant sibling-org or unrelated-org access just because a user belongs to a parent company. --- ## Workspace Switching The active workspace is now stored in the authenticated user metadata and resolved on future admin requests. That means: - you can keep a single login - the active workspace can change without logging out - org context, permissions, and feature flags now resolve from the active org instead of always defaulting to the first membership - successful workspace switch responses now tell the admin client to refresh session metadata immediately so the next request resolves against the new active org - the switcher only appears when the current user can access more than one readable workspace - inactive workspaces stay visible to parent admins for management, but cannot be selected as the active workspace If a stored active org becomes stale or inaccessible, CE Pro falls back safely to the earliest active membership. --- ## Permissions Two new admin permissions were added for the franchise beta: - `franchise.view` - `franchise.manage` By default: - Owners get both - Managers get both - Other roles do not get them unless role permissions are customized The franchise sidebar area appears only when all of these are true: - the active org has the franchise hierarchy feature enabled - the active org type is a parent-capable type (`franchisor`, `operator`, or `hq`) - the active org plan is franchise-eligible (`commercial`, `base_plus_lights_commercial`, `base_plus_lights_commercial_sms`, or `enterprise`) - the current role includes `franchise.view` Write actions like creating child workspaces, changing workspace metadata, deactivating workspaces, and sending child-org invites require `franchise.manage`. --- ## Franchise Admin Workspace Eligible parent-org admins now get these pages inside the normal admin UI: - **Admin --> Franchise** — hierarchy overview and direct-child summary - **Admin --> Franchise --> Organizations** — full descendant workspace roster with child-org creation - **Admin --> Franchise --> Organizations --> [Workspace]** — child workspace details and activation state - **Admin --> Franchise --> Organizations --> [Workspace] --> Users** — child workspace roster and invite flow - **Admin --> Franchise --> Reports** — operational rollups for workspace counts, plans, and staffing - **Admin --> Settings --> Franchise** — hierarchy policy, permissions, and rollout guidance The root parent org is intentionally read-only inside the child-workspace detail page. Continue using the standard CE Pro settings flow to edit the active parent workspace itself. --- ## Reporting and Refresh Cadence Franchise reports now read from a precomputed summary snapshot instead of running live cross-org aggregate queries on every page load. That snapshot currently includes: - direct child counts - active team membership counts - 30-day estimate counts - 30-day job counts - 30-day paid invoice revenue For beta, the summary is refreshed every 15 minutes through the internal cron route: - `POST /api/cron/refresh-franchise-summary` This route uses the same `CRON_SECRET` bearer-header protection as the other internal cron endpoints. These rollups only count `live` application data. Sandbox or test-environment records are excluded from the franchise summary so beta reporting matches production-facing numbers. --- ## Audit Logging Franchise beta now records audit events for: - successful org switches - franchise overview access - descendant org roster access - child workspace detail access - child workspace user access - child workspace creation, updates, deactivation, and invites This hardening step gives the beta rollout a durable trail for cross-org activity before live franchise onboarding. --- ## Beta Setup Checklist Before onboarding a real franchise network: 1. Put the parent org on a franchise-eligible plan. 2. Enable the franchise hierarchy feature flag for the parent org and its child workspaces. 3. Confirm the parent org type is one of `franchisor`, `operator`, or `hq`. 4. Create the child org tree from **Admin --> Franchise --> Organizations**. 5. Grant `franchise.view` and `franchise.manage` only to the admins who should manage the hierarchy. 6. Verify org switching works for the intended parent and child users. 7. Confirm the summary refresh cron is scheduled and healthy before relying on beta reports. --- ## Rollout Notes This phase is intentionally beta-scoped rather than fully self-serve for all customers. Use it when you need to: - prepare franchise beta org trees - invite managers into child orgs - validate parent-child access rules - test active workspace switching in the real admin shell - confirm the 15-minute summary refresh is running - confirm cross-org audit logs are being recorded - manage inactive child workspaces without losing visibility into the hierarchy If you are a normal standalone org, this release should not change your day-to-day workflow. --- URL: https://docs.cleanestimate.pro/settings/gamification Title: Gamification Settings Description: Enable XP tracking, streaks, title sets, and leaderboard controls for your workspace. Category: settings Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-16 --- # Gamification Settings Use **Settings --> Gamification** to control the XP system for your workspace. This page turns on the leaderboard, level badges, streak tracking, and title tracks for Sales, Crew, and Office roles. [SCREENSHOT: Gamification Settings page showing the Gamification Engine, Title Sets, Streak Rules, and Leaderboard + Digest cards] --- ## What This Page Controls The Gamification page currently manages: - **Gamification Engine** toggle for XP, levels, streaks, and leaderboard tracking. - **Rewards store** toggle for spendable XP accounting. - **Title Sets** for Sales, Crew, and Office tracks. - **Working days** used when streaks are calculated. - **Leaderboard visibility** and weekly digest settings. If gamification is off, the Team Leaderboard stays dormant and the sidebar level/streak badges do not show active progress. --- ## Turn Gamification On At the top of the page, switch on **Enable XP, levels, streaks, and achievements**. This enables the live XP framework that powers: - Sidebar level and streak indicators in the admin app - The XP leaderboard at **Team --> Leaderboard** - XP event tracking from key workflows like estimate activity, job completion, invoicing, payments, and daily login > **Important:** Gamification is controlled per workspace. One organization can have it on while another remains off. --- ## Rewards Store Toggle The **Enable rewards store** switch turns on spendable XP accounting. Today, this means the app keeps track of **total XP** separately from **spendable XP** and shows spendable XP on the leaderboard when the setting is enabled. Use this setting if you want the workspace ready for reward-based programs such as: - Gas cards - PTO rewards - Cash bonuses - Branded gear If the rewards toggle is off, the leaderboard still works, but spendable XP is shown as off. --- ## Title Sets Each role track can use a different title theme: - **Sales** - **Crew** - **Office** Available title sets include themes like: - **Default** - **Swagger** - **Professional** - **Military** - **Trades** Choose the theme that best fits how you want rank progression to feel for each group. [SCREENSHOT: Title Sets section showing dropdowns for Sales, Crew, and Office track labels] --- ## Streak Rules Use the **Working days** section to define which days count toward streaks. For example: - If your office works Monday through Friday, only those days should be selected. - If crews work Saturdays during peak season, add Saturday so streaks stay accurate. Streaks only evaluate against the days marked as active workdays for the organization. --- ## Leaderboard and Weekly Digest The **Leaderboard + Digest** card controls how the team recap behaves. ### Leaderboard Visibility - **Full** shows the full leaderboard table and team comparisons. - **Rank only** limits visibility to a more minimal ranking presentation. ### Weekly Digest You can also configure: - **Digest day** - **Digest channel**: Email, SMS, or Both - **Weekly digest enabled** The settings are live and saved per workspace, even if your team has not started using the digest heavily yet. --- ## Open the Leaderboard Use the **Open Leaderboard** button at the top-right of the Gamification page, or go directly to **Team --> Leaderboard**. That page shows: - Current rank - Level - Title - Period XP - Total XP - Streak days - Spendable XP when rewards are enabled - Every achievement already earned by the signed-in user - The remaining track-relevant and universal achievements that can still be unlocked --- ## Current Production Scope The production app already includes the gamification foundation, but not every future layer is live yet. What is live now: - XP event tracking - Level progression - Streak tracking - Title set selection - Leaderboard visibility settings - Spendable XP accounting toggle - Full earned-achievement and unlockable-achievement catalog visibility on the leaderboard What may still appear limited: - Reward redemption workflows are not yet surfaced as a full end-user store flow This page still reflects the real production controls that are available today. --- URL: https://docs.cleanestimate.pro/settings/google-lead-ads Title: Google Lead Ads Description: Connect Google lead forms through the guided Google Ads webhook setup screen. Category: settings Difficulty: beginner Roles: owner, manager Last updated: 2026-04-14 --- # Google Lead Ads Use **Settings > Integrations > Google Lead Ads** when you want Google lead forms to create leads inside Clean Estimate Pro without hand-building a generic connector first. This page is the easy setup flow for Google Ads. It does four things for you: - creates or updates the underlying Google Ads connector - generates the Google verification key CE Pro expects on inbound webhooks - shows the exact webhook URL Google needs - shows the exact Google key your team pastes into the Google Ads form builder You still need to finish the webhook setup inside Google Ads, but the CE Pro side is handled from one screen instead of the general-purpose connector editor. --- ## Before You Start Make sure you have: - access to the Google Ads account that owns the lead form - permission to edit the form webhook inside Google Ads - optionally, a specific Google **Form ID** if you only want one form to import If you leave **Form ID** blank, CE Pro accepts any Google lead form that uses the generated key. --- ## Quick Setup 1. Open **Settings > Integrations > Google Lead Ads**. 2. Leave **Form ID** blank unless you want to limit the connector to one saved Google form. 3. Leave **Lead Source Label** as `google_ads` unless your team wants a more specific source label. 4. Click **Enable Google Lead Ads**. 5. Copy the **Webhook URL** shown on the page. 6. Copy the **Google Key** shown on the page. 7. In Google Ads, open the lead form webhook settings. 8. Paste the CE Pro **Webhook URL**. 9. Paste the CE Pro **Google Key** into Google's key field. 10. Run Google's webhook test, then submit one real lead. Once that test passes, CE Pro ingests live leads through the same shared connector pipeline used by Meta, API imports, website forms, and email parsing. --- ## What The Google Ads Page Saves Behind the scenes, the guided Google Ads setup page creates a native-webhook lead connector with: - provider `google_ads` - transport `native_webhook` - source label `google_ads` unless you override it - default Google lead-form field aliases for name, email, phone, address, service, and external id - the generated `google_key` - the saved optional `form_id` That means Google lead forms still get: - duplicate suppression using the Google `lead_id` - import-run logging - reviewable failures - normal CE Pro lead creation - speed-to-lead automation if the connector keeps it enabled --- ## Webhook Values The Google setup page shows two copy-ready values: ### Webhook URL This is the CE Pro endpoint Google posts lead events to. It looks like: ```text https://app.cleanestimate.pro/api/webhooks/google-ads ``` ### Google Key This is the secret value Google includes in the webhook payload as `google_key`. Paste it exactly as shown on the page. CE Pro verifies that the incoming `google_key` matches the saved connector before a lead is imported. --- ## Choosing Key-Only vs. Key + Form ID ### Google Key only Use this if: - you want multiple Google forms to land in the same CE Pro intake path - or your Google Ads team prefers to reuse one webhook key across related forms ### Google Key + Form ID Use this if: - you only want one specific Google form to create CE Pro leads - or you want tighter routing when the Ads team manages several forms If both a key-wide connector and a form-specific connector could match the same inbound event, CE Pro prefers the exact form match. --- ## Testing Google's form builder can send a sample webhook request. When that test fires: - CE Pro accepts it and logs the delivery in **Lead Connectors > Recent Imports** - the test payload is marked as accepted without creating a live customer lead - the best final validation is still one real lead submission after the test passes For a real lead, **Recent Imports** should show a Google Ads import run with status `imported` or `replayed`. --- ## Advanced Changes If you need deeper control later, go to [Lead Connectors](https://docs.cleanestimate.pro/settings/lead-connectors). That advanced screen lets you adjust: - field aliases - assigned rep defaults - notes prefixes - test imports - import history The dedicated Google Ads screen is meant to handle the common setup path quickly. --- ## Troubleshooting ### Google says the webhook test failed Check: - the webhook URL matches the value shown in CE Pro - the Google Key matches exactly - the Google form was saved with webhook delivery enabled - the app workspace has the connector tables migrated ### I ran the Google test and do not see a lead That is expected. The Google webhook test is accepted and logged, but CE Pro does not create a live lead from Google's sample payload. ### Real Google leads are not importing Check: - the webhook test passed in Google Ads - the Google Key is the same value shown in CE Pro - the saved **Form ID** is correct if you restricted the connector to one form - **Lead Connectors > Recent Imports** for delivery status and errors ### I need more than the simple Google screen Use the [Lead Connectors guide](https://docs.cleanestimate.pro/settings/lead-connectors) and open the advanced connector settings from the Google page. --- ## Related Guides - [Lead Connectors](https://docs.cleanestimate.pro/settings/lead-connectors) - [Connecting Your Integrations](https://docs.cleanestimate.pro/getting-started/connecting-integrations) --- URL: https://docs.cleanestimate.pro/settings/lead-connectors Title: Lead Connectors Description: Configure API, website form, and email-forward lead intake from one shared connector layer. Category: settings Difficulty: intermediate Roles: owner, manager Last updated: 2026-04-14 --- # Lead Connectors Lead Connectors let your workspace accept leads from outside Clean Estimate Pro without creating a separate lead-import workflow for every source. Use **Settings > Integrations > Lead Connectors** to: - create connector profiles for trusted API imports, website forms, and forwarded emails - map outside field names onto CE Pro lead fields - apply defaults like source labels, assigned reps, notes prefixes, and speed-to-lead behavior - test imports safely before going live - review low-confidence email parses before a lead is created - inspect recent import attempts, replays, and failures If you are connecting Facebook, Instagram, or Google lead forms, start with the dedicated setup pages first: - [Meta Lead Ads](https://docs.cleanestimate.pro/settings/meta-lead-ads) - [Google Lead Ads](https://docs.cleanestimate.pro/settings/google-lead-ads) Those guided screens create the native webhook connectors for you and leave this screen for advanced tuning after the easy setup path is done. [SCREENSHOT: Lead Connectors page showing the connector form, review queue, and recent imports tabs] --- ## What A Connector Does Every connector normalizes outside payloads into the same shared lead-intake pipeline used by the rest of CE Pro. That means imported leads still go through the same core behavior for: - client merge or create - lead creation - source tagging - territory-based assignment fallback - speed-to-lead automations when enabled - duplicate suppression when an external id is provided The connector page is the control panel. The real lead creation still happens through the shared intake system behind the scenes. --- ## Connector Types In Phase 1 The current production phase supports five connector types: ### API Connector Use this for: - Zapier - Make - middleware or worker services - custom CRMs - trusted server-to-server integrations API connectors use your CE Pro API key plus the connector key shown in the connector detail card. ### Website Form Connector Use this when: - you want a public website form to post directly into CE Pro - you need a connector-specific public endpoint without exposing a long-lived API key in browser code The connector card shows the public endpoint for that form. ### Email Forward Connector Use this when: - your marketing inbox, form inbox, or forwarded lead emails should become leads automatically - you want the parser to attempt extraction from unstructured emails - you want low-confidence emails held for review instead of blindly creating bad leads ### Meta Connector Use this when: - Facebook lead ads or Instagram lead ads should create CE Pro leads - you want Meta webhook intake to land on the same shared connector pipeline - you want the easy setup path from **Settings > Integrations > Meta Lead Ads**, but still want the advanced connector available here afterward CE Pro now enforces one active connector per provider and transport combination inside a workspace. Meta lead ads now also have a dedicated guided setup page under **Settings > Integrations > Meta Lead Ads**, but the underlying connector still lives here once it is created. The Meta guided setup now works like a real connection flow: click **Connect Meta**, approve the Meta login, choose the page if needed, and CE Pro subscribes the page to `leadgen` for you instead of asking the workspace to paste page ids and webhook tokens manually. If no active email-forward connector exists, inbound emails are still routed and logged, but CE Pro will not auto-create a lead from the parser fallback. If the app deploy lands before the workspace database migrations, the Integrations area now stays available and the Lead Connectors screen shows a migration-required notice instead of a generic error page. The Lead Connectors page now shows your saved workspace email slug, only displays a full forwarding address when inbound email routing is actually configured, and includes a direct link back to this guide so the forwarding setup is easier to follow in-product. ### Google Ads Connector Use this when: - Google lead forms should create CE Pro leads - you want Google webhook intake to land on the same shared connector pipeline - you want the easy setup path from **Settings > Integrations > Google Lead Ads**, but still want the advanced connector available here afterward CE Pro now enforces one active connector per provider and transport combination inside a workspace. Google lead forms now also have a dedicated guided setup page under **Settings > Integrations > Google Lead Ads**, but the underlying connector still lives here once it is created. --- ## Creating A Connector 1. Open **Settings > Integrations > Lead Connectors**. 2. Enter a **Display Name** that tells your team what the source is. 3. Choose the **Provider** and **Transport**. 4. Set the connector to **Draft** while you configure it. 5. Add an optional **Source Label** such as `website_form`, `meta`, `google_ads`, or `email_forward`. If you leave **Source Label** blank, CE Pro now falls back to the connector provider key, so email-forward connectors still land as `email_forward` instead of a generic `connector` source. 6. Choose an **Assigned Rep** if this connector should default to one person. 7. Add a **Notes Prefix** if you want every imported lead to carry source context. 8. Turn **Trigger speed-to-lead** on or off depending on whether imported leads should immediately fire the normal follow-up flow. 9. For email connectors, set an **Email review threshold** like `0.65` or `0.75` if uncertain parses should pause for human review. 10. Save the connector. Leave connectors in **Draft** until the mapping and test import look right. --- ## Field Mapping Outside systems rarely use the same field names CE Pro expects. Use **Field Aliases** to tell CE Pro which incoming fields map to which lead fields. Common examples: - `full_name` -> `customer_name` - `phone_number` -> `customer_phone` - `street_address` -> `service_address` - `requested_service` -> `service_interest` - `message` -> `notes` - `leadgen_id` or provider message id -> `external_id` - `lead_id` -> `external_id` If a connector sends standard CE Pro field names already, you can leave most aliases blank. --- ## API Connector Setup API connectors are the best fit for trusted server-to-server lead intake. ### Recommended Request Pattern - Use a scoped CE Pro API key with `leads:write` - POST to `/api/v1/leads` - Include the connector key in `connector_key` - Send `Idempotency-Key` on every request - Send `external_id` whenever the upstream system provides a stable id Example payload: ```json { "connector_key": "lc_live_abc123", "customer_name": "Pat Example", "customer_email": "pat@example.com", "customer_phone": "(717) 555-1212", "service_address": "123 Main St", "city": "Lancaster", "state": "PA", "zip": "17601", "service_interest": "House Wash", "notes": "Requested from landing page", "external_id": "lead-12345" } ``` Use the upstream lead id as both `external_id` and the `Idempotency-Key` when possible. That gives CE Pro the cleanest replay protection. --- ## Google Ads Connector Setup Google Ads connectors are best created from the dedicated [Google Lead Ads](https://docs.cleanestimate.pro/settings/google-lead-ads) page. That guided page: - generates the Google verification key for you - shows the webhook URL Google needs - saves the optional form id if you want tighter routing - keeps the underlying connector editable here afterward Google test payloads appear in **Recent Imports** so your team can verify delivery, but CE Pro does not create a live lead from Google's built-in sample payload. --- ## Website Form Connector Setup Website form connectors are meant for browser-based form posts. Use them when you want: - a connector-specific public endpoint - connector defaults and source tagging applied automatically - a safer browser path than exposing a private API key The connector detail card shows the public endpoint for that connector. Best practices: - keep the connector in **Draft** until you test the endpoint - submit a sample form through the **Run Test Import** button first - map your website field names before embedding the form live - still include an external id if your frontend or middleware can provide one - CE Pro applies both IP-based throttling and contact-aware throttling on the public endpoint to slow down spam bursts and repeated form abuse --- ## Email Forward Connector Setup Email-forward connectors let CE Pro parse lead information from inbound emails. Use them for: - marketing platform notifications - inbox-forwarded form fills - referral emails - vendor or partner lead emails Forwarded lead notifications that put labels and values on separate lines, like: ```text Name Kathy Kline Email customer@example.com Phone (717) 555-1212 Address 123 Main St Lancaster, Pennsylvania 17601 ``` are now supported directly by the parser. Email connectors add two important controls: - **Parser confidence** scoring - a **Review Queue** for low-confidence imports When an email parse falls below your configured threshold, CE Pro stores the raw message preview and the normalized lead candidate, then waits for someone to approve or reject the import. When a forwarded email does create a lead, CE Pro keeps the connector-specific lead-source label for reporting while storing the client record under a database-safe intake category behind the scenes. That means email-forward imports no longer fail just because the parser source label is more specific than the older client-source whitelist. That protects the pipeline from bad parses like: - partial signatures - reply chains without enough contact detail - forwarded threads with multiple contacts in the same body ### Email Parser Quick Start 1. Open **Settings > Integrations > Lead Connectors**. 2. Create or edit a connector with **Provider = Email Forward** and **Transport = Email Inbound**. 3. Set the connector to **Active**. 4. Pick an **Email review threshold** like `0.65` if you want uncertain parses to pause for review. 5. Confirm the live inbound email address shown at the top of the page. 6. Create a forwarding rule in your mailbox provider that sends lead emails to that address. 7. Watch **Recent Imports** for successful parses and **Review Queue** for low-confidence emails. The forwarding address uses your workspace email reply-to slug, but CE Pro only shows the full mailbox address after inbound email routing is configured for the current environment. When a forwarded email first lands, CE Pro may wait a couple of seconds before parsing it so the full message body is available from the inbound mail provider. That short delay is normal. If the provider fires the webhook before the full message body is ready, CE Pro now keeps polling for longer and asks the provider to retry instead of logging a blank inbound email and silently skipping the lead import. Until that happens, the page still shows your saved slug so you know what mailbox local-part will be used later. When routing is live, the address looks like: ```text your_slug@your-inbound-domain ``` If you need to change the local-part, go to **Settings** and update **Email Reply-To Slug**. --- ## Review Queue The **Review Queue** tab shows email imports waiting for a human decision. For each pending item you can see: - provider - parse confidence - sender - subject - body preview Choose: - **Approve Import** to create the lead through the normal intake pipeline - **Reject** to discard the candidate and keep it out of the pipeline Review actions are single-use. Once an item has been approved or rejected, CE Pro will block additional review actions so the same parsed email cannot be imported twice. Rejected review items stay in the import log as rejected history. --- ## Recent Imports The **Recent Imports** tab is your first stop when a connector is not behaving the way you expect. Use it to confirm: - whether the connector received the payload - whether the payload imported, replayed, failed, or paused for review - which `external_id` was used - which lead record was created Status meanings: - **imported** - a lead was created - **replayed** - CE Pro recognized the lead as a duplicate and reused the earlier record - **review_required** - waiting on human approval - **failed** - the payload was missing required fields or the intake failed - **ignored** - the item was rejected during review --- ## Testing Before Go-Live Each connector card includes **Run Test Import**. Use it before you go live to confirm: - field mapping is correct - notes prefix and source label are right - assignment defaults look right - review-threshold behavior is doing what you expect For API connectors, also run one real end-to-end test from the upstream system with a safe test payload and a stable idempotency key. --- ## Assignment And Territories If a connector has an **Assigned Rep**, that value is used first. If not, CE Pro can still fall back to territory-based assignment when the imported lead includes a usable ZIP code. For territory routing details, see [Territories](https://docs.cleanestimate.pro/settings/territories). --- ## Recommended Rollout Order Most teams should set this up in order: 1. API connector for trusted middleware or no-code automations 2. Meta or Google lead ads if paid lead forms are already live 3. Website form connector for browser forms 4. Email-forward connector for inbox automation That gives you the safest path first, then adds public intake, then adds parser-driven email imports once the team is comfortable reviewing edge cases. --- ## Troubleshooting ### Import shows `failed` Usually this means the connector could not produce the minimum lead payload. Confirm that the incoming payload includes: - a customer name - at least one contact method: email or phone Then review the field alias mapping. ### Import shows `replayed` This means CE Pro matched the incoming payload to a previously imported lead using the external id / idempotent intake path. That is normal for retries. ### Email imports never hit the review queue Check: - the connector is active - the transport is **Email Inbound** - the review threshold is set high enough to catch uncertain parses - at least one active email-forward connector exists, because phase 1 no longer auto-imports parsed emails without a connector - the Lead Connectors page is showing a real forwarding address, not just the saved slug placeholder ### Website form import is missing source or assignee defaults Review the connector defaults. The public endpoint uses the connector configuration, not your website form labels, to set those fallback values. ### The Lead Connectors page says a migration is required That means the app code is live but the workspace database has not applied the April 14 lead-connector migrations yet. The rest of **Settings > Integrations** will keep working, but connector creation and review actions stay disabled until those migrations are applied. --- ## Related Guides - [Meta Lead Ads](https://docs.cleanestimate.pro/settings/meta-lead-ads) - [Google Lead Ads](https://docs.cleanestimate.pro/settings/google-lead-ads) - [Connecting Your Integrations](https://docs.cleanestimate.pro/getting-started/connecting-integrations) - [Webhook Integrations](https://docs.cleanestimate.pro/settings/webhooks) - [Territories](https://docs.cleanestimate.pro/settings/territories) --- URL: https://docs.cleanestimate.pro/settings/brands Title: Managing Brands Description: Run multiple brands under one account for different service lines. Category: settings Difficulty: intermediate Roles: owner Last updated: 2026-03-18 --- # Managing Brands Brands let you operate multiple business identities under one CE Pro account. This is useful when you run different service lines under different names. For example, you might run "Rolling Suds Power Washing" for your exterior cleaning business and "Penn Holiday Lights" for your holiday lighting installations. Go to **Settings -> Brands** to manage your brands. [SCREENSHOT: Brands page showing a list of configured brands with logos, names, and edit buttons] --- ## What a Brand Controls Each brand is a separate identity that appears on customer-facing materials. A brand can have its own: - **Name** - The business name customers see on proposals, estimates, and emails. - **Slug** - A lowercase, hyphenated identifier used to keep the brand record unique. - **Logo URL** - The hosted logo image used on documents and portal pages. - **Colors** - Primary and secondary hex colors used on branded surfaces. - **Contact Information** - The phone number, email, website, and mailing address associated with this brand. - **Stripe Connect account** - An optional connected account id for brand-specific payment routing. When you assign an estimate or proposal to a brand, all customer-facing output uses that brand's identity instead of your default company information. --- ## Create a Brand 1. Go to **Settings -> Brands**. 2. Click the **Add Brand** button. 3. Fill in the brand details: - **Brand Name** - Required. - **Slug** - Required. Use lowercase letters, numbers, and hyphens only. - **Legal Entity Name** - Optional back-office name for contracts or payouts. - **Primary Color** and **Secondary Color** - Use valid hex colors such as `#1a1a1a`. - **Logo URL** - Paste a hosted image URL if this brand needs a separate logo. - **Phone, Email, Website, Address, City, State, ZIP** - Optional contact details for this brand. - **Stripe Account ID** - Optional `acct_...` value if this brand has its own Stripe Connect account. 4. Click **Save**. [SCREENSHOT: Add Brand form with fields for name, slug, color, logo URL, phone, email, and Stripe account] The brand appears in your brand list and is available for assignment. If you leave optional fields blank, CleanEstimate Pro stores them as empty values instead of guessing defaults. Invalid email addresses, ZIP codes, or color values are rejected before the brand saves. --- ## Assign a Brand to an Estimate When creating or editing an estimate, you can assign it to a specific brand. 1. Open the estimate in the editor. 2. Look for the **Brand** dropdown in the estimate settings. 3. Select the brand you want. 4. The estimate preview updates to show the selected brand's logo, name, and colors. [SCREENSHOT: Estimate editor with the Brand dropdown open showing available brands] The customer sees only the selected brand's identity. They do not see your other brands or your default company information. --- ## Assign a Brand to a Module The Brands settings page also includes **Module Brand Assignments**. This lets you pick a default brand for each supported service line: - Residential Power Wash - Commercial - Fleet - Holiday Lights If a module is left on **Organization Default**, CleanEstimate Pro falls back to your workspace branding for that module. --- ## Edit a Brand 1. Go to **Settings -> Brands**. 2. Click the **Edit** button on the brand you want to change. 3. Update any fields. 4. Click **Save**. Changes apply to all future estimates assigned to this brand. Existing sent estimates keep the branding they had when they were sent. Editing one field now leaves every untouched brand field alone. Updating a phone number or logo no longer resets saved colors or other optional brand settings behind the scenes. [SCREENSHOT: Brand edit form with updated fields] --- ## Delete a Brand 1. Go to **Settings -> Brands**. 2. Click the **Delete** button on the brand. 3. Confirm the deletion. Deleting a brand does not delete estimates assigned to it. Those estimates keep their branding. Future estimates can no longer be assigned to the deleted brand. --- ## When to Use Brands Brands work best when you have genuinely separate service lines with different customer bases. Common scenarios: - A power washing company that also does holiday lights under a different name. - A cleaning company with separate residential and commercial identities. - A franchise operator running multiple locations under different names. If you use one name for everything, you do not need brands. Your default company information covers all your output. --- ## Tips - Keep brand logos consistent in size and format. Square logos with transparent backgrounds work best. - Keep slugs stable after launch when possible. Existing links and internal references are easier to follow when the slug stays consistent. - Make sure each brand has accurate contact information. Customers will call the number on their proposal. - Review your brands list when adding a new service line. Set up the brand before creating estimates for that service. --- URL: https://docs.cleanestimate.pro/settings/equipment Title: Managing Equipment Description: Track equipment, maintenance details, and inventory records from the settings workspace. Category: settings Difficulty: intermediate Last updated: 2026-03-18 --- # Managing Equipment Use **Settings -> Equipment** to manage the broader equipment catalog your operation depends on. [SCREENSHOT: Equipment settings page showing tabs for equipment records and inventory controls] ## What Lives Here The Equipment page is for assets beyond the truck assignment list, including: - Surface cleaners - Pressure washers - Reels and hose systems - Ladders and specialty tools - Vehicle records that also need maintenance and inventory tracking ## How It Relates to Trucks Trucks are surfaced separately in **Settings -> Trucks** for faster dispatch setup. Use the Equipment area when you need the fuller asset record, such as: - Maintenance history - Purchase details - Assigned locations - Notes and lifecycle tracking Equipment saves now reject malformed type, status, date, and cost payloads before they hit the database. Maintenance log entries use the same guardrails, so incomplete repair notes or invalid maintenance amounts fail with a readable error instead of storing broken records. ## Operations Use Keeping equipment records current helps your team: - See what assets are available - Track where equipment is stored - Keep maintenance records organized - Avoid booking jobs without the right gear available ## Related Guides - Learn more about [Inventory](https://docs.cleanestimate.pro/operations/inventory). - Learn how [Locations](https://docs.cleanestimate.pro/operations/locations) help organize equipment across shops and yards. --- URL: https://docs.cleanestimate.pro/settings/subcontractors Title: Managing Subcontractors Description: Add subcontractors, assign them to jobs, and track their work and payments. Category: settings Difficulty: intermediate Last updated: 2026-03-18 --- # Managing Subcontractors CE Pro lets you maintain a roster of subcontractors and assign them to jobs. This is useful when you bring in outside help for installations, overflow work, or specialized services. Go to **Settings --> Subcontractors** to manage your subcontractor list. [SCREENSHOT: Subcontractors page showing a table of subcontractors with name, phone, email, specialty, and status columns] --- ## When to Use Subcontractors Subcontractors are external workers or companies that you hire on a per-job basis. Common scenarios include: - **Overflow work** -- You have more jobs scheduled than your in-house crew can handle. - **Specialized services** -- A job requires skills or equipment your team does not have, such as electrical work for holiday lights or high-rise window cleaning. - **Seasonal scaling** -- During peak seasons, you bring in additional crews to handle increased demand. - **Geographic coverage** -- You subcontract work in areas outside your primary service territory. Subcontractors are tracked separately from team members. They do not have login access to CE Pro and do not appear in team management or permission settings. --- ## Adding a Subcontractor 1. Go to **Settings --> Subcontractors**. 2. Click the **Add Subcontractor** button. 3. Fill in the subcontractor details: - **Name** -- The subcontractor's full name or company name. - **Phone** -- Their primary phone number. - **Email** -- Their email address. - **Specialty** -- The type of work they perform (for example, "Holiday Light Installation", "Pressure Washing", "Electrical"). - **Notes** -- Any additional information, such as certifications, insurance details, or scheduling preferences. 4. Click **Save**. [SCREENSHOT: Add Subcontractor form with fields for name, phone, email, specialty, and notes] The subcontractor appears in your list and is immediately available for job assignment. CE Pro now validates these saves before the record is written. Company name and contact name are required, email fields must be valid when provided, and rates or insurance dates must parse cleanly instead of saving half-valid data. --- ## Editing a Subcontractor 1. Go to **Settings --> Subcontractors**. 2. Click the **Edit** button on the subcontractor you want to update. 3. Modify any fields. 4. Click **Save**. Changes take effect immediately. Existing job assignments are not affected by edits to the subcontractor record. --- ## Removing a Subcontractor 1. Go to **Settings --> Subcontractors**. 2. Click the **Delete** button on the subcontractor. 3. Confirm the deletion. Removing a subcontractor does not delete their historical job assignments. Past jobs retain the subcontractor's name and details for reporting purposes. The subcontractor is simply removed from the list of available assignees for future jobs. --- ## Assigning Subcontractors to Jobs Once a subcontractor is in your roster, you can assign them to any scheduled job. ### From the Schedule Page 1. Go to **Schedule** in the sidebar. 2. Click on a job to open the job detail sheet. 3. In the **Crew Assignment** section, click **Assign**. 4. Select the subcontractor from the list. Subcontractors appear in a separate section from your in-house team members. 5. Confirm the assignment. [SCREENSHOT: Job detail sheet with the Crew Assignment section showing a subcontractor being selected from the assignment dropdown] ### From the Job Detail Page 1. Go to **Jobs** in the sidebar. 2. Click on a job to view its details. 3. Scroll to the **Assigned Crew** section. 4. Click **Add Crew Member**. 5. Select the subcontractor. 6. Save the change. ### Multiple Assignments You can assign multiple subcontractors to a single job, or mix in-house crew members with subcontractors on the same job. Each person assigned to the job appears in the crew list. --- ## Tracking Subcontractor Work CE Pro tracks subcontractor activity alongside your regular crew work. ### Job History Each subcontractor's work history is visible on the Subcontractors page. Click on a subcontractor's name to see: - **Jobs Assigned** -- A list of all jobs the subcontractor has been assigned to. - **Jobs Completed** -- The number of jobs marked as complete. - **Date Range** -- The date of their first and most recent assignment. [SCREENSHOT: Subcontractor detail view showing job history with job IDs, client names, dates, and completion status] ### On the Schedule Subcontractor assignments are visible on the daily and weekly schedule views. They appear with a distinct indicator so you can quickly distinguish between in-house crew and subcontractors. ### Job Completion When a subcontractor completes a job, mark it as complete the same way you would for any crew: 1. Open the job from the Schedule or Jobs page. 2. Click **Mark Complete**. 3. The job status updates and any follow-up automations (review requests, invoicing) trigger as normal. --- ## Payment Tracking CE Pro helps you track what you owe subcontractors, though actual payments are processed outside the system. ### Recording Subcontractor Pay When a job is completed with a subcontractor assigned, you can record the payment amount: 1. Open the completed job. 2. In the **Subcontractor Pay** section (visible only when a subcontractor is selected for the job), enter the amount agreed upon for this job. 3. Set the payment status: - **Unpaid** -- The subcontractor has not been paid yet. - **Paid** -- Payment has been issued. 4. Save the record. [SCREENSHOT: Subcontractor Pay section on a completed job showing amount field and payment status toggle] ### Payment Summary View a summary of all subcontractor payments from the Subcontractors page: 1. Go to **Settings --> Subcontractors**. 2. Click on a subcontractor's name. 3. The **Payment Summary** section shows: - **Total Owed** -- Sum of all unpaid job amounts. - **Total Paid** -- Sum of all paid job amounts. - **Jobs Pending Payment** -- Number of completed jobs with unpaid status. [SCREENSHOT: Subcontractor payment summary showing total owed, total paid, and pending payment count] ### Filtering by Payment Status Use the filters on the Subcontractors page to quickly find outstanding payments: 1. Click the **Status** filter dropdown. 2. Select **Unpaid** to see all subcontractors with outstanding balances. 3. Click on a subcontractor to see which specific jobs need payment. --- ## Subcontractors vs. Team Members Understanding the difference helps you choose the right approach: | | Team Members | Subcontractors | |---|---|---| | CE Pro login access | Yes | No | | Appear in team management | Yes | No | | Role and permissions | Configurable | Not applicable | | Commission tracking | Yes | No | | Payment tracking | Via Crew Pay | Via Subcontractor Pay | | Schedule visibility | Full | Job-level only | | Notifications | Email and SMS | None from CE Pro | If a subcontractor needs to log in to CE Pro, view their schedule, or access client information, add them as a team member with a restricted role instead. --- ## Tips - Keep subcontractor records up to date. Verify phone numbers and email addresses regularly, especially before peak season. - Use the specialty field consistently. This makes it easy to find the right subcontractor when assigning specialized jobs. - Add notes about insurance coverage, license numbers, and expiration dates. Review these before assigning work that requires current credentials. - Record subcontractor pay promptly after job completion. A backlog of untracked payments makes reconciliation difficult at month-end. - Use the payment status filter weekly to identify outstanding subcontractor payments and avoid delays. - If you work with the same subcontractors regularly, consider adding them as restricted team members so they can view their own schedule and job details. --- URL: https://docs.cleanestimate.pro/settings/trucks Title: Managing Trucks Description: Add trucks and service vehicles, track availability, and use them in dispatch. Category: settings Difficulty: beginner Last updated: 2026-03-10 --- # Managing Trucks Use **Settings -> Trucks** to manage the trucks and service vehicles your crews run each day. If your workspace already used **Operations -> Vehicles** before the truck dispatch tools were added, those legacy vehicle records still show up in dispatch selectors. CleanEstimate Pro will translate them into dispatch truck records automatically when you assign them to a job. [SCREENSHOT: Trucks settings page showing a list of trucks with status badges and edit actions] ## What This Page Controls The Trucks page is where you: - Add new trucks and service vehicles - Update truck names, plates, and status - Mark a truck as available, in use, or in maintenance - Keep dispatch options current for the schedule and job detail pages ## Dispatch Workflow CleanEstimate Pro uses a truck-first dispatch flow when equipment matters: 1. Assign the truck to the job. 2. Assign the crew running that truck. 3. Save the job. The truck you add here becomes available in: - **Schedule and Dispatch** - **Job Detail** - **Create Job** ## Typical Setup Create one record for each dispatchable vehicle, such as: - Wash rigs - Box trucks - Holiday lights install trucks - Service vans with dedicated equipment packages If a vehicle should not appear for dispatch, set its status so it is no longer active for scheduling. ## Related Guides - Learn how [Schedule and Dispatch](https://docs.cleanestimate.pro/operations/schedule) groups work by truck. - Learn how [Managing Jobs](https://docs.cleanestimate.pro/operations/jobs) uses truck assignment on each job. --- URL: https://docs.cleanestimate.pro/settings/meta-lead-ads Title: Meta Lead Ads Description: Connect Facebook and Instagram lead ads through the guided Meta connect flow. Category: settings Difficulty: beginner Roles: owner, manager Last updated: 2026-04-15 --- # Meta Lead Ads Use **Settings > Integrations > Meta Lead Ads** when you want Facebook and Instagram lead forms to create leads inside Clean Estimate Pro. This is now the fast setup path. The default flow is: 1. click **Connect Meta** 2. sign into Meta 3. choose the page 4. start receiving leads You do not need to paste the Meta Page ID or copy webhook values around on the common path anymore. Clean Estimate manages the shared Meta developer app, shared webhook, and shared page-subscription logic centrally. Workspace users should only need to click **Connect Meta**, approve Meta, and choose the page. --- ## What This Page Does The guided Meta page now: - starts the Meta login flow for you - lets you choose which Meta page should send leads into this workspace - subscribes that page to the shared `leadgen` webhook automatically - creates or updates the underlying Meta connector for duplicate-safe lead intake That means Meta lead ads still use the same shared pipeline as other CE Pro imports: - duplicate suppression by `leadgen_id` - import-run logging - consistent lead creation - optional advanced mapping later in **Lead Connectors** --- ## Before You Start Make sure you have: - access to the Meta page that owns the lead form - permission to manage that page in Meta - at least one Facebook or Instagram lead form already attached to the page If the page is available to your Meta login, CE Pro can do the rest from the guided flow. ### One-Time Platform Note The Meta developer app, webhook, and Meta app-review steps are handled once at the platform level, not by each workspace. Your team should not need to: - open Meta for Developers - paste webhook URLs or verify tokens - manage the shared app id or secret If Meta ever blocks the shared app because it is still in app review or not yet switched to **Live**, that is a platform-admin task, not a workspace setup step. --- ## Quick Setup 1. Open **Settings > Integrations**. 2. Open **Meta Lead Ads**. 3. Click **Connect Meta**. 4. Approve the Meta login prompt. 5. If Meta returns more than one page, click **Use This Page** on the one you want. 6. Wait for the success state on the CE Pro page. 7. Submit one real Meta lead form. That is the normal setup. If you only have one eligible page, CE Pro can finish the connection automatically right after the Meta login. --- ## Optional Settings After the page is connected, you can still adjust: - **Lead Source Label** - **Optional Form ID** ### Lead Source Label Leave this as `meta` unless your team wants a more specific source label for reporting. ### Optional Form ID Leave this blank if every lead form on the connected page should import. Only save a Form ID when: - the page has multiple lead forms - and you only want one of them to create leads in CE Pro If you need deeper control later, open [Lead Connectors](https://docs.cleanestimate.pro/settings/lead-connectors). --- ## What Happens Behind The Scenes When the connection finishes, CE Pro: - stores the connected Meta page on the workspace integration record - stores the page token needed to retrieve lead details from Meta - creates or updates the native Meta lead connector - keeps the connector mapped to the selected page This is why the simple Meta page can stay easy while the shared connector pipeline still does the real lead-intake work. --- ## Testing The best test is one real lead-form submission from the connected Meta page. After the test: - the lead should appear in CE Pro - **Lead Connectors > Recent Imports** should show the Meta import run - the created lead should use the `meta` source label, or your custom source label if you changed it --- ## Legacy Setup If your workspace already had the older Meta connector saved by Page ID, the Meta screen will show that as a legacy setup. You can keep it temporarily, but the recommended path is: 1. click **Reconnect Meta** 2. approve the Meta login 3. choose the page through the guided flow That moves the workspace onto the simpler connection model. --- ## Troubleshooting ### The card says `Needs Env` That means the shared server-side Meta app is missing one or more required env vars. Your workspace cannot use the one-click Meta connect flow until those are present. ### Meta login worked, but I do not see my page Check: - the Meta login you used actually has access to that page - the page is the one that owns the lead form - the Meta permissions prompt was fully approved If needed, disconnect and run **Connect Meta** again. ### Meta says the page is already connected That page is already linked to another Clean Estimate workspace. Disconnect it in the other workspace first, then run **Connect Meta** again here. ### Meta login opens, but Meta says the app is still in review That means the shared Clean Estimate Meta app is still waiting on Meta's platform-level review or Live-mode activation. Your workspace setup is still the simple path, but a Clean Estimate admin must finish that one-time Meta approval before ordinary workspace users can connect pages. ### I connected the wrong page Click **Reconnect Meta** and choose the correct page. ### I only want one form on the page to import Save the **Form ID** in the optional settings area after the page is connected. ### I need custom field mapping or deeper defaults Use the [Lead Connectors guide](https://docs.cleanestimate.pro/settings/lead-connectors) and open the advanced connector settings from the Meta page. --- ## Related Guides - [Connecting Your Integrations](https://docs.cleanestimate.pro/getting-started/connecting-integrations) - [Lead Connectors](https://docs.cleanestimate.pro/settings/lead-connectors) --- URL: https://docs.cleanestimate.pro/settings/onboarding Title: Onboarding Checklist Description: Complete the getting started checklist to set up your CE Pro account and hit the ground running. Category: settings Difficulty: intermediate Last updated: 2026-04-24 --- # Onboarding Checklist When you first create your CE Pro account, the onboarding checklist guides you through the essential setup steps. It appears as a panel on your dashboard and tracks your progress until every step is complete. Go to **Dashboard** to see the checklist, or access it from the **Onboarding** link if you are still in the initial setup flow. New self-serve owners can now create a workspace directly from `/signup`. The signup flow creates the owner account, organization, owner membership, starter service and pricing data, and a 44-day trial before sending the owner to `/onboarding`. If your organization was provisioned through the early-access waitlist, the account owner receives an invite email first. After accepting the invite and setting a password, you land in the same onboarding flow described here. If that setup link has expired or was already used, CleanEstimate Pro now routes you back into the password-setup recovery path instead of sending you to the public waitlist. From there, use **Forgot password** with the same invited email to request the right workspace-specific access email again. If you click **Forgot password** with that same invited email before first-time setup is complete, CleanEstimate Pro now sends another workspace-specific setup link automatically instead of a generic password-reset email that drops the workspace activation context. Fresh setup and password-recovery emails now pass through a short **Finishing Sign-In** handoff screen before they open the reset-password form. That handoff is expected. It fixes the earlier production issue where a valid invite or recovery email could still land on an expired-link message because the old server callback could not consume the auth fragment returned by Supabase. If that page still says the access link has expired, the same card now includes a direct resend action. You can trigger a fresh setup email without leaving the password screen or re-entering the invited email address manually. If the handoff page itself needs a retry, its **Need A New Link?** action now preserves the original workspace redirect too. That keeps multi-workspace users pointed at the invited org instead of dropping them into a generic reset path. If a newly provisioned workspace is missing starter setup data temporarily, the onboarding flow now repairs the standard defaults automatically before you continue. That means the **Services** step should still load the starter service catalog and the **Pricing** step should still load starter pricing fields instead of appearing blank. If the unfinished workspace was provisioned for a team member with the **manager** role, that manager can now complete the first-run onboarding flow too. Company Info, Services, Pricing, and the final completion step no longer require the owner role during the initial unfinished-workspace setup window. The final **Go to Dashboard** action now treats the workspace completion save and the dashboard load as separate moments. If the setup save succeeds but the dashboard takes longer than expected to render, the page shows an **Open Dashboard** fallback link instead of leaving the finishing button disabled. [SCREENSHOT: Onboarding checklist panel on the dashboard showing completed and incomplete steps with progress bar] --- ## How the Checklist Works The onboarding checklist is a step-by-step guide that walks you through configuring the core parts of your account. Each step represents a critical setup task. As you complete each one, a checkmark appears next to it and the progress bar advances. The checklist is persistent -- it stays visible on your dashboard until you either complete all steps or manually dismiss it. Your progress is saved automatically, so you can leave and return at any time without losing your place. The full-page onboarding flow now uses the standard CleanEstimate logo header instead of a plain text wordmark, so the first-run setup screen matches the rest of the product branding more closely. --- ## Checklist Steps The onboarding checklist includes the following steps. You can complete them in any order, though the listed order is recommended. ### 1. Company Information Fill in your business details, including your company name, phone number, email, website, and mailing address. This information appears on all customer-facing documents. **How to complete:** 1. Click the **Company Information** step in the checklist. 2. You are taken to the Settings page. 3. Fill in all fields in the Company Information card. 4. Click **Save Changes**. 5. Return to the dashboard. The step is marked as complete. See the [Account Settings](https://docs.cleanestimate.pro/docs/settings/account) article for details on each field. ### 2. Set Up Pricing Configure your service pricing, including base rates, add-ons, and pricing tiers. This determines how estimates are calculated. **How to complete:** 1. Click the **Set Up Pricing** step. 2. You are taken to the Pricing configuration page. 3. Enter your base rates for each service type. 4. Configure add-on pricing. 5. Save your pricing configuration. 6. The step is marked as complete when at least one service has pricing configured. See the [Setting Up Pricing](https://docs.cleanestimate.pro/docs/getting-started/setting-up-pricing) article for a detailed walkthrough. During first-time onboarding, the quick pricing step saves through the same versioned pricing path used by the main Pricing Manager. If you update starter values here, the workspace keeps a valid active pricing version instead of relying on a one-off temporary setup record. ### 3. Connect Stripe Link your Stripe account to accept online payments, send invoices, and enable the customer portal's payment feature. **How to complete:** 1. Click the **Connect Stripe** step. 2. You are taken to the Stripe integration page. 3. Click **Connect with Stripe**. 4. Follow the Stripe OAuth flow to authorize CE Pro. 5. Once connected, the step is marked as complete. See the [Stripe Settings](https://docs.cleanestimate.pro/docs/settings/stripe) article for details. ### 4. Configure Phone / Voice (Optional) Configure Esendex or Twilio to send and receive SMS messages through CE Pro. This step is optional but recommended if you plan to use text messaging, customer replies, call routing, or phone automations. **How to complete:** 1. Click the **Configure Phone / Voice** step. 2. Choose **Esendex** or **Twilio** in the **Telecom Provider** selector. 3. Save the workspace phone number and required provider credentials. 4. Save the configuration. 5. The step is marked as complete. See [Connecting Esendex](https://docs.cleanestimate.pro/docs/settings/esendex) or [Connecting Twilio](https://docs.cleanestimate.pro/docs/settings/twilio) for details. ### 5. Invite Your Team Add team members so they can log in and start creating estimates, managing leads, and handling jobs. **How to complete:** 1. Click the **Invite Your Team** step. 2. You are taken to the Team Management page. 3. Click **Invite Member**. 4. Enter the team member's email and assign a role. 5. Click **Send Invite**. 6. The step is marked as complete when at least one team member has been invited. See the [Team Management](https://docs.cleanestimate.pro/docs/settings/team-management) article for details on roles and permissions. ### 6. Create Your First Estimate Create a test estimate to familiarize yourself with the estimator workflow. **How to complete:** 1. Click the **Create Your First Estimate** step. 2. You are taken to the new estimate form. 3. Fill in a client name, select services, and complete the estimate. 4. Save or send the estimate. 5. The step is marked as complete. See the [Your First Estimate](https://docs.cleanestimate.pro/docs/getting-started/your-first-estimate) article for a step-by-step guide. ### 7. Customize Your Portal Configure the customer portal with your branding and select which features to make available to customers. **How to complete:** 1. Click the **Customize Your Portal** step. 2. You are taken to the Portal Settings page. 3. Select your branding. 4. Toggle the features you want to enable. 5. The step is marked as complete when you visit the page and have at least one feature enabled. See the [Customer Portal Settings](https://docs.cleanestimate.pro/docs/settings/portal-settings) article for details. --- ## Progress Tracking The checklist includes a progress bar at the top showing how many steps you have completed out of the total. The bar fills incrementally as you complete each step. [SCREENSHOT: Onboarding progress bar showing 4 of 7 steps completed] ### Step States Each step shows one of three states: - **Incomplete** -- The step has not been started or finished. Shown with an empty circle. - **Complete** -- The step has been finished. Shown with a filled checkmark. - **Skipped** -- Optional steps (like Phone / Voice) that you chose to skip. Shown with a dash. --- ## Dismissing the Checklist If you want to remove the checklist from your dashboard before completing all steps: 1. Click the **Dismiss** button at the bottom of the checklist panel. 2. Confirm the dismissal. The checklist disappears from your dashboard. Your progress is preserved, and you can bring it back at any time. > **Note:** Dismissing the checklist does not complete any unfinished steps. Your account functions normally without completing every step, but some features may not work correctly until their setup is done. For example, you cannot send SMS messages without configuring a telecom provider. --- ## Re-Enabling the Checklist If you dismissed the checklist and want to see it again: 1. Go to **Settings**. 2. Scroll to the **Onboarding** section. 3. Click **Show Onboarding Checklist**. 4. The checklist reappears on your dashboard with your previous progress intact. [SCREENSHOT: Settings page showing the Show Onboarding Checklist button in the Onboarding section] Alternatively, you can access the full onboarding page directly by navigating to: ``` app.cleanestimate.pro/onboarding ``` This page shows the same checklist in a full-page layout, which can be easier to work through than the dashboard panel. --- ## Completing the Checklist When all steps are marked as complete, the checklist panel displays a success message and automatically hides after a few seconds. A congratulations notification appears confirming that your account is fully set up. You can still access any of the configured settings pages at any time through the sidebar navigation. --- ## Tips - Complete the checklist in the recommended order. Later steps (like creating your first estimate) work better when earlier steps (like pricing setup) are done first. - You do not have to finish everything in one session. The checklist saves your progress automatically. - Optional steps can be skipped and completed later. Do not let them block your launch. - If you are setting up the account for someone else, complete the technical steps (Stripe, Phone / Voice) and let them handle the business steps (pricing, first estimate). - Use the onboarding page at `/onboarding` for a distraction-free setup experience. --- URL: https://docs.cleanestimate.pro/settings/permissions Title: Roles and Permissions Description: Control what each team member can see and do with role-based access. Category: settings Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Roles and Permissions CE Pro uses role-based access control to determine what each team member can see and do. There are five built-in roles. Each role has a default set of permissions that you can customize. Go to **Team --> Permissions** to manage access. Permissions are enforced in the admin APIs too, not only in the visible UI. If a role does not include a permission like `messages.send`, `automations.manage`, `holiday_lights.manage`, or `estimates.manage`, CE Pro now returns `403` even if someone tries to hit the route directly from the browser or a copied API request. Some record-detail actions also keep role- and ownership-based rules on top of the broad permission system. For example, sales reps can still delete only their own assigned leads and estimates, while client and job deletes stay limited to owner and manager roles even if someone can open the detail page. The franchise beta adds two more admin permissions: - `franchise.view` - `franchise.manage` These control access to the franchise hierarchy APIs, the sidebar franchise workspace, and the new org-switching workflow. By default, Owners and Managers receive both permissions. When `franchise.view` is present and the active org is a parent-capable workspace on a franchise-eligible plan, the user can open **Admin --> Franchise** and the dedicated **Settings --> Franchise** area. When `franchise.manage` is also present, that same admin can create child workspaces, edit child-workspace metadata, deactivate child workspaces, and send child-org invites. [SCREENSHOT: Permissions page showing the role list on the left and permission groups on the right] --- ## The Five Roles ### Owner (Purple Badge) Full access to everything. Owners can manage billing, delete the organization, and control all settings. Every account needs at least one Owner. ### Manager (Blue Badge) Access to everything except billing management and organization deletion. Managers can invite team members, configure pricing, manage clients, and view all reports. ### Sales Rep (Green Badge) Can create and manage estimates, view clients, work the sales pipeline, and send messages. Sales reps can delete only leads assigned to them and estimates assigned to them. Cannot delete clients or jobs, and cannot access organization settings or team management. ### Crew Lead (Orange Badge) Can view the job schedule, update job statuses, and see details for assigned jobs. Cannot create estimates, delete records, or access settings. ### Technician (Yellow Badge) The most limited role. Can view today's schedule and update job status for assigned jobs. Cannot delete records or access anything else. --- ## Permission Groups Permissions are organized into groups. Each group controls access to a section of the app. ### Dashboard and Analytics - View the main dashboard - View revenue analytics - View service mix analytics - View geography analytics - View sales cycle analytics - Export analytics data **Default access:** Owner, Manager. ### Jobs and Schedule - View the schedule - Create and edit jobs - Assign crews to jobs - Update job status - View route optimization - Delete jobs from the job detail page (owner and manager only) **Default access:** Owner and Manager have both **Schedule view** and **Schedule manage**. Sales Reps, Crew Leads, and Technicians start with **Schedule view** only unless an Owner customizes the role. ### Estimates and Clients - Create estimates - Edit estimates - Send estimates - Delete estimates - View client list - Edit client records - View pipeline **Default access:** Owners and managers can delete any client, lead, or estimate in their org. Sales reps can delete only leads and estimates assigned to them. Crew leads and technicians cannot delete records. Proposal reassignment and rep handoff actions also follow the **Estimates manage** permission now. A teammate who can only view estimates can still open the record, but they cannot reassign ownership or push a handoff through the API. ### Communications - Send SMS messages - Send emails - View message threads - Access the messaging inbox - Trigger manual review requests **Default access:** Owner, Manager, Sales Rep. ### Services These permissions cover specialized service modules: - **Holiday Lights** — Create and manage holiday lighting proposals, inventory, and designs. - **Fleet** — Create and manage fleet wrap proposals and vehicle inventory. - **Commercial** — Create and manage commercial building proposals and the commercial pipeline. **Default access:** Owner, Manager, Sales Rep (create and manage). Crew Lead (view assigned jobs only). ### Administration These permissions cover system-level settings: - **Automations** -- View workflow analytics and run history, or create, edit, activate, pause, test, and manually enroll contacts in workflows. - **AI** -- Access AI-powered tools such as lead scoring, pricing analysis, and supported estimator helpers. - **Operations** — Manage inventory, locations, equipment, and quality checklists. - **Pricing** — View and edit service pricing configuration. - **Team** — Invite and remove team members, change roles. - **Marketing** — Create and manage marketing campaigns and promotions. - **Billing** — View and manage the subscription, payment methods, and invoices. - **Settings** — Edit company information, integrations, portal settings, and brands. **Default access:** Owner has full access. Manager has access to everything except Billing and organization deletion. All other roles have no access. [SCREENSHOT: Permission groups expanded showing checkboxes for each permission within the Administration group] --- ## How to Customize Permissions 1. Go to **Team --> Permissions**. 2. Select a role from the list on the left. 3. The permission groups for that role appear on the right. 4. Check or uncheck individual permissions within each group. 5. Changes save automatically. [SCREENSHOT: Permissions page with the Sales Rep role selected and the Estimates and Clients group expanded with checkboxes visible] > **Warning:** Only Owners can modify permissions. Managers can view the Permissions page but cannot make changes. > > Permission saves now reject malformed payloads before anything is written. In practice, that means CE Pro accepts only the built-in editable roles and known permission keys, instead of silently storing broken custom payloads. --- ## Default Permission Summary | Feature Area | Owner | Manager | Sales Rep | Crew Lead | Technician | |---|---|---|---|---|---| | Dashboard | Full | Full | Limited | No | No | | Analytics | Full | Full | No | No | No | | Estimates | Full | Full | Full | No | No | | Clients | Full | Full | Full | No | No | | Pipeline | Full | Full | Full | No | No | | Schedule | Full | Full | View | View | View | | Jobs | Full | Full | View | Assigned | Assigned | | Messages | Full | Full | Full | No | No | | Holiday Lights | Full | Full | Full | Assigned | No | | Fleet | Full | Full | Full | Assigned | No | | Commercial | Full | Full | Full | Assigned | No | | Operations | Full | Full | No | No | No | | Pricing | Full | Full | No | No | No | | Team | Full | Full | No | No | No | | Marketing | Full | Full | No | No | No | | Billing | Full | No | No | No | No | | Settings | Full | Full | No | No | No | --- ## Tips - Start with the default permissions. Customize only when a team member needs more or less access than their role provides. - Use Sales Rep for field estimators. They can do everything customer-facing without touching system settings. - Grant **Automations view** to teammates who only need analytics and run history. Grant **Automations manage** only to people who should build workflows, cancel runs, or manually enroll contacts. - Remember that delete actions are narrower than simple page access. A role might be allowed to open a lead, estimate, client, or job detail page and still be blocked from deleting that record if the built-in ownership or manager-only rule does not allow it. - The holiday lights **Measure with AI** action follows permissions too. A signed-in user needs Holiday Lights manage, Estimates create, or AI access before the estimator can call the measurement service. - Crew Lead and Technician are designed for people who work in the field and usually only need schedule visibility. Grant **Schedule manage** only if they should create jobs, reorder dispatch, or update schedule data directly. - Review permissions quarterly. As your team grows, make sure access levels still match job responsibilities. --- URL: https://docs.cleanestimate.pro/settings/territories Title: Sales Territories Description: Define geographic territories and assign team members to specific service areas. Category: settings Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Sales Territories Territories let you divide your service area into geographic zones and assign reps to each zone. When a new lead comes in, CE Pro checks the address and routes it to the rep who covers that area. Go to **Team --> Territories** to set up your zones. [SCREENSHOT: Territories page showing a list of defined territories with assigned reps and area descriptions] --- ## Why Use Territories - **Faster response times.** Leads go directly to the rep closest to the job site. - **Clear ownership.** Each rep knows exactly which area they cover. No overlap, no confusion. - **Better analytics.** See revenue and close rates broken down by territory in the Geography analytics view. --- ## Create a Territory 1. Go to **Team --> Territories**. 2. Click the **Add Territory** button. 3. Fill in the territory details: - **Name** -- A descriptive name for the zone (e.g., "North Metro" or "Downtown"). - **ZIP Codes** -- Enter one or more 5-digit ZIP codes separated by commas or spaces. 4. Click **Save**. [SCREENSHOT: Add Territory form with fields for name and geographic area definition] The territory appears in the list. It has no rep assigned yet. If a ZIP code is malformed, CE Pro blocks the save before the territory is written. This keeps routing rules clean and avoids half-saved territory records. --- ## Assign a Rep to a Territory 1. Find the territory in the list. 2. Click the **Assign Rep** button or the rep dropdown. 3. Select a team member from the dropdown. Only users with the Sales Rep, Manager, or Owner role appear in the list. 4. The assignment saves automatically. [SCREENSHOT: Territory row with the rep dropdown open showing available team members] A single rep can cover multiple territories. A territory can only have one primary rep assigned. --- ## How Lead Routing Works When a new lead enters CE Pro -- through the customer portal, an integration, or manual entry -- the system checks the lead's address against your defined territories. 1. The address is matched to a territory based on ZIP code. 2. The rep assigned to that territory receives the lead. 3. If no territory matches, the lead goes to the default queue for manual assignment. > **Tip:** Make sure your territories cover your entire service area. Gaps mean leads fall into the unassigned queue and may get delayed. --- ## Edit or Delete a Territory - **Edit:** Click the territory name to open it. Change the name, ZIP coverage, or assigned rep. Click **Save**. - **Delete:** Click the **Delete** button on the territory row. Confirm the deletion. Existing leads assigned through this territory keep their current rep. Future leads for that area go to the unassigned queue. [SCREENSHOT: Territory edit view with updated geographic area fields] --- ## Tips - Name territories after recognizable areas your team already uses. "South Side" is better than "Territory 3." - Review territory assignments when you hire or lose a rep. Uncovered territories mean missed leads. - Use the [Geography analytics](https://docs.cleanestimate.pro/docs/analytics/geography) view to compare performance across territories and spot imbalances. --- URL: https://docs.cleanestimate.pro/settings/schedule-dispatch Title: Schedule & Dispatch Settings Description: Set the shop location, truck capacity, crew pay overlay, and dispatch defaults used by the schedule board. Category: settings Difficulty: intermediate Roles: owner, manager Last updated: 2026-03-18 --- # Schedule & Dispatch Settings Open **Admin > Settings > Schedule & Dispatch** to control the defaults used by the dispatch board. The settings surface now sits inside the refreshed blue/slate admin workspace and uses the same card styling as the rest of `/admin`, but the underlying controls and dispatch behavior are unchanged. [SCREENSHOT: Settings page showing the Schedule & Dispatch card with shop address, capacity, and toggle controls] ## Shop / Yard Address Set the address your routes should start from. If you also enter latitude and longitude, the route map can anchor the shop marker more accurately. Use this for: - The start point on the route map - Google route timing and map fitting on the day board - Distance heuristics when ordering stops before a saved route exists - Keeping routes centered around the right yard or office CE Pro now validates these values before saving. Invalid latitude or longitude values are rejected instead of silently saving bad route origins. ## Truck Capacity **Truck Capacity (Hours)** defines how many scheduled hours CE Pro treats as a full day for one truck. The daily and weekly boards use this number to show: - Capacity bars - Near-capacity warnings - Best-fit suggestions for unassigned jobs Dispatch settings also validate truck capacity more strictly now. Capacity must be a real number between 1 and 24 hours. ## Crew Pay on Schedule Turn on **Crew pay on schedule** if you want the schedule board to show the revenue-to-pay breakdown directly on truck routes and weekly planning cells. When enabled, CE Pro shows: - Crew pay total - Lead share - Technician share - Solo-day payout behavior ## Auto-Optimize on Assign Turn on **Auto-optimize on assign** if you want CE Pro to rebuild the route order when a job is dropped onto a truck. Leave it off if your dispatcher prefers to place jobs first and optimize later by hand. When the live map is available, CE Pro also saves stop order, drive minutes, drive miles, and arrival timing back into dispatch records after optimization so the next load uses the same route timing. If your workspace is still missing the newer dispatch columns, saving this card now returns a direct migration/setup message instead of a raw database error. ## Related Guides - Learn the daily workflow in [Schedule and Dispatch](https://docs.cleanestimate.pro/operations/schedule). - Learn how the truck list feeds dispatch in [Managing Trucks](https://docs.cleanestimate.pro/settings/trucks). --- URL: https://docs.cleanestimate.pro/settings/leaderboard Title: Team Leaderboard Description: Rank the team by XP, level progression, streaks, and role-based momentum. Category: settings Difficulty: beginner Roles: owner, manager Last updated: 2026-03-30 --- # Team Leaderboard The Leaderboard ranks your team members by XP and momentum. Use it to see who is leveling up, carrying streaks, and driving the behaviors your workspace wants to reward. Go to **Team --> Leaderboard** to view rankings. The admin workspace now also shows a clickable **XP progress card in the left sidebar**, between the workspace section and **Quick Start**. Click it from anywhere in admin to jump straight into the leaderboard and personal XP view. If the workspace is still initializing gamification data in the background, the rest of admin stays usable and the XP card simply waits until that data is ready instead of blocking the page. [SCREENSHOT: Leaderboard page showing period filters, track filters, personal stats, the achievement catalog, and team rankings by XP] --- ## What the Leaderboard Shows The production leaderboard is tied to the workspace gamification system. Each row represents a team member and currently shows: - **Rank**: The member's current position for the selected view - **XP**: Period XP or all-time XP, depending on the filter - **Level**: The user's current level - **Title**: The current title from the selected role track title set - **Key Metric**: A supporting metric for that track, such as closed revenue or another primary behavior signal - **Streak**: Consecutive active workdays with qualifying activity - **Trend**: Whether the member is moving up, down, or staying flat The page also shows a personal summary card with: - Current level - Title - Progress to next level - Period XP - Current streak - Current rank - Spendable XP if rewards are enabled - Achievement counts for unlocked badges and remaining unlockable badges Below the summary card, the page now shows a full **Achievement Catalog** for the signed-in user: - **Unlocked**: Every achievement already earned by that profile - **Available To Unlock**: The remaining achievements for that user's role track plus universal achievements - **Criteria and XP reward**: Each achievement card shows the unlock criteria summary and XP value When new XP is earned, CleanEstimate Pro now raises an in-app XP notification and a short sound cue so the user sees the progress immediately. If browser notification permission is already allowed and the tab is in the background, the XP event can also raise a desktop notification. [SCREENSHOT: Personal stats card showing level, title, progress bar, period XP, streak, rank, spendable XP, and achievement counts] --- ## Filters Use the controls at the top of the page to switch both **time period** and **role track**. ### Time Period - **This Week**: Monday through today - **This Month**: The current calendar month - **This Quarter**: The current calendar quarter - **All Time**: Total XP across the full lifetime of the user profile ### Track Filter - **All** - **Sales** - **Crew** - **Office** The leaderboard updates immediately when you change either filter. [SCREENSHOT: Leaderboard header showing period chips and track chips] --- ## How Rankings Work Now The leaderboard does not use manual column sorting in the current production version. Instead, ranking is based on XP for the selected view. - If the period is **All Time**, rankings reflect total XP - If the period is **Week**, **Month**, or **Quarter**, rankings reflect XP earned during that period - Users without recorded XP for the selected view do not appear in the rankings list If gamification is disabled for the workspace, the page shows a message with a shortcut to **Settings --> Gamification**. --- ## Using the Leaderboard The leaderboard is now best used as a coaching and engagement tool. Here are practical ways to use it: - **Weekly check-ins**: Recognize high XP earners and people maintaining strong streaks - **Track-specific coaching**: Flip between Sales, Crew, and Office to see where momentum is building or slipping - **Level progression**: Use level and title changes as milestones for recognition - **Rewards planning**: If rewards are enabled, use spendable XP to support incentive programs > **Tip:** Review the leaderboard together with the Gamification Settings page so the team understands which behaviors are being rewarded. --- ## Tips - Turn on gamification first in **Settings --> Gamification** or the page will remain inactive - Use the **Sales**, **Crew**, and **Office** filters instead of trying to compare very different roles in one list - Watch streaks alongside XP. A smaller but consistent streak often matters more than one strong day - Spendable XP only shows when the rewards toggle is enabled for the workspace - Use the Achievement Catalog to see both the full earned badge history and what is still left to unlock for the current role track --- URL: https://docs.cleanestimate.pro/settings/team-management Title: Team Management Description: Invite team members, manage roles, track activity, and configure permissions. Category: settings Difficulty: beginner Roles: owner, manager Last updated: 2026-04-21 --- # Team Management The Team page is where you manage everyone on your account. You can invite new members, change roles, track activity, and remove people who no longer need access. Go to **Team** in the sidebar to get started. The refreshed admin shell keeps the same team workflows, but the page now uses the shared blue/slate workspace styling, summary cards, and tighter tab treatment used across the rest of the admin area. [SCREENSHOT: Team page showing the member table with columns for name, email, role badge, last active date, and action buttons] --- ## Team Page Layout The main Team page displays a table with one row per team member. Each row shows: - **Name** — The person's full name. - **Email** — The email address they use to log in. - **Role Badge** — A color-coded badge indicating their role: - Owner — purple badge - Manager — blue badge - Sales Rep — green badge - Crew Lead — orange badge - Technician — yellow badge - **Last Active** — The date and time they last logged in or took an action. - **Actions** — Buttons to change the role or remove the member. [SCREENSHOT: Close-up of the role badges showing Owner in purple, Manager in blue, Sales Rep in green, Crew Lead in orange, and Technician in yellow] Above the table, the page now also shows summary cards for current team counts so owners can scan active membership before opening invite or edit actions. --- ## Sub-Navigation The Team section has five tabs across the top of the page: - **Team** — The member list described above. - **Activity** — A log of recent actions taken by team members. - **Leaderboard** — Performance rankings for your sales team. - **Permissions** — Role-based access control settings. - **Territories** — Geographic territory assignments for sales reps. Click any tab to switch views. Each tab has its own dedicated article in this documentation. The tab strip now matches the rest of the admin workspace with blue active states instead of the older mixed accent styling. [SCREENSHOT: Team sub-navigation bar showing the five tabs: Team, Activity, Leaderboard, Permissions, Territories] --- ## Invite a New Member 1. Click the **Invite Member** button in the top right corner of the Team page. 2. A dialog appears with four key fields: - **Email** — Enter the person's email address. - **Role** — Select a role from the dropdown: Owner, Manager, Sales Rep, Crew Lead, or Technician. - **Red Line Access** -- Turn this on when the teammate should be allowed to use the Red Line estimator workflow. - **Rehash Access** -- Turn this on when the teammate should be allowed to work the residential Rehash queue and reporting pages. 3. Click **Send Invite**. [SCREENSHOT: Invite Member dialog with the email field filled in and the role dropdown open showing all five role options] The person receives an email with a link to finish account setup. New team members land on a password-creation screen first, then enter the dashboard with their role already assigned. Existing users who are being re-granted access receive a direct sign-in link instead. Their role determines what they can see and do. See the [Roles and Permissions](https://docs.cleanestimate.pro/docs/settings/permissions) article for details. By default, managers and sales reps are usually the best candidates for Red Line access, but the toggle lets you override that per person. That makes it easy to run mixed teams where some people use Red Line and others stay on standard pricing. That override now flows all the way back into the residential estimator's rep-assignment list too. If you explicitly enable **Red Line Access** for a teammate outside the default owner / manager / sales-rep roles, that person can now be selected as the assigned rep on residential estimates instead of being silently filtered out. When you change the role in either the invite dialog or the edit sheet, CE Pro now refreshes the **Red Line Access** toggle to that role's default starting point. You can still flip the toggle manually afterward if this teammate is an exception. That same role reset now applies to **Rehash Access** too, so switching someone into or out of the residential sales-manager workflow does not leave the Rehash workspace open by accident. The setup and access links now carry the invited workspace context all the way through the sign-in flow, so the member returns to the same admin workspace that sent the invite or resend. If the direct sign-in link path is temporarily unavailable for an existing teammate, CleanEstimate Pro now falls back to a recovery-style setup link automatically instead of failing the send altogether. --- ## Change a Member's Role 1. Find the person in the team table. 2. Click the **role badge** next to their name. 3. A dropdown appears with all five roles. 4. Select the new role. The change takes effect immediately. The next time the person loads a page, they see updated navigation and access. [SCREENSHOT: Role badge dropdown open on a team member row showing all five role options] > **Tip:** Changing a role does not affect past activity. Estimates they created, messages they sent, and jobs they worked remain in your records. --- ## Edit Red Line Access Open a team member from the table to edit their profile. The edit sheet includes a **Red line access** toggle so you can enable or disable the Red Line estimator for that specific teammate without changing their role. The same edit sheet now also includes a **Rehash access** toggle. Use it when someone should work residential win-back activity and recovered-close reporting without changing their base role. This same per-person setting also drives which assigned rep gets Red Line floor logic on residential estimates. If a manager builds a quote for Rep A and then switches the assigned rep to Rep B, the estimator now follows Rep B's Red Line access instead of the manager's own login. If the residential estimator says the assigned rep is on standard pricing, come back here and check that teammate's **Red Line Access** toggle. Red Line visibility is based on the rep attached to the estimate, not the office user who happened to open the quote. If an estimate still points to an old or unavailable rep record, CE Pro now fails closed and keeps the quote on standard pricing instead of falling back to whoever opened the estimate. That protects Red Line floors from changing just because a manager or owner happened to review the deal later. Use this when: - A manager should review Red Line deals but a technician should not see them. - A new rep is training and should stay on standard pricing for a while. - A mixed-comp team needs some people on Red Line and others on a different plan. - A residential sales manager should work the Rehash queue even if the rest of the team does not. [SCREENSHOT: Team member edit sheet showing the Red line access toggle] --- ## Remove a Team Member 1. Find the person in the team table. 2. Click the **Remove** button on the right side of their row. 3. A confirmation dialog appears. Click **Confirm**. [SCREENSHOT: Confirmation dialog asking to confirm removal of a team member] The person loses access immediately. They cannot log back in. Their historical activity stays in your account. > **Warning:** You cannot remove yourself. Another Owner must remove your account if needed. --- ## Activity Tab Click the **Activity** tab to see a chronological log of actions taken by your team. Each entry shows the team member's name, what they did, and when they did it. Use this tab to: - Audit who changed a proposal or estimate. - See when a team member last logged in. - Track productivity across the team. [SCREENSHOT: Activity tab showing a list of recent actions with team member names, action descriptions, and timestamps] --- ## Tips - Invite team members with the least access they need. You can always upgrade a role later. - Check the team page monthly. Remove people who have left your company. - Use the Activity tab to spot issues before they become problems. If a rep has not logged in for a week, follow up. - Color-coded role badges make it easy to scan the table and see your team structure at a glance. --- URL: https://docs.cleanestimate.pro/settings/webhooks Title: Webhook Integrations Description: Send signed real-time event data to external systems when actions happen in CE Pro. Category: settings Difficulty: intermediate Last updated: 2026-03-18 --- # Webhook Integrations Webhooks let you push real-time event data from CE Pro to external systems whenever something meaningful happens. Use them to connect CE Pro to your CRM, project management tool, accounting software, warehouse, or automation platform. Go to **Settings --> Integrations --> Webhooks** to get started. [SCREENSHOT: Webhooks page showing the list of configured webhook endpoints with status indicators and Add Webhook button] --- ## How Webhooks Work A webhook is an HTTP POST request that CE Pro sends to a URL you provide whenever a specific event occurs. Instead of polling CE Pro for changes, your system receives a push notification with the relevant data the moment something happens. For example, when a customer accepts a proposal, CE Pro sends a POST request containing the proposal details to your configured endpoint. Your server processes the data and takes action -- creating a project in your PM tool, adding a row to a spreadsheet, or triggering a downstream workflow. Webhooks are a developer-oriented feature. You need a server or service capable of receiving HTTP POST requests. No-code platforms like Zapier, Make, and n8n can receive webhooks without custom code. --- ## Available Events CE Pro supports webhooks for the following event types: | Event | Description | |---|---| | `lead.created` | A new lead is created. | | `lead.status_changed` | A lead changes status. | | `estimate.created` | A new estimate is created. | | `estimate.accepted` | A customer accepts an estimate. | | `job.created` | A job is created. | | `job.completed` | A scheduled job is marked complete. | | `invoice.created` | A new invoice is created. | | `invoice.paid` | An invoice is fully paid through the approved payment flow. | | `proposal_created` | A legacy internal proposal is generated. | | `proposal_sent` | A legacy internal proposal is delivered. | | `proposal_accepted` | A legacy internal proposal is accepted. | | `proposal_declined` | A legacy internal proposal is declined. | | `estimate_created` | A legacy estimate-created event for older integrations. | | `job_completed` | A legacy job-completed event for older integrations. | | `bug_report_created` | A bug report is submitted through the in-app reporting flow. | Each event includes a JSON payload with the relevant data. You can subscribe a single endpoint to multiple events, or create separate endpoints for different events. --- ## Setting Up a Webhook 1. Go to **Settings --> Integrations --> Webhooks**. 2. Click the **Add Webhook** button. 3. Fill in the configuration fields: - **URL** -- The full HTTPS endpoint that will receive the webhook POST requests. HTTP URLs are not accepted, and CE Pro rejects localhost, private-network, and other internal-only addresses. - **Events** -- Check one or more event types you want to listen for. - **Active** -- Toggle on to enable the webhook immediately. 4. Click **Save**. [SCREENSHOT: Add Webhook form with fields for URL, event type checkboxes, active toggle, and Save button] Use the **Send Test** action after saving to send a sample webhook to your endpoint. Your endpoint should return a `2xx` response so you can confirm the URL, auth, and payload handling are correct. If the test fails before CE Pro can reach your endpoint, the UI now keeps the error short and actionable. You may see setup errors like **Webhook config not found** or **Webhook URL must be an external HTTPS endpoint**. Other remote delivery failures return a generic **Webhook test failed** message while still showing the HTTP status and response body for debugging. --- ## Payload Format Every webhook request includes a JSON body with a consistent structure: ```json { "event": "proposal_accepted", "timestamp": "2026-03-08T14:30:00Z", "data": { "id": "prop_xyz789", "client_name": "Jane Smith", "client_email": "jane@example.com", "total": 2500.00, "status": "accepted", "accepted_at": "2026-03-08T14:29:45Z" } } ``` ### Top-Level Fields - **event** -- The event type string (matches the values in the table above). - **timestamp** -- ISO 8601 timestamp of when the event occurred. - **data** -- An object containing the event-specific details. The fields inside `data` vary by event type. ### Request Headers Each webhook request includes the following headers: - `Content-Type: application/json` - `X-Webhook-ID` -- The delivery id for dedupe and tracing. - `X-Webhook-Signature` -- The HMAC-SHA256 signature for verification (see below). - `X-Webhook-Event` -- The event type. - `X-Webhook-Timestamp` -- The delivery timestamp. - `X-Webhook-Attempt` -- Which delivery attempt this is. --- ## Testing Webhooks Before configuring a webhook in CE Pro, verify that your endpoint works correctly. ### Using a Request Inspector 1. Go to a service like [Webhook.site](https://webhook.site) or RequestBin. 2. Copy the generated URL. 3. Paste it into the CE Pro webhook URL field. 4. Save the webhook, then use **Send Test**. CE Pro sends a sample delivery to the endpoint. 5. Check the request inspector to see the payload. ### Testing in Development If you are building a custom integration: 1. Use a tunneling tool like ngrok to expose your local server to the internet. 2. Start your local server. 3. Copy the ngrok HTTPS URL and add your webhook path (for example, `https://abc123.ngrok.io/webhooks/cepro`). 4. Configure the webhook in CE Pro with this URL. 5. Trigger an event (create a test estimate, for example) and check your server logs. ### Test Delivery Payload The sample test delivery uses this format: ```json { "event": "estimate.created", "timestamp": "2026-03-08T14:30:00Z", "data": { "test": true, "message": "This is a test webhook from CleanEstimate Pro", "estimate_id": "00000000-0000-0000-0000-000000000000", "estimate_number": "TEST-001", "customer_name": "Test Customer", "total": 250.0 } } ``` --- ## Security and Signature Verification CE Pro signs every webhook request using HMAC-SHA256. This lets you verify that the request genuinely came from CE Pro and was not tampered with in transit. ### How Signing Works 1. When you create a webhook, CE Pro generates a signing secret. Copy it immediately and store it securely. It is shown only once. 2. For each webhook delivery, CE Pro computes an HMAC-SHA256 hash of the raw request body using your signing secret. 3. The hash is sent in the `X-Webhook-Signature` header. ### Verifying the Signature on Your Server Compute the HMAC-SHA256 hash of the raw request body using your stored signing secret. Compare the result to the value in the `X-Webhook-Signature` header. If they match, the request is authentic. **Node.js example:** ```javascript const crypto = require('crypto'); function verifyWebhookSignature(rawBody, signatureHeader, secret) { const expectedSignature = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); const expectedBuffer = Buffer.from(expectedSignature); const receivedBuffer = Buffer.from(signatureHeader); return ( expectedBuffer.length === receivedBuffer.length && crypto.timingSafeEqual(expectedBuffer, receivedBuffer) ); } ``` **Python example:** ```python import hmac import hashlib def verify_webhook_signature(raw_body, signature_header, secret): expected = hmac.new( secret.encode(), raw_body.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature_header) ``` > **Warning:** Always verify webhook signatures in production. Without verification, anyone who discovers your endpoint URL can send fake events to your system. ### Best Practices for Signing Secrets - Store the signing secret in an environment variable, not in your source code. - Rotate your signing secret periodically by deleting and re-creating the webhook. - Use constant-time comparison functions (like `timingSafeEqual` in Node.js or `compare_digest` in Python) to prevent timing attacks. --- ## Retry Logic If your endpoint returns an error (any HTTP status code other than `2xx`) or does not respond within 10 seconds, CE Pro queues the delivery and retries it automatically. Retries follow this backoff schedule: | Attempt | Delay After Previous Failure | |---|---| | Retry 1 | about 10 seconds | | Retry 2 | about 60 seconds | | Retry 3 | about 300 seconds | After the final retry, the delivery is marked as failed. Failed deliveries remain visible in the delivery log for troubleshooting. > **Tip:** If your endpoint is consistently failing, CE Pro may automatically disable the webhook after a sustained period of failures. Check the delivery log and fix the issue, then re-enable the webhook. --- ## Delivery Logging CE Pro logs every webhook delivery attempt. View the log by clicking on a webhook endpoint in the list. The log shows: - **Event Type** -- The event that triggered the delivery. - **Timestamp** -- When the delivery was attempted. - **Status Code** -- The HTTP response code your endpoint returned. - **Response Time** -- How long your endpoint took to respond (in milliseconds). - **Outcome** -- Success, Failed, or Retrying. - **Attempt** -- Which attempt number (1 through 3). [SCREENSHOT: Webhook delivery log showing recent deliveries with status codes, response times, and outcomes] Click on any delivery entry to see the full request payload and response body. Use this to debug issues with your integration. ### Manual Retry For any failed delivery, click the **Retry** button to resend the webhook immediately. This is useful when your endpoint was temporarily down and you need to replay missed events. [SCREENSHOT: Failed delivery entry in the log with a Retry button] --- ## Managing Webhooks ### Edit a Webhook 1. Go to **Settings --> Integrations --> Webhooks**. 2. Click on the webhook you want to modify. 3. Update the URL, subscribed events, or active status. 4. Click **Save**. ### Disable a Webhook Toggle the **Active** switch off to stop deliveries without deleting the webhook. This preserves your configuration and delivery history. ### Delete a Webhook 1. Click on the webhook. 2. Click **Delete**. 3. Confirm the deletion. Deleting a webhook removes the endpoint and all delivery history permanently. --- ## Tips - Test your webhook endpoint with a request inspector before configuring it in CE Pro. - Keep your endpoint response time low. CE Pro gives each delivery about 10 seconds before it counts as a failed attempt. - Use the delivery log to debug integration issues. A string of `500` errors usually means your endpoint is crashing. - Store your signing secret in an environment variable, never in source code. - If you use Zapier or Make, use their "Webhooks" trigger to receive CE Pro events without writing any code. - Subscribe only to the events you need. Unnecessary events create noise and consume processing resources on your server. - Implement idempotency on your server using `X-Webhook-ID`. Network issues and retries can produce repeat deliveries. --- URL: https://docs.cleanestimate.pro/troubleshooting/common-issues Title: Common Issues Description: Quick answers to the 10 most frequently asked questions. Category: troubleshooting Difficulty: beginner Roles: owner, manager, sales_rep, crew_lead Last updated: 2026-04-23 --- # Common Issues Quick answers to the 10 most frequently asked questions about CE Pro. --- ## 1. "My estimate won't send" Check that the customer has an email address or phone number. At least one is required for delivery. Verify a telecom provider is configured if you are sending via SMS. Go to **Settings > Phone / Voice** and confirm Esendex or Twilio is saved for the workspace. Make sure your account is active and not past due on billing. If you see an error toast message, note the exact text and contact support. [SCREENSHOT: Estimate send dialog showing an error when no email or phone is provided] --- ## 2. "Client says they didn't receive the estimate" For email delivery, ask the client to check their spam or junk folder. Some email providers flag automated messages. For SMS delivery, verify the phone number is correct. It should be 10 digits in US format with no country code prefix. Go to **Messages** in the sidebar and check if the outbound message shows a delivery error. [SCREENSHOT: Messages inbox showing an outbound message with a delivery error indicator] --- ## 3. "My pricing doesn't look right" Go to **Pricing Manager** and verify your default rates are set correctly. Check if the estimate has manual overrides on individual services. Manual overrides replace the default pricing calculation. Make sure the dirtiness level is set correctly. Heavy dirtiness adds a significant multiplier to the base price. [SCREENSHOT: Pricing Manager showing default rates for common services] --- ## 4. "I can't see a feature" Some features are restricted by role. Sales Reps cannot access Billing, Settings, or Team Management. Ask your account owner to check your role. Go to **Settings --> Team** to view and update team member roles. [SCREENSHOT: Team page showing a list of team members with their assigned roles] --- ## 5. "How do I change my plan?" 1. Go to **Billing** in the sidebar. 2. Click **Manage Subscription**. 3. The Stripe customer portal opens. 4. From there you can upgrade, downgrade, or update your payment method. [SCREENSHOT: Billing page with the "Manage Subscription" button highlighted] --- ## 6. "How do I cancel a sent estimate?" You cannot unsend an estimate. However, you can change its status. 1. Open the estimate from the Estimates list. 2. Update the status to **Expired** or **Cancelled**. 3. The customer sees the updated status if they visit the estimate link. [SCREENSHOT: Estimate detail page with the status dropdown showing Expired and Cancelled options] --- ## 7. "Can I edit an estimate after sending?" No. Sent estimates are locked to preserve the record of what the customer received. To make changes: 1. Open the sent estimate. 2. Click **Duplicate** to create a new draft with the same details. 3. Edit the duplicate. 4. Send the new version to the customer. [SCREENSHOT: Estimate detail page with the Duplicate button highlighted] --- ## 8. "How do I export data?" Most table views have an **Export** or **CSV** button. You can find it on the Clients, Estimates, and Jobs pages. 1. Apply any filters you want (date range, status, etc.). 2. Click **Export** or **CSV**. 3. A spreadsheet file downloads with the current filtered view. [SCREENSHOT: Estimates list page with the Export button highlighted in the toolbar] --- ## 9. "The app is slow" Try these steps in order: 1. Clear your browser cache. 2. Switch to Chrome or Edge if you are using a different browser. 3. Check your internet connection speed. 4. Wait a few minutes and try again. The issue may be a temporary server spike. If the problem persists across multiple browsers and devices, contact support. --- ## 10. "I forgot my password" 1. Go to the login page. 2. Click **Forgot password?** 3. Enter your email address. 4. Check your inbox for a reset link. 5. Click the link, set a new password, and log in. [SCREENSHOT: Login page with the "Forgot password?" link highlighted] The reset link expires after a limited time. If it has expired, request a new one. If the Sign In page now shows the shorter **Email or password is incorrect** message, that is expected. CleanEstimate Pro keeps the low-level auth provider details out of the login card now, so the next step is to double-check the email address, retry the password, or use **Forgot password?** for a fresh access email. If CE Pro says password reset email delivery is not configured, the reset flow itself is available but the workspace or environment is missing outbound email setup. Contact support so email delivery can be enabled. If a brand-new reset or setup email opens straight to **Invalid or expired reset link**, request one more fresh link. CleanEstimate Pro now routes recovery and invite emails through a browser handoff screen that finishes the Supabase session in the app before opening the password form, so fresh links no longer fail just because the old server callback could not read the auth fragment from the email provider redirect. --- ## 11. "My invite link sent me back to sign in or the waitlist" If your workspace was provisioned through the early-access waitlist, use the same invited email address from the onboarding email. If the original setup link has expired or was already used: 1. Open the link anyway. 2. On the password setup screen, click **Use Forgot Password Instead**. 3. If you land on Sign In instead, click **Forgot password?** 4. Enter the same invited email address. CleanEstimate Pro now routes expired invite recovery through the same shared forgot-password flow used everywhere else. That keeps the email response generic, rate-limited, and still sends the right workspace-specific setup or recovery link for provisioned accounts without dropping you back into the public waitlist flow. If you choose **Forgot password?** before the invited account has ever completed setup, CleanEstimate Pro now detects that pending workspace state and sends another setup email automatically instead of a generic password-reset email. Fresh workspace setup emails now open through a short **Finishing Sign-In** screen before the password card. That handoff is expected and fixes the earlier issue where a brand-new setup email could still bounce to **Invalid or expired reset link** even though the Supabase invite was valid. If you do land on the expired-link screen, CE Pro now lets you send yourself a fresh link right there from the same card. The button keeps the invited email address attached, so you do not need to retype it on a separate forgot-password page first. If the shorter **Finishing Sign-In** handoff screen is the part that fails, its **Need A New Link?** link now preserves the same workspace redirect too. That retry path should keep you aimed at the invited workspace instead of falling back to a generic sign-in destination. If the workspace-auth lookup has a temporary hiccup while that pending-invite check runs, CE Pro now falls back to the standard recovery email path instead of showing a hard server error from the forgot-password screen. If an older invite email shows `http://` or a `localhost` address, do not use that email. Request a fresh setup link. New workspace setup emails now force the production CleanEstimate URL outside local development so invite links do not point at a developer machine. The password setup and forgot-password cards now use the shared CleanEstimate logo treatment too. If you still see the older plain text logo after deploy, refresh once to pull the latest auth screen bundle. --- ## 12. "My onboarding Services or Pricing step is blank" If you are entering a brand-new workspace from a waitlist or invite flow and the **Services** or **Pricing** step looks empty, refresh once first. CleanEstimate Pro now repairs the default onboarding catalog automatically when a provisioned workspace is missing starter setup records. The page should repopulate the standard service list and starter pricing fields instead of leaving you stuck on a blank step or a pricing save error. If the page still stays empty after refresh, report the workspace email address and company name to support so the org bootstrap data can be inspected directly. --- ## 13. "Onboarding says failed to save company info" or another setup step If you are a provisioned **manager** entering a workspace that is still unfinished, the onboarding flow should now let you complete the Company Info, Services, Pricing, and final completion steps without waiting for the owner to log in first. If you still see a save error: 1. Refresh once and retry the same step. 2. Note the full inline error text shown in the onboarding card. 3. Confirm which workspace you are entering, especially if you belong to a franchise operator and a child location. CleanEstimate Pro now shows the real onboarding API error message instead of the older generic **Failed to save company info** message, so support can usually diagnose the issue from that exact text. --- ## 14. "An admin page says it failed to load" If the **Estimates**, **Jobs**, or **Invoices** pages show a load error right after a rollout, refresh once first. CleanEstimate Pro now falls back to the core record tables while newer read models and optional payroll tables catch up, so those pages should keep loading even during schema rollout windows. If the **Estimates** page was blank with a `Failed to load estimates` toast on March 16, 2026, that was a server-side loading bug in the estimate summary call path, not a data-loss issue. The fix is now live; if you still see the old error after deploy, hard refresh the admin app once and retry. If the invoice page opens and **Create Pay Link** shows a setup error, the workspace is missing secure invoice-link signing. Ask support to confirm `CUSTOMER_TOKEN_SECRET` is set for the environment. **Send Invoice** can still succeed in that state, but the outgoing email will skip the online pay button until secure link signing is configured. If **Billing** says the portal is temporarily unavailable, Stripe may still be missing customer-portal configuration or the workspace may not have a Stripe customer record yet. If **Messages**, **Billing**, or account recovery now show a short plain-language error instead of a long technical provider message, that is expected. CE Pro now keeps the low-level Stripe, Twilio, Mailgun, Supabase, and database details in server logs and shows the operator the next useful action instead. --- ## Need to report a bug? Use the floating **Report a Bug** button in the lower-right corner of the admin app. When you submit a bug report, CleanEstimate Pro automatically captures the current window, browser details, recent errors, and other diagnostics to help the team troubleshoot faster. See **[Reporting Bugs](https://docs.cleanestimate.pro/troubleshooting/reporting-bugs)** for the full workflow. ## Workspace Switcher Says the Workspace Identifier Is Invalid If you were already signed in during a franchise rollout, the browser may hold an older workspace identifier briefly after a deploy. CleanEstimate Pro now accepts the current workspace UUID, the readable workspace slug, and the exact workspace name when switching orgs, including older root-workspace ids that do not look like version-stamped UUIDs. If the switcher still feels stuck, refresh the admin app once and try again. --- URL: https://docs.cleanestimate.pro/troubleshooting/estimate-sending Title: Estimate Delivery Issues Description: What to do when an estimate doesn't reach your customer. Category: troubleshooting Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-04-23 --- # Estimate Delivery Issues When an estimate does not reach your customer, follow these steps to diagnose and fix the problem. --- ## When Email Delivery Fails ### Ask the customer to check spam Automated emails sometimes land in spam or junk folders. Ask the customer to search their spam folder for a message from cleanestimate.pro. ### Verify the email address Open the estimate and check the customer's email address for typos. A single wrong character prevents delivery. [SCREENSHOT: Estimate detail page showing the customer email field] ### Whitelist the sender Some corporate email servers block unknown senders. Ask the customer to add **notifications@cleanestimate.pro** to their contacts or whitelist. ### Check the Messages inbox Go to **Messages** in the sidebar and find the conversation for this customer. Look for any error indicators on the sent message. [SCREENSHOT: Messages inbox showing a sent estimate email with a delivery status indicator] --- ## When SMS Delivery Fails ### Verify the phone number The phone number must be a US mobile number. Enter 10 digits with no country code prefix, dashes, or spaces. [SCREENSHOT: Customer record showing the phone number field with correct 10-digit format] ### Landlines cannot receive SMS If the customer gave you a landline number, SMS delivery fails silently. Ask for a mobile number instead. ### Carrier filtering Some carriers filter automated messages. This is more common with shared business SMS numbers. If a customer reports they never receive your texts, carrier filtering may be the cause. ### Check provider delivery status Log in to the active provider console and find the message. The status usually shows one of: - **Delivered** — The carrier accepted the message. - **Sent** — The provider accepted the message but has no delivery confirmation. - **Undelivered** — The carrier rejected the message. - **Failed** — The message could not be sent. [SCREENSHOT: Provider messaging logs showing message delivery statuses] --- ## How to Resend an Estimate If the original delivery failed, you have two options. ### Option 1: Send the link manually 1. Open the estimate from the Estimates list. 2. Copy the estimate link. 3. Go to **Messages** and open the customer's conversation. 4. Paste the link and send it via SMS or email. [SCREENSHOT: Estimate detail page with the estimate link and copy button highlighted] ### Option 2: Duplicate and resend 1. Open the estimate. 2. Click **Duplicate** to create a new draft copy. 3. Make any needed changes. 4. Send the new estimate. [SCREENSHOT: Estimate detail page with the Duplicate button highlighted] ### Save or send showed an error after the draft already saved If you return to the estimates list and can see the draft there, the estimate save completed successfully even if the previous tab showed an error toast. Refresh the estimate record from the list before creating a second copy. Generic quotes and standard estimate edits now share the same save-response path, so successful saves should return cleanly instead of reporting a false `500` after the record is already written. --- ## Checking Delivery Status Estimate sends are processed asynchronously. That means the estimate can move to **Sent** right away while the PDF, email, SMS, and legacy sync tasks finish in the background. ### What queued delivery means - **Queued** -- CE Pro accepted the send request and is preparing delivery tasks. - **Processing** -- Some tasks finished, but others are still running. - **Sent** -- All delivery tasks completed successfully. - **Failed** or **Partial Failure** -- At least one task needs a retry or manual follow-up. ### SMS delivery status Go to **Messages** and find the outbound message. SMS messages may show a delivery status: - **Delivered** — The message reached the customer's phone. - **Sent** — The message left CE Pro but delivery is unconfirmed. - **Failed** — The message could not be delivered. ### Email delivery status Email delivery is confirmed by the email service provider. CE Pro updates delivered, opened, clicked, and failure states when that provider reports them back. Final delivery to the inbox still depends on the recipient's email provider and mailbox filters. If the thread shows a failure or bounce, double-check the address and ask the customer for an alternate email if needed. [SCREENSHOT: Messages inbox showing an outbound message with delivery status badges for both SMS and email] --- ## When you hit a burst-protection limit If many teammates in the same organization send estimates at once, CE Pro may temporarily block new send requests with a "try again shortly" message. This protects the queue so one burst does not crowd out every other customer-facing task. Wait a minute, then resend the estimate. The previous send request is not lost unless the UI explicitly shows a failure. --- ## Prevention Tips - Always confirm the customer's email and phone number before sending. - Ask customers to save your workspace SMS number as a contact so carrier filtering is less likely. - Send estimates via both email and SMS (dual-channel) to maximize the chance of delivery. - If a customer consistently does not receive emails, switch to SMS-only delivery. --- URL: https://docs.cleanestimate.pro/troubleshooting/messages-not-showing Title: Messages Not Showing Up Description: Troubleshoot missing messages in your inbox. Category: troubleshooting Difficulty: beginner Roles: owner, manager, sales_rep Last updated: 2026-04-23 --- # Messages Not Showing Up If you expect to see a message in your inbox but it is not there, work through the following checks in order. Some client, lead, and job screens can also open the inbox in a side drawer. If that embedded panel does not load correctly, click **Open full inbox** from the drawer header and continue troubleshooting there. --- ## Check You Are Looking at the Right Conversation The inbox groups conversations by phone number. If a customer has multiple phone numbers, their messages may appear in separate threads. Search by the customer's name to find all related conversations. [SCREENSHOT: Messages inbox with the search bar showing a customer name search and multiple conversation results] --- ## Check Your Filters If you have any text in the search bar, clear it. An active search hides conversations that do not match. Make sure you are not filtering by a specific channel or date range. Reset all filters and scroll through the full conversation list. [SCREENSHOT: Messages inbox with the search bar and filter controls highlighted, showing how to clear them] --- ## Missing Inbound SMS If a customer says they sent you a text but it does not appear in CE Pro: 1. **Verify the customer texted the correct number.** Your active telecom number is shown in **Settings > Phone / Voice**. The customer must text that exact number. 2. **Check that your provider webhook is configured correctly.** Esendex and Twilio each have their own inbound SMS webhook URL. If the provider is misconfigured, it receives the message but cannot forward it to CE Pro. 3. **Look for the message in the provider console.** If it appears there but not in CE Pro, the issue is usually the inbound webhook URL or postback token. 4. **Wait and check again.** The inbox polls every 15 seconds. If the message just arrived, give it a moment to appear. [SCREENSHOT: Provider console messaging logs page showing a received message entry] --- ## Missing Outbound Messages If you sent a message but it does not appear in the conversation: 1. **Check if the send action showed a success toast or an error.** If you saw an error, the message was not sent. 2. **Verify the customer's phone number or email is correctly formatted.** Phone numbers should be 10 digits with no dashes, spaces, or country code prefix. 3. **Check your SMS usage.** If you have exceeded your monthly allocation, messages may be blocked. Go to **Settings --> Billing** to check your usage. [SCREENSHOT: Billing page showing SMS usage counter approaching the monthly limit] --- ## Missing Email Replies If a customer replied to an email but their reply does not appear in CE Pro: 1. **Check that inbound email routing is configured.** Go to **Settings** and confirm CE Pro shows a live reply-to address, not just a saved slug with a setup-required notice. 2. **Check for forwarded conversations.** If you forwarded the conversation to your personal email, replies to that personal email do not show in CE Pro. 3. **Verify your email slug.** Go to **Settings** and confirm your email slug is configured. The slug determines the mailbox local-part CE Pro uses once inbound routing is live. [SCREENSHOT: Settings page showing the Email Slug configuration field] --- ## Follow-Up Sequence Messages Automated messages from follow-up sequences are logged in the conversation timeline. If you do not see them: 1. **Check if the customer opted out.** If a customer texted STOP, all future automated messages are suppressed. The customer record shows an opt-out flag. 2. **Check if the customer replied.** When a customer replies to a follow-up message, the sequence is paused automatically. This prevents double-messaging. You need to manually resume the sequence or respond to the customer directly. 3. **Check the sequence status.** Go to **Settings --> Automations** and verify the sequence is active and the customer is enrolled. [SCREENSHOT: Follow-up sequence detail showing a paused status with the reason "Customer replied"] --- ## Still Not Resolved If none of these steps fix the issue, contact support with: - The customer's phone number or email address. - The approximate time the message was expected. - Whether the message is inbound or outbound. - Any error messages you saw. --- URL: https://docs.cleanestimate.pro/troubleshooting/mobile-sync Title: Mobile App Troubleshooting Description: Fix common issues with the CE Pro mobile app including sync, login, and notifications. Category: troubleshooting Difficulty: beginner Roles: owner, manager, sales_rep, crew_lead Last updated: 2026-03-08 --- # Mobile App Troubleshooting The CE Pro mobile app works alongside the web app. Your data syncs between both. This guide covers the most common mobile issues and how to fix them. --- ## App Not Syncing If changes you made on the web are not appearing in the mobile app, or vice versa: 1. **Check your internet connection.** The app needs Wi-Fi or cellular data to sync. Open a browser on your phone and load any website to confirm you are connected. 2. **Pull down to refresh.** On the main screen, pull down to force a manual sync. [SCREENSHOT: Mobile app main screen with a pull-to-refresh indicator at the top] 3. **Check for offline changes.** If you made changes while offline, they sync automatically when you reconnect. Look for a sync indicator at the top of the screen. [SCREENSHOT: Mobile app showing a sync indicator bar at the top of the screen] 4. **Close and reopen the app.** If sync is stuck, force-close the app and reopen it. This resets the sync connection. --- ## Cannot Log In If you cannot log in to the mobile app: 1. **Use the same credentials as the web app.** Your mobile login uses the same email and password as the web version. There is no separate mobile account. 2. **Reset your password.** Tap **Forgot password?** on the login screen. Enter your email address and follow the reset link. [SCREENSHOT: Mobile app login screen with the "Forgot password?" link highlighted] 3. **Check your account status.** If your account has been deactivated by an administrator, you cannot log in. Ask your admin to check your status in **Settings --> Team** on the web app. --- ## Push Notifications Not Working If you are not receiving push notifications: ### Check phone settings Go to your phone's **Settings --> CE Pro --> Notifications** and make sure notifications are enabled. [SCREENSHOT: Phone settings screen showing CE Pro notification permissions toggled on] ### Check app settings In the CE Pro app, go to **Settings --> Notifications** and verify all notification types are turned on. [SCREENSHOT: Mobile app Settings --> Notifications screen with toggle switches for each notification type] ### Android battery optimization On Android, battery optimization can block background notifications. Go to **Settings --> Battery --> CE Pro** and set it to "Unrestricted" or "Don't optimize." ### Re-register for notifications Force-close the app and reopen it. This re-registers your device for push notifications. --- ## Photos Not Uploading If photos you take or attach are not uploading: 1. **Check your internet connection.** Photos require an active connection to upload. 2. **Check app permissions.** Go to your phone's **Settings --> CE Pro --> Permissions** and make sure Camera and Photo Library access are granted. [SCREENSHOT: Phone settings screen showing CE Pro with Camera and Photo Library permissions enabled] 3. **Wait for slow connections.** Large photos take longer on slow cellular connections. Look for an upload progress indicator before navigating away. 4. **Reduce photo quality.** If uploads consistently fail, check the app settings for a photo quality option. Lower quality means smaller file sizes and faster uploads. --- ## Offline Mode CE Pro works offline for core features. Here is what you can do without an internet connection: - View your schedule. - Update job status. - Take notes on jobs. - View previously loaded client information. ### How offline sync works Changes made offline are stored locally on your device. When you reconnect to the internet, the app syncs your changes automatically. [SCREENSHOT: Mobile app Settings --> Offline screen showing sync status and queue size] ### Sync conflicts If someone edited the same record on the web while you were offline, a sync conflict occurs. The most recent change wins. Check the record after syncing to make sure your changes were applied. ### Check sync status Go to **Settings --> Offline** in the app to see: - **Sync status** — Whether the app is currently synced or has pending changes. - **Queue size** — The number of changes waiting to upload. --- ## App Crashing or Freezing If the app crashes or becomes unresponsive: 1. **Update to the latest version.** Open the App Store (iOS) or Google Play (Android) and check for updates. Running an outdated version is the most common cause of crashes. This is especially important if the app crashes while creating proposals or adding line items. Recent mobile builds include stability fixes for proposal creation flows. 2. **Clear the app cache.** Go to your phone's **Settings --> CE Pro --> Storage --> Clear Cache**. This removes temporary data without deleting your account. 3. **Restart your phone.** A full restart clears memory and can resolve intermittent issues. 4. **Reinstall the app.** If the issue persists, uninstall and reinstall CE Pro from your app store. Your data is stored on the server, not on your phone. Nothing is lost when you reinstall. [SCREENSHOT: Phone storage settings for CE Pro showing the Clear Cache button] --- ## Getting Help If none of these steps resolve your issue: - Note your phone model and operating system version. - Note the app version (found in **Settings --> About** in the app). - Describe the issue and when it started. - Contact support with these details. --- URL: https://docs.cleanestimate.pro/troubleshooting/reporting-bugs Title: Reporting Bugs Description: Submit a bug report with auto-captured diagnostics and a screenshot of the current window. Category: troubleshooting Difficulty: beginner Roles: owner, manager, sales_rep, crew_lead Last updated: 2026-03-28 --- # Reporting Bugs Use the in-app **Report a Bug** button in the lower-right corner of the admin app to send a bug report without leaving the page you are on. [SCREENSHOT: Floating Report a Bug button in the lower-right corner of the admin app] --- ## How to Open It You can open the bug report panel in two ways: - Click the floating **bug** button in the bottom-right corner. - Use the keyboard shortcut: - **Ctrl+Shift+B** on Windows - **Cmd+Shift+B** on Mac This opens a right-side panel where you can describe the issue and send the report. --- ## What Gets Captured Automatically When you submit a report, CleanEstimate Pro automatically captures: - The current page URL - Page title - Recent page history - Browser and operating system - Viewport and screen size - Last detected action - Recent console errors - Recent failed network requests - Session and app version details - A screenshot of the current app window The automatic screenshot captures the page state you were looking at when you pressed **Send Report**. > **Note:** The screenshot is taken automatically on submit, so you do not need to attach one manually for most reports. If automatic capture fails, the form now tells you right away so you can still send the report or attach one yourself. --- ## Replacing the Automatic Screenshot The **Screenshot** section still lets you attach your own image. Use that if you want to: - Replace the automatic capture with a cropped or annotated image - Upload a screenshot from another device - Share a screenshot taken before the issue changed state Images over 2MB are compressed before upload. Final upload size is capped at 5MB. [SCREENSHOT: Bug report panel showing the Screenshot section with an attached preview image] --- ## Filling Out the Report The most useful reports include: - **What went wrong?** - **What were you trying to do?** - **What did you expect to happen?** - **Severity** - **Category** If you are short on time, the description is the only required field. The diagnostic context and screenshot do a lot of the rest automatically. Owners and managers are no longer capped at only five reports per hour. The app still applies a server-side abuse limit, but it is set high enough for real bug sweeps. --- ## Offline Behavior If you are offline when you submit a report: - The report is queued locally - The app keeps the captured details - The report submits automatically when the browser comes back online If your session expires during submission, the draft is restored after you sign back in. --- ## Who Can Review Reports Submitted reports are reviewed from **Admin --> Bug Reports**. That review page is limited to owner accounts, and the owner inbox now stays tied to the owner's accessible org scope instead of disappearing or shrinking down to only the currently switched child workspace. That view is where your team can: - Open the full report - Track the report by its bug number, such as `BUG-0042` - Review the screenshot - Read diagnostics and reproduction notes - Update the report status - Track whether the issue is new, acknowledged, in progress, resolved, or won't fix - Review the automated intake verdict before escalating it - Open the linked GitHub issue when bug-duty sync is enabled --- ## GitHub Bug Duty When GitHub bug sync is configured, CleanEstimate Pro can push strong bug reports directly into your repository as `bug` issues. The app does **not** blindly sync every report. It first scores each submission for signal quality using the report details, reproduction notes, and captured diagnostics. - **Accepted** reports sync automatically to GitHub and receive the `openclaw:auto` label for runner pickup - **Needs review** reports stay in **Admin --> Bug Reports** until an owner decides to push them - **Rejected** reports are treated as likely training or low-signal submissions and stay out of the repo by default If GitHub is unavailable, or if an owner wants to override the automatic gate, the bug report detail page includes a manual **Sync to GitHub** action. If sync fails, the bug report detail page now shows the sync error instead of looking like a silent no-op. To enable GitHub bug-duty sync, configure the production app with: - `GITHUB_BUG_REPORTS_REPO` - `GITHUB_BUG_REPORTS_TOKEN` For instant OpenClaw pickup without cron polling, install the self-hosted runner on the always-on machine and keep these repo files in place: - `.github/workflows/openclaw-bug-dispatch.yml` - `dispatch-bug.sh` The runner listens for issues with all of these labels: - `bug` - `triage:accepted` - `openclaw:auto` The workflow adds `openclaw:started` before dispatching so the same issue cannot be picked up twice. --- ## Best Practices - Submit the report as soon as the bug happens so the automatic screenshot reflects the right state. - Add one sentence describing what you clicked just before the problem started. - If pricing, totals, or customer data look wrong, mark the severity accurately so the team can triage it faster. - If the issue blocks work entirely, use **High** or **Critical**. --- URL: https://docs.cleanestimate.pro/whats-new/changelog Title: Product Changelog Description: A running history of Clean Estimate Pro product updates, fixes, launches, and release work. Category: whats-new Difficulty: beginner Roles: owner, manager, admin Last updated: 2026-04-28 --- # Product Changelog This page is the running release history for Clean Estimate Pro. It is built from the `cleanestimatepro` git history and captures shipped product work across features, fixes, hardening, and rollout changes. This log currently covers releases from **2026-03-06** through **2026-04-28**. Merge-only commits, docs-only mirror commits, and housekeeping-only commits are intentionally left out so the list stays focused on product changes. Going forward, every production-facing change should add an entry here before the work is considered done. ## 2026-04-28 - Hardened the public health check after the page-speed stress run showed Supabase-backed probes degrading while public pages stayed fast. The health endpoint now aborts its Supabase reachability query at the timeout boundary so repeated uptime checks do not leave extra database requests running during a Supabase incident. - Followed up on the page-speed audit with a smaller Clients loading path and lighter telemetry ingest. The Clients workspace now opens its page shell without waiting on the full account tree API during server navigation, then hydrates rows through the existing client-side loader, and route telemetry rate limiting no longer spends an extra database RPC before writing sampled timings. - Started the admin usage-reduction pass for the highest-traffic workspaces. Dashboard metrics keep exact visible totals while caching the heavy chart RPC, Estimates opens without server-side self-fetches and keeps exact workbench counts with cached summary metadata, Schedule caches its reference data briefly, and admin route telemetry samples more heavily by default so real logged-in slow pages show up faster. - Extended the exact-number guarantee across admin dashboards and reports. Revenue, pipeline, schedule, clients, commissions, crew pay, franchise, retention, operations, lead-source, holiday-lights, sales-cycle, geography, and margin reporting now avoid hidden row caps, display money to the cent, and fail visibly when a report source cannot be loaded instead of showing guessed or partial totals. - Tightened Revenue Analytics so money reports stay exact instead of fast-but-approximate. Revenue rollups now page through every matching accepted record, include fleet/building/holiday lights in the time series, sum in cents, fail closed on query errors, and display penny-level totals on the revenue report. ## 2026-04-27 - Reduced shared admin-page load pressure after Schedule and Clients were still taking several seconds to open. Admin org resolution now skips unnecessary franchise descendant lookups, sidebar gamification no longer performs setup/write work during normal navigation, admin API middleware rate limiting no longer spends a database RPC on protected office reads, and the Clients list avoids unused count and all-org health work where it can. - Fixed an admin alert feedback loop that could make the logged-in app feel slow. The alert bell now reads without regenerating managed alerts, dashboard alert generation is throttled, unchanged alert rows are no longer rewritten, realtime only refreshes on new alerts, and slow alert fetches stop instead of stacking in the browser. - Hardened the East-backed login and worker recovery path. Password sign-in now surfaces a clear auth-service timeout instead of spinning forever, minute-by-minute background workers have incident kill switches and lower default concurrency, super-admin pages stay dynamic during deployment, and the public ingress rate limiter now fails closed quickly when a hot key is locked instead of holding database workers until gateway timeout. - Expanded the incident scheduler pause so `DISABLE_CRON_JOBS=true` now stops follow-ups, drip campaigns, proposal expiration, automation waiting runs, scheduled automation triggers, franchise summary refreshes, background jobs, and webhook delivery before those routes open Supabase connections. This gives the team a safer recovery path when Supabase warns that the project is near Disk IO Budget exhaustion. - Reorganized the admin sidebar around daily office work. The top group now reads **Daily work** and pins **Command Center**, **Inbox**, **Estimates**, **Schedule**, and **Jobs**, while Pipeline and AI Hub move into the growth/admin area so the left rail matches the actual day-to-day workflow more closely. - Updated the owner dashboard into a more action-first **Command Center**. The page now opens with live office signal pills and a full-width **Daily admin queue** before reports, charts, and secondary shortcuts, keeping follow-ups, replies, and handoffs above analytics. - Refocused the admin **Estimates** page into an **Estimate workbench** with priority cards for drafts, viewed follow-ups, unassigned estimates, and accepted job handoffs, plus row-level **Next action** controls for the most common send, follow-up, job, payment, schedule, review, and detail workflows. ## 2026-04-26 - Added the Phase 0 production telemetry baseline for scaling work. CE Pro now samples production route and API timing, exposes service-role-only exports for top route latency, `pg_stat_statements`, and Supabase connection snapshots, and documents the stop condition, business-load target prerequisite, kill switches, and MRR-based cost gates before any speculative scale phases continue. - Moved commercial fleet and building proposal delivery onto the background job queue. The send dialog now acknowledges a queued delivery immediately while the worker renders the proposal PDF, sends email/SMS, retries transient failures, and records final delivery state in the background; `COMMERCIAL_PROPOSAL_SEND_QUEUE_DISABLED=true` rolls the path back to synchronous delivery. ## 2026-04-25 - Added docs-site discovery surfaces for `docs.cleanestimate.pro`. The help center now publishes a generated `/sitemap.xml`, `/site-map`, `/llms.txt`, `/llms-full.txt`, and `/robots.txt`, all sourced from the MDX docs catalog so search engines and AI ingestion tools can find the current documentation. - Connected the mobile CRM and residential estimate handoff to live Clean Estimate data. Signed-in mobile users now load, create, and update customers through authenticated live client APIs, client/lead **New estimate** actions carry CRM context into the builder, and mobile residential address entry now uses the same property lookup service as the web estimator to prefill square footage, stories, lot size, and year built. ## 2026-04-24 - Repaired live customer-portal Stripe invoice payments after QA found Checkout sessions could open but paid portal invoices stayed pending. The production app URL environment value was corrected, and the central Stripe webhook now recognizes portal invoice Checkout metadata so successful test-mode payments mark the portal invoice paid while declined cards remain unpaid. - Added Red Line pricing to the mobile residential sales flow. Eligible sales reps now see per-service floors, status, and visible commission in the mobile pricing/review steps, below-floor mobile edits are clamped or blocked before save/send, mobile pricing settings show the active Red Line model, and queued mobile residential proposals now carry the Red Line snapshot for audit. - Hardened the Android mobile sales QA blockers found in the live app pass. Mobile API calls now default to `app.cleanestimate.pro`, mobile-created customers show back up in CRM search and detail, proposal-client records no longer dead-end the client page, commercial building proposals cannot advance to final review with missing client/property/service/pricing/frequency data, modal headers respect safe areas, and Android Back now asks before discarding unsaved lead or customer details. - Restored self-serve workspace signup so new owners can create an account, create their organization, receive starter setup data, start a 44-day trial, sign in, and land in onboarding from `/signup`. The public CTAs now point at the trial signup path, stale waitlist signup blocks were removed from the public marketing surface, and the new regression test covers owner creation, org creation, membership creation, bootstrap seeding, duplicate-workspace blocking, and rollback on partial signup failure. - Hardened the first-run onboarding finish path. Service toggles now save in one parallel pass instead of holding the setup flow through a long sequence of individual saves, and the final dashboard handoff now shows an **Open Dashboard** fallback link if the workspace completion save succeeds but the admin dashboard is slow to render. - Added a read-only browser QA script for the super-admin portal and used it against the live site. The pass now checks the signed-out redirect guard, super-admin magic-link sign-in, Dashboard, Organizations, organization detail, Users, Waitlist, Activity, and empty-result filters, while the underlying fixes stabilize super-admin table hydration and allow the deployed Google Analytics collect endpoint through CSP so real portal failures are easier to spot. - Added a live browser QA script for self-serve signup and onboarding. The pass creates a fresh AgentMail inbox, signs up a new owner/org, completes onboarding, verifies the database state, confirms password login, and opens a real delivered access-link email; the dashboard Lead Sources shortcut now points at the live Lead Source ROI report instead of a missing analytics route. ## 2026-04-23 - Added a safe dual telecom provider path for **Phone / Voice**. Workspaces can now choose **Esendex** or **Twilio**, provider-specific settings and token-protected webhook URLs are shown in Settings, outbound SMS/manual messaging/ETA texts/automation calls use the active provider, and legacy Twilio workspaces keep Twilio validation and callback behavior. Provider switches also fail safe by turning voice off until the selected provider has a ready number and forwarding setup. - Tightened the live QA accessibility blockers found in the admin and customer estimator flows. Icon-only alert, table action, route, and schedule controls now have screen-reader names, admin and estimator filters expose clear select labels, customer/property inputs are associated with labels, XP progress bars are named, dark-sidebar contrast is stronger, login/signup paragraph links no longer rely on color alone, the customer portal footer has stronger contrast, and the admin theme toggle no longer risks a hydration mismatch during page load. - Fixed the customer magic-link login page on `app.cleanestimate.pro/customer/login`. Signed-out customers can now open the login form directly instead of getting caught in a redirect loop from the protected customer portal shell. ## 2026-04-22 - Cleaned up the main admin dashboard top section so the report shortcuts now live inline beneath the office snapshot instead of as a separate skinny right-side rail. The awkward **Open the next read** panel copy is gone, the new section simply reads **Top reports**, and the dashboard header area is easier to scan at laptop widths. - Tightened the live portal referral gate and the public discovery surfaces after the latest production QA pass. Unknown emails on the portal referral tab are blocked again instead of falling into the referral-code enrollment step, known customers without a saved code can still create one, and the asphalt-maintenance module is once again listed across `/site-map`, `/sitemap.xml`, and `/llms-full.txt`. ## 2026-04-21 - Repaired another live Rehash popup failure after reproducing the exact broken estimate against the real workspace schema. The detail drawer and inline Rehash quote-save path now tolerate older workspaces that are still missing legacy estimate pricing columns like `minimum_adjustment` and `taxable_amount` instead of crashing the popup with a generic request failure. - Expanded the Rehash detail drawer into a true quote-editing popout. Managers can now see each residential service's list price, current quoted price, and saved Red Line floor side by side, adjust quoted service prices inline without leaving Rehash on standard residential service-line quotes, and save those line-item changes directly from the drawer while the app keeps the floor guardrails intact. Package and maintenance-plan quotes now stay read-only in that drawer and point managers back to the full quote editor instead of allowing a risky partial inline save. - Hardened the Rehash popup after live failure reports. The quote drawer now fails open when older records have malformed parent-estimate links, invalid legacy rep ids, or bad Rehash template rows, so the manager can still open the quote summary instead of getting a generic request failure. - Added Red Line room summaries to the Rehash queue so managers can spot discountable residential quotes faster. Queue rows and the Rehash detail drawer now show quoted service totals versus the saved Red Line floor, plus a clear room / at-floor / below-floor badge for faster win-back review. - Hardened the Rehash setup diagnostics again after more live rollout feedback. The queue and analytics loaders now tolerate optional missing Rehash columns where they can, the setup warning now includes the exact missing `estimates.rehash_*` or disposition fields when the production database is still missing the core Rehash foundation migration, and unrelated missing-column errors no longer get mislabeled as a Rehash rollout problem. - Tightened the Rehash setup fallback after another live production report. The queue no longer treats missing legacy `message_templates` storage as a fatal Rehash-foundation failure, so `/admin/rehash` can still load with the built-in staged copy while only the actual Rehash estimate/disposition schema remains a hard requirement. - Repaired the live Rehash route guard after another audit pass. `/admin/rehash` is now registered in the admin permission map, so direct visits to the queue no longer bounce back to the dashboard before the Rehash access checks can run. - Audited the new Rehash Phase 4 rollout and repaired three gaps before the next production pass: Rehash analytics now fails soft with the same setup warning as the queue when a workspace is missing migrations, the Commissions page no longer hard-crashes in that partial-rollout state, and payroll exports now keep legacy accepted lead-source payouts instead of skipping them. - Began Phase 4 of the residential Red Line rollout. The Rehash queue now works much better on mobile, Pricing Manager can toggle Rehash template A/B testing, Rehash analytics now tracks template performance and queue-pressure aging buckets, and the Commissions dashboard can export payroll-ready CSVs including recovered Rehash split payouts. - Hardened the Rehash rollout path after the first live feedback. If a workspace is still missing part of the Rehash database setup, the Rehash page now loads with a clear setup message instead of failing outright while the queue API crashes. - Began Phase 3 of the residential Red Line rollout with the new **Rehash** bolt-on. Residential quotes can now require a saved Rehash disposition, unsold quotes can auto-enroll into the staged win-back sequence, managers get a dedicated `/admin/rehash` queue with text, call, email, touch, dead, and re-quote tools, and the new Rehash analytics page tracks recovered revenue plus saved recovered-close attribution. - Hardened the residential Red Line rollout after another audit pass. Residential estimates now fail closed to standard pricing when an assigned rep record can no longer be resolved instead of borrowing Red Line access from whoever happened to open the quote, explicitly enabled non-sales teammates now appear in the residential rep-assignment list, and the Commissions dashboard now keys its **Red Line** badge off the saved Red Line snapshot instead of assuming every stored commission amount came from Red Line. - Began Phase 2 of the residential Red Line rollout. Residential reps can now save below-floor drafts when manager override tracking is enabled, request a Red Line override directly from the estimator, and owners or managers can approve or reject that request from the review step or the estimate detail page before the quote is allowed to send. ## 2026-04-18 - Added background autosave to the residential estimate wizard for internal office users. New and edited residential drafts now save as you work instead of waiting for Step 3, pending changes are flushed if the office clicks away right after editing, the review/send tools reuse that same saved draft, and service or add-on price overrides can be typed directly into the estimator instead of relying on browser spinner arrows. - Tightened CRM navigation and lead handoff workflows. New leads now open directly on their detail page after creation, estimate/job/invoice workspaces now include clearer **View Client** shortcuts, and lead-launched residential estimates keep the linked customer context without forcing duplicate data entry. - Expanded the mobile sales flow into a close-ready proposal detail experience. Reps can now open a secure customer-facing proposal from mobile, hand the device to the customer for on-the-spot acceptance and signature, and launch either a 25% deposit checkout link or a full-balance payment link without leaving the proposal screen. - Added `sales_rep` access to the mobile payment-link creation endpoints so sales users can launch hosted Stripe Checkout links from proposal detail instead of waiting on a manager or crew-lead role. - Broadened the mobile proposal shell to recognize all live estimate wizard families. Dashboard cards, proposal lists, and client proposal history now normalize commercial building, generic quote, asphalt maintenance, residential, fleet, and holiday-lights estimates correctly instead of hiding unsupported module types behind fallback labels. - Added guided mobile web handoff cards for **Generic Quote** and **Asphalt Maintenance**, so sales reps can still launch those live quote builders from the app and then come back to mobile proposal detail for presentation, signature, and payment follow-up. - Fixed the mobile **Present and Close** handoff to prefer the live customer estimate view before the legacy proposal path. That keeps holiday lights, fleet, commercial building, asphalt, and other quote-core-backed estimates from opening a dead-end customer URL when reps launch the close flow from mobile. - Fixed the residential mobile builder entry path to reset correctly when starting a brand-new proposal, preventing old in-memory quote state from bleeding into the next residential estimate. - Fixed a CRM handoff gap when launching residential estimates from lead and client context. **New Estimate** actions now carry the linked client, lead source, service address, and saved property square footage into the wizard automatically so the office no longer has to re-enter customer details after starting from a lead or client record. - Made the Red Line rollout easier to understand during setup. The residential estimator now shows an inline notice when Red Line is hidden because the workspace setting is off or the assigned rep is on standard pricing, and the Team / estimate-assignment lookups now fail soft in older workspaces that have not finished the Red Line membership migration yet. ## 2026-04-17 - Added the first Red Line pricing foundation to the residential estimator. Floor pricing can now be derived from the live suggested service price instead of a separate flat table, so square footage, service size, and dirtiness all flow into the floor automatically before reps adjust pricing. - Added real-time Red Line estimator feedback for eligible users. Residential service rows can now show the floor, status, and commission context while pricing, review screens carry that same information forward, and the API now rejects attempts to save Red Line estimates below the floor. - Added the first admin controls for the Red Line rollout. Pricing Manager now includes a Red Line section for workspace-wide toggles, commission percentages, and per-service floor percentages, while Team Management now includes a per-user Red Line access toggle for mixed-comp teams. - Started persisting Red Line payout data with residential estimates and canonical line items so the Commissions dashboard can use explicit commission amounts and flag those rows as **Red Line** instead of relying only on the older 5% / 10% lead-source model. - Followed up on the Red Line rollout after the local audit. Residential estimate saves now keep `redline_snapshot` populated even for standard-pricing deals, the estimator and API now resolve Red Line access from the assigned sales rep instead of whoever happens to be editing the estimate, and team role changes now reset the Red Line access toggle to that role's default instead of leaving stale settings behind. ## 2026-04-14 - Hardened the first Lead Connectors rollout after the local audit pass. Public website-form connector endpoints now enforce an IP bucket before the contact-aware rate limit, review-queue items can only be approved or rejected once, connector import-run logging now has database-level replay guards on external ids and idempotency keys, connector-backed API imports preserve explicit `existing_client_id` handoff into the shared lead-intake pipeline, and CE Pro now enforces one active connector per provider/transport pair instead of silently choosing the oldest active record. - Tightened email-forward lead parsing so phase 1 now requires an active email-forward connector before inbound emails can auto-create leads. Low-confidence email candidates continue to pause in the review queue when a connector threshold is configured, but the old no-connector parser fallback no longer creates leads on its own. - Added the first phase of the new **Lead Connectors** platform in **Settings > Integrations**. Workspaces can now configure connector-driven lead intake for trusted API imports, browser-safe website forms, and forwarded email parsing from one shared admin surface instead of treating every source like a separate custom integration. - Added connector-level field mapping, defaults, test imports, recent import history, and a low-confidence email review queue. Teams can now normalize outside field names into CE Pro lead fields, apply source or assignee defaults, test the connector before launch, and approve or reject uncertain parsed emails before they become live leads. - Hardened duplicate suppression for connector-based lead intake by carrying external ids and idempotent request keys through the shared lead pipeline, while the docs now include a dedicated **Lead Connectors** guide and updated integrations onboarding steps. ## 2026-04-10 - Canonicalized authenticated web entry points to the dedicated app host. Marketing-site **Log In** and direct admin links now send users to `app.cleanestimate.pro`, root-domain requests for `/admin`, `/login`, password reset, and auth callback routes now hand off to the app host automatically, and invite plus recovery emails now generate their setup links on the same app subdomain instead of mixing root-site and app-site entry paths. ## 2026-04-08 - Hardened the Esendex phone rollout right after the first audit pass. Voice transfer scripts now preserve the provider command syntax Esendex expects, voice status callbacks now reuse the tokenized webhook URL contract shown in Settings instead of drifting from protected environments, and the **Phone / Voice** setup now clearly stays on text-to-speech greetings for Phase 1 instead of advertising custom audio playback that is not live yet. - Replaced the old Twilio-shaped phone setup with Esendex across the app and docs. Workspaces now configure a shared Esendex number, SMS license key, and Voice license key from the **Phone / Voice** settings card, while the docs now point to the new Esendex setup guide instead of the retired Twilio instructions. - Shipped the Esendex phone stack for daily office use. Shared SMS sends and replies now run through Esendex, inbound customer calls transfer to the saved office line, missed calls log into **Messages**, and the phone timeline now uses provider-neutral message and call ids instead of depending on Twilio-only SIDs. - Updated automation call behavior for the Esendex rollout. **Make Call** and **Voicemail Drop** now use the shared Esendex number, phone triggers now cover `Call Received`, `Call Answered`, `Missed Call`, and `Call Completed`, and the docs now clearly mark AI Voice Agent and inbound voicemail recording playback as out of scope for this Phase 1 release. ## 2026-04-05 - Smoothed another big chunk of the mobile page-by-page QA pass. Proposal builders now keep the residential step state in sync without mutating state during render, the standalone proposal detail screen now has working call, email, and maps actions plus a proper back header, the estimate-type picker now gives reps clearer field-quoting guidance with step counts, the dashboard sync indicator now behaves like a real queued-sync shortcut instead of a dead notification bell, and client notes save more reliably when a rep leaves the notes field. - Fixed the mobile client detail and proposal shells so they line up with the live estimate data model instead of a stale proposal-table contract. Client detail now pulls proposal history from current estimate records, proposal lists stop breaking when you scroll or refresh, and remote proposal cards no longer show fake `0%` margin badges when margin data is unavailable. - Reworked the mobile pipeline around what field users can actually act on. Pipeline cards now normalize service labels correctly, the summary bar shows **Needs Follow-Up** instead of a misleading always-zero average margin metric, empty pipelines explain what to expect, and the deal detail sheet now gives real proposal, call, and email actions when contact data exists. - Cleaned up the mobile account/settings shell on phones. The **Settings** hub now opens on a safer padded account card with organization context, and the Profile, Organization, Notifications, Offline, and About screens now respect the safe area so content no longer crowds the top system chrome on smaller devices. - Fixed the first mobile startup blockers that were making the current Expo shell feel dead on arrival during testing. The app no longer crashes during startup because of WatermelonDB model field syntax, the web-safe auth storage path now avoids the `expo-secure-store` failure on browser-based QA runs, and the tab shell no longer registers the **Jobs** tab against the wrong nested route. - Refreshed the mobile auth flow so the first-run experience looks intentional instead of bare. The sign-in and forgot-password screens now use branded intro and recovery cards, stronger spacing, proper input chrome, and consistent action buttons instead of the older stacked text-and-button layout. - Cleaned up the mobile dashboard shell for small screens by removing the duplicate tab header and replacing the cramped quick-action strip with larger proposal-type cards that hold up better on phone-width layouts. - Fixed the mobile auth shell so route protection now lives in the nested auth and app layouts instead of firing redirects from the root navigator. Internal beta testers should no longer see the startup/login warning banner that previously made the Android dev client feel broken before they even signed in, and the local debug build now suppresses the two known development-only native-library warnings that were still pinning a generic warning bar to the bottom of the login screen. ## 2026-04-04 - Hardened the Clean Estimate Pro mobile internal beta for the current Expo app instead of splitting into separate iOS and Android codebases. Mobile preview builds now use the internal beta lane, the app reads the required public Expo/Supabase support config consistently, profile editing now writes back to the live user-profile schema, and field proposal drafts reopen through one shared deep-link contract instead of occasionally landing on the wrong step. - Added the first crew-lite mobile ops slice behind scheduling. Eligible roles now get a dedicated **Jobs** tab, job-assigned notifications open the same typed job route as the rest of the app, job detail now reads the live customer/job fields correctly, and crews can review schedule, address, invoice balance, crew alerts, and payment collection from one mobile screen. - Replaced the remaining mobile residential placeholder pricing and tax assumptions with shared live config reads. The residential builder now applies the active web pricing config and shared state tax overrides, while the mobile **Pricing Defaults** and **Tax Rates** settings screens now act as read-only references to the same data sources the web app uses instead of writing to stale legacy fields. - Finished the crew-alert rollout on the current generic-quote and job stack. Generic quote line items now expose a dedicated internal crew-alert field again, estimate edit/save flows preserve that value, jobs created from those quotes keep the alert on each line item, and both the web job detail screen plus the mobile crew job screen now show a clear Crew Alerts callout without exposing those notes to customers. - Added internal crew-alert support to commercial building proposals, generic quotes, and downstream job detail views. Office staff can now save field-only instructions alongside customer-facing line-item descriptions, commercial building catalog adds prefer the shared price-book description when available, and both quote flows preserve crew alerts when drafts are reopened without exposing those notes on customer-facing proposals, quotes, or PDFs. - Made commercial building line-item descriptions actually visible and editable in the wizard as a dedicated **Customer Description** field, then backfilled clearer default scope copy across the stock commercial building services, seeded fleet vehicle types, and built-in residential add-ons so default catalog rows stop starting blank when they are reused in shared quote-core line items. Older commercial draft rows that were saved blank now also repopulate that customer description when the proposal is reopened. - Unified customer-facing item descriptions across the remaining quote builders. Residential services and add-ons now expose editable **Customer Description** fields in both the office wizard and the public standalone estimator, generic quote detail notes now render on the customer quote page and PDF, and fleet vehicle rows plus add-ons now carry editable customer descriptions through builder, review, customer proposal, and PDF flows. ## 2026-04-02 - Fixed the lead-creation modal launched from linked client records on shorter laptop viewports. The **New Lead** dialog now becomes vertically scrollable instead of trapping the save button below the fold when the selected-client flow expands with address and appointment fields. ## 2026-04-01 - Fixed a residential estimate save failure on quotes that included mirrored offer children such as proposal packages and maintenance plans. CE Pro now allows the residential offer-mirror workflow to persist multiple child estimate rows for the same parent quote instead of tripping the one-to-one source-proposal uniqueness rule that only applies to linked commercial, fleet, and holiday-lights estimates. - Followed that residential mirror hotfix through the rest of the office and platform surfaces. Revenue, service-mix, geography, retention, franchise, admin-alert, sales-rep dashboard, residential overview, commissions, estimate-list, marketing audience, sales follow-up schedule, and super-admin estimate rollups now treat mirrored residential offer children as internal support rows instead of counting them as extra quotes, so maintenance or package siblings no longer inflate analytics, stale-deal alerts, rep follow-ups, estimate lists, or back-office totals. ## 2026-03-31 - Tightened customer-engagement tracking across messages, quotes, and invoices. Public estimate, proposal, maintenance, and shared-quote opens now wait for the alert write instead of leaving those inserts as best-effort background work, so live admin popups are more reliable when a customer opens the document. - Added invoice-viewed engagement alerts to the hosted customer invoice page. Token-based invoice opens now log an `Invoice viewed` system event in the customer thread, update the invoice's first-viewed timestamp, and raise the same live popup plus alert-bell notification pattern used for proposal and quote views. - Expanded outbound email history in the Messages thread. Resend email webhooks now keep first/latest open timestamps, first/latest click timestamps, open counts, click counts, and the latest clicked URL on the outbound message metadata, while the thread UI shows those details directly under the email bubble instead of only a single `Opened` or `Clicked` badge. - Hardened Resend status syncing so later open events no longer downgrade a previously clicked email back to `Opened`. The email row now keeps the higher click state while still counting each additional open that Resend reports. - Made those customer-engagement events much more visible inside **Messages**. Quote, proposal, estimate, maintenance proposal, and invoice views now render as highlighted activity cards in the thread, and outbound emails now show a dedicated engagement panel for email opens and tracked link clicks instead of leaving that history buried in tiny status text. ## 2026-03-30 - Hardened the Twilio phone-call rollout after the first deep audit. Inbound conference callbacks no longer misclassify successful conversations as missed calls, voice recordings now post to the dedicated recording webhook instead of disappearing into the generic status callback, completed-call automations no longer fire on no-answer outcomes, voicemail drops now fail closed when a live human answers, and the legacy auto-dial migration now carries forward usable phone visibility before the old table is retired. - Added Phase 1 Twilio phone calling across CleanEstimate Pro. The shared Twilio number can now receive inbound customer calls, forward them to the office line, record voicemail, log call and voicemail events into the unified Messages timeline, and raise missed-call or voicemail alerts for the team. - Added Twilio voice support to the automation engine. Workflows can now trigger from `Call Received`, `Call Answered`, `Missed Call`, `Voicemail Received`, and `Call Completed`, and they can execute live `Make Call` and `Leave Voicemail` steps instead of treating those call nodes as unsupported placeholders. - Expanded the Phone / Voice settings and docs so operators can configure forwarding numbers, voicemail greetings, voice readiness, recording, and missed-call alerts from the same Twilio integration area used for SMS. - Fixed customer-engagement alerting around sent quotes and invoices. Proposal, estimate, and invoice emails now log under the live Resend provider id used by outbound delivery, older mismatched rows can self-heal when Resend open webhooks arrive, and the admin alert bell plus live popup feed now raise a new alert every time a customer opens the email or opens the proposal page itself across residential, maintenance, fleet, commercial building, and shared quote flows. Public quote and proposal pages now also ignore common crawler and link-preview traffic so bot fetches do not create false viewed alerts or premature viewed-state changes. - Fixed the new asphalt module entry path so it always opens the live editor. The canonical `/admin/asphalt-maintenance` route now forwards into the working asphalt quote builder, the admin route-permission guard recognizes that module path instead of redirecting it back to the dashboard, Quick Start uses that stable module path, and global search keeps a separate **New Asphalt Quote** action for the explicit create flow instead of leaving some clicks or bookmarks on a missing landing page. - Fixed the next asphalt send regression for older shared-manual drafts. When a generic or asphalt quote is missing its persisted `public_quote_token`, the send stack now seeds and saves that shared quote token before email/SMS delivery, so older drafts can still send with a working shared quote link. If secure signing is not configured, the customer still gets a view-only link instead of the office seeing a false "Secure estimate links are temporarily unavailable" error. - Fixed another customer-link delivery failure behind estimate sends. Quote, proposal, maintenance-plan, and shared quote link generation now fall back to the configured public site URL when the older dedicated app URL env is blank, so sends keep working instead of throwing a generic secure-link error during production config drift. - Followed that send hotfix with the remaining link and state-hardening pass. Holiday-lights sends now use the same public-site URL fallback as the other customer-link flows, and shared quote token repair now merges against the latest stored delivery state before it writes so newer payment or send-tracking metadata is not wiped while older drafts self-heal. - Fixed the next estimate-send troubleshooting blind spot. Office send errors no longer collapse unrelated delivery failures into the generic secure-link warning, so missing proposal data, missing maintenance plans, and email-provider setup issues now surface their own actionable messages while true customer-link setup problems keep the secure-link error. - Fixed the actual generic and asphalt send blocker behind that misleading warning too. Quote delivery no longer selects rollout-only pricing columns like `minimum_adjustment` and `taxable_amount` from the live `estimates` table before building the email, so workspaces on older production schemas can send quote emails again instead of failing the send before Resend is ever called. - Removed the last false secure-link warning on shared quote sends. If a quote already has a persisted public quote token, CE Pro now treats that shared `/quote/[token]` route as fully configured even when `CUSTOMER_TOKEN_SECRET` is missing, so successful generic, asphalt, residential, fleet, commercial building, and holiday-lights sends no longer tell the office the delivered link is only "view-only." - Hardened the new automation visual builder after the first live review pass. The canvas **Wizard** button and mobile fallback now route back into the real workflow edit screen instead of a dead `/wizard` URL, new drag-and-drop nodes save with UUID-safe ids, graph saves no longer briefly wipe all edges before rewriting them, and the save badge now shows **Save failed** correctly when a graph write errors instead of getting stuck on a stale **Saved** state. - Rebuilt the automation visual builder into a real graph editor instead of the old loose card pile. Workflows now return step positions and edge labels from the API, save the full graph through one dedicated graph endpoint, auto-arrange into a readable layered layout when positions are missing, preserve manual drag edits after save, and expose clearer canvas save states plus **Auto Arrange**, **Fit Workflow**, and **Reset View** controls. CE Pro also now surfaces the visual builder much earlier through **Open Visual Builder** on the new automation flow and **Build Visually** on template cards instead of hiding the canvas until after a workflow is already saved. - Built and activated a shared **Estimate Accepted** automation flow through the production automation builder so accepted estimates now trigger a customer thank-you email, a customer thank-you text, and an internal follow-up task for scheduling and next steps from one shared workflow instead of requiring per-module handoff rules. - Fixed the automation workflow detail page for newly created workflows. The single-workflow API now returns the same run counters and last-run metadata the overview cards expect, and the detail view now falls back safely if those metrics are still empty on a brand-new workflow. - Fixed the last live signature-save failure on commercial proposal acceptance. Fleet and commercial building proposal signatures now recreate the missing proposal-signature storage bucket automatically before retrying the upload, and CE Pro now has regression coverage across all three signature pipelines: shared estimate/quote signatures, commercial proposal signatures, and holiday-lights contract signatures. - Fixed the last shared quote acceptance-auth gap across estimate types. Shared `/quote/[token]` pages for residential, proposal packages, maintenance plans, fleet, commercial building, holiday-lights linked estimates, generic quotes, and asphalt quotes now treat the saved public quote token as a valid interaction token for signatures, package selection, maintenance acceptance, public PDFs, and deposit actions, so customers and office previews no longer see a false "online approval unavailable" state just because the server could not mint a separate customer-token URL. - Fixed the last public-acceptance preview mismatch across estimate types. Office-side **View Public Page** actions for fleet, commercial building, holiday-lights linked estimates, and the older raw estimate/proposal/maintenance routes now resolve the same valid customer-link contract used in sent emails and texts, so internal previews no longer fall into a read-only "online approval unavailable" state just because they opened from an older module URL. - Closed the last two module rollout seams found during a live cross-module smoke pass. Residential estimates now stay compatible with older `addon_structures` schemas that do not expose `created_at` yet, and holiday-lights draft saves now keep the shared estimate-list projection writing `delivery_state` as JSON so seasonal quotes no longer fail on partially upgraded production databases. - Fixed the fleet proposal create path after the quote-core rollout for older production schemas. Fleet and commercial proposal list-projection sync now write `delivery_state` as JSON again, so first draft saves from **Admin > Fleet > New Proposal** no longer fail on workspaces that still had the older estimate-list trigger definitions in place. - Tightened that fleet launch flow again so proposals opened from a lead now preload the lead source into step 1 and carry it through the first draft save automatically instead of dropping the source unless staff reselected it by hand. - Launched the Asphalt Maintenance module across the product and website. Teams can now create asphalt quotes from the office navigation, Quick Start, and global search, reopen them in a dedicated asphalt editor, publish the live asphalt marketing page, and keep asphalt quotes on the shared quote-core send, PDF, payment, and customer-link path instead of hiding that workflow as a proof-only slice. - Fixed the last shared-manual quote hardening gaps that surfaced during the asphalt rollout. Asphalt edits now fail closed instead of silently flattening back into generic quote data, untaxed shared manual quotes stay untaxed when reopened, maintenance acceptance copy uses the workspace brand instead of a hardcoded provider name, and the shared quote delivery-state alignment migration now handles already-JSONB projection rows safely during deploy. - Refined the admin workspace chrome again so XP now lives in the left sidebar between the workspace section and **Quick Start** on every admin page, while the page-level header keeps Search everywhere and only shows the duplicate **Help** and **Alerts** actions inside the content area on desktop. Mobile pages now rely on the fixed top bar for Help and Alerts instead of repeating those bubbles again inside the page body. ## 2026-03-29 - Started the asphalt maintenance proof slice for the unified quote core. CleanEstimate Pro now has a registered `asphalt_maintenance` wizard plugin plus shared global baseline price-book items for single-coat sealcoat, double-coat sealcoat, crack fill, line striping refresh, and patch repair, which proves a net-new estimate type can plug into the shared quote core without adding a new send stack, payment stack, public page stack, or quote tables. - Extended that asphalt proof slice into the shared manual-quote persistence path too. The asphalt quote builder can now prepare a real shared quote-core payload with `wizard_key = asphalt_maintenance`, shared payment/send/public compatibility, wizard-specific measurement snapshots, and asphalt document/review metadata without introducing a new estimate route or another bespoke quote save service. - Finished the next asphalt proof read path too. Office estimate lists, type counts, type filters, and estimate-detail edit actions can now surface wizard-backed asphalt maintenance quotes as their own estimate type instead of collapsing them into the generic quote bucket, while still routing those rows back into the shared quote editor correctly. - Tightened the asphalt proof edit/save round-trip. Reopened asphalt quotes now reload their description and internal notes from the `asphalt_maintenance` module namespace correctly, and asphalt canonical line items keep their own `source_wizard` plus shared `price_book_item_id` linkage instead of being flattened back through the generic quote normalizer during save. - Tightened the asphalt proof shared-quote lane too. Asphalt maintenance quotes now stay on the same shared manual quote path for customer links, public quote rendering, pricing normalization, send-time generic detection, and PDF selection instead of depending on `generic`-only checks that could miss wizard-backed manual quotes. - Finished the last shared-manual asphalt office blind spots. Asphalt-backed quotes can now reopen through the shared office quote editor without failing the old `estimate_type = generic` filter, the shared estimate create/update routes now keep asphalt on the shared manual lane instead of falling back to residential-only assumptions, and office-side send copy now uses asphalt-specific quote wording when staff send those quotes from the shared editor. - Tightened that last shared-manual send layer again so asphalt quote sends now record `asphalt_maintenance_quote` in shared delivery history and quote events instead of being mislabeled as generic, and shared manual-quote delivery now falls back to a neutral sender label if the workspace name cannot be loaded instead of defaulting to another provider's brand name. - Fixed another final quote-core data-contract batch: shared public quote token lookups now use the indexed quote-token expression instead of a slower JSON containment scan, the estimate-list projection now stores shared delivery state as JSON so payment fallback badges keep reading the live quote payment metadata, asphalt zero-footage drafts no longer create a phantom `$0` sealcoat row, and canonical total math now preserves non-taxable line-item value when a taxable subtotal is supplied separately. - Fixed the shared price-book settings rollout for existing workspaces. Older orgs now backfill their active residential pricing under the same nested `residential_pricing_config` key the quote-core readers expect, so the move into shared price-book settings preserves current pricing instead of silently snapping those workspaces back to the platform defaults. - Extended quote-core payment tracking on estimates. Stripe pay-link creation, successful estimate payments, and office-recorded estimate payments now write shared quote payment metadata and payment-state history onto the canonical estimate record, which keeps shared quote links, office payment follow-up, and quote event history aligned with the actual balance state. - Hardened that estimate payment sync again so it now merges against the latest shared quote delivery state before it writes. A payment update no longer risks overwriting newer shared quote-link or send-history metadata that landed a moment earlier on the same estimate. - Finished the next estimate-payment unification step by teaching the public estimate page, shared quote page, and office estimate list to fall back to the shared quote-core payment state when the older flat estimate payment columns are stale. That keeps payment badges and pay-link actions aligned with the latest quote delivery/payment history during the rollout. - Accepted residential maintenance agreements now keep their linked recurring templates aligned after later office edits too. If the team changes an already accepted maintenance estimate, CE Pro resyncs the recurring job-template series from the updated maintenance plan instead of leaving future recurring visits on the older scope. - Removed a redundant second residential package-offer hydration during customer package selection. Signed package accepts now validate from one shared offer-core pass instead of doing the same database rehydrate twice inside the public proposal-selection flow. - Pricing Manager saves, restores, onboarding pricing setup, and org bootstrap now all keep the active residential pricing config mirrored into the workspace default price book. That means the shared quote-core price-book layer stays current immediately after an office pricing change instead of waiting for a later catalog repair to catch up. - Fixed another holiday-lights quote-core reporting gap. The first customer open on a holiday-lights quote now advances the seasonal source quote itself from **Sent** to **Viewed** instead of only stamping the viewed timestamp, so holiday-lights list filters, viewed-status dashboards, and seasonal reporting stay aligned with the real first open. - Tightened that holiday-lights lifecycle again so **Viewed** quotes still stay resendable from the office, shared `/quote/[token]` opens record as shared-quote opens instead of portal-only opens in the seasonal activity trail, and traced zone-based draft edits no longer fail just because the manual linear-feet field was left at zero. - Continued the shared offer-layer migration for residential quotes. Customer dashboard links, customer estimate-list links, portal proposal lookup links, and office resend/SMS offer routing now all classify residential package proposals versus maintenance offers through one shared offer rule instead of each surface re-checking the old parent estimate JSON on its own. - Started the next shared offer-layer ownership cut for residential package proposals. Customer package selection now rehydrates proposal options from the mirrored `estimate_offer_groups` records before it validates the request, so signed customers can still accept the right package even when the rollout has already moved those proposal options off the parent estimate JSON. - Pushed that residential offer-layer ownership further into acceptance flows. Customer maintenance-agreement approvals, maintenance proposal PDF preparation, and customer package acceptance now keep the linked child offer quotes in sync with the parent estimate state so later reads, sends, and recurring-template automation stay aligned to the same accepted offer. - Moved another holiday-lights ownership seam behind the shared quote-core services. Holiday-lights create/edit routes now reuse one shared draft-save path for pricing recalculation, linked-estimate sync, design updates, and bundled power-wash linkage, office or customer **Declined / Expired** actions now write the matching shared quote event onto the linked estimate instead of stopping at the seasonal source record, and holiday-lights opens through the shared `/quote/[token]` page now feed their viewed timestamp and seasonal pipeline move back into the source seasonal quote too. - Reworked the shared price-book foundation so CE Pro can carry one platform-wide default price book and keep each organization's custom default book private. Catalog bridges still write org-local custom books during the migration, but shared fallback reads can now land on the global default baseline when an org has not customized its own book yet. - Tightened that shared pricing model again so org-specific price-book reads now behave like overrides on top of the shared default book instead of an all-or-nothing switch. If one workspace customizes a shared catalog item, CE Pro keeps that override private to that workspace while untouched shared items still inherit from the global baseline. - Hardened that overlay model again so shared baseline price-book items still participate in residential lookup and repair flows even after an org-specific sync runs, non-legacy org overrides can replace shared defaults cleanly by name, and hourly fleet vehicle pricing now keeps its minimum quoted price when it round-trips through the shared price book. - Moved another commercial ownership seam into the shared quote-core layer. Fleet and commercial building draft edits now let the quote services own status-field bookkeeping and linked-estimate sales-transition logging, while commercial proposal send routes now reuse the shared quote-link preparation helper instead of rebuilding customer URLs in each route. - Followed that pricing-foundation change with a tighter residential catalog write path. Residential service, add-on, and custom-template admin saves now update only the touched shared price-book rows instead of rebuilding the whole residential catalog bridge after each edit, while still rolling the legacy save back if the shared price-book write fails. - Tightened recurring maintenance-template sync so CE Pro no longer re-ends already-ended recurring templates every time a maintenance agreement is reaccepted or resynced. Historical ended templates now keep their original `ended_at` audit trail unless they are actively being changed again. - Tightened the fleet and commercial linked-estimate bridge again so draft saves now treat canonical quote-core line-item sync as part of the save itself. If the linked estimate cannot keep its canonical line items aligned, the draft save rolls back instead of leaving the proposal tables ahead of the shared quote workspace, and older linked-estimate fallback writes now reuse the existing estimate number instead of creating duplicate orphaned estimates on retry. - Followed that with another ownership cut for fleet and commercial building drafts. Those draft-save services now own the linked shared estimate write directly and only use the old `sync-to-estimates` path as a compatibility loader wrapper, which keeps the proposal save and the shared estimate workspace on one tighter success-or-rollback path. - The **Create Recurring Template** shortcut on accepted fleet and commercial building estimates now prefers canonical quote-core line items from the linked estimate workspace and carries the source estimate id into the saved recurring template. That keeps recurring-template prefill aligned with the shared quote-core breakdown, gives later recurring automation a direct quote-to-template link to follow, and surfaces the source quote link directly on the recurring-template list and detail screens. - Accepted residential maintenance agreements now create linked recurring job templates automatically. CE Pro seeds one recurring template per repeating seasonal visit pattern from the shared maintenance offer quote, rolls the public maintenance-accept action back if that recurring-template setup fails, and records the quote-core conversion so recurring residential work starts from the same canonical quote data instead of a manual rebuild. - Tightened the commercial catalog bridge so fleet vehicle-type saves plus commercial building service/surface-type creates now fail closed if the shared price-book write cannot be completed. Instead of quietly updating only the old settings tables and leaving `price_book_items` stale, CE Pro now rolls those admin changes back and surfaces a real save error. - Applied that same fail-closed catalog rule to the residential and holiday-lights admin settings paths too. Residential service, add-on, and custom-template writes, plus holiday-lights inventory creates and edits, now roll back if the shared price-book bridge cannot be updated instead of silently leaving the legacy catalog tables ahead of the unified quote-core catalog. - Narrowed those shared catalog writes again so fleet vehicle types, commercial building service/surface types, and holiday-lights inventory now update only the touched shared `price_book_items` rows instead of rebuilding each module's entire shared catalog bridge after every admin mutation. - Tightened the shared commercial quote-link handoff so fleet and commercial building resends now reuse the saved `/quote/[token]` link from the linked estimate workspace before falling back to an older signed estimate URL. If the linked commercial source record can no longer be reloaded, the shared quote route now fails closed instead of showing the wrong residential/generic page. - Fixed commercial customer totals so fleet and commercial building proposal views only apply tax when the saved proposal actually includes a tax rate. Blank tax proposals no longer assume a default 6% tax on the public page, and recurring building portfolio summaries now use the saved maintenance visit pricing in the per-visit totals instead of quietly showing the one-time initial-clean price there. - Moved residential estimate updates from `PATCH /api/v1/estimates/{id}` onto the shared residential quote-core save path, so supported API-side updates now preserve canonical quote snapshots, canonical line-item sync, delivery-state metadata, and shared quote events instead of bypassing that newer persistence layer. - Hardened the shared estimate send and status routes before more wizard families move onto them. Holiday-lights sends from linked estimate workspaces now stay on the seasonal delivery helper, office-side estimate status changes now require estimate permissions inside the active workspace, and commercial linked estimates now refuse the wrong shared send path instead of silently using the residential sender. - Shared estimate and quote public pages now show the workspace organization name or a neutral product fallback instead of a hardcoded Rolling Suds label, so customer-facing public links stay correctly branded across workspaces during the quote-core rollout. - Expanded the shared quote page into the first commercial linked-estimate slice. Fleet and commercial building linked estimates with persisted public quote tokens can now open through `/quote/[token]`, and the shared route renders the matching commercial proposal layout instead of forcing those linked-estimate previews back through legacy signed estimate URLs. - Wired holiday-lights linked estimates more directly into that same shared public-token model by carrying the source seasonal estimate id on the linked estimate row, so shared quote-core public links can rebuild the holiday-lights summary when office or customer flows open the linked estimate outside the dedicated portal send path. - Followed that holiday-lights public-link rollout into delivery too. When a linked holiday-lights estimate already has a persisted public quote token, CE Pro now delivers the shared `/quote/[token]` URL in seasonal email and SMS sends instead of defaulting back to the older portal link, while still keeping the portal as the fallback path if the shared quote link is not ready yet. - Tightened shared delivery again so quote SMS sends no longer fall back to a broken unsigned estimate URL when secure customer-link generation is unavailable, and holiday-lights email/SMS delivery events now stay linked to the originating estimate record for cleaner communication history. - Fixed a fleet quote-core regression that could show optional `$0.00` add-ons as real estimate line items. Non-included fleet add-ons now stay out of the shared estimate breakdown unless they actually carry a billed price, while intentionally included add-ons still render as included items. - Fixed commercial building custom-item pricing in the shared quote core so quantity-based custom service rows now derive a real per-unit rate from the saved total instead of copying the whole line total into `unit_price` and breaking downstream math. - Finished another residential offer-layer hardening pass across the summary surfaces. Customer dashboards, customer estimate lists, portal proposal lookups, and the office estimate list now rebuild residential package-proposal and maintenance-plan classification from the mirrored shared offer records instead of relying only on the legacy parent estimate JSON, so those links and badges stay correct during the quote-core migration. - Fixed one more legacy residential handoff into the shared quote page. Older `/p/[id]` public links now preserve whether the customer opened a base estimate, package proposal, or maintenance proposal when they redirect into `/quote/[token]`, which keeps quote-view analytics aligned with the original public context. - Tightened the shared residential quote page so it now behaves correctly in read-only mode. If secure customer-token signing is temporarily unavailable, customers can still open the shared quote link to review pricing and scope, but package selection, maintenance-plan approval, and customization actions stay hidden instead of failing after the click. - Preserved residential proposal and maintenance-plan analytics when those older public links hand off to the shared quote page. Proposal-option links and maintenance-plan links now keep their own public-view context, so reporting and follow-up history no longer collapse those opens into a generic quote-view event. - Moved another residential offer-layer read seam onto the shared quote core. Residential customer/public reads can now rebuild proposal-option and maintenance-plan data from mirrored `estimate_offer_groups` child quotes, so those pages stay aligned to the shared offer model even while the older parent-estimate JSON remains in place for compatibility. - Extended that residential offer-layer hydration into customer actions and document reads too. Residential package selection, residential send classification, and maintenance-plan PDF reads now rebuild proposal-option or maintenance-plan state from the mirrored shared offer records before they decide which package flow, send path, or maintenance document to use, which keeps those actions aligned with the shared offer model during the migration. - Hardened the shared commercial proposal lifecycle helper so accepted fleet and commercial-building proposal writes stay org-scoped just like the shared send path, which reduces the chance of future cross-workspace drift as more commercial flows move onto the quote core. - Hardened the next Sprint 8 ownership seam too. Fleet proposal PATCH requests now strip unexpected fields before they hit the shared draft-save service, fleet linked estimates keep `lost_notes` aligned with the proposal workspace, residential shared price-book lookups now honor org overrides correctly in their item-id resolution path, and commercial resend prep now preserves the same shared quote token plus linked-estimate send history even if the status flip hits a transient failure. ## 2026-03-28 - Started the remaining commercial catalog bridge into the shared price-book foundation. Fleet vehicle types plus commercial building service/surface catalogs now read through the shared `price_book_items` layer when available, and the matching admin create/update/delete routes refresh that shared catalog copy after legacy commercial settings writes so the next wizard migrations can stop depending on standalone catalog tables. - Tightened that commercial quote-core bridge so fleet and commercial building linked estimates now preserve the real shared `price_book_item_id` on their canonical line items for bridged vehicle and service catalog rows instead of only copying the catalog metadata into the linked estimate snapshot. - Filled in another shared quote-event gap for commercial quote-core migration. Fleet and commercial building draft create/edit saves now write quote-core `created` and `saved` events on their linked estimate records as soon as the linked estimate sync succeeds, so commercial draft activity shows up in the same event stream the generic, residential, and holiday-lights quote flows already use. - Moved fleet and commercial building draft-save ownership into shared quote-core services instead of leaving the full persistence choreography inline in the proposal routes. Those draft saves now complete linked-estimate sync before the API returns, and they roll back more cleanly if the shared estimate workspace cannot be updated, which keeps commercial proposal drafts and their linked estimate records from drifting apart during save failures. - Moved the public fleet and commercial building signature routes onto one shared commercial acceptance helper. Both proposal types now use the same signature upload, accepted-alert, pipeline, linked-estimate sync, and accepted-estimate follow-up path, which keeps customer signatures resilient even when later follow-up bookkeeping has a temporary issue. - Moved fleet and commercial building proposal send follow-up onto one shared quote-core helper too. Those proposal sends now refresh the linked estimate workspace before the API returns, and the shared estimate record now writes its sent-event and send-history state from the same commercial send path instead of relying on a best-effort background sync after delivery. - Moved commercial accepted follow-up onto the shared quote-core path for both customer signatures and office-side won-stage actions. Fleet and commercial building proposals now sync the linked estimate workspace and reuse the same accepted follow-up automation path whether the proposal was signed publicly or marked won from the internal commercial pipeline. - Moved the first public fleet and commercial building proposal view onto one shared quote-core helper too. Customer opens now record the source proposal view, pipeline movement, linked-estimate viewed status, and shared quote event from one path instead of depending on a best-effort linked-estimate sync after the public page already rendered. - Started the holiday-lights quote-core bridge too. Linked holiday-lights estimates now normalize through a dedicated wizard plugin and write canonical shared quote-core line items plus quote snapshots, so the shared estimate workspace can carry a structured holiday-lights breakdown instead of only the older compatibility JSON line-item snapshot. - Followed that holiday-lights bridge with a V2 pricing alignment pass. Zone-based holiday-lights quotes now sync their linked estimate totals from the saved 1-year or 3-year contract term instead of the old midpoint install range, the office editor reopens with the saved contract term and proposal media intact, and holiday-lights design records now keep the proposal media payload alongside the design snapshot. - Extended that holiday-lights selected-term pricing alignment into the rest of the office surfaces too. Holiday-lights send copy, AI review totals, sales-cycle math, client-detail totals, and revenue / lead-source reporting now use the saved 1-year or 3-year contract price before falling back to the older low/high range fields, so the number the office sees stays aligned with the customer’s actual contract term. - Moved holiday-lights accepted follow-up work onto the same shared quote-core acceptance helper used by the newer estimate flows. Customer accepts and office contract-sign actions now re-sync the linked estimate workspace first, then reuse the shared accepted-event, pipeline, webhook, gamification, and accepted-job follow-up path instead of keeping a separate seasonal acceptance branch. - Tightened that holiday-lights acceptance bridge so customer status changes and office contract signing now update the source seasonal quote through the same shared helper too. The holiday-lights sales pipeline records the acceptance from one path, and already-accepted quotes no longer rewrite `accepted_at` when a contract record is patched later. - Started the holiday-lights inventory catalog bridge into the shared price-book foundation too. The office inventory list and holiday-lights dashboard low-stock count now read shared bridged SKU rows when they exist, and holiday-lights inventory create/update actions refresh the shared `price_book_items` copy after legacy SKU writes so that catalog can migrate onto the same shared pricing infrastructure as the other estimate wizards. - Moved holiday-lights quote sending onto the same shared review-and-send path used by the other estimate wizards. The admin holiday-lights quote page now opens the shared double email/text modal before anything is sent, seasonal send completion now writes linked-estimate send history and sent quote events from the quote-core path, and holiday-lights sends keep their portal link instead of falling back to the standard residential customer page. - Moved holiday-lights portal quote viewing onto the shared quote-core path too. When a customer opens the holiday-lights portal from a delivered quote link, the latest open seasonal quote now records its viewed timestamp, public pipeline move, and linked-estimate viewed event from one shared helper instead of leaving those portal opens outside the unified quote send/view history. - Started the unified quote-core foundation under the existing estimates system and migrated generic quotes onto the first shared slice. Generic quote saves now write canonical quote metadata plus canonical line items, preview/send/open actions all reuse one persisted customer quote link, and the shared `/quote/[token]` page is now the source of truth for generic quote delivery and acceptance. - Hardened that first generic quote-core slice so generic quote edits no longer silently reset sent quotes back to draft, quote send/view/accept activity now records as **Generic Quote** instead of leaking into residential pipeline history, and the shared `/quote/[token]` page now stays viewable in read-only mode when customer-link signing is not configured instead of crashing on open. - Tightened the local quote-core foundation before Phase 2 so the new quote tables now carry org-scoped access policies, the three-axis quote fields are written by both residential and synced module estimate writers, generic quote send history only records channels that actually delivered, and the shared generic quote page now shows the workspace organization name instead of a hardcoded brand label. - Closed another generic quote-core cleanup pass before Phase 2: generic quote creation no longer burns two estimate numbers per save, generic edit saves now preserve numeric estimated-hours values from string-based form posts, tenant scoping was added to canonical line-item rollback reads, and the generic send flow now refuses to deliver a quote when no working customer link can be generated. - Started the residential catalog bridge into the shared price-book core. Residential estimator entrypoints and the services/add-ons/custom-template admin reads now hydrate through the shared price-book-backed catalog layer, keeping the office and public residential wizard aligned to one normalized catalog surface while the legacy pricing screens remain in place. - Added the first residential wizard plugin under the shared estimate-core registry and started feeding residential estimate saves into the canonical quote line-item table. Residential create/update still preserve the legacy estimate fields and line-item snapshot for compatibility, but the shared quote core now receives the residential service/add-on/custom-item breakdown too. - Hardened that residential bridge so estimator page loads now read the shared residential catalog without trying to resync the price book on every render, public residential estimators now merge partial pricing configs with the same defaults used by the office flow, and canonical residential line items now carry real shared price-book item links instead of saving as unlinked shadow rows. - Finished another residential quote-core hardening pass so estimate edits now persist roof, gutter, and saved measurement-source fields correctly, add-on rebuilds match stored selections by label instead of fragile array position, and PDF/email regeneration waits for the canonical residential line-item sync before it rebuilds customer-facing documents. - Followed that residential hardening pass with safer rollback behavior when quote-core sync fails during save, and kept template-based custom items linked to the shared residential price-book rows even though editable custom items use runtime-generated row ids in the estimator UI. - Moved residential estimate create/update onto the shared quote-core persistence layer instead of leaving save ownership inline in the residential API routes. Residential writes now save quote snapshots and quote events alongside the canonical line-item sync, residential send plus public view flows now write the same shared delivery-state and quote-event telemetry used by generic quotes, and API-created residential estimates now land on that same shared quote-core path too. - Continued the quote-core migration by moving accepted-side effects onto one shared helper for generic and residential estimate flows. Customer signatures and accepted-status updates now share the same event logging, webhook dispatch, pipeline history, gamification credit, and accepted-estimate automation path instead of duplicating those follow-up actions in separate route branches. - Extended that shared residential acceptance path into customer package selection too. When a signed customer accepts one of the residential proposal options, CE Pro now runs the same accepted-event, pipeline, webhook, gamification, and accepted-estimate automation flow instead of only overwriting the selected package totals on the estimate row. - Extended the shared quote-core public link model into residential base estimates too. New residential saves now keep a persisted public quote token in `delivery_state`, office/customer open actions can reuse the shared `/quote/[token]` page for the base estimate, and the shared public quote page can now render residential estimates alongside generic quotes while proposal-option and maintenance-plan pages remain on their specialized screens. - Started the residential offer-layer bridge under that same quote-core rollout. Residential proposal options and maintenance plans now mirror into hidden child estimates plus shared `estimate_offer_groups` / `estimate_offer_members` records, and customer proposal-package picks or maintenance-plan decisions now keep those shared offer pointers in sync even though the current residential public pages still render from the legacy JSON fields for compatibility. - Moved the next residential customer-link slice onto the shared quote page. When a residential estimate already has a persisted public quote token, the legacy `/estimate`, `/proposal`, `/maintenance-proposal`, and unified `/p/[id]` customer links now redirect into the shared `/quote/[token]` experience so the customer sees one quote page with the estimate, package-option, and maintenance tabs instead of separate residential public readers. - Pulled another commercial quote-core seam into shared ownership. Fleet and commercial building proposal sends plus public acceptance now reuse the same shared lifecycle writer for source-proposal status updates, sales transition logging, pipeline advancement, and linked-estimate follow-up instead of each path maintaining its own copy of that lifecycle bookkeeping. - Started the first fleet quote-core migration slice under the existing commercial proposal flow. Fleet linked estimates now normalize through a real `fleet` wizard plugin and write canonical shared quote-core line items, so the estimate workspace tied to a fleet proposal keeps a structured fleet service/add-on breakdown instead of only the older compatibility JSON snapshot. - Extended that same quote-core bridge pattern into commercial building proposals. Linked commercial building estimates now normalize through a dedicated wizard plugin and write canonical per-property service line items, so the shared estimate workspace holds a structured building-service breakdown instead of relying only on the older compatibility snapshot. - Restored the owner-facing **Admin > Bug Reports** inbox so it no longer disappears when ownership records are reordered, and widened that inbox back to the owner's accessible org scope so bug reports from any managed workspace keep rolling into the same review queue instead of narrowing to only the currently switched child workspace. - Added direct **Residential** and **Holiday Lights** shortcuts to the main **Settings** hub so those workspace pages are easier to find without adding more permanent items to the left sidebar. ## 2026-03-27 - Consolidated residential estimates, generic quotes, holiday lights, fleet proposals, and commercial building proposals onto one shared review-and-send modal. The office now edits the email and SMS copy in the same module everywhere, generic quotes no longer fire immediately without review, and the residential plus holiday-lights send routes now honor the edited email/SMS copy instead of silently falling back to their old defaults. - Fixed the fleet proposal Review & Send margin mismatch so the review summary and AI review now use the saved quote's real fleet pricing, wash-time assumptions, visit schedule, and fleet cost settings. The old hardcoded preview calculator that could show a healthy gross margin while the quote was actually below target is gone, and seasonal proposals now use the full quote mix instead of only one season's visit math. - Hardened estimate and invoice attachments so uploads now accept a defined set of images, PDFs, TXT or CSV files, and common Word/Excel/PowerPoint documents, then verify the uploaded bytes before saving. Renamed or mismatched files are rejected with a plain-language message instead of being stored anyway. - Tightened another production error-handling pass across sign-in, review-request creation, estimate-list fallback loading, photo deletes, and attachment deletes. Those flows now keep raw auth, storage, and database details in server logs while the operator sees the shorter action-oriented message. - Moved Jobs and Invoices tag filters fully into the database join path instead of loading every matching client id into app memory first, which makes tagged list views hold up more cleanly in larger workspaces. - Fixed the Google Places address dropdown inside the office lead and client dialogs so staff can click an autocomplete suggestion directly again instead of having to use the keyboard to apply it. - Fixed fleet proposal draft creation when the client is prefilled from a lead or native CRM record. The fleet save flow now creates or reuses the correct proposal-side contact automatically instead of failing until the office switches to a custom manual client, and it no longer rewrites another saved proposal contact just because two records share the same office email or phone. - Fixed the Fleet Inventory step so active org vehicle types load with the full pricing/category data the wizard expects, while the fleet read path now stays limited to fleet/commercial readers instead of exposing fleet pricing and margin settings to broader estimate-only roles. - Reworked the admin header search into a more compact trigger so the command palette still opens from the top rail or `Cmd/Ctrl` + `K`, but the workspace chrome no longer leads with the oversized search field. - Fixed seasonal fleet proposal totals across review, customer view, and PDF export. Saved fleet drafts now persist their month-range schedule split, seasonal biweekly service now counts as two visits per configured month instead of averaging to an extra visit, and regenerated proposals keep the same annual math after reopen or resend. - Reworked fleet proposal PDFs so seasonal pricing now prints as separate standard and alternate schedule sections, while the Scheduling & Service Plan page lists every service month in the split cadence instead of collapsing the whole year into one generic frequency line. - Fixed commercial building and fleet proposal PDF cover dates so saved date-only proposal records print on the correct calendar day instead of shifting backward by one day in U.S. time zones. - Added editable commercial proposal default terms in **Admin > Commercial > Settings** for both fleet wash and commercial building proposals, then wired those defaults into the PDF generators whenever a proposal does not override its own terms. The main **Settings** workspace and left navigation now expose the commercial dashboard/settings routes more directly, while **Admin > Fleet > Settings** keeps the fleet-specific setup tabs and links into the shared proposal-defaults editor. - Hardened the public commercial and fleet signature flow so customers can no longer accept those proposals without a valid saved signature image. Signed-proposal bell alerts now refresh live in the admin header, accepted-alert writes retry before giving up, and downstream activity/pipeline/automation hiccups no longer turn a completed customer signature into a false failed-sign result after the proposal is already accepted. - Fixed the shared commercial-client detail API for fleet/commercial proposal workspaces so linked proposal-side contacts load again on older production schemas that never had a `proposal_clients.updated_at` column. The linked tags/contact card no longer falls through to **Failed to load commercial client** for those records. ## 2026-03-26 - Extended every current `trialing` workspace by another 30 days on the live system, using the later of the existing trial end or "today" as the base so already-expired workspaces were restored instead of staying blocked. - Raised the default trial length for newly provisioned waitlist workspaces from 14 days to 44 days, and updated the app's public trial copy to match. - Fixed Google Maps preview availability so the internal Property Visual, MapMeasure, and holiday-lights Street View routes can fall back to `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` when `GOOGLE_MAPS_SERVER_API_KEY` is missing, while still surfacing the plain-language unavailable message if that public key is browser-only or denied for server-side geocoding / Street View requests. - Added the shared Property Visual workspace to the standalone Generic Quote Builder, so office users can open Street View, satellite imagery, CompanyCam links, and quote-linked site photos from the `/admin/estimates/quote` flow. New standalone quotes can now save a draft in place from the panel to unlock persistent photo uploads before the quote is sent. ## 2026-03-25 - Fixed the lead-creation dialog so teams with client-management access can create a brand-new customer inline instead of leaving the workflow to build the client first. The same dialog now auto-selects the only saved property when a linked customer has exactly one address on file. - Fixed the Google Places suggestion handling in lead and client address flows so clicking text inside an autocomplete suggestion no longer closes the dialog before the address is applied. - Fixed commercial building and fleet proposal launch links that start from a lead record. New proposal pages now honor `lead_id` as well as `client_id`, so the customer preloads correctly on step 1. - Stabilized the admin Estimates list first render so date and stale-follow-up badges hydrate deterministically instead of tripping the production React mismatch error on page load, while keeping the displayed estimate date on the office user's local calendar. ## 2026-03-22 - Added a dedicated Supabase region-migration guide plus repo-side cutover, audit, and validation runbooks so the Oregon-to-Virginia project move has an explicit checklist for auth settings, mobile config, storage buckets, edge functions, and the post-cutover stress rerun. - Fixed two stress-test regressions on the admin office data layer: lead-source admin reads no longer request a non-existent `updated_at` column, and Jobs/Invoices pagination now returns an empty page instead of a `500` when the requested offset is beyond the currently available rows. - Followed that pagination fix with a production-shape compatibility patch so the empty-page guard also catches the real PostgREST `416 Range Not Satisfiable` response format returned by Supabase. - Added a repeatable developer stress-test harness and runbook for the core office hot paths, including the server-rendered admin dashboard/list pages, paginated Jobs and Invoices APIs, cached reference-data reads, and the health/queue checks we now rely on for scale validation. - Followed up on the Phase 2 async-delivery pass so queued recovery, setup-link, account-reset, and manual admin-email jobs now retry on transient provider failures instead of dead-lettering after a single blip once the user already received a success response. - Tightened the new direct-upload attachment surface so invoice attachment reads and writes now follow billing permissions instead of estimate permissions, which closes the cross-surface access mismatch between estimate-only and billing-only roles. - Hardened the Phase 4 paginated Jobs and Invoices list helpers by sanitizing free-text search terms before they are interpolated into PostgREST OR filters, preventing punctuation-heavy searches from breaking or reshaping the filter expression. - Scrubbed the remaining enqueue-failure email logs so forgot-password, setup-link, account-reset, and admin-email queue failures stop writing plaintext recipient addresses into structured logs. - Followed up on the Phase 4 scale pass by hardening the root request proxy against injected active-org context headers, so request-scoped org hints are now stripped from inbound traffic and only re-applied inside the trusted admin proxy flow. - Tightened the baseline `/api/admin/*` middleware throttling again so those buckets now key off the authenticated admin user when one is present, which prevents one fast user behind a shared office IP from rate-limiting everyone else on the same route shape. - Fixed a cached lead-source regression in the admin reference-data layer so active-only lead-source reads stop leaking inactive records back into office pickers and settings screens. - Removed the invoice-number race from admin single-create, admin bulk-create, and API v1 invoice creation by moving all three paths onto one shared atomic allocator seeded from existing invoice numbers for the current org and day. - Smoothed the server-hydrated Jobs and Invoices admin pages so their initial React Query payload is treated as fresh instead of immediately double-fetching crews, trucks, and first-page list data on mount. - Tightened the background-job cron worker to claim a smaller bounded batch per run, and added dedicated created-at indexes for the primary Jobs and Invoices admin list queries so those Phase 4 list pages hold up more cleanly under real office traffic. - Followed up on the Phase 5 operations pass by making `/api/health` fail fast when Supabase or the internal queue snapshot is slow, instead of hanging until the hosting platform times the request out. - Tightened the campaign delivery worker so one failed recipient no longer aborts the rest of the batch or skips the campaign stats reconciliation step. - Scrubbed structured email-worker logs so recovery and manual admin-email jobs stop writing full recipient addresses into the production log stream, while still leaving masked recipient detail for debugging. - Fixed the background-job processor metrics so jobs that fail before they can be finalized are tracked as stuck processing work instead of being misreported as dead-letter completions they never actually reached. ## 2026-03-21 - Started the Phase 1 platform-stability pass so authenticated admin, onboarding, super-admin, and logged-in customer routes now run through a shared root session proxy instead of relying on scattered session-refresh behavior. That gives the app a more reliable baseline for session continuity as traffic grows. - Added a baseline middleware rate limit across `/api/admin/*`, so every admin API route now inherits a shared protection floor even before any tighter route-specific throttles apply. - Followed up on that root session work so mixed-auth office API surfaces like `/api/email`, `/api/sms`, `/api/estimates/*`, and `/api/holiday-lights/*` also refresh browser session cookies when staff reach them from the app, while inbound webhook routes remain outside the proxy on purpose. - Added a new uncached `/api/health` endpoint for uptime and deployment monitoring, and tightened the shared Supabase bootstrap path so missing critical env vars now fail loudly instead of surfacing later as partial runtime breakage. - Added app-wide route and global error boundaries so unexpected render failures now fall back to a recovery screen with retry actions instead of dropping staff onto a blank white screen. - Tuned that new reliability layer so the baseline admin API limiter now buckets by normalized route shape instead of forcing every office user behind one shared IP bucket, and the shared crash fallback now routes people back to the right product surface instead of always sending everyone to `/admin`. - Began the Phase 2 async-delivery pass by moving one-time marketing sends, manual admin inbox emails, forgot-password delivery, setup-link emails, and account-reset emails onto the shared background jobs queue. Those flows now return faster and finish delivery on the minute-by-minute worker instead of waiting inline on email fan-out. - Added short-lived server-side caching plus tag-based invalidation across the admin services, add-ons, lead-sources, pricing, and tags reads, and added TTL caching to the office dashboard metrics so common admin screens stop hammering the same database queries on every load. - Followed that hardening pass with stricter admin-boundary and auth work: sensitive admin routes now rely on explicit permission helpers instead of auth-only org membership, new recovery and invite emails prefer the server-established auth callback path instead of the older client token handoff, session timebox and inactivity limits are now active in Supabase config, and the external API v1 CORS behavior is narrowed to an explicit allowlist instead of returning authenticated responses to every origin by default. - Started the 10K framework work by introducing a shared org-cache abstraction, aligning admin proxy org-selection with the same active-org resolution model the page layer uses, adding hot-path indexes for estimates, jobs, and campaign messages, and increasing the background-job worker duration and throughput budget for the async queue. - Rebuilt the admin Jobs and Invoices workspaces around paginated query-backed list APIs, moved those pages onto server-first initial loads plus React Query hydration for smoother first paint and cheaper refreshes, and removed the old fixed 200-row ceiling from those two high-traffic office views. - Tightened that Phase 4 framework pass again so request-scoped active-org hints are validated against the same franchise-aware membership rules instead of being blindly trusted, and the new Jobs and Invoices pagination now pushes search and status filtering through the server query path so records do not disappear just because they are not in the first loaded slice. - Added a structured logging layer around the background worker and internal delivery jobs, expanded `/api/health` so internal monitors can inspect queue backlog with the cron bearer secret, and documented the incident, monitoring, and backup/restore operating model in the platform runbooks. - Followed up on the Phase 2 queueing rollout by fixing two campaign correctness edges and one auth-recovery edge: active background-job dedupe keys now only block duplicate work while a matching job is still pending or in flight, campaign dispatch stat reconciliation now runs through an atomic database sync instead of an app-side last-writer-wins update, and forgot-password throttling now keys off the normalized email address while collapsing immediate duplicate recovery jobs into one queued send. - Followed up on the Phase 3 auth-boundary work by separating read and destructive permissions more cleanly: estimate deletes now require `estimates.manage`, lead detail reads now use the read-side client permission instead of the lead write tuple, and the API v1 response helper only emits `Vary: Origin` when it actually returned a CORS allow-origin header. ## 2026-03-20 - Added shared custom date-range filtering across the admin Estimates, Leads, Jobs, Invoices, and Pipeline workspaces. Office staff can now use quick presets or open an exact start/end picker instead of being limited to fixed canned windows. - Added a **Jump to** date picker on the Schedule board so dispatch can open a specific service date immediately instead of stepping day by day through the calendar header. - Hardened the customer portal and logged-in customer pages so proposal lookups, estimate history, and message history stay isolated to the correct live provider workspace. Customers who share the same email across multiple companies now see a safe direct-link prompt instead of mixed account data, and proposal search results still load even when secure customer-link signing has not been configured yet. - Tightened admin invoice payment-link generation so the office only reuses or writes hosted payment links for live invoices in the active workspace. - Added the same preset and exact custom date-range controls across the Analytics report suite, including Revenue, Margins, Services, Sales Cycle, Geography, Lead Source ROI, Retention, Operations, Schedule, Franchise, Automations, and Holiday Lights. - Followed up on the analytics date-range rollout so incomplete custom URLs now fall back safely instead of expanding into accidental open-ended ranges, custom typed dates use the same local-day boundaries as presets, and first-load server rendering now matches the shared picker logic across the analytics pages. ## 2026-03-19 - Fixed the fresh account-recovery and workspace-setup email flow so valid invite and password-reset emails no longer die on the **Invalid or expired reset link** screen. Recovery, invite, magic-link, and super-admin reset emails now land on a client-side auth handoff that finishes the Supabase session before sending the user into the password form or dashboard, and the expired-link card can now send a fresh access email inline without bouncing the operator through a separate forgot-password page first. - Followed up on that auth-link recovery rollout so the **Need A New Link?** retry action on the temporary **Finishing Sign-In** handoff now keeps the original workspace redirect attached too. Multi-workspace waitlist owners and brand-new team members no longer lose the invited org context if they need one more recovery email from the handoff step itself. - Closed the last false `500` save edge on residential estimate and generic quote creation. First-time draft saves now reload the just-written estimate summary when the insert succeeds but PostgREST does not return the full row immediately, so the office no longer sees a failed-save toast after the draft is already stored. - Hardened the invite and password-recovery flow again for provisioned workspaces. **Forgot password** is now rate-limited, no longer reveals whether an address is waiting on first-time setup versus a normal account, and expired invite recovery now routes through the shared forgot-password screen instead of firing another access email directly from the reset page. - Followed up on that auth hardening with another reliability/security pass. Customer-token estimate status updates are now write-scoped to the estimate's owning org, office-side estimate signing is rate-limited too, and pending-invite recovery now falls back to the standard reset path instead of surfacing a server error when the auth-admin lookup has a temporary hiccup. - Tightened team-access resend safety so the system verifies the generated auth user matches the membership before any workspace access email is sent. That closes a bad-edge case where a mismatched setup link could have been delivered before the guard tripped. - Fixed commercial proposal draft persistence so the selected sales rep now saves with both fleet and building proposal drafts, and brand-new building drafts keep their property rows and service line items on the first save instead of dropping that scope until a later edit. - Hardened commercial proposal client creation on both fleet and building draft POST routes so new proposal-side client records are normalized and validated before they are inserted. Malformed emails or bad client payloads now fail as clean input errors instead of quietly saving broken proposal contact records. - Fixed the admin Jobs tag filter for larger workspaces so tag searches are scoped before the 200-row list cap. Offices with more than 200 jobs now get the full matching tagged set instead of a silently incomplete subset from only the newest rows. - Hardened the public estimate customer-action flow so only live sent/viewed proposal links can be accepted, declined, or signed. Draft estimates no longer jump straight to an accepted state just because someone has a token, and the public-route auth test suite now covers the estimate status endpoint too. - Fixed invited workspace access again so waitlist-provisioned owners and brand-new team members who click **Forgot password** before completing first-time setup now get a fresh workspace setup link automatically instead of a generic reset email that cannot finish activation. - Fixed the Bulk Schedule job write path so newly created jobs are marked for the same live environment that the Admin Jobs list reads. Bulk-created jobs now appear immediately in **Admin > Jobs** instead of being hidden by the list filter. - Fixed the admin Jobs list API so the page no longer crashes on workspaces where the old `jobs.tags` column is absent. Jobs load again, recently created work reappears immediately in **Admin > Jobs**, and the tag filter continues to use the linked client tags instead of a missing job-side field. - Fixed the shared linked-contact tags card on commercial building proposal detail pages so stale or deleted linked contacts no longer throw a false **Client not found** toast during page load. Those proposals now open cleanly and show an unavailable state for the missing linked record instead of interrupting the office with an error toast. - Fixed the shared analytics export picker so the print-friendly export no longer downloads with a fake `.pdf` filename. The analytics export menu now labels that option as **Print**, and downloaded files keep the correct server-provided name and `.html` extension for browser printing or Save as PDF. - Fixed commercial and fleet proposal deep links that start a new quote from an existing client. New proposal pages now honor the incoming `client_id` on load, prefill the selected client on step 1, and avoid the loader/invalid-id failures that previously showed up when staff launched commercial or fleet proposal creation from a client shortcut. - Fixed admin team invite and resend emails so the generated setup link keeps the invited workspace id in the redirect path, and access-email sends now fall back to a recovery-style setup link when the direct magic-link path is unavailable. Team members now return to the same admin workspace that sent the invite instead of falling back to a generic `/admin` redirect or a failed resend toast. - Fixed the admin invoice detail API so invoice pages no longer depend on a removed `customer_phone` column just to load. Older invoice records now open reliably again, which also keeps the invoice-side payment workspace reachable instead of falling through to a false **Invoice not found** state. - Fixed the admin-side estimate acceptance preview so office users can complete the same **View Public Page** signature flow without the sign step silently failing just because they are signed in as staff instead of following a customer-token link. Accepted estimate status changes are also more resilient now, so a follow-up automation or sales-pipeline logging hiccup no longer makes the UI report a failed save after the estimate status already changed. - Fixed the shared office **Collect Payment** modal width on estimate detail so the payment workspace now honors its full desktop frame instead of collapsing into the small default dialog size and squeezing the left-side payment setup pane into unreadable vertical text. - Fixed the standard estimate send and resend flow so CE Pro now confirms email delivery before it reports success, and already-sent quotes can be resent without tripping the old draft-only guard that produced "Quote updated but failed to send" after a legitimate retry. - Fixed the commercial building proposal send flow so the review step now confirms the email destination after a successful delivery, and follow-up pipeline/history sync issues are surfaced as warnings instead of a misleading hard failure after the client email already went out. - Fixed the commercial building client picker and linked tags flow so native CRM contacts can be swapped with **Change** during edits without crashing the wizard, and older building proposals tied directly to native clients no longer show a false **Client not found** error on the detail page. - Fixed the commercial building proposal wizard so the Property Type, Primary Surface, and service-catalog pickers load again on both new and edit flows instead of failing behind silent 500s. The review step now also includes an explicit **Save Draft** button, and the send area explains whether the draft or client email is the missing requirement when the email action is disabled. - Fixed the commercial building catalog loaders so proposal editors with the broader commercial proposal permissions can still see the Property Type, Surface Type, Service Type, and pricing-setting options. When a saved workspace catalog still fails to load, the wizard now falls back to built-in building defaults instead of leaving those dropdowns and the service catalog empty. - Fixed the residential estimate wizard so client-prefilled **New Estimate** links now keep the selected CRM client attached through save instead of dropping the known `client_id` and trying to recreate the customer during estimate creation. - Fixed office-side residential estimate send fallback when secure customer-link signing is not configured. Staff can now still send the estimate email with the PDF attached, and the send flow returns a clear warning that the browser-based estimate link is temporarily unavailable instead of blocking delivery with a `CUSTOMER_TOKEN_SECRET` setup error. - Fixed invoice send retries for workspaces that still do not have secure customer-link signing configured. The office can now send the invoice email anyway, with any stored billing links included when available, instead of the whole send flow stopping on a generic setup failure. - Fixed the invoice detail payment workspace so long customer names and emails now wrap cleanly on the page, and the invoice-side **Collect Payment** keyed-card flow no longer trips the intermittent office crash caused by the dialog re-registering its Stripe submit callback every render. - Fixed the Manage Billing button so the Stripe portal return URL is built from the current request origin instead of a potentially stale app URL setting. That removes the "Not a valid URL" failure mode when admins open the billing portal. - Fixed the mobile Messages layout so the inbox uses mobile-safe viewport sizing and long customer names no longer overflow the thread header on smaller screens. - Fixed the analytics export whitelist so Retention, Operations, Schedule Efficiency, and Franchise reports now export through the shared CSV/PDF endpoint again instead of returning a 400 for valid report types. - Fixed the shared analytics export button so failed report exports now show a visible error message instead of silently doing nothing when a report-specific export throws. That gives the office immediate feedback on Retention, Operations, Schedule Efficiency, Franchise, and any other shared analytics export path that cannot generate a file. - Fixed the customer estimate acceptance flow so signed estimates now keep the accepted state even if follow-up automation has a transient failure, and customer request-changes notes now stay attached to the rep-facing estimate record instead of getting dropped during the save fallback path. - Fixed the waitlist join flow so duplicate submissions now return a retryable conflict instead of locking the form into a success state. Users can try a different email after a failed join attempt without refreshing the page. - Fixed the holiday-lights send queue so admin quote sends now stay on the holiday-lights email and SMS delivery path instead of falling back to the residential estimate sender behind the scenes. - Fixed holiday-lights proposal sending so the office now gets a real email-delivered confirmation before CE Pro reports success, failed sends stay retriable instead of silently flipping the quote to sent, and the header action becomes **Resend Proposal** after the first successful delivery. - Hardened the measurements and recurring-template admin routes so load/save/generate failures now show plain-language errors instead of raw database messages, while still preserving the expected not-found and validation statuses for the user. - Hardened the mobile payment, public invoice checkout, and Stripe billing-portal error paths so staff and customers now see plain-language payment or setup guidance instead of raw provider and Stripe exception text. Safe business-rule feedback like missing records or invalid amounts still stays readable, while the detailed failure context now stays in server logs. - Fixed the shared office **Collect Payment** dialog so long invoice labels, customer names, and receipt email text now wrap inside the modal on invoice detail instead of overflowing past the dialog frame. - Fixed invoice collect-payment retry behavior so invoice pay-link actions reuse an already stored invoice link instead of failing when the customer-token setup path is unavailable, which also keeps older invoices resilient during send/link retries. - Updated the Workiz setup flow so the copied value is now just the webhook endpoint while the org-specific webhook key is copied separately. That keeps the secret out of the copied URL/query string while still letting teams assemble the full Workiz callback URL when they configure the integration. - Fixed a late admin review batch across job detail editing, refunds, client updates, promotions, and holiday-lights estimate sidecars. Job detail no longer opens in a false dirty state with the Save button stuck on, Stripe refund actions now write an internal adjustment trail before the gateway refund is issued and failed Stripe refund attempts now mark that pending trail as failed instead of leaving it hanging, client detail updates fail safely instead of returning a truncated row after a refresh error, missing promotion deletes now return a real not-found response instead of silently succeeding, and holiday-lights sidecar creation now uses the same narrower config read path as the main holiday-lights estimator flow while keeping later client-link backfills scoped to the same workspace record. - Improved another backend throughput pass for automations, drip marketing, Workiz sync, and proposal expiration jobs. Matching one inbound event to multiple workflow runs now executes those runs in parallel instead of serially, large drip campaigns process due recipients faster once each message claim is secured, Workiz lead backfills upsert each page concurrently, and the nightly proposal-expiration sweep now preloads loss stages per org before it advances expired proposals. - Tightened another stability pass across billing, integrations, and estimate editing. The Billing page now keeps its main subscription controls visible even if invoice-history, referral, or AI-usage side data has a temporary loading failure; Workiz settings no longer leave the full inbound webhook secret sitting inline on screen; revoked external API keys now flip inactive immediately in the admin UI; and estimate detail status changes now surface the actual save failure instead of silently falling back to a generic toast. - Continued the admin API hardening pass across clients, schedule, commercial proposals, jobs, inbox threads, holiday-lights routes, and automation/follow-up flows. These routes now keep raw database/provider errors out of the UI while still logging the detailed failure context server-side, and a broad set of high-traffic reads now fetch explicit columns instead of whole rows by default. - Shipped the missing public v1 estimate update path so `PATCH /api/v1/estimates/:id` is now a real idempotent endpoint instead of a docs gap. External integrations can now patch estimate customer/contact metadata, address/property details, assignment, draft-or-sent status, source, and expiration through the same scoped API-key model as the rest of the public v1 surface, and the OpenAPI contract plus developer examples now match the shipped behavior. - Fixed a follow-up review batch in brands, operations QC, and workflow scheduling. Brand edits now leave untouched fields alone instead of resetting saved colors or optional settings, checklist-template edits no longer reactivate inactive templates unless you explicitly flip them back on, waiting workflow runs now verify that their wake time has actually arrived before the engine resumes them, and automation **Least Loaded** assignment now compares only active estimates, jobs, and leads instead of lifetime historical totals. - Fixed a follow-up review batch across automations, estimates, AI review, and recurring templates. Automation **Assign User** now distinguishes stable round-robin routing from real least-loaded routing based on current assigned leads/jobs/estimates, delayed workflow runs resume from **Waiting** correctly, bulk estimate status changes now report real batch success instead of a false failure toast, optional admin note fields no longer overwrite untouched values with `null`, holiday-lights AI review compares nearby work against the first-year annual contract price when present, and visit-capped recurring templates now count manual skips or catch-up occurrences correctly so they end on time. ## 2026-03-18 - Followed up on the payments and analytics refactors after review. The office keyed-card flow now keeps the Stripe card form mounted when staff adjust the amount or tip, but it requires an explicit **Refresh Card Entry** before charging so the final Stripe intent stays in sync, and sales-cycle timing now honors commercial decline timestamps when they exist instead of stretching loss timing to a later generic close date. - Followed up on the latest inbox/dashboard refactor after review. Switching to a different customer conversation now clears the previous draft and resets the compose area before the new thread finishes loading, targeted inbox summary refreshes no longer apply sidebar workflow filters while patching a single row, and the admin dashboard now keeps empty commercial gross-margin cards on a clean dash while the sales rep pace card reflects new estimates created month-to-date instead of only currently sent ones. - Followed up on the dispatch and inbox refactors after another review pass. The route header no longer shows a misleading stop-level hourly-only label, route optimization guidance is now documented more clearly for truck-days without a saved shop origin, and targeted inbox fallback refreshes now normalize legacy phone and email thread keys before deciding a conversation row is truly missing. - Fixed the commercial and fleet proposal creation flows so selecting a native CRM contact or entering a new client no longer crashes the building client picker or sends synthetic ids into the proposal save APIs. Building proposals now handle sparse client-name data safely, and both commercial proposal modules now create or reuse the correct proposal-side contact record before saving. - Fixed the admin estimate send/resend flow so the quote builder now carries the generated customer token through the final send step, and email delivery routes now fail loudly when the mail provider is missing instead of reporting a successful send with no outgoing message. - Clarified the external API docs so the Developers section now explicitly shows that public v1 integrations can write notes to client, lead, and job records, with ready-to-use `POST` and `PATCH` examples for each workflow. - Fixed manager-led first-run onboarding for unfinished workspaces, especially franchise child locations invited through an operator workspace. Managers can now save the Company Info, Services, Pricing, and completion steps during onboarding instead of getting stuck behind generic save failures, and the onboarding UI now shows the actual API error text when a step is rejected. - Hardened the automation engine's internal bearer-secret handling so delayed workflow resumes, scheduled-trigger processing, direct run execution, and event-to-workflow matching now all use the same secret precedence and timing-safe bearer-token validation. This reduces edge-case failures where one internal automation endpoint could accept a request that another identical engine path rejected in the same environment. - Added a stricter browser Content Security Policy across the web app and aligned frame protections with the product's actual surfaces. CleanEstimate Pro still blocks external embedding, but the built-in same-origin message drawer can now load correctly while Stripe, Google Maps, Supabase realtime, analytics, and approved embedded panels continue to work under explicit allowlists. - Standardized high-risk billing, messaging, password-reset, webhook, and super-admin error paths so the UI now shows plain-language setup or action messages instead of leaking raw Stripe, Twilio, Mailgun, Supabase, or database error text. Common business-rule feedback like invalid payment amounts or missing records still stays readable, while low-level diagnostics now stay in server logs. - Added shared Zod-backed validation for the highest-risk messaging mutation routes, including manual SMS sends, manual email sends, inbox note creation, and conversation ownership/needs-response updates. Those inbox actions now reject malformed payloads consistently before they hit Twilio, Mailgun, or the unified messaging write path. - Expanded shared validation again across admin team and dispatch actions, including approval requests, handoffs, alert actions, rep availability changes, role-permission saves, territory edits, crew creation, ETA sends, job-status updates, route-day assignments, and crew-job assignments. These admin flows now reject malformed ids, ZIP codes, dates, and permission payloads before they can write partial schedule or settings data, and several of the touched routes now return cleaner setup errors instead of raw database messages. - Expanded the same validation pass into operations settings, including subcontractors, business locations, equipment records, and equipment maintenance logs. Those forms now reject malformed emails, ZIP lists, dates, rates, costs, and lifecycle payloads before they can save inconsistent operations data, and the touched routes now return cleaner admin-facing errors instead of raw database messages. - Extended that operations hardening into inventory items plus quality-control checklist and report workflows. Inventory writes now validate categories, quantities, reorder levels, unit costs, and reorder dates before saving, while QC templates and reports now validate nested checklist items, pass/fail states, notes, scores, and photo references before they create report history. - Hardened another settings/configuration batch covering brands, module-brand assignments, lead sources, and tag creation. Those admin forms now validate slugs, module keys, commission rates, sort order, ids, and tag colors before saving, use safer fallback handling when older tag tables are still rolling out, and return cleaner setup errors instead of raw database messages. - Tightened another workspace-settings pass covering pricing, email reply slugs, Twilio phone number storage, Google review links, and schedule dispatch defaults. These settings now validate E.164 SMS numbers, custom inbox slugs, Google review URLs, route-origin coordinates, truck-capacity values, and pricing version payloads more consistently, while the settings UI now surfaces the review-link and slug errors directly instead of failing silently. - Hardened the service catalog admin too. Service, add-on structure, and custom item template saves now validate slugs, ids, prices, sort order, and units more consistently, the matching admin APIs return cleaner setup errors instead of raw database messages, and the Services page now keeps edit dialogs open and shows the actual failure reason when a save or toggle request is rejected. - Tightened the estimate detail mutation flows for rep assignment, appointment scheduling, and estimate-to-job conversion. Those actions now validate ids, dates, time windows, and override flags more consistently, keep cross-org or archived users from being assigned as reps, reject invalid appointment ranges before they save, and return cleaner admin-facing errors instead of raw database messages. - Hardened the marketing campaigns, promotions, and legacy follow-up sequence admin APIs too. Campaign drafts now validate scheduled send windows and structured drip-step payloads before saving, promotions now enforce cleaner promo-code/date-window validation and safer admin-side errors, and legacy follow-up sequence/template saves now reject malformed step payloads or invalid business-hour ranges instead of partially overwriting the workflow. - Tightened the external API key admin flows as well. API key create/update screens now validate environments, scopes, rate limits, and expiration values more consistently before saving, the request-log endpoint now validates log-limit input, and the API key admin routes return cleaner setup errors instead of raw provider or database messages. - Improved commercial pipeline stage saves so bulk stage edits now validate the full payload before writing and update stage rows in parallel instead of one at a time. Reordering or renaming a full stage board should feel faster now, and malformed stage batches fail cleanly instead of leaving a partial stage configuration behind. - Tightened the dispatch route-sync save path as well. Daily route timing syncs now validate dates, stop ids, metrics, and map coordinates before writing, coordinate backfills run in parallel instead of nested per-stop awaits, and route-sync storage failures return cleaner dispatcher-facing errors instead of raw database messages. - Followed up on the same hardening pass with a cleanup batch for edge cases the review caught. Inventory items can now be patched one field at a time without re-sending every create-only field, campaign drip steps reject blank message bodies, legacy follow-up sequence APIs now respect the same `marketing.view` and `marketing.manage` permission split as the rest of Marketing, step reads stay tenant-scoped, proposal handoffs now require the same estimate-manage permission as other assignment changes, team approval/handoff routes no longer leak raw database errors, shared API sanitization now still logs unexpected failures even when a route forgets to pass a custom log context, and the public promo-code validator now rate-limits repeated bursts so anonymous code-guessing is harder. - Continued the performance pass in AI and automation analytics too. AI lead-score recalculation now persists refreshed scores in one bulk upsert instead of one row at a time, and the automation analytics sequence-performance panel now rolls up enrollment counts in one org-scoped query instead of issuing a separate enrollment query for every legacy follow-up sequence. - Finished the same loop-await cleanup in bulk job scheduling. Bulk Schedule now resolves truck assignments in parallel and appends per-truck route-stop groups concurrently, so larger multi-property batches with route mode should create jobs and initial stop order faster before dispatch opens the board. - Started the inbox performance pass too. The admin messages page now only refetches the open thread when that thread's own messages change, and the communications contact-summary read now uses a tighter recent-message window instead of scanning an oversized backlog on every reload. - Continued the inbox performance pass with a more targeted live-refresh path. The shared Messages list now refreshes only the contact rows that changed in the common case instead of reloading the entire inbox after every new message, and the communications summary route now looks up only the clients tied to the recent contact set instead of hydrating every client in the workspace just to decorate the inbox list. - Followed up on the inbox and promotions hardening pass after review. Service-restricted promo codes now stay blocked until the estimate includes a matching service instead of validating when service data is missing, targeted inbox sidebar refreshes now fall back to a full reload instead of dropping a conversation row on a summary miss, and inbox read-marking now catches both normalized thread keys and raw inbound phone values more reliably. - Cleaned up another commercial admin error-leak cluster. Commercial proposal template and fleet vehicle-type admin actions now return plain-language save/delete failures instead of raw database messages, while still logging the detailed failure context server-side for support and debugging. - Followed up on those commercial admin routes after review. Fleet vehicle-type edits now return a real not-found response when the record has already been removed from the active workspace, and proposal-template edits now validate PATCH payloads before save so bad field types fail cleanly as input errors instead of throwing inside the route handler. - Tightened another small admin error-handling cluster around AI settings, AI conversation history, estimate attachments, and estimate photos. Those routes now return plain-language load/save/upload failures instead of raw provider or database text, while the detailed diagnostics stay in server logs for support. ## 2026-03-17 - Smoothed the missing Google Maps server-key error path so Property Visual previews now show a plain-language unavailable message instead of exposing the raw `GOOGLE_MAPS_SERVER_API_KEY is not configured.` config string in the admin UI. - Refreshed the `/admin` workspace with the CleanEstimate Pro brand kit while keeping routes, workflows, and page structure intact. The admin shell now uses the brand blue/slate palette, tighter shared surfaces, brand-safe sidebar states, stronger mono KPI treatment, and updated report/schedule/settings chrome without changing behavior. - Fixed the generic quote and estimate edit save-response path so successful draft saves no longer return false `500` errors after the record is already stored, and estimate detail pages now surface customer change requests with submitted totals plus included/removed line items. Manual SMS sends and Stripe billing-portal launches also return clearer setup and provider errors instead of opaque server failures. - Tightened the admin shell again so the top search, XP, and Help/Alerts bubbles now share the same height and visual treatment, the franchise org switcher has stronger contrast in the dark sidebar, and the oversized **Operations Command** hero on the main dashboard has been replaced with a smaller office snapshot plus direct report links. - Followed up on the admin shell spacing so the XP, Help, and Alerts bubbles now sit in cleaner individual pills with tighter alignment and less wasted space in the top bar. - Followed up on the admin shell cleanup by removing the non-essential role, focus, and mode card from the left rail, shrinking XP progress into a compact top-bar pill, and simplifying the sidebar create menu into a single **Quick Start** dropdown bubble. - Simplified the admin workspace header by removing the oversized command-center banner. The top of the admin app now focuses on a full-width search bar with Help and Alerts actions on the right, while workspace plan and trial badges moved into compact pills on the Settings and Account pages. - Updated franchise reporting visibility so it now turns on automatically when a workspace already has franchise hierarchy or multi-location capability enabled, instead of requiring a separate franchise-reporting toggle. - Updated the first-run onboarding screen to use the shared CleanEstimate logo header and removed the duplicate text-only wrapper so new workspaces land in a cleaner branded setup flow. - Updated the password setup and forgot-password screens to use the same shared CleanEstimate logo header so the activation and recovery flow matches onboarding instead of showing the older text-only branding. - Fixed invite and password-setup emails so shared provisioning scripts and resend flows no longer leak `http://localhost` links outside a real development session. Workspace setup emails now fall back to the production CleanEstimate URL automatically when a non-dev process has a local app URL configured. - Fixed early onboarding for newly provisioned workspaces so starter services, pricing, add-ons, and related defaults now self-heal if bootstrap records are missing. The setup UI now keeps the Services and Pricing steps usable instead of leaving those screens blank or throwing a pricing-save error. - Fixed early-access workspace activation so waitlist-approved users no longer get dumped back into public waitlist/signup prompts when their original invite link expires or has already been used. - Waitlist and team-access emails now preserve the invited workspace context more reliably, including a password-setup recovery path for provisioned users who exist in auth but have never completed first-time sign-in. - Improved auth fallback screens so expired invite and magic-link flows prefill the invited email, route users toward a fresh setup link, and avoid treating provisioned workspace owners like brand-new public signups. - Fixed the expired setup-link recovery flow again so the reset screen now resends the actual workspace setup path for pending users, keeps the UI on the recovery state after resend, and preserves the target workspace context for waitlist-provisioned owners. ## 2026-03-16 - Refreshed the core UI across the admin workspace, public marketing site, and mobile app around a shared operator-first visual system. The admin shell now uses a darker command-style sidebar and updated workspace chrome, the homepage showcases the live dashboard/operations/analytics/AI/mobile story, and the mobile tabs now use the tighter card, KPI, and section styling from the same system. - Updated the public pricing page so every plan card now shows **Pricing coming soon** instead of public numeric plan prices while still keeping plan names, feature differentiation, and waitlist CTAs visible. - Expanded the Analytics area into a shared reporting hub without removing the existing revenue, margin, lead source, service, geography, holiday-lights, or automation reports. Revenue now has its own first-class page, and the analytics rail adds retention, operations, schedule efficiency, and franchise reporting. - Upgraded Margin Analysis with sold-to-job conversion coverage plus clearer callback reporting that separates explicit callback-tracking records from inferred callback signals in job notes. - Upgraded Lead Source ROI with module filters, rep attribution, upsell revenue, and brand-funded source rollups, and added a new brand-funded toggle to Lead Sources so franchise and ad-fund reporting can use durable source tagging. - Added retention reporting for healthy, at-risk, dormant, and new accounts, including quick **Generate Quote** actions that jump into a prefilled estimate flow for the selected client. - Added operations reporting that combines crew productivity, crew pay totals, AR aging, and overdue invoice reminder actions using the same AI follow-up flow already available from invoices. - Added schedule-efficiency reporting for daily production, schedule fill rate, on-time performance, and reschedule/cancellation breakdowns. - Added franchise-gated reporting for royalty, ad-fund, and territory utilization rollups using the existing organization feature-flag model. - Limited the admin Marketing area to the approved workspace during tester rollout. Other workspaces now see marketing in read-only mode and cannot create, activate, edit, delete, or send campaigns and promotions. - Fixed team access links so invited users who already belong to another CleanEstimate Pro workspace now land in the invited workspace instead of getting stuck in the wrong org or being pushed toward waitlist/signup flows. - Expanded the admin XP leaderboard so each user can now see every achievement already earned on their profile plus the remaining role-track and universal achievements that are still available to unlock. - Fixed the admin Estimates tab loading path again so the summary RPC stays bound to the Supabase client instance, resolving a server-side `500` that could leave the Estimates page blank even when the underlying estimate data was healthy. - Fixed the admin Estimates center so it can fall back to the unified `estimates` table when the newer estimate-list projection objects have not been applied in the database yet, restoring list loading and search during rollout windows. - Hardened admin job detail loading so optional Crew Pay and assignment lookups no longer turn the whole page into a `500` when newer payroll tables are missing from the live schema cache. - Hardened invoice creation and invoice detail loading around secure customer-link signing. Draft invoices now still generate even if customer-link signing is not configured yet, and invoice detail pages stay readable instead of failing outright. - Updated invoice send and payment-link actions to return a clear setup error when secure invoice-link signing is unavailable, instead of a generic server error. - Improved the billing portal error path so Stripe customer-portal configuration or customer-record problems now surface as a temporary availability/setup message instead of an opaque failure. - Added rollout-safe fallbacks for missing payment and crew-pay relations in the live schema cache so office billing and job workflows degrade gracefully while databases catch up. - Finished Franchise Phase 4 beta hardening with 15-minute franchise summary refreshes, durable org-switch and cross-org franchise audit logging, franchise plan gating for parent-workspace management, descendant-read RLS coverage on the core org-scoped workflow tables used in the beta, and live-only franchise summary rollups. - Added the first self-serve franchise admin workspace on top of the beta hierarchy foundation, including the admin sidebar org switcher, franchise overview, descendant workspace roster, child-workspace detail screens, child-workspace user invites, operational reports, and the new Settings --> Franchise page for rollout guidance. - Added the Phase 2 franchise beta APIs for active workspace switching, parent-org overview, child-org management, descendant user listing, and child-org invites, plus the new `franchise.view` and `franchise.manage` permissions that gate those flows. Parent org admins can now keep inactive child workspaces visible for management and reactivation instead of losing them from the hierarchy tree after deactivation, and successful workspace-switch responses now tell the admin client to refresh session metadata immediately. - Laid the franchise hierarchy foundation in the database by adding parent/child org metadata, organization relationship records, scoped multi-org membership fields, reusable hierarchy traversal helpers, and locked-down relationship-table access for upcoming franchisor, operator, and multi-location account management. - Reconciled the developer docs, navigation, examples, and changelog around the actual public `/api/v1` surface. The shipped external API remains the core workflow resources plus webhook management; the previously documented proposal and reporting endpoints are deferred and are no longer presented as live production routes. - Fixed franchise bug-report visibility so parent workspaces can review descendant workspace bug reports from the parent dashboard instead of only seeing reports created directly inside the active workspace. - Hardened franchise workspace switching to accept readable workspace slugs as a rollout-safe fallback when a stale browser session submits an older identifier format. - Hardened franchise workspace switching again so stale browser sessions can also recover when they submit an exact readable workspace name instead of the current UUID or slug format. - Fixed franchise workspace switching for legacy root workspaces whose ids are UUID-shaped but not version-stamped UUIDs, so operators like Lancaster can switch back from child workspaces without hitting `Invalid workspace identifier`. ## 2026-03-15 - Added crew tip collection and visibility across invoices, admin payment collection, mobile job payments, and the Crew Pay dashboard. Customers can now choose 10%, 15%, 20%, custom, or no tip from the taxable amount, while cash, check, and card tips stay visible by method in crew-pay reporting. - Cleaned up the remaining mobile TypeScript regressions in the dashboard proposal list, About screen asset loading, and CRM client-provider mappings so the Expo app compiles cleanly again. - Rebuilt Crew Pay around versioned policy settings instead of hardcoded crew percentages, adding editable pool rates, solo and leader caps, pay-period and overtime controls, minimum-wage overrides, commission exclusions, crew split templates, route-day hourly-only overrides, and job-level participant compensation editing with callback tracking. - Followed up on the Crew Pay rebuild with payroll hardening fixes: minimum-wage top-ups now report deficits correctly, hourly overtime only counts hourly-only hours, callback-origin jobs no longer dilute the rest of a capped crew day, route-day save errors surface in the UI, and the new crew-pay policy tables now enforce tenant-scoped RLS plus database-level payout guardrails. - Added rollout compatibility fallbacks for Crew Pay so the admin crew-pay pages can still render safely while older org databases catch up on the latest split-template and compensation schema changes. - Fixed the inverted `commissionTopUp` formula so minimum-wage top-ups now correctly report employer deficits instead of commission surpluses. - Fixed overtime threshold tracking so commission hours no longer count against the hourly-only overtime threshold, preventing incorrect overtime pay on mixed-pay crews. - Excluded callback-origin jobs from daily cap group accumulation so they no longer dilute the capped commission pool for other jobs on the same crew-day. - Added RLS policies and positive-value CHECK constraints to `crew_pay_policies` and `job_compensation_settings` to enforce tenant isolation and prevent negative rates or unbounded commission shares at the database level. - Added commission share sum-to-100% validation in the job compensation editor UI and error feedback on route-day assignment save failures. - Replaced hardcoded 57/43 lead/tech pay preview splits in the schedule day route view with the active policy's configurable `leaderMaxShare`. - Added effective-date future validation to the crew pay policy editor so past-dated policy versions cannot be created from the admin UI. - Tightened Supabase type safety across the app by introducing strict client factories alongside the legacy loose path, fixing high-value schema drift in the admin dashboard, automations analytics, AI estimate review, chat route, Meta and Angi webhooks, and the holiday-lights customer portal mapper. - Replaced the dead inbound automation webhook auth path with the external API v1 scoped key model, requiring `webhooks:write` scope, SHA-256 hashed key comparison, and timing-safe verification. Existing integrations using the old `webhook_api_keys` table or `X-Webhook-Signature` HMAC path must migrate to scoped API keys. - Fixed the `safeHashEqual` function in the inbound webhook auth path to return `false` on invalid hex inputs instead of comparing two zero-filled buffers. - Wired the strict middleware Supabase client into the auth session refresh path and replaced the unguarded inline service client with the singleton `createStrictServiceClient`. - Added shared JSON boundary helpers for safely parsing `unknown` Supabase JSON columns into typed objects, arrays, and scalars without raw `as` casts. - Added an integration connections helper to replace direct `organizations.integrations` JSONB reads with a dedicated `integration_connections` table lookup pattern. - Stabilized the flaky public route auth test and added a real `typecheck` script to `package.json`. - Started the Phase A reliability pass by fixing the commercial bulk-scheduling template conversion regression, scoping admin team activity commercial proposal reads back to org-owned proposal IDs, switching CI back to Linux, and aligning the Mailgun inbound email setup docs around Bearer-header auth instead of legacy query-string secrets. - Followed up on the Phase A review by adding mobile Jest coverage to CI, escaping customer delivery email templates, documenting the required `CUSTOMER_TOKEN_SECRET` and `GOOGLE_MAPS_SERVER_API_KEY` deployment settings, recording residential MapMeasure applies as `property_data_source = "mapmeasure"`, and clarifying that Workiz lead updates stay scoped to the org that owns the sync. - Rebuilt the admin Estimates list and linked client estimate history on a unified indexed read model that combines residential estimates, generic quotes, holiday lights records, fleet proposals, and commercial building proposals, so search, tags, rep filters, source filters, and pagination now run in SQL instead of the old in-memory multi-table merge path. - Hardened map preview and measurement APIs by moving admin and holiday-lights Google geocode and Street View lookups behind internal server routes, adding burst protection to MapMeasure endpoints, and improving inline visual-panel error states when Google cannot resolve a preview. - Started the Phase B reliability pass by switching follow-up, automation, SMS, invoice-payment, and legacy proposal-delivery links onto the canonical tokenized customer-link builders, so customer-facing estimate, proposal, maintenance, and invoice links stay valid across web and mobile sends. - Fixed mobile offline proposal delivery retries so failed background `send-proposal` calls stay queued instead of being marked complete, and made follow-up service merge fields tolerant of both legacy string arrays and the newer structured service-selection payloads. - Finished the next estimate-list correctness pass by filling the missing projection upsert fields, passing estimate type filters through the summary RPC, exposing `entity_type` in the admin estimates API, and adding shared proposal-client tags so fleet and commercial proposal records participate in the same tag filters as residential estimates. - Made client-account primary-contact promotion transactional and added shared tag management to fleet and commercial proposal detail pages, so concurrent admin edits cannot leave duplicate primaries and commercial contacts can now power unified estimate-list filtering. - Followed up on the Phase B account work by preventing non-primary client moves from clearing another account's existing primary contact, and by adding a rollout-safe fallback when the new `set_client_account_primary_contact` RPC has not been applied yet during deployment. - Finished the client account-integrity pass by moving contact-account membership changes onto a transactional RPC path as well, so primary-contact promotions and account moves no longer depend on a separate post-update reconciliation step. - Fixed the remaining legacy mobile proposal-delivery gap by adding a signed `/p/:proposalId` customer-token path for proposals without linked estimates, restoring secure SMS and email delivery for direct mobile-created proposal records instead of leaving those sends stuck on a missing-link error. - Hardened customer delivery links again by moving HMAC signing onto the dedicated `CUSTOMER_TOKEN_SECRET`, adding token expiry to estimate, proposal, maintenance, and invoice links, tightening the legacy proposal viewer's PDF allowlist, and fixing portal proposal lookups to filter in SQL instead of silently dropping older customer proposals after an org-wide top-50 cutoff. - Rebuilt the Phase C security pass on top of the shipped Phase B baseline, making shared public rate limiting fail closed by default, keeping public-customer-token and property lookup paths on explicit in-memory fallback only where needed, and finishing the admin auth-wrapper migration for the remaining high-traffic client, estimate, lead, schedule, and marketing routes. - Locked the admin Property Visual and Street View proxies behind estimate-view permission checks, required the server-side `GOOGLE_MAPS_SERVER_API_KEY` for those routes, rejected non-image Street View upstream responses, and moved the holiday-lights photo designer's Street View fetches onto the same internal proxy path. - Followed up on the Phase C audit by restoring the intended auth-only access model on lead, estimate, follow-up sequence, client-delete, and job-delete routes that still rely on record-level role checks, adding missing org and environment guards to follow-up step replacement, invoice payment-link writes, and schedule completion re-reads, and making public property auto-fill fail closed again when shared rate-limit storage is unavailable. ## 2026-03-14 - Hardened core security and customer-delivery flows by enforcing admin API permissions server-side, locking holiday-lights AI mockups behind authenticated permissions plus image-size limits, moving inbound email webhooks to bearer-header auth, rate-limiting manual email/SMS/review sends and selected AI actions, and fixing signed customer links for SMS, Stripe returns, and public estimate/proposal access. - Migrated app email delivery from Resend to Mailgun, including batch marketing sends, inbound reply routing, delivery/open/click/failure webhooks, and the deployment DNS guidance needed to run the new email stack. - Added MapMeasure to the shared satellite Property Visual Panel so residential, commercial building, fleet, and holiday lights workflows can save geodesic map measurements with live draft totals, keyboard drawing shortcuts, and workflow-aware apply actions. - Hardened MapMeasure persistence and edit flows with atomic commercial proposal graph saves, safer residential estimate reconstruction on reopen, and saved measurement round-tripping for map-based property values. - Followed up with additional MapMeasure hardening for org-scoped target validation, draft undo and double-click stability, safer inline CompanyCam previews, and stricter commercial proposal payload sanitizing. - Hardened background follow-up, drip, and waiting-automation processing with claim-safe batching, restored the intended follow-up and drip cron cadence, and reduced duplicate-send risk during overlapping scheduler runs. - Rebuilt the public homepage with an estimate-first story, stronger mobile and desktop layout, and a sharper power-washing-specific visual design. - Updated the shared marketing navigation, footer, and sticky mobile CTA so the public site keeps the same stronger positioning across pages. - Added a new docs article covering the public website and waitlist experience. - Shipped and hardened external API v1 with scoped live and test API keys, atomic idempotent writes, stricter state validation, request correlation, rate-limit fail-closed behavior, cursor pagination, durable outbound webhook delivery, and a typed `/api/v1/openapi.json` contract. - Followed up with the final external API pre-production hardening pass for exact key-environment verification, live-only webhook queue processing, and additional idempotency guardrails. - Published Phase 2 proposal and reporting API planning/docs work, but the public `/api/v1` contract remained limited to the core workflow resources plus webhook management. - Documented the three supported SMS consent flows in the public privacy policy and mirrored that legal guidance in the docs site. - Hardened background follow-up, drip, and waiting-automation processing with claim-safe batching, restored the intended follow-up and drip cron cadence, and reduced duplicate-send risk during overlapping scheduler runs. - Began moving estimate delivery fan-out onto a durable background job queue so send actions can return faster while PDF, email, SMS, and Workiz tasks finish in the background. - Followed up with the first scalable-monolith hardening pass: estimate sends now return async delivery state details, Workiz sync uses the shared background job queue, org-level estimate send burst protection is enforced in Postgres, and the remaining cron sweepers now use overlap-safe database leases. ## 2026-03-13 - `d969ff4` Guarded empty automation stats states in the admin UI. - `e50027e` Fixed automations admin session fetches. - `56ffb6e` Added super-admin waitlist provisioning. - `7ae422c` Auto-seeded QA automation workflows. - `2a90947` Shipped automation engine templates and runtime fixes. - `2007595` Added the missing commercial route helper. - `6b50429` Fixed the remaining open bug sweep items. - `f3d4bd9` Finished the remaining open bug sweep fixes. ## 2026-03-12 - `f6701ab` Fixed residential estimate draft edit persistence. - `0f3201f` Shipped missing shared modules required for Vercel builds. - `3d016f2` Fixed lead, job, payment, and delete UX flows. - `e739c55` Fixed the schedule Google Maps loader conflict. - `e56bb06` Fixed estimate override conversion to jobs. - `36d9d1e` Followed up with additional estimate override conversion fixes. - `4eb08e8` Fixed automation step availability and fleet save guards. - `bd0897f` Simplified shared flows and removed dead code. - `019ed8b` Fixed the automation test route build regression. - `36e8b21` Hardened automations and external URL flows. - `62de95c` Fixed the Margin Calculator render path when `costSettings` is missing. - `fcf71c2` Linked Settings to the new Automations area and added a legacy banner. - `24bd131` Added `automations.view` and `automations.manage` permissions. - `566a121` Added the AI-assisted Margin Calculator Engine with optimization suggestions. - `73c3203` Added Automation Engine v2 with a visual workflow builder. - `1b6e0fa` Added bulk multi-property job scheduling. ## 2026-03-11 - `65c9bfd` Restored navigation discoverability surfaces. - `e8dbea7` Fixed public `/ai` landing page access. - `3afe3c5` Added hard delete flows for core records. - `f362481` Temporarily disabled SMS sending through an environment flag. - `bda1ffa` Rebuilt the schedule dispatch board. - `466ea66` Fixed payment dialog warning text layout. - `3b26cea` Fixed payment dialog overflow behavior. - `88b642e` Widened the payment collection dialog. - `a94a03e` Added client navigation from lead detail. - `3a1de78` Fixed payment history modal layout. - `9ca5f56` Fixed AI Hub tone and formatting. - `0103b5b` Added client account job scheduling. - `ab29c14` Fixed AI Hub assistant quick actions. - `c440734` Switched AI lead scoring to legacy-safe columns. - `0d2e155` Hardened the AI lead scoring estimate query. - `3f8f694` Fixed AI lead score recalculation fallback behavior. - `dadb963` Added a shared tag picker workflow. - `2e763e0` Fixed recurring template scheduling. - `db24460` Fixed payment balance carryover and receipts. - `ddaf665` Fixed truck assignment compatibility. - `3579c1f` Required start and end dates for new jobs. - `9b12543` Removed PWA app prompts. - `2bf6856` Fixed crew and truck job assignment. - `b7a1b67` Polished payment collection dialog layout. - `7e49990` Fixed crew pay modeling and team compensation. - `bd8b6b8` Fixed estimate portal approvals and additional pending bugs. ## 2026-03-10 - `0e57f6f` Fixed bug reporting and client workflows. - `c771115` Dispatched accepted bugs to the OpenClaw runner. - `f407082` Added Telegram notifications when bug issues are created. - `4f9d925` Synced vetted bug reports to GitHub issues. - `dc00011` Added client address book and account setup flows. - `021a1cc` Fixed the admin gamification runtime crash. - `30e1c5b` Polished estimate detail and XP navigation. - `7384a51` Improved invoice send and payment workflows. ## 2026-03-09 - `9639502` Fixed messaging, conversion, and invoice workflows. - `d9b0008` Stabilized admin performance and inbox threads. - `970afa2` Added recurring job templates. - `e23fee5` Updated the quick start create menu. - `6c78c24` Installed missing build dependencies for Stripe and `html2canvas`. - `8c2654f` Fixed the commercial cost assumptions display data key mismatch. - `8bd4ff9` Fixed the Resend webhook build cast. - `b8d9a9d` Fixed email reply routing fallback behavior. - `c8d5a81` Fixed inbox sync and message delivery updates. - `64c3552` Fixed the admin sidebar and widened the workspace. - `804119f` Fixed dispatch assignment and settings navigation. - `b90ef28` Added legacy payments schema handling in the payment endpoint. - `e9780ba` Added a unified payment collection workflow. - `96d4081` Hardened webhook authentication and payment processing. - `17b3d21` Switched the marketing site to waitlist mode and disabled self-serve registration. - `2594332` Hardened the admin toaster and gamification seeding. - `b8579cc` Fixed a Next 15 API-route `params` await regression that caused 500 errors. - `2541fc3` Fixed gamification org membership profile lookups. - `4ba42d8` Fixed ambiguous org membership profile lookups. - `79ea433` Added automatic bug report screenshots. - `81c7ed3` Restored waitlist CTAs on marketing pages. - `875c1f5` Added the gamification foundation and leaderboard. - `3d4b2db` Updated the privacy policy and terms of service with official legal content. - `35778b8` Improved team onboarding and archive lifecycle behavior. - `ef2fc30` Fixed follow-up schema drift and restored admin links. - `f3b3904` Added the admin help button and docs search results. - `9682720` Added guarded MCP inbox write tools. - `9b923a3` Added MCP Phase 1 agent access. - `e69baae` Added actual job cost tracking to CRM margins. - `064f403` Added unified inbox internal notes. - `95dfe22` Bridged Workiz intake and hardened CRM analytics. - `2ad92b4` Routed admin lead creation through intake. - `98fd69e` Unified intake adapters and hardened sales timestamps. - `a4aa1bc` Deduplicated unified email message logging. - `41cfec3` Hardened lead intake and inbox filters. ## 2026-03-08 - `6242c0c` Added inbox ownership and response controls. - `9114acb` Rolled out the unified messaging foundation. - `65d8a76` Fixed the bug report email truncation suffix. - `33a46c2` Kept message threads scrollable during refresh. - `431ce4c` Added a bug report queue poller for automations. - `cf65b48` Improved bug report email details and JSON export. - `da618d1` Added bug report webhook alerts. - `e5f38f3` Fixed admin message scroll locking. - `3e00a57` Added the bug reporting system and app hardening work. - `728029f` Finished the CRM buildout and QA hardening push. ## 2026-03-07 - `5cadd2b` Restored Automations in the Settings nav. - `2bfbcc2` Fixed searching existing customers while scheduling jobs. - `85f7657` Hardened audited estimate and billing flows. - `f7bcfef` Shipped a lead-first workflow and added a jobs creation entry point. - `d34c3b7` Fixed the client account migration rollout. - `582242f` Added nested client accounts and estimate pagination. - `f89aa5d` Fixed holiday lights measure and drawing flow. - `4c0fbf7` Retired the legacy estimator and fixed the job invoice flow. - `f2382a1` Hardened estimate intake and send permissions. - `ad46c31` Fixed secure estimate links and auto-dial routing. - `787cd99` Fixed customer portal estimate links. - `b270e16` Restricted portal actions to known customers. - `c13fe52` Hardened public portal throttling and Workiz sync. - `843bea3` Finished a broad hardening and product redesign pass. ## 2026-03-06 - `3c3dad3` Unified web and mobile pricing logic and deduplicated `escapeHtml`. ## Generation Notes - This file is generated from the same MDX catalog that powers the docs site. - Article URLs are canonical docs.cleanestimate.pro URLs.