[{"t":"Welcome to Zodiac Tech CRM","u":"\/docs\/getting-started\/welcome","s":"Getting Started","sk":"getting-started","d":"What this documentation is, who it is for, and where to start \u2014 in the first five minutes.","b":"Welcome to Zodiac Tech CRM Zodiac Tech CRM is a **complete client-getting system** for small and mid-sized businesses: it catches every lead from Facebook and Instagram, drops it into a CRM your team actually uses, follows up automatically on WhatsApp and calls, and shows you exactly where your enquiries get stuck. This documentation covers **every part of the product** \u2014 for every person who touches it. Who is this for? Business owners** \u2014 you bought the system; this is your manual. Sales teams** \u2014 your daily workflows: leads, calls, follow-ups, WhatsApp. Ad specialists & agency staff** \u2014 the Meta ads console and client delivery. Super admins** \u2014 running the platform, creating businesses, billing and onboarding. Developers & hosting admins** \u2014 architecture, API, deployment and operations. Where to start The fastest path If you are setting up a new business, go straight to Client onboarding from zero \u2014 a complete walkthrough from first login to a live, tested CRM. If you run the platform, read the Client delivery playbook. I am a\u2026 | Start here | Business owner | Quick start (15 minutes) | Sales agent | Sales agent guide | Super admin | Super Admin overview | Ad specialist | Ads specialist guide | Developer | Architecture overview | Hosting admin | cPanel deployment | How to read this documentation Every guide answers the same questions: 1. **What is this?** \u2014 plain-language explanation. 2. **Who uses it and when** \u2014 the role and the moment. 3. **Exactly what to click** \u2014 step by step, with expected results. 4. **What can go wrong** \u2014 common mistakes and fixes. 5. **What happens underneath** \u2014 the technical detail, for when you need it. Can't find something? Use the **search** (top of every page, or \/ + ) \u2014 it searches every guide, error message and setting name."},{"t":"What is Zodiac CRM?","u":"\/docs\/getting-started\/what-is-zodiac-crm","s":"Getting Started","sk":"getting-started","d":"The product in plain language \u2014 the Meta \u2192 CRM \u2192 WhatsApp \u2192 reports loop, who it is built for, and what it honestly does and does not do.","b":"What is Zodiac CRM? Zodiac Tech CRM is a **client-getting system for Indian small and mid-sized businesses**. It catches every enquiry from your Facebook and Instagram ads, puts it into a CRM your team actually opens, follows it up on WhatsApp and phone calls, and shows you where enquiries are stuck \u2014 in one place, on web and Android. It is not just a contact list. It is the full path from *\"someone tapped your ad\"* to *\"someone paid you\"*. The core value loop Every part of the product exists to keep that loop turning: Stage | What Zodiac Tech CRM does | Capture** | Meta lead forms stream into the CRM automatically \u2014 webhook-verified, no CSV exports. | Organise** | Leads are assigned to agents, scored, and moved through your sales stages. | Follow up** | WhatsApp messages, templates and automations, plus click-to-call from the lead. | Convert** | Follow-up tasks, appointments and reminders so no enquiry is forgotten. | Measure** | Reports on lead volume, source performance, agent response times and revenue. | Who it is for Indian SMBs that advertise on Meta** \u2014 clinics, real estate, coaching centres, gyms, dealers, local services \u2014 anyone whose enquiries arrive through Facebook or Instagram. Business owners** who want to see exactly how many leads came in, who followed up, and what it earned. Sales teams of 1\u201320 people** who need a simple daily list \u2014 not a spreadsheet or a 100-screen enterprise tool. Digital agencies** that run Meta ads for many clients and need one operations console (the panel) to deliver them. Platform operators** who sell or self-host the CRM and manage many businesses from . The product is India-first: rupee formatting and GST-style billing details, Razorpay and Cashfree payment providers, WhatsApp as the primary follow-up channel, and a navigation built around the day plan (Leads \u2192 Follow-ups \u2192 Calls \u2192 WhatsApp \u2192 Appointments). What you get Leads & pipeline** \u2014 list, Kanban board, and the Lead 360 view with the full history of one customer. S"},{"t":"How the platform works","u":"\/docs\/getting-started\/how-the-platform-works","s":"Getting Started","sk":"getting-started","d":"The three panels, the public site, the docs portal and the mobile app \u2014 and how businesses, roles and data fit together on one install.","b":"How the platform works One installation of Zodiac Tech CRM runs many businesses. Each business gets its own workspace; the platform team, the Meta ads team and the business's own staff each see a different panel, built for their job. The surfaces of one install Surface | Address | Who uses it | Public website | and | Visitors, prospects; can self-register at when enabled | Documentation | | Everyone \u2014 this portal | Business workspace** (tenant panel) | | Business owner, managers, sales agents | Super Admin** (platform panel) | | The company running this install | Agency panel** (Meta Ops) | | Account managers, ads\/creative specialists, QA reviewers, support agents | REST API | | Integrations using API keys; health at | Mobile API | | The ZodiacTech CRM Android app ( ) using device tokens | API reference | | Developers | Businesses = tenants The **Business** (listed at ) is the unit of everything: users, leads, WhatsApp number, Meta connection, billing agreement. In developer language it is the table \u2014 the two words mean the same thing. Every database row belongs to exactly one business via a , enforced by a fail-closed global scope. A user signed into one workspace can never read another's data. The Super Admin panel binds an internal **LeadHub HQ** workspace so platform staff can use the same CRM surface for their own selling \u2014 it never appears in the client onboarding pipeline. The role model at a glance Where | Roles | Panel | Business workspace | (owner), , (sales agent) | | Platform | | | Agency (Meta Ops) | , , , , | | Business roles** are invited from inside the workspace. The owner ( ) has everything, managers run the team and day-to-day operations, members work leads. Platform super admins** bypass every gate \u2014 the canonical check is (the flag column OR the role). Agency roles** carry granular permissions checked on the panel pages themselves. Only holds ; a support person can never launch a campaign. Full details, including what each role cannot do, are in"},{"t":"Roles & who does what","u":"\/docs\/getting-started\/roles-overview","s":"Getting Started","sk":"getting-started","d":"Every real role on the platform, the panel it signs into, what it can do, and what it deliberately cannot do.","b":"Roles & who does what Nine roles exist in the product, across three panels. A person's role decides which panel they sign into and what they see once inside. Role | Panel | What they do | What they can't do | \u2014 Business Admin \/ Owner | | Everything in their own workspace: leads, team, WhatsApp, ads tools, reports, settings, Billing portal, guided setup. | Touch any other business; open the Super Admin or agency panels. | \u2014 Sales Manager | | Run day-to-day: all lead actions incl. delete\/import\/export\/assign, pipelines, forms, automations, reports, invite\/edit team members, send WhatsApp and manage templates, manager-tier settings (General, Branding, Business hours, Team). | Open the Billing portal; change admin-only settings (Email\/SMTP, WhatsApp connection, Security, API keys, Storage, AI, Messaging, Queue, Realtime); grant or revoke the role; edit or delete an admin. | \u2014 Sales Agent | | Work leads: view, create, edit and assign; move stages; log calls; send WhatsApp; view follow-ups, forms, reports. Works from the Android app too. | Delete or export\/import leads; manage team, settings, ads campaigns, billing, or automations. | \u2014 Platform Owner | | Manage every business, user and agency staff member; run the Client Onboarding dashboard; configure Meta Developer credentials, billing providers, mobile app settings, backups and updates. | Nothing platform-side \u2014 this role bypasses all gates. It is intentionally rare. | Own client delivery: Setup Queue, client workspace info, connect Meta, Client Requests, Support Desk, Live Chat, performance views. | Launch or pass QA ( is not granted); create\/edit campaigns; edit creatives. | Meta setup for clients, campaign building and pausing (permission set), Active Campaigns, Needs Attention, performance and portfolio views. | Pass QA \/ go live; manage creative work; edit client info; support desk. | Create and edit creatives in Creative Work (versioned); view campaigns and performance read-only. | Setup Queue work, client edits,"},{"t":"Your first login","u":"\/docs\/getting-started\/first-login","s":"Getting Started","sk":"getting-started","d":"Sign in as the business owner, understand the guided setup wizard, change your password, and find help \u2014 in the first ten minutes.","b":"Your first login You are the owner (or admin) of a new workspace. The platform team created your Business and sent you a welcome email \u2014 this page gets you signed in, secured and pointed at the guided setup. Who this is for Business owners and workspace admins on their first sign-in. Sales agents: sign in the same way, then read the Sales Agent guide \u2014 the setup wizard is owner-only. Prerequisites:** the welcome email from the platform team (it contains your login email and either a temporary password or a one-time password-setup link). Step 1 \u2014 Sign in at 1. Open your workspace login page \u2014 for a hosted install this is ; on the local XAMPP test install it is . 2. Enter your email and password, then submit. 3. If the email says \"set your password\", open the one-time link first ( ) and choose a password, then sign in. Expected result:** you land on the Home dashboard with a greeting and a summary of your day. Locked out? 5 failed attempts \u2192 15 minute cooldown The login page locks after 5 wrong attempts for 15 minutes (tracked in cache and a table). Wait it out or ask the platform team to reset your password. If you are on the **Super Admin** login page by mistake, the page banner links to the correct . Step 2 \u2014 The first-time welcome and setup chip On your first visit you will see a short welcome modal, and a **Setup NN%** chip in the topbar. They both point at the same thing: the guided setup wizard. 1. Dismiss the welcome modal (or click through its first steps). 2. Note the Setup chip \u2014 it stays in the topbar until onboarding is complete. 3. Explore freely first if you like: the wizard never punishes you for looking around. Expected result:** you know where the Setup chip is. It is your home base for the rest of setup. Step 3 \u2014 Start the guided setup wizard 1. Click the **Setup chip** (or the dashboard welcome banner) to open . 2. The wizard walks 12 client steps in order: Business details \u2192 industry \u2192 Connect Meta \u2192 Page & Ad Account \u2192 Lead forms \u2192 sales process "},{"t":"Quick start (15 minutes)","u":"\/docs\/getting-started\/quick-start","s":"Getting Started","sk":"getting-started","d":"The shortest honest path from a fresh workspace to your first real lead visible in the CRM \u2014 five steps, fifteen minutes, deep links where you need them.","b":"Quick start (15 minutes) This is the fastest path that actually works: finish the essential setup, connect Meta, push one test lead through, and see it in Leads. Fifteen focused minutes \u2014 the optional steps (WhatsApp, team, mobile) come after. Who this is for:** the workspace owner doing initial setup. Prerequisites:** you can sign in at (see Your first login), you administer the Facebook Page your ads run from, and you know which Meta ad account you use. Step 1 \u2014 Fill in the business basics (3 min) 1. Open the **Setup chip** in the topbar \u2192 . 2. Complete **Business details** (name, type, city) and **What type of business** (your industry). 3. Click through to **Connect Meta** and stop there for now. Expected result:** the setup progress moves past the first two steps the moment the data is saved \u2014 progress is derived from backend state, never from clicking. Step 2 \u2014 Connect Meta and pick your assets (5 min) 1. On the **Connect Meta** step, start the Facebook OAuth flow and approve the requested permissions for your Page and ad account. 2. On **Choose Page & Ad Account**, select the Facebook Page that receives your leads. 3. On **Lead forms**, select which lead forms may ingest into the CRM. No forms yet? Skip and return later \u2014 the step auto-completes once forms are selected. 4. Map the form fields to CRM fields (name, phone, email are matched automatically; fix anything that landed in the wrong column). Expected result:** the Meta connection shows healthy and your selected Page, ad account and forms are listed. Only selected forms ingest Leads arrive only from the forms you tick here. This is deliberate \u2014 a shared ad account with campaigns you don't run cannot pollute your CRM. Deep dive: Connect Meta (Facebook) and Lead forms & mapping. Step 3 \u2014 Sales process and routing (3 min) 1. Continue to **Set up your sales process** \u2014 either install an industry pack or accept the default pipeline stages. 2. On **Lead assignment**, choose how new leads are distributed: off "},{"t":"Client onboarding from zero","u":"\/docs\/client-setup\/onboarding-from-zero","s":"Client Setup","sk":"client-setup","d":"The complete client onboarding journey \u2014 from your first login to a live, tested CRM, step by step through the guided setup wizard.","b":"Client onboarding from zero This is the complete journey for a brand-new workspace: you log in for the first time, the **guided setup wizard** walks you through 12 short steps, and you finish with a CRM that is connected to your Facebook Page and has proven it can catch a real lead. Nothing here is technical. If you can use Facebook and WhatsApp, you can do this yourself. The wizard is always there for you The wizard lives at ** ** and is called **\"Set up your workspace\"**. While you are a workspace owner or admin and setup is not finished, opening the CRM takes you straight there. A small **Setup NN%** chip in the top bar shows your progress and opens the step drawer. Who this is for Business owners** doing their own setup (no technical knowledge needed). Workspace admins** setting the CRM up on behalf of the business. Anyone re-checking what a skipped step means. Difficulty:** Easy \u00b7 **Time:** 30\u201345 minutes \u00b7 **Prerequisites:** Your login email and password (sent to you when your workspace was created). A Facebook account that can already manage the Facebook **Page** you advertise with, and access to the **ad account** that runs your campaigns. Email addresses of the team members you want to invite (optional \u2014 you can add them later). Only owners and admins see the wizard Sales agents (members) never get redirected into the wizard. Only workspace **owners\/admins** run setup. The journey at a glance Wizard step | What you do | Detail guide | 1 | Business details | Your business name, type and city | Business details | 2 | What type of business | Pick your industry \u2014 installs a ready-made template | Business details | 3 | Connect Meta | Log in to Facebook safely (OAuth) \u2014 no password is ever shared | Connect Meta | 4 | Choose Page & Ad Account | Tell the CRM which Page and ad account to watch | Choose your Page & Ad Account | 5 | Lead forms & mapping | Tick the Meta lead forms to import and map their answers | Lead forms & mapping | 6 | Sales process | Your pipeline"},{"t":"Business details","u":"\/docs\/client-setup\/business-details","s":"Client Setup","sk":"client-setup","d":"Wizard steps 1\u20132 \u2014 tell the CRM about your business, then pick your industry so a ready-made sales process is installed for you.","b":"Business details The first two wizard steps are about **who you are**: your business identity (step 1, \"Tell us about your business\") and your industry (step 2, \"What type of business do you run?\"). The industry choice is the important one \u2014 it installs a ready-made sales process, lead fields and automations tuned to your line of work, so you start with a working CRM instead of a blank one. Who this is for Workspace owners and admins doing initial setup. Anyone changing the recorded business name, type or industry later. Difficulty:** Easy \u00b7 **Time:** 3\u20135 minutes \u00b7 **Prerequisites:** you are logged in as owner\/admin and the guided wizard is open. Step 1 \u2014 Tell us about your business 1. Open (the first step is waiting on a fresh workspace). Enter: Business name** \u2014 how your business should appear everywhere in the CRM (for example \"Sunrise Institute\"). Business type** \u2014 the kind of company you run (helps recommendations and reporting). City** \u2014 where you operate; used on customer-facing messages and reports. 2. Save the step. 3. **What happens:** the values are written to your workspace settings and the step is verified against real state. 4. **Expected result:** the step shows **Done** and the wizard advances to **What type of business do you run?** Use these values on invoices for details The business name is what your team sees across the CRM. Use the name your customers know you by. Step 2 \u2014 What type of business do you run? 1. Pick the card that matches your business best. The available packs are: Industry | Pack key | Agency | | Automobile \/ dealership | | Coaching \/ training | | Dental clinic | | Ecommerce | | Education \/ institute | | Finance & CA | | Law firm | | Local services | | Medical clinic | | Real estate | | 2. If none fits, choose **Other** \u2014 you will build your own sales process later in the wizard. 3. Confirm the step. 4. **What happens:** choosing an industry installs that **industry pack** into your workspace: one pipeline with its stages (your "},{"t":"Connect Meta (Facebook)","u":"\/docs\/client-setup\/connect-meta","s":"Client Setup","sk":"client-setup","d":"Wizard step 3 \u2014 connect your Facebook Page to the CRM safely with OAuth. You never share your Facebook password, and you can revoke access any time.","b":"Connect Meta (Facebook) This is wizard step 3: **\"Connect your Facebook account\"**. Connecting lets the CRM read the lead forms on your Facebook Page and receive new leads the moment someone submits them. The connection uses Facebook's official login (OAuth) \u2014 **your Facebook password is never entered into, seen by, or stored in the CRM**. Who this is for Workspace owners and admins doing initial setup. Admins re-connecting after a token expired or a password change. Difficulty:** Easy \u00b7 **Time:** 3\u20135 minutes \u00b7 **Prerequisites:** A Facebook account that **manages the Facebook Page** you advertise with (usually a business admin of the Page). Pop-up windows allowed for your CRM address (the Facebook login opens in a popup). Your CRM is reachable over HTTPS in production \u2014 Meta only redirects back to secure addresses. What the CRM asks Facebook for Four standard permissions: read your **lead forms and leads** ( ), see your **Pages** ( , ), and manage **ads** for reporting ( ). Nothing is posted to Facebook on your behalf. Step by step 1. Start the connection 1. In the wizard step **Connect your Facebook account**, click **Connect Facebook**. You can also do this outside the wizard: **Settings \u2192 Connections \u2192 Lead Source Connections \u2192 Connect** (one of the connection rows for Meta). 2. **What happens:** a Facebook login window opens. Log in (if asked) and approve the permissions for the Page(s) you manage. 3. **Expected result:** Facebook redirects back to your CRM and the connection row shows a connected state. In the wizard you should now see a checklist with four lines: Checklist line | What it confirms | Facebook Page | The CRM can see your Page | Instagram | Whether an Instagram account is linked to the Page | Ad Account | The CRM can look up your ad accounts | Lead Forms | The CRM can read (or later fetch) forms on the Page | 2. What happens next If you manage **one Page**, the CRM selects it automatically and you continue straight to **Choose your Page & Ad Accou"},{"t":"Choose your Page & Ad Account","u":"\/docs\/client-setup\/select-page","s":"Client Setup","sk":"client-setup","d":"Wizard step 4 \u2014 tell the CRM exactly which Facebook Page to watch for leads and which ad account your campaigns run in.","b":"Choose your Page & Ad Account This is wizard step 4: **\"Choose your Page & Ad Account\"**. Two choices: Page** \u2014 the Facebook Page whose lead forms the CRM watches. Leads only flow in for the Page selected here. Ad Account** \u2014 the ads account your campaigns run in. It lets the CRM link each lead back to the campaign and ad that produced it. Both are required: the step completes when the CRM has a Page **and** an ad account stored. Who this is for Workspace owners and admins finishing Meta setup. Anyone re-selecting after being given access to a different Page or ad account. Difficulty:** Easy \u00b7 **Time:** 3\u20135 minutes \u00b7 **Prerequisites:** Connect Meta is complete \u2014 the CRM can already see your Facebook assets. Step by step 1. Choose your Page 1. In the **Page** dropdown (labelled **\"Choose your Page\u2026\"**), select the Page your ads and lead forms belong to. 2. **What happens:** the CRM stores the Page id and its Page access token on your Meta connection. 3. **Expected result:** the Page name appears in the selection, the step is satisfied for the Page half, and the lead forms for that Page become fetchable. If you only manage one Page The CRM selects it automatically during Connect Meta and you may not see a dropdown at all. You can still change it later from the connection row. 2. Choose your ad account 1. Pick your ad account from the dropdown. If the list is empty or incomplete, click **Find my Ad Accounts** to re-fetch them. You can also type the ad account id manually \u2014 the format is (the prefix plus the numeric id from Ads Manager). 2. **What happens:** the ad account id is saved with the connection and used to attribute incoming leads to campaigns and ads. 3. **Expected result:** both fields are filled; the wizard step shows done and the next step (**Choose your lead forms**) opens. 3. Changing a selection later (multi-Page workspaces) 1. Go to **Settings \u2192 Connections \u2192 Lead Source Connections**. 2. On the Meta connection row choose **Select Page** \u2014 an **Active "},{"t":"Lead forms & mapping","u":"\/docs\/client-setup\/lead-forms","s":"Client Setup","sk":"client-setup","d":"Wizard step 5 \u2014 fetch your Meta lead forms, tick the ones to import, and confirm where each answer lands in the CRM.","b":"Lead forms & mapping This is wizard step 5: **\"Choose your lead forms\"**. Two jobs: 1. **Choose which Meta lead forms to import** \u2014 the CRM only ingests leads from forms you tick here. Everything else stays in Meta. 2. **Map each form answer to a CRM field** \u2014 so a Meta form question (\"Full name\") lands in the right place ( , , \u2026) instead of a generic blob. Who this is for Workspace owners and admins finishing Meta setup. Anyone adding a new Meta form later, or fixing a mapping after a test lead failed. Difficulty:** Easy \u00b7 **Time:** 5 minutes \u00b7 **Prerequisites:** Choose your Page & Ad Account is complete. Step by step 1. Fetch your forms 1. In the step, click **Find my lead forms**. 2. **What happens:** the CRM asks Meta for the lead forms on your selected Page and lists them with their names and statuses. 3. **Expected result:** your forms appear as checkboxes. If the list is empty, your Page genuinely has no forms yet (create one in Meta Ads Manager first, then click **Find my lead forms** again). 2. Tick the forms to import 1. Tick every form you actually advertise with. Only ticked forms are imported. Unticked forms are actively **skipped** when a lead arrives \u2014 by design, so test or obsolete forms never pollute your CRM. 2. **What happens:** the selection is saved with an \"enabled\" marker, and the CRM starts watching exactly those forms. 3. **Expected result:** the tick list shows your chosen forms. The warning below the list disappears once at least one form is ticked. Tick at least one form to start receiving leads If nothing is ticked, the step shows: *\"Tick at least one form to start receiving leads. You can also come back later.\"* With no form selected, live leads are **skipped**, not queued. 3. Confirm the field mapping 1. Review **\"Where should each answer go in your CRM?\"** \u2014 one row per form question, with a suggested destination already filled in. 2. Adjust any row if needed. Available destinations: Destination | Meaning | \/ | Split name fields | Ful"},{"t":"Set up your sales process","u":"\/docs\/client-setup\/sales-process","s":"Client Setup","sk":"client-setup","d":"Wizard step 6 \u2014 create your pipeline and stages with a ready-made industry template, or build your own.","b":"Set up your sales process This is wizard step 6: **\"How should your team handle new leads?\"**. A sales process is a **pipeline** (the overall journey) made of **stages** (the steps a lead moves through \u2014 for example New \u2192 Contacted \u2192 Visit booked \u2192 Won \/ Lost). Every lead card sits in a stage, and moving cards through stages is how your team works the board. Who this is for Workspace owners and admins during setup. Managers who want to reshape the pipeline after setup. Difficulty:** Easy \u00b7 **Time:** 3\u20135 minutes \u00b7 **Prerequisites:** earlier wizard steps are done (or at minimum, you are logged in as owner\/admin). Step by step 1. Choose how to build it The step offers two paths: Button | What it does | Create my sales process** | Installs a ready-made pipeline and stages for your industry (based on the industry chosen in step 2) \u2014 you can edit it any time | Set it up myself** | Opens the Pipelines area so you can create your own pipeline and stages from scratch | 1. Click **Create my sales process** for the fast path. 2. **What happens:** a pipeline with several stages is created for your workspace, based on your industry pack. 3. **Expected result:** the step shows your stages as a coloured flow, for example: 2. Review and edit stages 1. If a pipeline already exists, the step shows **\"Your sales process is ready. Leads move through these steps:\"** with the stage list and an **Edit** link. 2. Click **Edit** (or **Set it up myself**) to open the Pipelines area, where you can: rename stages to match how your team actually talks, add or remove stages, reorder stages into the real progression, give each stage a colour for the board. 3. **Expected result:** the step settles as done once your largest pipeline has **at least two stages**. Why two stages minimum A single-stage pipeline cannot show movement \u2014 no \"where is this lead now?\" state, no Kanban columns to drag between, and no funnel reporting. The wizard deliberately requires 2+ stages before the step counts as comple"},{"t":"Lead assignment & follow-ups","u":"\/docs\/client-setup\/lead-routing","s":"Client Setup","sk":"client-setup","d":"Wizard steps 7\u20138 \u2014 decide who receives each new lead and set up the automatic follow-up that stops leads being forgotten.","b":"Lead assignment & follow-ups These are wizard steps 7 (**\"Who should receive new leads?\"**) and 8 (**\"Make sure no lead is forgotten\"**). Together they answer two questions an unattended CRM gets wrong every day: Who owns a new lead?** \u2014 so it is never left in a queue nobody checks. What reminds us to work it?** \u2014 so a lead is contacted within the hour, not \"eventually\". Who this is for Workspace owners and admins during setup. Managers fine-tuning routing after the team grows. Difficulty:** Easy \u00b7 **Time:** 3\u20135 minutes \u00b7 **Prerequisites:** at least one other team member exists if you choose anything other than **Unassigned** (invite them in Add team members). Step 7 \u2014 Who should receive new leads? Pick one of four modes: Option | Behaviour | Best for | Round Robin** | New leads are handed out one by one across the selected team members | Teams of 2+ who share lead intake fairly | Sales Manager** | New leads go to your workspace manager (the first active user with the Manager role) | Small teams where the manager triages | Specific Team Member** | Every new lead goes to one chosen person | A single-person sales operation | Unassigned** | Leads arrive in the list without an owner; your team picks them up | Review-first setups \u2014 **not recommended**, leads get missed | 1. Select a mode. For **Round Robin**, tick the team members who should share new leads. For **Specific Team Member**, choose the person. 2. **What happens:** the rule is saved to workspace settings as . From then on, every new lead that arrives **without** an owner is assigned by this rule. 3. **Expected result:** the step shows done and the follow-up step opens. Half the error messages you may see Choosing **Sales Manager** before a manager exists shows: *\"No Sales Manager is set up yet \u2014 invite one or choose another option.\"* Invite a manager first (Add team members) or pick another mode. Changing routing later Routing is not locked to the wizard: **Settings \u2192 Lead Assignment** holds the same rule wit"},{"t":"Add team members","u":"\/docs\/client-setup\/team-members","s":"Client Setup","sk":"client-setup","d":"Wizard step 9 \u2014 invite your sales agents and managers, understand seats and roles, and manage the team afterwards.","b":"Add team members This is wizard step 9: **\"Who will use the CRM?\"**. Invite the people who sell for you \u2014 each gets their own login, their own leads, and (optionally) the Android app. This step is **optional**: you can skip it and invite the team any time from **Settings \u2192 Team**. Who this is for Workspace owners and admins. Managers onboarding new sales agents mid-year. Difficulty:** Easy \u00b7 **Time:** 3\u20135 minutes \u00b7 **Prerequisites:** none. The step works before any other setup and can be re-run later. Step by step 1. Add rows for your people 1. In the step, click **+ Add team member** for each person and fill: Field | Notes | Name** | Shown across the CRM (lead activities, reports, assignment) | Email** | Where the invitation is sent \u2014 double-check it | Phone** | Optional, used for their mobile app identity and call matching | Role** | **Sales Agent** (works leads day to day) or **Manager** (sees the whole team's work) | 2. **Send invitations.** 3. **What happens:** each person gets an email invitation with a link to set a password and join your workspace. The invitation is valid for **7 days**. 4. **Expected result:** the step's seat line updates (for example *\"3 of 5 seats used\"*), and the wizard marks the step done once your workspace has more than one user. All seats in use? If the plan's seat limit is reached, the step shows **\"All seats are in use\"** and new invitations are blocked. Remove a member or upgrade the plan (your account manager can help), then invite again. 2. What people see Sales Agents** land in the regular CRM: their leads, pipeline, calls, WhatsApp, follow-ups. Managers** additionally get team-wide views: all leads, assignment controls, agent reports. The full picture is in Roles & who does what. 3. Manage the team afterwards Open **Settings \u2192 Team** for the single team hub: see seats used vs available, invite** more members (same flow as the wizard), suspend** an account (they can no longer sign in), reset a password**, remove** a member. Tea"},{"t":"Connect WhatsApp","u":"\/docs\/client-setup\/connect-whatsapp","s":"Client Setup","sk":"client-setup","d":"Wizard step 10 \u2014 connect your WhatsApp Business number via the WhatsApp Cloud API. Optional, but it is where most conversations happen.","b":"Connect WhatsApp This is wizard step 10: **\"Talk to leads on WhatsApp\"**. Connecting brings your WhatsApp Business number into the CRM: leads can be messaged, replies land in the WhatsApp inbox next to their lead record, and automations can greet new leads instantly. This step is **optional and skippable** \u2014 the wizard says it plainly: *\"You can set this up any time \u2014 it is not required to start using your CRM.\"* Who this is for Workspace owners and admins connecting the business number. Admins re-connecting after a token was rotated. Difficulty:** Medium (you copy a few values between Meta and the CRM) \u00b7 **Time:** 10 minutes \u00b7 **Prerequisites:** A **WhatsApp Business Account (WABA)** with a phone number registered on the WhatsApp Cloud API. A Meta app\/business that can see that WABA, with a **permanent access token** and the **app secret**. Admin access to the platform's Meta configuration (ask Zodiac Tech support if the number was set up for you). Step by step 1. Open the WhatsApp settings 1. In the wizard step, click **Connect WhatsApp** (or go directly to **Settings \u2192 Connections \u2192 WhatsApp**, ). 2. **What happens:** the WhatsApp connection page opens with the credential fields and a webhook callback URL. 2. Fill in the connection details Field | Where it comes from | WABA ID** | Your WhatsApp Business Account id (Meta Business settings) | Phone number ID** | The id of the sending phone number (Cloud API settings \u2014 the numeric id, not the phone number itself) | Display phone number** | The number your customers see (for example ) | Access token** | A permanent token with WhatsApp messaging permission | App secret** | The Meta app's secret (used to verify incoming webhooks) | Verify token** | A value **you choose** \u2014 it must be identical in Meta's webhook configuration and here | 1. Paste the values and **Save**. 2. **What happens:** the CRM runs a health check against the number, then stores the credentials **encrypted at rest**. On later saves, a masked value ("},{"t":"Mobile app setup","u":"\/docs\/client-setup\/mobile-app-setup","s":"Client Setup","sk":"client-setup","d":"Wizard step 11 \u2014 get the Android app onto your team's phones so leads, calls and notifications reach them wherever they are.","b":"Mobile app setup This is wizard step 11: **\"Get the app on your team's phones\"**. The Android app is how your sales team works from the field: sees new leads instantly, calls from the CRM, logs calls automatically, and gets push notifications. This step is **optional** \u2014 everything also works in the browser \u2014 but for calling and notifications it is where the real value is. \"Try the demo account\" is for your own preview only \u2014 your team signs in with their real CRM credentials.* Who this is for Workspace owners and admins distributing the app. Each team member installing it on their own phone. Difficulty:** Easy \u00b7 **Time:** ~5 minutes per phone \u00b7 **Prerequisites:** team members invited (Add team members); Android phones. Step by step 1. Download and install 1. In the wizard step, click **Download Android App** \u2014 this uses your workspace's download link. 2. On each phone: open the link, download the APK and allow installation from the browser when Android asks (\"Install unknown apps\" for that browser). 3. Open **LeadHub** after install. 4. **Expected result:** the app opens on the login screen. No Play Store needed The app is distributed as a direct download \u2014 your team does not need a Google Play account. 2. Log in 1. Sign in with the same credentials the person uses in the browser (email + password, or an OTP where your workspace enables it). 2. **What happens:** the app resolves the workspace from the account and registers the phone as a trusted device. 3. **Expected result:** the Dashboard\/Home screen shows their leads. 3. Grant permissions and check device health 1. Grant the permissions the app requests: Notifications** \u2014 for push notifications. Phone \/ Call log** \u2014 for calling and automatic call logging. Contacts** (optional) \u2014 nicer call handling. 2. Open **Device Health** in the app and verify the basics: server reachable, notifications enabled, call tracking allowed. The app also records what calling\/recording capabilities the phone supports \u2014 honestly, per "},{"t":"Test your setup","u":"\/docs\/client-setup\/test-lead","s":"Client Setup","sk":"client-setup","d":"Wizard step 12 \u2014 send a test lead through your real setup and read the five checks that prove your CRM works end to end.","b":"Test your setup This is the final wizard step: **\"See how a new lead flows in\"**. Clicking **Send test lead** runs your entire pipeline for real \u2014 routing, automation, notification \u2014 and reports back with five checks. It is the difference between \"we clicked through the setup\" and \"we know it works\". Who this is for Workspace owners and admins finishing setup. Anyone re-verifying after changing routing, forms or automations. Difficulty:** Easy \u00b7 **Time:** 1\u20133 minutes \u00b7 **Prerequisites:** you are in the wizard on the final step. Routing and follow-up steps are ideally settled \u2014 the test will tell you if they are not. Step by step 1. Send the test lead 1. Click **Send test lead**. 2. **What happens:** the CRM creates a **real lead** in your workspace: Source: **Meta**, Name: **Test** **Lead**, Phone: **+91 90000 00000** (a placeholder number), Tagged **Test Lead** in amber so it is impossible to miss, Then it runs your normal pipeline exactly as production would: assignment, follow-up automation, notification. 3. **Expected result:** the lead appears with a result line like **\"Test lead #42 is in your Leads list\"**, followed by the five checks. 2. Read the five checks Check | What it proves | If it fails | \u2713 **Lead created** | A lead row was actually written | Retry once; contact support if it persists | \u2713 **Fields mapped** | Name and phone arrived in their proper fields | Fix the Meta form mapping (Lead forms & mapping) | \u2713 **Assigned** | Your routing rule gave the lead an owner | Set an assignment mode (Lead assignment & follow-ups) | \u2713 **Follow-up created** | The automation created the \"+1 hour\" task | Enable the **New Lead Follow-up** automation | \u2713 **Notification** | The assignee received a CRM notification | Usually the same fix as **Assigned** \u2014 notifications go to the lead's owner | 4. **What happens:** the checks are recorded against your onboarding, the step is marked verified, and the wizard moves to the completion screen. 3. Clean up (optional) The test le"},{"t":"Finish & go live","u":"\/docs\/client-setup\/finish-setup","s":"Client Setup","sk":"client-setup","d":"What happens after the wizard completes \u2014 what Zodiac Tech does next, where to re-open setup, and what skipped steps mean.","b":"Finish & go live You made it: the wizard shows **\"Setup complete\"**. This page explains what that screen means, what happens behind the scenes next, and where to go if you ever need to revisit setup. Who this is for Business owners and admins who have just finished the guided onboarding. Anyone coming back later asking \"what did we skip?\" or \"how do I re-open setup?\". Difficulty:** Easy \u00b7 **Time:** 2\u20133 minutes reading \u00b7 **Prerequisites:** the wizard's steps are settled (all completed or explicitly skipped). What the completion screen shows 1. **\"Setup complete\"** with the message *\"Our team is preparing your campaigns. You don't need to do anything right now. We'll notify you when your campaigns are ready.\"* 2. A checklist of everything you configured \u2014 steps you deliberately skipped are marked **\"(skipped)\"**, so everyone can see exactly what is still open. 3. A **Go to Dashboard** button. Expected result:** clicking **Go to Dashboard** takes you into the CRM; the **Setup** chip disappears from the top bar and the CRM no longer redirects you to the wizard. Your setup is now verified, not assumed Every completed step was checked against the real system \u2014 the pipeline exists, the forms are ticked, the Meta token works, and a test lead flowed through. Skipped steps are the only soft spots, and they are visible to you and to us. What happens after you finish 1. **Zodiac Tech is notified automatically** that your setup is complete. 2. Our team works through its internal delivery checklist \u2014 CRM configuration, sales-process review, lead-routing review, campaign setup, creatives, tracking, QA, launch, monitoring. 3. **You do not need to do anything** until we tell you your campaigns are ready. Campaign work sits with our ad specialists; your CRM is already live and receiving leads from the forms you connected. Leads are already flowing Completing setup does not switch lead intake on or off \u2014 it was already live the moment forms were ticked and the Meta connection was heal"},{"t":"Business Admin \/ Owner","u":"\/docs\/roles\/business-admin","s":"Role Guides","sk":"roles","d":"The owner's routine \u2014 daily dashboard check, team and WhatsApp oversight, weekly reports, the billing portal, and the settings only you can touch.","b":"Business Admin \/ Owner You are the of a workspace \u2014 normally the business owner. You hold every permission in your workspace: nobody can see or change more than you, and a few things **only** you can do (Billing, admin-only settings, granting admin to others). Who this is for Owners and workspace admins of a single Business. If you manage the whole platform, you belong in Super Admin instead. Your daily routine (10 minutes) 1. **Home dashboard** \u2014 sign in at and glance at the top: today's greeting summary and the **live lead feed** \u2014 leads arriving right now; needs-attention** widgets \u2014 missed follow-ups, unanswered conversations, unassigned leads. 2. **Leads** \u2014 . Filter to *unassigned* or the first pipeline stage; make sure nothing is rotting at the top. 3. **Follow-ups** \u2014 anything overdue today should be reassigned or rescheduled before lunch. 4. **WhatsApp \u2192 Inbox** \u2014 . Check unanswered threads; you can reply inside the 24-hour window or send a template when it has closed. 5. Done \u2014 your team (and the mobile app) handle the calls. Expected result:** you always know your lead count, your overdue follow-ups and your unanswered chats without asking anyone. Your weekly routine (30 minutes) 1. **Reports** (sidebar group) \u2014 review at least: Lead volume** \u2014 did you get more or fewer leads this week? Source performance** \u2014 which Page\/form campaigns actually produce leads; Agent performance** and **Response time** \u2014 who is fast, who leaves leads waiting; Funnel \/ bottleneck** \u2014 the stage where deals stall. 2. **Ads \u2192 Overview** \u2014 \u2014 a quick read on spend vs leads (the full ads operation is run by the Zodiac Tech team via the agency panel). 3. **Team Members** \u2014 confirm everyone who needs access has it, and nobody who left still does. 4. **Billing** \u2014 see the section below. Managing the team Team Members (day-to-day) Sidebar \u2192 Team \u2192 **Team Members** ( ). Invite a teammate: create member \u2192 they receive an invitation; roles available are member**, **manager** and **admin**"},{"t":"Sales Manager","u":"\/docs\/roles\/sales-manager","s":"Role Guides","sk":"roles","d":"Run the sales floor \u2014 monitor reports and response times, keep the team moving, use the AI assistant, and know exactly which settings are (and are not) yours.","b":"Sales Manager You hold the role: the workspace's operations lead. You can do everything with leads and most things with the team, but you cannot touch credentials, billing, or promote anyone to admin. Who this is for Sales managers \/ team leads who run agents day to day and report to the business owner. Owners: read Business Admin \/ Owner instead. What you can do All lead operations** \u2014 view, create, edit, **delete, import, export, bulk-assign**; move stages; mark won\/lost; log calls and notes. Pipelines & stages** \u2014 view and manage ( ). Forms** \u2014 full CRUD on lead-capture forms. Automations** \u2014 create and edit lead automations. Integrations** \u2014 view and manage connected integrations (not platform credentials). Reports** \u2014 view and export everything the Reports group offers. WhatsApp** \u2014 send, manage templates, view logs. The connection\/credentials stay admin-only. Team** \u2014 invite members, edit member\/manager profiles, change roles between member\/manager. Never an admin's profile, and never the admin role itself. Manager-tier settings** \u2014 General, Branding, Business hours, Team. Your daily rhythm Morning \u2014 the numbers and the bottlenecks 1. **Home dashboard** \u2014 scan the live lead feed and the needs-attention widgets. 2. **Leads \u2192 first stage** \u2014 . Add the saved filter for \"new, uncontacted\" and assign or clear the queue. 3. **Follow-ups** \u2014 anything overdue before today gets owned by someone specific. 4. **Reports \u2192 Response time** \u2014 if today's first-response average is slipping, say so now, not at the weekly review. Mid-day \u2014 unblock the floor WhatsApp Inbox** ( ) \u2014 look for stale, unanswered threads. Remember the 24-hour rule: outside the customer-service window, free-form replies fail; send an approved template instead. AI assistant** ( ) \u2014 ask for a summary like \"leads in stage X this week with no activity\" and turn the answer into assignments. The assistant reads your workspace data; it does not act on its own. Calls** \u2014 spot-check that call outcomes are being "},{"t":"Sales Agent","u":"\/docs\/roles\/sales-agent","s":"Role Guides","sk":"roles","d":"The agent's full loop \u2014 receive a lead, open Lead 360, call, log the outcome, follow up, move the stage, book a meeting and message on WhatsApp, on desktop and Android.","b":"Sales Agent You hold the role \u2014 the person on the phone. Your job in the CRM is one loop, repeated: open the lead, call, log what happened, set the next step, move the stage.** Who this is for Sales agents working leads in a business workspace, on desktop ( ) or the Android app. You do not configure anything \u2014 if something is missing, ask your manager. Your day, start to finish 1. Receive the lead A new lead arrives by push notification (mobile app) or appears in your **Leads** list. If your workspace uses round-robin assignment, it is already yours. If not, your manager assigns it \u2014 check Leads \u2192 filter by assigned to you. 2. Open Lead 360 1. Sidebar \u2192 **Leads** \u2192 click the lead (or open it from a follow-up). 2. The detail page is the **Lead 360** view: contact details, source, stage, owner, the full timeline (notes, calls, WhatsApp, tasks, stage history), and the next-best-action hints. 3. Call the lead 1. Click **Call lead** on the lead \u2014 click-to-call rings **your** phone first, then bridges to the customer. (Make sure your profile has your correct phone number.) 2. On the mobile app the call opens in your dialer; supported devices can report call capabilities and, on some devices, import recordings \u2014 see Calling from the CRM and Call recording & what your phone supports. 4. Log the result (never skip this) 1. Back on the lead, click **Log call**. 2. Fill direction, duration and **Outcome** \u2014 Connected, Left Voicemail, No Answer, Not Interested, or Requested Callback. 3. Add a one-line note you would want to read next week. Expected result:** the call appears on the Lead 360 timeline and counts in every report. 5. Create the next follow-up 1. On the lead, click **Create task** (a follow-up). 2. Set title, due date, priority and reminder. 3. For a \"call me later\" outcome, set the date the customer asked for \u2014 not tomorrow by default. Expected result:** the task appears in **Follow-ups**, on your dashboard and in your mobile app. Nothing gets remembered in your he"},{"t":"Super Admin","u":"\/docs\/roles\/super-admin","s":"Role Guides","sk":"roles","d":"The platform owner's seat \u2014 businesses, users, the onboarding pipeline, Meta credentials, billing, the Android fleet and system settings, with the delivery playbook to run it all.","b":"Super Admin You run the install. Everyone else lives inside one workspace; you manage all of them \u2014 creating businesses, watching onboarding progress, holding the Meta app credentials, running billing, and keeping the system healthy. Who this is for The company operating Zodiac Tech CRM (platform owner \/ technical operator). Super admin is the only role that bypasses every gate; grant it sparingly. Prerequisites:** a super admin account ( column or the role \u2014 the canonical check is ), signing in at . The daily sweep (15 minutes) 1. **Home** ( ) \u2014 KPIs and activity: new workspaces, recent payments, total\/this-month leads. The banner tells you if a newer version is available. 2. **Client Onboarding** ( ) \u2014 one row per business: guided progress, current step, payment state, Meta connection health, and a **stuck-client** warning with a one-click *Request Action*. A daily sweep flags stuck clients automatically at 08:15**. 3. **Meta Developer** ( ) \u2014 check the health card: app credentials present and the last token check result. Webhook and token pings ride the scheduler, so a red card usually means cron is down, not that Meta broke. 4. **Backups** ( ) \u2014 confirm last night's backup ran (nightly at 02:00** when enabled). Businesses (tenants) \u2014 the list of every Business. Per business you can: Create** a workspace: name, slug (also the public landing URL), owner details, plan, trial dates and seat cap. The owner receives the welcome email with login details. Edit** plan, seats, trial\/subscription dates and status notes. Suspend \/ Reactivate** \u2014 suspended members lose access on their next request and see the subscription-required page; the owner is notified. Suspension is reversible. Impersonate** \u2014 sign in *as* the workspace to reproduce a support issue. An impersonation bar is shown for the whole session and the action is audited; never use it to make changes the client would not expect. Internal workspace \"LeadHub HQ\" \u2014 the install's own workspace for selling the product"},{"t":"Account Manager","u":"\/docs\/roles\/account-manager","s":"Role Guides","sk":"roles","d":"Own the client journey in the agency panel \u2014 setup queue, client workspaces, Meta connections, client requests, support desk and live chat.","b":"Account Manager You are the client's day-to-day owner inside Zodiac Tech. You run the Setup Queue, keep every client workspace moving, ask clients for what you need (like a Facebook connection), and handle their requests and support conversations. Who this is for Zodiac Tech agency staff with the role. You sign in at , not or . Your platform account is created by a super admin at . Prerequisites:** your agency account exists, and a super admin has assigned you as owner on at least one client workspace (or you work the shared queue). Your permissions in plain language From : Granted | Meaning | See the agency panel: Overview, All Clients, Active Campaigns, Needs Attention, Daily Brief, Portfolio Report, Team Workload. | Work the Setup Queue: tick checklist items, set stage status\/owner\/due dates. | Edit client workspace info, change client status, assign staff to roles. | Help connect a client's Meta (OAuth, page\/ad-account selection). | Client Requests queue, Support Desk, Live Chat. | Campaign and portfolio performance dashboards. | Not granted, deliberately: (go-live), , , , . Your daily routine 1. Work the Setup Queue 1. Open **Meta Ads \u2192 Setup Queue** ( ). 2. Read it as: *which client needs work, at what stage, owned by whom, doing what next, blocked by what, due when.* Sort by Due and clear the reds first. 3. Broken down by progress, stage, owner, status, next action, due date \u2014 filter by **Owner** to see only yours, or by **Status** ( , , ). Expected result:** every client has an owner and a next action; nothing sits unowned. 2. Open a client and drive the stages Click a client row to open the workspace view: 1. **Stages panel** \u2014 each stage (from CRM configuration through Go Live) has a checklist. Tick items as they are genuinely done, set the stage **status**, **owner** and **due date**. 2. **Edit Profile & Assignments** \u2014 update contact person\/phone\/email and assign the team: account manager, ads specialist, creative specialist, QA reviewer, support person."},{"t":"Ads Specialist","u":"\/docs\/roles\/ads-specialist","s":"Role Guides","sk":"roles","d":"Build and tune client Meta campaigns in the agency panel \u2014 setup, campaign work, performance monitoring \u2014 with the launch gate firmly outside your hands.","b":"Ads Specialist You build the Meta side of client delivery: get the client's account set up, keep campaigns healthy, watch performance, and hand work to QA for the go-live decision. You can create, edit and pause campaigns \u2014 but you **cannot launch**, and that is on purpose. Who this is for Zodiac Tech agency staff with the role, signing in at . Prerequisites: your agency account exists (created at ) and clients are assigned to you. Your permissions in plain language From : Granted | Meaning | See the agency panel screens. | Work the Setup Queue stages and checklists. | Help connect a client's Meta assets. | \/ \/ | Build, correct and pause campaigns. | Active Campaigns, Needs Attention, Daily Brief, Portfolio Report. | Not granted: (**only** holds it), (creative work belongs to the Creative Specialist), (client profile edits), (requests\/support desk). Your daily routine 1. Morning \u2014 the health sweep 1. **Meta Ads \u2192 Daily Brief** ( ) \u2014 the overnight summary: spend, delivery changes, anything flagged. An automated ops scan runs every 30 minutes and the brief lands at **07:15**. 2. **Needs Attention** ( ) \u2014 campaigns with delivery, tracking or lead problems. Fix in priority order: broken > under-delivering > optimising. 3. **Active Campaigns** ( ) \u2014 spot-check pacing and leads per campaign. 2. Work the Setup Queue for your clients 1. **Meta Ads \u2192 Setup Queue** ( ) \u2014 filter by **Owner** for yours. 2. Open a client and complete the ads-side stages and checklists: campaign setup, tracking, creative readiness. Tick only what is actually done; the pipeline feeds the client's progress and the platform team's dashboard. 3. If the Meta connection is missing, use **Request Facebook Connection** (or the account manager does) \u2014 nothing can be built before the Page\/ad account is connected. 3. Build and adjust campaigns Campaigns arrive as drafts with the client's brief (product, budget, objective, audience) \u2014 built from the client's workspace through the AI campaign builder, where t"},{"t":"Creative Specialist","u":"\/docs\/roles\/creative-specialist","s":"Role Guides","sk":"roles","d":"Build and version client ad creatives in the agency panel, route them through client review, and mark approved work ready for the ads team \u2014 view-only everywhere else.","b":"Creative Specialist You make the ads worth clicking. Your seat is one screen \u2014 **Creative Work** in the agency panel \u2014 where you build creatives from the client's brief, version them honestly, send them for client review, and hand approved work to the ads side. Campaigns, launches and the setup queue belong to other roles. Who this is for Zodiac Tech agency staff with the role, signing in at . Prerequisites: your agency account exists (created at ) and clients' campaigns are assigned to your team. Your permissions in plain language From : Granted | Meaning | See the agency panel and open client records. | The whole Creative Work screen: view, create and edit creatives. | Not granted, deliberately: (that is the Ads Specialist), (only QA Reviewer), , , , and . In Creative Work every action \u2014 view, create, edit \u2014 is gated on ; that page is the whole job. Your work loop 1. Open the queue Meta Ads \u2192 Creative Work** ( ). The screen is **one row per version** of a creative, with Client, Creative title, Version ( , \u2026), Campaign, Status, Creator, Reviewer and Updated. Two filters do the heavy lifting: Versions** \u2014 (default) or . Status** and **Client** \u2014 find what needs you. 2. Build or fix the creative Open** a row (or create a new one) and fill the record: Client, Campaign and **Creative Title**. The **brief**: Offer, Audience, Location, References \/ notes. The content: **Concept**, **Main Message \/ Copy**, **Headline**, **CTA**, **Asset**. Creator and Reviewer, plus the status and feedback fields. The creative moves through: \u2192 \u2192 \u2192 \u2192 \u2192 (or \/ ) \u2192 . 3. Version instead of overwriting When the client or your reviewer asks for changes, use **New Version** \u2014 it \"creates v:next from this one; the current version stays in history.\" Nothing anyone already reviewed gets edited underneath them; feedback stays attached to the exact version it was about. 4. Send to the client Send to Client** moves a creative from the working states ( , , , , ) into . The client sees it on their **Crea"},{"t":"QA Reviewer","u":"\/docs\/roles\/qa-reviewer","s":"Role Guides","sk":"roles","d":"The launch gate of the agency panel \u2014 run the 12-point QA checklist, pass or fail campaign drafts with a real fix note, and verify campaigns actually go live.","b":"QA Reviewer You are the gate between a built campaign and real money being spent. Nothing reaches Meta without your **Pass QA** \u2014 you are the only agency role that holds , and the platform enforces the gate outside the UI too. Your job is not to click through fastest; it is to be the last honest check. Who this is for Zodiac Tech agency staff with the role, signing in at . A super admin grants it at via the **Enable launch access** toggle \u2014 that toggle adds or removes only the role. Prerequisites:** your agency account exists and campaigns are reaching the QA queue. Your permissions in plain language From : Granted | Meaning | See the agency panel and open client records. | The QA Queue and everything on it \u2014 Start QA, Checklist, Pass QA, Fail QA, Verify Launch. | Not granted, deliberately: (building campaigns is the Ads Specialist), , , , , , . The QA Queue workflow Open **Meta Ads \u2192 QA Queue** ( ). The nav badge counts drafts currently **In QA**. The table shows Client, Campaign, Draft status, Checklist progress ( ), QA state ( , , , ), Submitted, Reviewer and Launch Check; filter by QA state and Draft status. 1. Start QA On a draft that has not been reviewed yet (**Start QA**), the system records the submission time and moves QA to **In QA**. That is your claim on the review \u2014 do it when you are actually about to look. 2. Walk the 12-point checklist Open **Checklist** on the In-QA row. The 12 items are: Item | How it is judged | Campaign Name, Objective, Budget, Location, Audience, Creative, Copy | Derived from the draft's own data \u2014 these must be complete before QA can pass at all. | Placements, Lead Form, Tracking, Destination, Correct Creative Selected | Validated by you against what the campaign actually needs. | 3. Pass or fail \u2014 no third option Pass QA** only becomes usable when all 12 items are done (\"All 12 checklist items must be done before QA can pass.\"). Passing sets and records you as the reviewer. Fail QA** requires **\"What needs fixing?\"** \u2014 a note"},{"t":"Support Agent","u":"\/docs\/roles\/support-agent","s":"Role Guides","sk":"roles","d":"The agency panel's client-facing desk \u2014 triage Client Requests, run the Support Desk tickets, answer Live Chat, and help clients get their Meta connection working.","b":"Support Agent You are the client's first human answer inside the agency panel. Three queues are yours \u2014 **Client Requests**, **Support Desk** and **Live Chat** \u2014 plus one superpower: you can send a client a secure link to connect their own Facebook assets. Nothing waits in the dark when you are on. Who this is for Zodiac Tech agency staff with the role, signing in at . Prerequisites: your agency account exists (created at ) and clients are live in the agency panel. Your permissions in plain language From : Granted | Meaning | See the agency panel and open client records. | Send a client the **Request Facebook Connection** link from their workspace. | Client Requests, Support Desk and Live Chat \u2014 all three queues. | Not granted, deliberately: (the Setup Queue belongs to the Account Manager), , (Ads Specialist), (Creative Specialist), (QA Reviewer), and . Your daily routine 1. Client Requests \u2014 the worklist Meta Ads \u2192 Client Requests** ( ). The nav badge counts new requests; the *Show* filter keeps open work in front of you. Requests arrive typed: **New creative**, **Budget change**, **Pause campaign**, **New campaign**, **Connection help**, **Reporting**, **Other** \u2014 with urgency Normal or Urgent. Assign** each one to a team member, set a **Due** date, and move the **Status** through New \u2192 In Review \u2192 Approved \u2192 In Progress \u2192 Done (or Declined). When you resolve or decline, write the **resolution note** \u2014 it is kept on the request so the client's next question answers itself later. Route execution properly: creative requests go to the creative specialist, campaign changes to the ads side. You triage and keep the client informed; you do not do their jobs. 2. Support Desk \u2014 the ticket queue Meta Ads \u2192 Support Desk** ( ) \u2014 every open ticket, with the nav badge showing how many are open. The lifecycle is New \u2192 Assigned \u2192 In Progress \u2192 Waiting for Client \u2192 Resolved \u2192 Closed; resolving or closing applies a **resolution note** to the ticket and the change is audited. Waitin"},{"t":"Super Admin overview","u":"\/docs\/super-admin\/dashboard","s":"Super Admin","sk":"super-admin","d":"What the Super Admin home screen shows, and where every platform section lives.","b":"Super Admin overview The Super Admin home screen is the control room for the whole platform. It answers two questions in one glance: **how is the business doing?** and **what needs attention first?** From here you can also reach every Super Admin section \u2014 this page is the map. Who this is for Platform owners and operators with the Super Admin role. No technical background is needed to read this page. Difficulty:** Easy Time:** 5 min Prerequisites:** A user account with the Super Admin role, signed in at . LeadHub HQ is not a client The Super Admin panel is bound to an internal workspace called **LeadHub HQ** (marker in the workspace settings). It never appears in business lists, onboarding dashboards, or billing. You do not manage it like a client workspace. Step 1 \u2014 Read the setup checklist first At the top of the dashboard is a first-login **setup checklist**. It tracks five things a brand-new install needs: Item | Done when | Goes to | Configure SMTP so emails actually send | SMTP host is saved | Settings \u2192 Script Settings | Enable at least one payment gateway | Any gateway toggle is on | | Set your brand name + colours | Branding is saved | Settings \u2192 Branding | Edit landing-page hero copy | Hero copy is set | | Onboard your first workspace | Any business exists | | Click any item to jump straight to the screen that fixes it. Once every item is green, dismiss the checklist \u2014 it stays dismissed. Status: not currently implemented. A consolidated \"Platform today\" widget on the dashboard (businesses, leads\/calls today, AI usage, Meta connection health, Android devices). The widget code exists in the codebase but is not placed on the dashboard. For a live platform-health view today, open **Settings \u2192 System Health** and the Meta Ads and Android App sections. Step 2 \u2014 Read the platform KPIs The **SaaS stats** cards show: Card | What it means | Total businesses | Every workspace registered on the platform | Active subscriptions | Workspaces in an active subscription s"},{"t":"Businesses (tenants)","u":"\/docs\/super-admin\/businesses","s":"Super Admin","sk":"super-admin","d":"Create, manage, suspend and impersonate client workspaces from the Super Admin panel.","b":"Businesses (tenants) Every client on the platform is a **business** (internally a *tenant*). The Businesses screen at is where you create them, hand over the admin login, watch subscription state, and \u2014 when needed \u2014 suspend or impersonate one. Who this is for Super Admins. Creating a business also creates that client's admin user, so read the hand-over options carefully. Difficulty:** Medium Time:** 10 min Prerequisites:** Super Admin access, and the client's admin name + email ready. Create the business from here, not inside There is no \"New business\" button in the client panel. The Super Admin create form is the only place a workspace (and its owner) is created. For the full end-to-end order of operations, follow the Client delivery playbook. Step 1 \u2014 Create a business 1. Open **Businesses** \u2192 click **New business** (top right). 2. Fill **Workspace Details**: Name** \u2014 the client's company name. The URL slug and subdomain are auto-filled from it; you can override the slug (reserved words are rejected). Max seats** \u2014 the hard cap on team members (default 5). Plan** \u2014 pick the plan the client is on. Choosing a plan auto-fills **Trial ends at** from the plan's . Subscription status** \u2014 Trial \/ Trial expired \/ Active (paid) \/ Cancelled \/ Expired. Leave it on the default at creation; it is normally driven by the lifecycle jobs afterwards. 3. Fill the **Tenant Admin** section \u2014 this creates the client's first user: Admin name** and **Admin email**. Password setup** \u2014 choose one: Email the admin a setup link (recommended)** \u2014 the admin receives a welcome email with a link and sets their own password. Auto-generate + show here** \u2014 a random 16-character password is generated and shown to you once. Set password now** \u2014 type a password (at least 10 characters) and pass it to the admin securely. 4. Click **Create**. The workspace is created, the admin user is created with the tenant **admin** role and set as owner, and the first-login onboarding wizard is marked pending. 5. H"},{"t":"Users & agency team","u":"\/docs\/super-admin\/users","s":"Super Admin","sk":"super-admin","d":"Manage platform users, reset passwords, suspend accounts, and run the agency team logins.","b":"Users & agency team There are two kinds of staff accounts in the Super Admin panel: Platform users** at \u2014 every client user (and any Super Admin), searchable across all businesses. Agency team** at \u2014 Zodiac Tech's Meta-ops staff who work in the panel. Who this is for Super Admins. Agency team management is Super-Admin-only by design. Difficulty:** Medium Time:** 10 min Prerequisites:** Super Admin access. There is no \"create user\" button on the Users page is a view-and-manage list (edit, reset password, suspend, impersonate). Client users are created elsewhere: the client's **first admin** \u2014 when you create a Business; additional client users** \u2014 by the client's admin in the tenant panel ( team page); agency staff** \u2014 on the Agency Team page below. Part A \u2014 Platform users ( ) Step 1 \u2014 Find a user The table lists name, email, business, whether they are a Super Admin, suspension status and created date. Use the **tenant** and **role** filters to narrow the list. Step 2 \u2014 Reset a password Click **Reset password** on the row. The user receives a Laravel password-reset email ( ). You never see or set their password from this screen. Step 3 \u2014 Suspend or unsuspend Suspend** sets and invalidates the user's sessions \u2014 they can no longer log in. You cannot suspend yourself. **Unsuspend** reverses it. Step 4 \u2014 Impersonate a client user Impersonate** is available only for tenant users (not Super Admins). You are logged in as that user and taken to ; the impersonation bar with **Stop** appears on every page. The action is audited. Step 5 \u2014 Edit profile details Edit** opens the standard user form (name, email, roles, business). Role changes take effect on the user's next request. Part B \u2014 The agency team ( ) The **Agency Team** page holds the logins for staff who run Meta operations in the separate panel. These users have **no business attached** \u2014 their only door is . Step 6 \u2014 Add a team member 1. Open **Meta Ads \u2192 Agency Team** \u2192 **New team member**. 2. Fill **Login**: name, em"},{"t":"Client onboarding dashboard","u":"\/docs\/super-admin\/client-onboarding","s":"Super Admin","sk":"super-admin","d":"Track every client's guided setup from payment to launch \u2014 progress, payments, Meta health and stuck steps.","b":"Client onboarding dashboard The Client Onboarding board at is the single view of every client's setup. One row per business, one click to the **Business 360** detail with both checklists, the payment card and the signed onboarding link. Who this is for Super Admins and Meta-ops staff who follow clients through delivery. The board is gated by the permission. Difficulty:** Medium Time:** 10 min Prerequisites:** Super Admin access (or the agency permission), and at least one client business created \u2014 see Businesses (tenants). LeadHub HQ never appears here The internal HQ workspace is excluded from the board and its detail page returns 404. Only real clients are tracked. The board columns Column | What it shows | Business** | Client workspace name | Progress** | Percentage badge of settled steps, or \"Not started\" | Current step** | Human label of the step the client is on ( ) | Payment** | Latest agreement amount and how much has been paid from PAID invoices (\"Paid \u20b9X\"), or the agreement status | Meta connection** | Connected \/ Needs attention \/ Not connected, from the client's Meta\/Instagram lead-source connection | Stuck** | \u26a0 when a required step has been waiting more than 24 hours | The stuck flag is automatic A daily sweep ( , 08:15) marks required client steps that have been unsettled for more than 24 hours and notifies the Super Admins. Each step is flagged at most once per day. Step 1 \u2014 Request action on a stuck client 1. Find the stuck row (\u26a0 in the **Stuck** column). 2. Click **Request Action**. A modal opens with a pre-filled message for the client. 3. Adjust the wording if needed and confirm. The client's current step moves to **Waiting for client** and the request is recorded. Use this when a client has gone quiet on a required step. It is the polite, traceable nudge \u2014 the client sees the request in their guided setup. Step 2 \u2014 Open the Business 360 detail Click the row (or the **Onboarding** action from the Businesses list) to open . The detail page has fi"},{"t":"Client delivery playbook","u":"\/docs\/super-admin\/delivery-playbook","s":"Super Admin","sk":"super-admin","d":"The 18-step Zodiac Tech Client Delivery Playbook \u2014 from confirmed payment to renewal, with the owner and panel for every step.","b":"Client delivery playbook This is the standard way Zodiac Tech delivers a new client on the platform. Follow it top to bottom: every step lists **who does it**, **where it happens**, and **the output that proves the step is done**. Do not skip ahead \u2014 later steps depend on earlier ones (launch, in particular, depends on QA). Who this is for Super Admins, account managers and Meta-ops staff delivering a client from \"payment received\" to \"renewed\". Keep this page open as your run sheet. Difficulty:** Medium Time:** 15 min (reading); the full delivery spans days Prerequisites:** A paid or approved client, and Super Admin (or agency) access. The 18 steps 1. Confirm payment Who:** Super Admin. **Where:** + . Output:** The agreement is active \u2014 meaning the provider **confirmed** the payment via webhook, not just that the client returned from a redirect. Never start delivery on a redirect alone. 2. Create the business Who:** Super Admin. **Where:** \u2192 **New business**. Output:** Workspace created, client admin user created, onboarding marked pending. See Businesses (tenants). 3. Set up the commercial agreement Who:** Super Admin. **Where:** \u2192 **Create** (5-step wizard: terms \u2192 pricing \u2192 services \u2192 review \u2192 send). Output:** The client has the agreement in their portal and can approve it. Details in Commercial agreements. 4. Start guided onboarding Who:** Super Admin (activation is already pending from step 2). **Where:** . Output:** The client's guided setup ( ) is live with the 12 client steps. See Client onboarding dashboard. 5. Send the client onboarding link Who:** Super Admin. **Where:** Business 360 detail \u2192 **Onboarding link**. Output:** The client has a signed link (valid 72 hours) that lands them directly in their setup. Regenerating revokes the old link. 6. Monitor progress Who:** Super Admin \/ Account Manager. **Where:** . Output:** Every stuck client is visible (\u26a0 24h+) and nudged with **Request Action**. The daily sweep (08:15) flags stalled required steps automa"},{"t":"Meta Developer settings","u":"\/docs\/super-admin\/meta-settings","s":"Super Admin","sk":"super-admin","d":"Configure the platform's Meta app once \u2014 clients never enter their own app credentials.","b":"Meta Developer settings The platform uses **one Meta Developer App** for every client. You configure it once at **Settings \u2192 Meta Developer** ( ), and every client authorization falls back to these credentials server-side. Clients connect with \"Continue with Facebook\" \u2014 they never type an App ID or Secret. Who this is for The person who owns the Meta Developer App (usually a Super Admin or the platform developer). This is an operator-only surface \u2014 the strings are deliberately plain to help non-developers. Difficulty:** Advanced Time:** 15 min Prerequisites:** A Meta Developer account, an app created at , and access to your domain's public URL settings. Step 1 \u2014 Create the app on Meta's side 1. Log in at and create an app (type: Business). 2. Note the **App ID** and **App Secret** from **Settings \u2192 Basic**. 3. In the app's Facebook Login settings, add the OAuth redirect URI shown on the Meta Developer page (see step 3). 4. Add the lead permissions the connect flow uses: , , , . Keep Development until App Review approves Newly requested lead permissions do not work in Production until Meta approves them. Keep the page on **Development** while testing; switch to **Production** only after App Review passes. Step 2 \u2014 Enter the credentials On **Settings \u2192 Meta Developer**, under **App Configuration**: Field | What to enter | App Name** | Display name only (e.g. your product name) | Environment** | Development \/ Production \u2014 see the warning above | Meta App ID** | The App ID from Meta's Settings \u2192 Basic | Meta App Secret** | The App Secret. Stored **encrypted**; it is never shown back to you | The App Secret is write-only The secret is encrypted at rest ( ) and never rendered back. If you save the form with the secret field blank, the stored secret is kept. If you ever need to change it, paste the new one \u2014 you can never read the old one from this page. Step 3 \u2014 Copy the OAuth redirect URI into Meta The page shows the **OAuth redirect URI** to use. On this install it reso"},{"t":"Mobile & app settings","u":"\/docs\/super-admin\/mobile-app-settings","s":"Super Admin","sk":"super-admin","d":"The Android device fleet, mobile app config (force-update, banner, support), and platform login options.","b":"Mobile & app settings The Android Sales App has two Super Admin surfaces: Devices** ( ) \u2014 a read-only fleet view: who has the app, on what phone, and what each device can honestly do (recording, tracking). Mobile App Login** ( ) \u2014 platform defaults for sign-in methods, Firebase OTP, push, and the app control gate (force-update, announcement banner, support contacts). The Devices view in the CRM shows this per phone; admins never see SIM identifiers \u2014 only the model, OS, app version and a device ID.* Who this is for Super Admins running the mobile side of the platform. Difficulty:** Medium Time:** 10 min Prerequisites:** Super Admin access; for push testing, at least one agent signed in on the Android app. Part A \u2014 The device fleet ( ) Step 1 \u2014 Read the summary Three counters at the top: Counter | Meaning | Registered devices | Every device that has registered | Active last 24h | Devices seen in the last day | Active last 7 days | Devices seen in the last week | Step 2 \u2014 Read each device row Rows show the business, agent, device model, OS, app version, SIM label, exclusions (device-level and workspace-level), last sync, **recording mode**, **tracking mode**, dialer package, and when the capability snapshot was last checked. Recording modes are honest per device \u2014 never a blanket promise: Mode | Meaning | Native** | The device can record calls natively through the app | Importable** | Calls can be imported after the fact | Metadata only** | Only call metadata (duration, number) is captured \u2014 no audio | Unknown** | Capability not yet detected | Recording is capability-based Never tell a client \"all calls are recorded\". The platform reports per-device capability from real snapshots; some phones can only provide metadata. The app shows the same truth to the agent on its Device Health screen (screenshot above). Step 3 \u2014 Handle a stale device If a device has not synced recently, that is a client-side issue: ask the agent to open the app and sync. Device-side fixes live in "},{"t":"System, SMTP & integrations","u":"\/docs\/super-admin\/system","s":"Super Admin","sk":"super-admin","d":"One map of the Super Admin Settings cluster \u2014 health, SMTP, AI, branding, backups, static pages and where to dig deeper.","b":"System, SMTP & integrations All platform settings live in one **Settings** entry ( ). Its **Overview** page is a directory of every settings screen \u2014 use it as your starting point. This page summarizes each area and deep-links to the detailed guide. The scheduler is the heartbeat Almost everything on this page relies on the scheduler: cron must run every minute. Locally the queue uses ; production should use + a worker. See Queues, jobs & scheduler and Cron & queue workers. System Health ( ) One-click maintenance for shared hosting (no SSH needed): Action | What it runs | Clear all caches** | | Apply pending migrations** | | Rebuild caches** | Clear then re-warm config \/ route \/ view caches | Create storage symlink** | Recreates (for fresh installs) | Restart queue workers** | Gracefully restarts workers to pick up new code | The page also shows a **WhatsApp Platform** health card with cross-tenant aggregates \u2014 connection status, messages and failures. For deeper WhatsApp guidance see WhatsApp Business API. Destructive-looking actions are guarded In demo mode these actions are hidden. On a live install, each asks for confirmation first. \"Apply pending migrations\" is safe \u2014 applied migrations are skipped. Script Settings ( ) The big one. Sections: Reporting & Localisation** \u2014 currency, timezone, date format, language. Backups** \u2014 the **auto nightly backup** toggle gates at 02:00. If the toggle is off, no backups run. See Backups & restore. AI** \u2014 provider ( or ), API key, model (default ) and base URL. Voice** \u2014 transcription provider ( whisper or ), key, model and language. Public Marketing Landing** \u2014 landing page variant for the public site. Outbound Email SMTP** \u2014 mailer ( \/ \/ \/ ), host, port, encryption, username, password, from address and name. The password is never revealed. **Send Test Email** sends a dry-run using the values in the form. Configure SMTP on day one Password resets, onboarding links, invoices and notifications all depend on working email. If S"},{"t":"Billing overview","u":"\/docs\/billing\/overview","s":"Billing","sk":"billing","d":"How commercial billing fits together \u2014 agreements, invoices, payments, providers and failure handling \u2014 and where every screen lives.","b":"Billing overview Commercial billing on this platform is built around one idea: **an agreement is a contract with a price, and separately a list of features the client is entitled to.** The two never bleed into each other. A \u20b90 discount, a changed price, or an extra line item never silently unlocks a feature \u2014 only the agreement's entitlements do. This page is the map. Follow the links for the detail. Who this is for Super Admins who run client contracts and collections. Difficulty:** Easy Time:** 5 min Prerequisites:** Super Admin access. Where everything lives All commercial billing screens are in the Super Admin **Billing** group: Sidebar entry | URL | What it does | Overview** | | Platform revenue dashboard: MRR, ARR, ARPU, churn, status breakdown, revenue by plan, recent billing events | Commercial Billing** | | Counting cards + the \"Needs Attention\" queue for agreements | Agreements** | | Create and manage commercial agreements \u2192 Commercial agreements | Invoices** | | Append-only invoice list \u2192 Invoices & payments | Payments** | | All payment transactions | Change Requests** | | Client-requested changes to live agreements | Providers & Settings** | | Razorpay \/ Cashfree configuration \u2192 Payment providers | Billing Settings | | Legacy platform settings: enabled gateways, trial\/lifecycle days, affiliate %, manual bank details | Two billing layers exist The **Overview** page ( ) reports the platform's own SaaS subscriptions at the *plan* level (tenants on trial\/paid plans). The **commercial billing** pages manage per-client **agreements** with custom pricing. Clients see their side of commercial billing in the client billing portal. The counting cards ( ) Card | Counts | Active businesses | Distinct businesses with a live agreement | Active agreements | Agreements in a live state | MRR | Current monthly recurring revenue | Pending client approvals | Agreements awaiting the client's approval | Pending autopay | Agreements awaiting payment authorization | Payment fai"},{"t":"Commercial agreements","u":"\/docs\/billing\/agreements","s":"Billing","sk":"billing","d":"Create a client agreement with the 5-step wizard \u2014 pricing, entitlements, client approval and provider-verified activation.","b":"Commercial agreements A **commercial agreement** is the contract behind a client's service: its price, its entitlements (the features the client may use), and its lifecycle. Everything else in billing \u2014 invoices, payments, restrictions \u2014 hangs off the agreement. Create and manage them at . Who this is for Super Admins who set up client deals. Difficulty:** Medium Time:** 15 min Prerequisites:** A client business, a payment provider configured (Providers), and the agreed commercial terms. Price and entitlements are separate \u2014 by design Line items decide **what the client pays**. Entitlements decide **what the client can use**. Adding a price line never grants a feature, and a discount never removes one. Only the checkboxes on the **Services** step control access. This is enforced in code, not just policy. Step 1 \u2014 Start the wizard Open **Billing \u2192 Agreements** \u2192 **Create**. The wizard has five steps; you can revisit any step before saving: 1. **1. Agreement** 2. **2. Pricing** 3. **3. Services** 4. **4. Review** 5. **5. Send to Client** Step 2 \u2014 Step 1: Agreement basics Field | Notes | Business** | The client workspace this agreement is for | Name** | Internal name, e.g. \"Acme \u2014 Growth plan 2026\" | Description** | Optional summary | Billing type** | Default: Custom (monthly) | Currency** | Default: INR | Start \/ End dates** | Contract window | AutoPay enabled** | On by default \u2014 the client is asked to authorize AutoPay after approving | Payment provider** | Razorpay or Cashfree | Notes \/ Internal notes** | Client-visible notes vs staff-only notes | Step 3 \u2014 Step 2: Pricing Discount** at agreement level, and per line item. Tax**: enable, mark included or added, set the rate (default 18% GST). Recurring interval and count** \u2014 how often the recurring amount bills. Line items** (repeater): name, type, amount, quantity, service key, discount, description. A live total is kept by the billing calculator as you build. The **recurring** total is the amount the provider will d"},{"t":"Invoices & payments","u":"\/docs\/billing\/invoices-payments","s":"Billing","sk":"billing","d":"How invoices are generated and renewed, where to find invoice and payment records, and what the client sees.","b":"Invoices & payments Agreements define the deal; **invoices** and **payments** are the paper trail. This page explains how invoices are created, how renewals work, and where to look when a client says \"I paid\". Invoices: Payments: Client side: and Who this is for Super Admins and support staff answering billing questions. Difficulty:** Medium Time:** 10 min Prerequisites:** At least one active agreement. How invoices appear Renewal invoices \u2014 automatic, daily at 06:30 For every **Active** agreement whose next billing date has arrived, the renewal job: 1. Creates the renewal invoice for the agreement's **recurring gross amount** (one-time line items are never re-billed). 2. Issues it and advances the next billing date in the **same database transaction** \u2014 this is the idempotency anchor, so a job re-run cannot double-bill. 3. Generates the invoice PDF and notifies the client. The amount invariant The provider debit, the renewal invoice and the agreement's recurring gross amount are always the same number. If you ever see them disagree, stop and investigate \u2014 that is a reconciliation bug, not a rounding quirk. Manual invoices and manual payments Offline arrangements are recorded, not emailed: use **Record Manual Payment** on the agreement (amount, method, reference\/UTR, date, apply-to-invoice, notes). This is the correct way to log a bank transfer. Overdue marking \u2014 hourly The payment-failure job scans issued and partially-paid invoices whose due date has passed with an amount still due, notifies the client once (no duplicate spam), and marks the invoice **Overdue**. Step 1 \u2014 Read the invoice list is an **append-only** list. Columns: invoice number, business, status, total, paid, due, issue date, due date, overdue flag, currency. Internal invoice statuses: , , , , , , . Draft and void invoices never reach the client. Step 2 \u2014 Read the payments list shows every transaction: ID, business, provider, amount, status, method, provider reference, paid time. Payment statuses: "},{"t":"Payment providers (Razorpay \/ Cashfree)","u":"\/docs\/billing\/providers","s":"Billing","sk":"billing","d":"Configure Razorpay or Cashfree once \u2014 encrypted keys, webhook URLs, test vs live, and the health check that proves it works.","b":"Payment providers (Razorpay \/ Cashfree) Commercial billing talks to **one active provider** at a time. Configure it at **Billing \u2192 Providers & Settings** ( ). Keys are encrypted at rest and never echoed back \u2014 this page shows the flow, not the secrets. Who this is for Super Admins and the person who owns the payment provider account. Difficulty:** Advanced Time:** 15 min Prerequisites:** A Razorpay or Cashfree merchant account; access to set webhooks in that account; the platform's public URL. Step 1 \u2014 Choose the provider and environment Under **Commercial Billing**: Setting | Options | Notes | Enable commercial billing** | On \/ Off | When off, AutoPay is not offered and no provider API calls are made | Provider** | Razorpay \/ Cashfree | The single active provider for commercial billing | Environment** | Sandbox \/ Production | Sandbox for testing; switch after go-live | Grace period (days)** | default 7 (max 90) | How long a failed payment waits before escalating \u2014 see Payment failures & restrictions | Test with sandbox keys first Sandbox credentials cannot move real money, and production credentials can. Complete the full agree \u2192 authorize \u2192 renew \u2192 fail-recover cycle in Sandbox before switching to Production. Step 2 \u2014 Enter the credentials Razorpay The Razorpay fields use the **same credentials as the platform's checkout** \u2014 they are shared, not duplicated. Enter them here or on the Billing Settings page ( ); both read the same stored values: Key ID Key Secret Webhook Secret Cashfree App ID Secret Key Webhook Secret All secret fields behave the same way: stored **encrypted at rest**, never rendered back, and a **blank field keeps the stored value**. The helper text says it exactly: \"Already saved \u2014 leave blank to keep it unchanged.\" No secrets are echoed \u2014 on purpose You cannot view a saved key or secret from this page. If one is lost, generate a new one at the provider and paste it in. Never paste credentials into support tickets or docs. Step 3 \u2014 Register the we"},{"t":"Payment failures & restrictions","u":"\/docs\/billing\/failures","s":"Billing","sk":"billing","d":"What happens when a payment fails \u2014 the grace and restriction ladder, what stays open at each stage, and how recovery works.","b":"Payment failures & restrictions When a client's AutoPay payment fails, the platform does not cut them off instantly. It walks a ladder: **friendly \u2192 firm \u2192 blocked**, with time (and clear messages) at every step. This page explains the ladder, exactly what a client can still do at each stage, and how they get restored. Who this is for Super Admins and support staff handling a client whose payment failed. Difficulty:** Medium Time:** 10 min Prerequisites:** A configured provider (Payment providers) and the grace period setting on that page. The ladder Stage | Triggered by | What the client sees | Payment failed** | A provider event, or a revoked mandate | Failure message; retry is still possible | Grace period** | The grace job ( , daily 07:15) after a failed payment | Reminder messaging; everything still works | Past due** | The catch-up sweep when the grace window is exhausted | Stronger reminder; still no restriction yet | Restricted** | (daily 07:30) once Past due is older than the grace period | Only four core features remain | Suspended** | The same job once Restricted is older than 7 days ( ) | Every feature denied | Times are configurable: the **grace period** (default 7 days, max 90) is set at Billing \u2192 Providers & Settings. The 7-day Restricted-to-Suspended window is fixed. What \"Restricted\" actually leaves open allows only: **CRM**, **lead management**, **follow-ups** and **reports**. Everything else \u2014 Meta, WhatsApp, automations, AI, mobile, API \u2014 is denied, with the message: \"This feature is not included in your current service agreement. Please contact your account manager.\" denies **everything** \u2014 every feature check returns false. Two different \"suspended\" ideas \u2014 don't mix them up A commercial **Suspended** agreement blocks features through entitlements. A manually **suspended workspace** (the Suspend button under Businesses) sets the workspace inactive and bounces its users to . They are independent mechanisms \u2014 a workspace can be active while its a"},{"t":"Client billing portal","u":"\/docs\/billing\/client-portal","s":"Billing","sk":"billing","d":"What a client sees and does in Billing \u2014 view the agreement, approve it, set up AutoPay, download invoices and raise a change request.","b":"Client billing portal Everything a client needs for billing lives in one place in their own panel: . This page covers what they see, what they can do, and the honest rules behind approvals and change requests \u2014 so support conversations stay short. Who this is for Business owners and admins (the client side), and Super Admins who need to know what the client sees. Difficulty:** Easy Time:** 5 min Prerequisites:** Signed in as the workspace **owner or an admin**. Managers and members never see billing at all. The four client pages Page | URL | What it shows | Billing & Subscription** | | The workspace's billing overview | Your Billing** | | The commercial agreement: status, price, included services, approval and AutoPay setup | Invoices** | | Their invoices, with plain statuses and signed download links | Payment History** | | Every recorded payment | Step 1 \u2014 Approve the agreement 1. Open **Your Billing** ( ). 2. Read the plain-language summary: agreement name, price, billing start\/end, included services and any notes. 3. Click **Approve**. The approval is recorded with the time, IP address and user agent \u2014 that is the audit trail. After approval the status becomes **AutoPay setup pending** and the next step is to authorize AutoPay. Step 2 \u2014 Set up AutoPay Click the AutoPay button to go to the payment provider (Razorpay or Cashfree) and authorize the mandate. Coming back from the provider is not the finish line When the client returns to the CRM, the platform does **not** trust the redirect. It re-checks with the provider directly and only shows **Active** once the provider confirms the authorization. Until then the status stays \"AutoPay setup pending\" with the message: \"We are still confirming your payment setup.\" If a mandate already exists, the platform re-verifies it instead of asking for a second authorization. Step 3 \u2014 Read the status in plain words Status shown | What it means to the client | Draft | Not sent yet (internal) | Awaiting your approval | Sent \u2014 wa"},{"t":"Leads","u":"\/docs\/crm\/leads","s":"Using the CRM","sk":"crm","d":"The All Leads list \u2014 find, filter, act on, import and export every lead in your business from one screen.","b":"Leads All Leads** is the master list of your business \u2014 every enquiry from Facebook, Instagram, forms, imports and manual entries lands here. It is the screen your sales team lives in all day: search, filter, call, WhatsApp, assign and move leads forward without leaving the page. Who this is for Sales agents** \u2014 your daily worklist: new leads, follow-ups due, calls to make. Managers** \u2014 monitor the team, reassign, run exports, spot leads going cold. Admins** \u2014 configure pipeline behaviour, imports and limits. Difficulty:** Easy Time:** 10 minutes to learn the essentials Prerequisites:** You are signed in to the tenant panel ( ). At least one lead exists, or you can create one. What is on the screen Above the table: search, the **filters** panel, and header buttons. Below it: one row per lead with these columns: Column | What it tells you | Name + email | The lead. Click the row to open Lead 360. | Phone | Copyable at a click \u2014 used for dialling and WhatsApp. | Company | Company name, when captured. | Source | Badge showing where the lead came from (Facebook, form, import, manual\u2026). | Status | The lead status (new, contacted, qualified, converted, lost). | Health | Calculated badge (healthy \/ needs attention \/ at risk) \u2014 hover for the reason. See Lead routing, scoring & health. | Stage | The pipeline stage the lead sits in. | Deal value | Estimated deal size in \u20b9. | Expected close | The date the deal should close. | Score | Points from your scoring rules. | Tags | Your labels. | Assigned | The team member who owns the lead. | Created | When the lead entered the CRM. | Waiting on | Who is holding things up \u2014 **us**, **them**, or a **new** lead nobody has answered yet. | Small icons matter too: Star** \u2014 flag a lead as important (filter by starred). Duplicate icon** \u2014 the CRM has spotted a possible same person (same email\/phone); a manager can merge from the lead view. The page refreshes itself every 30 seconds, and the **Leads** menu badge shows how many new leads arri"},{"t":"Lead board (Kanban)","u":"\/docs\/crm\/lead-board","s":"Using the CRM","sk":"crm","d":"Drag-and-drop your pipeline \u2014 move leads between stages and watch the value in each column.","b":"Lead board (Kanban) The **Board** is your pipeline as columns. Each column is a stage, each card is a lead, and dragging a card moves it \u2014 the same update as changing the stage on the Lead 360 view, just faster to do in bulk. Who this is for Sales agents** \u2014 work one stage at a time: move yesterday's \"contacted\" leads to \"qualified\" as you talk to them. Managers** \u2014 see at a glance how many leads and how much money sit in each stage. Difficulty:** Easy Time:** 5 minutes Prerequisites:** At least one pipeline with stages exists (a default pipeline is created for you). See Sales process & stages. Before you start Columns come from a pipeline.** Use the pipeline selector in the page header to switch between pipelines (for example *Sales* vs *Support*). Each pipeline has its own stages. The Unassigned column is special.** It collects leads that have no stage yet ( is empty). It is *pull-only*: you can drag a card **out** of it into a stage, but you cannot drop a card **into** it. To pull a lead out, drag it to any stage column. Steps 1. Open the board 1. Go to **Leads \u2192 Board** ( ), or click **Kanban** from the All Leads header. Expected result:** your default pipeline renders as columns in stage order, each column showing its lead count and the total deal value it holds. 2. Move a lead between stages 1. Grab a card and drag it onto a column. Expected result:** the card drops into the new column and the lead's stage is saved immediately (the CRM records the moment the stage was entered, which feeds response-time and stuck-deal reports). Column counts and values update. 3. Work a full column 1. Drag the cards you have progressed through the day. Expected result:** the board becomes your stand-up view \u2014 \"these 6 are qualified, these 3 need a quote\". 4. See more than fits 1. If a column has more than 50 cards, the board shows the first 50 and a **+N more** link at the bottom. Expected result:** click the link to open the filtered lead list for exactly that stage. Expected "},{"t":"Lead 360 view","u":"\/docs\/crm\/lead-360","s":"Using the CRM","sk":"crm","d":"Everything about one lead on a single screen \u2014 timeline, next best action, calls, messages, tasks, quotes and privacy tools.","b":"Lead 360 view The **Lead 360** is the single-lead command centre. Instead of hunting through tabs, you get the whole relationship in one screen: what happened, what to do next, and every tool to do it \u2014 call, WhatsApp, email, task, quote, invoice. Who this is for Sales agents** \u2014 open it before every call; it tells you the next best action. Managers** \u2014 audit a lead's full history and step in. Admins** \u2014 the same view is where GDPR tools live (export, anonymise, erase). Difficulty:** Medium Time:** 10 minutes to know your way around Prerequisites:** You can open a lead from All Leads or the Board. What is on the screen The action bar (top buttons) Button | What it does | Edit** | Change the lead's fields (name, contact, value, stage, tags\u2026). | Add line item** | Build a deal: product, description, unit price, quantity, discount. Feeds quotes. | Create task** | A follow-up task \u2014 title, assignee, due date (defaults to tomorrow 9:00), priority, reminder. | Send email** | Pick a template (or write from scratch), attach files, send. If the install has no SMTP configured, the CRM warns that mail is written to the log instead of delivered. | Call lead** | In-app calling, when your business has voice enabled. Requires your own phone number on your profile. | Send message** | Send on WhatsApp, SMS, Viber or Telegram \u2014 the channels your business has switched on. | Open conversation** | Jumps into the shared WhatsApp inbox thread with this lead. | Log call** | Record a call you made elsewhere: direction, duration, outcome (connected, voicemail, no answer, not interested, callback), notes. | Add note** | A free note on the timeline. Mention teammates with to notify them. | Move stage** | Change the pipeline stage (same as dragging on the board). | Mark won** | Closes the deal: enter the final amount \u2014 it is stored as won value and stamped with the win date. | Mark lost** | Closes as lost with a reason. | Assign** | Hand the lead to another team member. | Enroll in sequence** | "},{"t":"Sales process & stages","u":"\/docs\/crm\/sales-process","s":"Using the CRM","sk":"crm","d":"Build the pipelines and stages your team drags leads through \u2014 names, colours, order and won\/lost rules.","b":"Sales process & stages Your **sales process** is the set of steps a lead walks through to become a customer: for example *New \u2192 Contacted \u2192 Qualified \u2192 Quoted \u2192 Won*. Each step is a **stage**, and stages live inside a **pipeline**. The Lead board draws one column per stage; every stage change is stamped with a time, which powers funnel, bottleneck and response-time reports. You can run more than one pipeline (for example *New Sales* and *Renewals*) \u2014 each with its own stages. New leads land in your **default** pipeline. Who this is for Admins** \u2014 configure the process once, correctly. Managers** \u2014 adjust stages as the business evolves. Difficulty:** Medium Time:** 15 minutes for a full first-time setup Prerequisites:** You are an admin (or have the pipeline permission). Leading a sales process design? Decide your steps on paper first. Steps 1. Open pipeline management 1. In the sidebar open **Settings** (the single Settings entry) \u2192 the **Leads & Sales** tab \u2192 **Sales Process**. The URL is . Expected result:** the list of pipelines shows each pipeline's name, how many stages it has, and how many leads sit in it. 2. Create a pipeline 1. Click **New pipeline**. 2. Fill in: Name** \u2014 the process name your team will see (for example *Sales*, *Renewals*, *Support*). Description** \u2014 optional note. Default** toggle \u2014 the pipeline new unassigned leads enter. 3. Add **stages** (see next step). Expected result:** saving creates the pipeline straight away; it appears in the list and in the pipeline selector on the Board. Keep the default pipeline default Exactly one pipeline should be the default. That is where Facebook\/Instagram leads, form submissions and imports land unless a lead form routes them elsewhere. 3. Add and arrange stages 1. Inside the pipeline form, use the **Stages** list. Add a row per step. 2. For each stage set: Name** \u2014 what the team calls it (*Contacted*, *Demo Booked*, *Negotiation*\u2026). Colour** \u2014 used on the board, badges and reports (default indigo ). Wo"},{"t":"Follow-ups & tasks","u":"\/docs\/crm\/follow-ups","s":"Using the CRM","sk":"crm","d":"Your day plan \u2014 every task you owe a lead, overdue first, plus reminders and the calendar view.","b":"Follow-ups & tasks Deals are won or lost in follow-up. The **Follow-ups** page is your day plan: every open task, sorted by due date, overdue first. A task can also be created automatically (by automations, by AI SDR agents, or by appointment reminders) and by hand from any lead. Who this is for Sales agents** \u2014 start every day here. If it is on this list, somebody is waiting. Managers** \u2014 see who is behind on commitments (filter by team member). Difficulty:** Easy Time:** 8 minutes Prerequisites:** None to view. Creating tasks is available to all sales roles. Steps 1. Open your day plan 1. In the sidebar open **Follow-ups** ( ). Expected result:** the list of open tasks appears, sorted by due time. Overdue tasks are shown in red with an **overdue** note. The menu badge shows how many tasks are due by the end of today. 2. Read a task row Each row shows: The **lead** (click the name to open Lead 360) and their phone. The **task title** (what you committed to do). The **assignee** and the **due** time. A **priority** badge: urgent (red), high (orange), normal (blue), low (grey). 3. Work a task 1. Do the work (call, WhatsApp, email). 2. Click **Complete** on the row and confirm. 3. If you promised a next step, create the follow-up task immediately (see below) \u2014 do not rely on memory. Expected result:** the task leaves the open list and the completion is recorded on the lead's timeline. Completing a task also earns points on the lead's score. The row's **WhatsApp** action opens a template picker and starts the chat (details); **Open lead** jumps to the full record. 4. Create a follow-up 1. Click **New follow-up** (header button). 2. Choose the **lead** (searchable \u2014 the picker lists your recent leads), write the **title**, set the **due date\/time** (defaults to tomorrow 10:00), assign it (defaults to you), and pick a priority. 3. Save. Expected result:** the task appears on the list and notifies the assignee, who also receives a reminder before it is due. One task per p"},{"t":"Appointments & calendar","u":"\/docs\/crm\/appointments","s":"Using the CRM","sk":"crm","d":"Let leads book meetings from a link, manage booking types, availability and the team calendar \u2014 Google sync included.","b":"Appointments & calendar Give a lead a link, they pick a free slot, and the meeting lands in your CRM as a booking attached to the lead \u2014 with a calendar entry and reminder automations. This guide covers the booking page link (**Appointment Types**), the resulting **Bookings**, **Availability** per team member, and **Calendar connections** (Google sync). Who this is for Admins** \u2014 create appointment types and hand out booking links. Sales agents** \u2014 set your weekly availability; work your bookings. Managers** \u2014 monitor upcoming and no-show bookings. Difficulty:** Medium Time:** 12 minutes Prerequisites:** Admin access for Appointment Types; the plan feature (visible in your menu). Part 1 \u2014 Create an appointment type (admin) 1. Open Appointment Types 1. Go to **Settings \u2192 Appointments \u2192 Appointment Types** ( ). Expected result:** the list of meeting types with a bookings count per type. 2. Define the meeting 1. Click **New appointment type** and fill in: Name** and **slug** (the slug is used in the public booking URL). Description** \u2014 what the meeting is. Duration** \u2014 15 to 90 minutes (default 30). Buffer** \u2014 minutes of breathing room after each booking. Advance notice** \u2014 minimum hours before a slot can be booked. Future limit** \u2014 how many days ahead people may book. Colour**, **location type** and **location details** (in person \/ phone \/ video, with the address or link). Lead routing** \u2014 which pipeline and stage a booking lead lands in. Active** toggle. 2. Save. Expected result:** the type appears in the list with its **public booking link** and an **embed snippet** you can paste on your website. 3. Share the booking link 1. Copy the booking link (or the embed snippet) from the appointment type. Expected result:** anyone opening the link sees your open slots for this meeting type; a completed booking creates\/attaches a lead routed to the pipeline and stage you chose, and sends the visitor a confirmation. Part 2 \u2014 Set availability (each team member) 4. Open your ava"},{"t":"Calls","u":"\/docs\/crm\/calls","s":"Using the CRM","sk":"crm","d":"Log, review and analyse every call \u2014 outcomes, durations, recordings where your phone supports them, and AI summaries.","b":"Calls The **Calls** screen is the record of every conversation your team has with leads: who called whom, when, for how long, and how it ended. Calls enter the CRM from the click-to-call flow, from the Android app, and from manual **Log call** on Lead 360. Who this is for Sales agents** \u2014 check history before dialling; log calls you made elsewhere. Managers** \u2014 coach from real numbers: connect rates, durations, outcomes. Admins** \u2014 understand what the phone system records and for how long. Difficulty:** Medium Time:** 10 minutes Prerequisites:** The plan feature. Voice calling inside the CRM needs voice switched on and a phone number on your profile; the Android app adds device calling. How calls get into the CRM 1. **Click-to-call** \u2014 the **Call** action on a lead or task opens your dialler \/ softphone ( link). When your business has voice enabled, calls can be placed in-app through the configured voice provider. 2. **Android app** \u2014 the mobile app detects calls to CRM numbers and records the outcome; on phones that support it, the call recording and\/or its metadata is uploaded afterwards (see below). 3. **Manual log** \u2014 for calls made on your personal phone: open the lead \u2192 **Log call** \u2192 direction, duration, outcome, notes. Log the outcome, not just the call Outcomes are what reports and automations use. *Connected, Voicemail, No answer, Not interested, Callback* \u2014 pick honestly; \"connected\" on a call that never happened corrupts every response-time report. Steps 1. Review the call list 1. Open **Calls \u2192 Calls** ( ). Expected result:** the list of calls, newest first. There is deliberately **no \"New call\" button** here \u2014 calls are created by the calling flows so that a call record always has a real source; use **Log call** on the lead instead. 2. Open a call 1. Click a call to open its details: The **lead** (clickable), the **agent**, **direction**, **status**, **from\/to numbers**, **duration** and start time. Recording** \u2014 a player appears when a recording exist"},{"t":"WhatsApp inbox","u":"\/docs\/crm\/whatsapp-inbox","s":"Using the CRM","sk":"crm","d":"One shared team inbox for WhatsApp: read replies, send templates or free messages, and respect the 24-hour window.","b":"WhatsApp inbox The **Inbox** is where your business talks to leads on WhatsApp. It is shared: whoever on the team handles the reply, the conversation and its full history belong to the lead in the CRM \u2014 not to someone's personal phone. Who this is for Sales agents** \u2014 answer replies, send follow-ups, share templates. Managers** \u2014 watch response coverage across the team. Admins** \u2014 connect the WhatsApp number and manage approved templates. Difficulty:** Medium Time:** 15 minutes Prerequisites:** WhatsApp is connected for your business (Settings \u2192 Connections \u2192 WhatsApp \/ Messaging) and the plan feature. Templates must be approved before you can start a conversation outside the reply window. What is on the screen Left rail** \u2014 every lead with a conversation (most recent first), with an **unread count** for new inbound messages. Thread** \u2014 the messages with that lead, oldest to newest. Opening a conversation marks the inbound messages as **read**. Composer** \u2014 where you write. It has two modes: **free-form** and **template**. The 24-hour window (the one rule to remember) WhatsApp only lets a business send **free-form** messages within **24 hours of the lead's last message**. Outside that window, every message you start must be an **approved template**. Free text outside the window is rejected If the last inbound WhatsApp is missing or older than 24 hours, Meta rejects free-form sends (error **131047**). The CRM detects this situation and steers you to templates \u2014 but plan ahead: if you need to reach someone tomorrow, send an approved template today. Steps 1. Open the inbox 1. In the sidebar open **WhatsApp \u2192 Inbox** ( ). Expected result:** the conversation list loads with unread counts on the leads who replied. 2. Read and reply 1. Click a conversation. The thread opens with the full history. 2. Type in the composer if the window is open, or pick a **template** if it is not. 3. Send. Expected result:** your message is delivered through your business WhatsApp number. Th"},{"t":"Reports","u":"\/docs\/crm\/reports","s":"Using the CRM","sk":"crm","d":"The numbers behind the work \u2014 volume, sources, funnels, bottlenecks, response time, revenue and scheduled email reports.","b":"Reports Reports answer the uncomfortable questions with real data: *Are leads arriving? Where do they come from? Where do they get stuck? Who is answering fast enough? What did the ads actually earn?* Every report reads live from your CRM database \u2014 no estimates, no invented numbers. Who this is for Admins** \u2014 the whole picture. Managers** \u2014 team and pipeline performance. Sales agents** \u2014 your own numbers are visible in Team Performance and Revenue by Team Member. Difficulty:** Medium Time:** 15 minutes Prerequisites:** The plan feature. Reports appear in the sidebar for managers and above. The report list Open the **Reports** group in the sidebar. Each page has filters (date range, source, pipeline, user) and **CSV \/ PDF export**. Report | Question it answers | Lead Volume** ( ) | How many leads arrived over time \u2014 by day\/week\/month, split by source. | Source Performance** ( ) | Which sources deliver volume *and* quality (conversion, value). | Source Attribution** ( ) | UTM-based: which campaign (utm_source + utm_campaign) produced won deals and how much revenue \u2014 a lead counts as won when its status is converted or it has a won date. | Form Analytics** ( ) | Views vs submissions per lead form \u2014 where visitors give up. | Sales Funnel** ( ) | Stage-by-stage drop-off: how many leads reach each step of your process. | Where Leads Get Stuck** ( ) | Stages where leads sit longest \u2014 the fix list for your process. | Team Performance** ( ) | Per team member: leads handled, activities, conversions. | Response Time** ( ) | How fast leads get their first touch \u2014 by person and source. | Revenue by Team Member** ( ) | Won revenue and won deals per rep. | Follow-up Performance** ( ) | Email sequence engagement: sent, opened, replied. | Automation Performance** ( ) | Which automations run, and what they achieve. | Start every week with two reports Response Time** (is anyone slow?) and **Where Leads Get Stuck** (where does the process jam?). Fix the worst number first \u2014 most reven"},{"t":"AI assistant","u":"\/docs\/crm\/ai-assistant","s":"Using the CRM","sk":"crm","d":"Ask plain questions and get answers from your own CRM data \u2014 plus AI follow-up agents that work leads for you.","b":"AI assistant The **AI Assistant** lets you ask your CRM questions in plain language \u2014 *\"How many leads came in this week?\"*, *\"Show me my overdue follow-ups\"*, *\"Draft a WhatsApp follow-up for this lead.\"* Behind the scenes it does not guess: it reads live numbers from your workspace's data through controlled tools, so the answer is the same number a report would show. There are two AI features in this area: 1. **AI Assistant** (this page) \u2014 you ask, it answers\/does. 2. **AI Follow-up Agents** \u2014 autonomous agents you enroll leads into (see below). Who this is for Managers and admins** \u2014 this menu is shown to manager-and-above roles. Sales teams** \u2014 benefit from the AI-drafted emails and WhatsApp messages on Lead 360. Difficulty:** Medium Time:** 10 minutes Prerequisites:** The AI Assistant menu is visible to managers and above. Using a real LLM needs an AI provider key (see \"Setup\" below) \u2014 without one, the assistant degrades honestly instead of pretending. Steps 1. Ask a question 1. Open **AI Assistant** in the sidebar ( ). 2. Type a question, for example: \"How many leads do we have and how many are new?\" \"Which leads haven't been contacted yet?\" \"What are my overdue follow-ups this week?\" \"How is the team performing this month?\" \"What did Meta ads produce last month?\" Expected result:** an answer grounded in your data. Numbers come from live queries against your workspace \u2014 never a guess. 2. Ask it to do something The assistant can also act, within your permissions: Create a follow-up** \u2014 \"Create a follow-up for Ramesh tomorrow at 10am to discuss pricing.\" Draft a WhatsApp message** \u2014 it writes the draft; *you* approve and send it from the inbox. Expected result:** the follow-up appears in Follow-ups with the details you gave; drafts land ready to review, never sent behind your back. Answers are scoped to your business The assistant is tenant-clamped: it can only see (and only report on) your workspace's data. It cannot cross into other businesses. 3. Know what it"},{"t":"Notifications","u":"\/docs\/crm\/notifications","s":"Using the CRM","sk":"crm","d":"What the CRM tells you about, where it tells you, and how to tune it \u2014 bell, email, hourly digest and mobile push.","b":"Notifications The CRM should tap you on the shoulder at the right moments: a new lead arrived, someone assigned you a lead, a lead replied, a task is due, an export is ready. This guide shows where notifications appear and how to tune them to *your* taste \u2014 per event type and per channel. Who this is for Everyone \u2014 notification preferences are personal. Difficulty:** Easy Time:** 5 minutes Prerequisites:** Signed in to the tenant panel. Where notifications appear Channel | Where | In-app (bell)** | The bell icon in the top bar of the CRM panel. | Email** | Your inbox, immediately or as an hourly digest \u2014 your choice. | Mobile push** | Your phone, through the Android app (needs push configured for your business; see below). | Task reminders** | The assignee of a follow-up task gets a reminder notification (bell + email) before it is due. | The event types you can tune Open **Settings \u2192 Business \u2192 Notifications** ( ). You will see a row per event type: Event | When it fires | Lead received** | A new lead enters your business (webhook, form, import\u2026). | Lead assigned** | A lead is assigned to you. | Lead stage changed** | A lead you own moves stage. | Automation ran** | An automation executed for one of your leads. | Integration sync failed** | A connection (Meta, WhatsApp, calendar\u2026) failed to sync. | Export ready** | A large export finished and is ready to download. | Team mentioned** | Someone @mentioned you in a note. | For each type you choose the **channels**: **in-app**, **email**, **push** \u2014 and for email, the **frequency**: **immediate** (as it happens) or **hourly** (collected into a digest). Steps 1. Open your preferences 1. Go to **Settings \u2192 Business \u2192 Notifications**. Expected result:** the preference matrix loads, showing your current choices per event type. 2. Tune a type 1. For an event you care about (for example **Lead assigned**), tick **in-app** and **email**, and set email frequency to **immediate**. 2. For noisy events (for example **Automation r"},{"t":"Lead routing, scoring & health","u":"\/docs\/crm\/performance","s":"Using the CRM","sk":"crm","d":"Automatic lead assignment, scoring rules that rank leads, and health badges that flag deals going cold before it is too late.","b":"Lead routing, scoring & health Three quiet systems decide who gets each lead, which leads rise to the top, and which ones are quietly dying: 1. **Routing** \u2014 automatic assignment of new leads to the right person. 2. **Scoring** \u2014 points that rank leads by how promising they are. 3. **Health** \u2014 a live badge (healthy \/ needs attention \/ at risk) on every lead, with the reason. This guide configures all three. The result is visible on All Leads (health + score columns), Lead 360 (the guidance cards) and your dashboard's **Needs your attention** panel. Who this is for Admins** \u2014 set up routing, scoring and thresholds once. Managers** \u2014 tune them as the team changes. Difficulty:** Medium Time:** 12 minutes Prerequisites:** Admin access ( ). Lead auto-assignment needs at least one active team member. Part 1 \u2014 Lead routing (auto-assignment) 1. Open Lead Assignment 1. Go to **Settings \u2192 Leads & Sales \u2192 Lead Assignment** ( ). Expected result:** the assignment settings page opens with a mode selector. 2. Choose a mode 1. Pick one: Off** \u2014 every lead waits for a human to assign it. Specific user** \u2014 every new lead goes to one person. Round robin** \u2014 new leads alternate through the team members you select. 2. For specific\/round-robin, pick the person or the pool. 3. Save. Expected result:** from now on, every lead that arrives **without an assignee** is routed by this rule. Leads created with an assignee already set (imports with an owner column, webhooks that specify one, manual entries where you picked someone) are **never** overridden. Round robin with a small team Add only the people who genuinely respond fast \u2014 a round robin that includes someone on leave is worse than no rotation. Revisit the pool when the team changes. Part 2 \u2014 Lead scoring 3. Open Lead Scoring 1. Go to **Settings \u2192 Leads & Sales \u2192 Lead Scoring** ( ). Expected result:** the list of scoring rules (a fresh install has none \u2014 scores simply stay 0). 4. Create rules 1. Click **New scoring rule**. Each rule h"},{"t":"Meta overview","u":"\/docs\/marketing\/meta-overview","s":"Marketing \/ Meta","sk":"marketing","d":"How Facebook & Instagram ads connect to the CRM \u2014 who does what, where everything lives, and how the pieces fit together.","b":"Meta overview Facebook and Instagram are where many businesses win their leads \u2014 and where money quietly leaks: forms that fail, pages that reject leads, campaigns that spend without producing. Zodiac Tech CRM connects your Meta world (pages, lead forms, ad accounts) directly to the CRM, so a form submission becomes a lead with an owner in seconds. This page is the map. The other marketing guides go deep on each area. Who this is for Business owners (clients)** \u2014 see what ads produce without asking the agency for a spreadsheet. Admins** \u2014 connect Meta, choose pages and forms. Ad specialists** \u2014 run campaigns, creatives and QA. Difficulty:** Easy Time:** 8 minutes to understand the layout Prerequisites:** None to read. Connecting needs admin access and a Meta login with access to your business's pages. The three surfaces Meta work touches three different panels. Knowing which one you are in saves confusion: Surface | URL | Who works there | What it does | Tenant CRM** | | Your team | Connect Meta, choose pages\/forms, see ad results, approve creatives, build campaign drafts. | Agency console** | | Account managers, ads specialists, creative\/QA\/support staff | Run the ads service: setup queue, QA, active campaigns, client support. | Super Admin** | | Platform owner | The platform's Meta app credentials, all clients, health\/issues oversight. | If you are a client: your day-to-day is the **tenant CRM's Ads group** \u2014 [Ads overview dashboard, Campaign drafts, Creative approvals]. If an agency runs your ads, the agency console is *their* workspace; you will see the outputs in your CRM and receive creatives for approval. What the connection gives you 1. **Lead delivery** \u2014 Facebook\/Instagram lead-form submissions land in the CRM as leads with source, campaign, ad and form details attached (see Meta lead capture pipeline). 2. **Ad results next to sales results** \u2014 the Ads dashboard shows 30-day spend, impressions, clicks, leads, cost per lead, qualified leads, appointments, s"},{"t":"OAuth & permissions","u":"\/docs\/marketing\/oauth-and-permissions","s":"Marketing \/ Meta","sk":"marketing","d":"Connect Facebook\/Instagram to the CRM \u2014 what you grant, how to pick the Page and Ad Account, and how to keep the connection alive.","b":"OAuth & permissions Connecting Meta is a permission handshake: Facebook asks *\"do you allow this app to see and manage these assets?\"*, you approve, and the CRM receives an access token it uses to fetch leads and run ads. This page explains what you are granting, how to complete the connection, and what to do when it expires or misbehaves. One platform app, many businesses Your business never creates a Meta developer app or types an app secret. The platform has one Meta app configured by the Super Admin (Super Admin \u2192 Settings \u2192 Meta Developer). Each business connects through it and can only ever see its own Pages and data. Who this is for Admins** \u2014 perform the connection. Business owners** \u2014 understand what you are approving. Support** \u2014 diagnose \"Meta won't connect\" situations. Difficulty:** Medium Time:** 12 minutes Prerequisites:** You are an admin of the CRM workspace. Your Facebook account must be an **admin of the Page** you want to connect (and have access to the ad account). What you grant (the permissions, in plain language) When you connect **Meta** (Facebook), the app asks for these permissions: Permission | What it allows \u2014 in plain language | Read the leads people submitted through your Facebook\/Instagram lead forms. | List the Pages you manage, so you can pick the right one. | Read your Page's content and engagement. | Manage the ads related to your Page (used for the campaign features). | Connecting **Instagram** asks for , , and . Reads what you approve \u2014 nothing else The CRM can only see the Pages you select during connection. If a Facebook account manages several Pages, you will be asked which one belongs to this business, and only that Page's leads flow in. Steps 1. Start the connection 1. Go to **Settings \u2192 Connections** ( ). 2. Find the **Meta** source row and click **Connect** (the OAuth action). Expected result:** you are redirected to Facebook's login\/consent screen. 2. Approve the permissions 1. Sign in to the Facebook account that manages"},{"t":"Meta lead capture pipeline","u":"\/docs\/marketing\/lead-capture","s":"Marketing \/ Meta","sk":"marketing","d":"End to end \u2014 how a Facebook or Instagram form submission becomes a CRM lead with an owner and follow-up, with the exact gates it passes.","b":"Meta lead capture pipeline Someone taps **Submit** on your Facebook\/Instagram lead form. Seconds later their name is a lead in your CRM, assigned to a salesperson, with an automation already saying hello. This page traces that journey exactly \u2014 including the gates that can stop it \u2014 so you can operate and debug it with confidence. Who this is for Admins** \u2014 choose which forms feed the CRM and map their fields. Ad specialists** \u2014 understand why a campaign's leads do (or do not) appear. Developers\/support** \u2014 the webhook, signature and job internals. Difficulty:** Medium Time:** 15 minutes Prerequisites:** Meta is connected (OAuth & permissions) and at least one Instant Form exists on the connected Page. The pipeline, visually What each stage means for you 1. **The webhook URL** \u2014 every business has its own webhook endpoint with a secret token. Meta posts new lead events there. The same endpoint answers Meta's verification challenge (a GET request) so the subscription can be set up. 2. **Signature verification** \u2014 every POST is signed by Meta with the app secret. Requests that fail the check are rejected, so nobody can inject fake leads. 3. **The webhook log** \u2014 each accepted call is stored (status *pending*), then a background job processes it. The log is your audit trail: accepted, processed, skipped or failed, with notes. 4. **Form allowlist** \u2014 *only the lead forms you explicitly selected* in the CRM are ingested. A form that is not on the list produces a deliberate **skip note** on the webhook log, not a failure. This is how you keep a test form (or another team's form) out of your pipeline. 5. **Field mapping** \u2014 submitted answers are mapped to CRM fields (name, phone, email, and your custom fields). Answers with no mapping are preserved in the lead's raw data under \u2014 nothing is thrown away. 6. **Lead creation + routing** \u2014 the lead is created with its Meta identifiers (source id, ad id, form id) and the original payload. The standard assignment rules and automa"},{"t":"Campaigns","u":"\/docs\/marketing\/campaigns","s":"Marketing \/ Meta","sk":"marketing","d":"The governed campaign workflow \u2014 draft a campaign in minutes, the client approves, QA checks it, and only then does it launch (paused).","b":"Campaigns Zodiac Tech CRM runs Meta campaigns through a **deliberate gate**, not a one-click gamble: Brief \u2192 Draft \u2192 Client approval \u2192 QA checklist \u2192 Launch (paused) \u2192 Verify.** The point is simple: nothing spends money until a human approved it, a QA reviewer verified it, and it goes live **paused** so the first impression can be checked before budget flows. Who this is for Business owners \/ admins** \u2014 create the brief and approve the draft. The drafting screen lives in **your** CRM ( , menu **Ads \u2192 Campaigns**), for managers and above. Ads specialists** \u2014 shape and monitor campaigns in the agency console. QA reviewers** \u2014 the only role allowed to pass QA and launch campaigns. Difficulty:** Medium Time:** 15 minutes Prerequisites:** Meta connected and a client workspace provisioned for the agency (Agency panel). Campaign creation requires the manager role or above in the business. Part 1 \u2014 Draft a campaign (business side) 1. Write the brief 1. Open **Ads \u2192 Campaigns** ( ) and click **Create**. 2. Fill in the brief: Product \/ service** you are advertising. City \/ location** to target. Daily budget** (\u20b9) \u2014 within the allowed range (minimum \u20b9100; your platform sets the maximum, default \u20b910,000). Objective** \u2014 leads, WhatsApp messages, website visits, or sales. Notes** \u2014 anything the ad should say or avoid. 3. Submit. Expected result:** the CRM drafts the campaign copy immediately \u2014 using AI when an AI key is configured, and a solid template otherwise. **Nothing is sent to Meta at this point**; this is a draft inside your CRM. 2. Review and approve 1. Open the draft and read it like a customer would. 2. Use **Approve** (a human decision, recorded in the audit trail), or **Reject** to discard it. Expected result:** the draft moves to **Approved**. It now waits for the QA gate. Part 2 \u2014 QA and launch (agency side) The QA queue lives in the **agency console** ( \u2192 **Meta Ads \u2192 QA Queue**) and is available only to the **QA reviewer** role \u2014 the one role with the launch perm"},{"t":"Creatives","u":"\/docs\/marketing\/creatives","s":"Marketing \/ Meta","sk":"marketing","d":"How ad creatives travel from idea to approved asset \u2014 versioned, client-reviewed, and released for ads only when approved.","b":"Creatives A **creative** is the ad itself \u2014 image or video, headline, copy, and the offer it points to. Creatives in Zodiac Tech CRM are **versioned** (every revision is a new version, nothing is overwritten) and **client-reviewed** (you see and approve what will run with your name on it). Only after approval is a creative released \"ready for ads\". Who this is for Clients** \u2014 approve creatives or request changes, from your own CRM. Creative specialists** \u2014 move creatives through the pipeline. Ad specialists \/ QA** \u2014 pick up creatives marked ready for ads. Difficulty:** Medium Time:** 10 minutes Prerequisites:** An agency workspace provisioned for your business (the creative pipeline lives in the agency console; approvals land in your ). The lifecycle Additional states exist for completeness: **brief required** and **content required** (the creative needs a brief or assets before work can start), and **changes requested** loops back into production. The rule that matters: **a new version is created for every revision** \u2014 the client's feedback is stored on the exact version it judged, so \"what did we approve?\" is always answerable. Part 1 \u2014 Approve a creative (client) 1. Open Creative Approvals 1. In your CRM open **Ads \u2192 Creative Approvals** ( ). Expected result:** creatives waiting on you (status *client review*) are listed as pending, each with the version's preview, copy and details. 2. Approve or request changes 1. Review the creative exactly as a customer would. 2. Choose: Approve** \u2014 the creative becomes approved and moves toward \"ready for ads\". Request Changes** \u2014 a comment box appears; **write what must change** (this is mandatory \u2014 a vague \"not happy\" just costs a round trip). Expected result:** your decision is recorded on that version (feedback stored on the creative version, status updated, audit logged). The agency side is notified. If you requested changes, a new version will come back through the same path. Review like a customer, not a colleague You "},{"t":"Tracking & attribution","u":"\/docs\/marketing\/tracking","s":"Marketing \/ Meta","sk":"marketing","d":"Put a tracking snippet on your website so the CRM sees which pages leads visit \u2014 and which campaign actually earned the money.","b":"Tracking & attribution Attribution answers the hardest ads question: *which campaign produced the sale, not just the click?* Zodiac Tech CRM does this in two layers: 1. **Web tracking** \u2014 a small snippet on your website records which pages each visitor sees (and links the visit to a lead once you know who they are). 2. **UTM capture** \u2014 the campaign tags on the links that brought a lead in ( , , \u2026) are stored on the lead itself and used by the **Source Attribution** report to credit **won revenue** to the campaign that earned it. Who this is for Admins** \u2014 create the snippet and install it. Ad specialists** \u2014 verify the UTM habit across all campaign links. Developers** \u2014 paste the snippet and use correctly. Difficulty:** Medium Time:** 12 minutes Prerequisites:** Admin access to the CRM; the ability to edit your website's templates (or a developer who can). Part 1 \u2014 Create and install the snippet 1. Create a tracking snippet 1. Go to **Settings \u2192 Automation \u2192 Web Tracking** ( ). 2. Click **New**, give it a **name** (for example *Main website*), and list your **allowed domains** (the sites permitted to send data \u2014 your production domain, and if you test there). 3. Save. Expected result:** the snippet appears in the list with a **views** counter starting at zero. 2. Get the snippet 1. Use the **Get snippet** action on the snippet row and copy the code. Expected result:** you have a small block to paste before on your website (all pages you want tracked). 3. Install it 1. Paste the snippet into your site's global footer\/template so it loads on every page. Expected result:** the snippet loads and, on each page view, sends the page's URL, path, title, referrer and any UTM tags to the CRM. A visitor token is kept in the browser's local storage ( ) so repeat visits stay linked to the same anonymous visitor. Each view becomes a **PageView** record. 4. Verify it works 1. Open your website in a browser, visit a few pages. 2. Back in the CRM, check the snippet's **views** coun"},{"t":"Agency panel (Meta Ops)","u":"\/docs\/marketing\/agency-panel","s":"Marketing \/ Meta","sk":"marketing","d":"The agency console at \/agency \u2014 which role sees which menu, and the daily operating loop for each job.","b":"Agency panel (Meta Ops) The **agency console** ( ) is the workplace for the team that runs Meta ads *for* clients: account managers, ads specialists, creative specialists, QA reviewers and support agents. It is deliberately separate from both the client CRM ( ) and the platform Super Admin ( ) \u2014 agency staff see client workspaces, not the platform's plumbing. Everything in the panel sits under one navigation group: **Meta Ads**. Who this is for Agency staff** \u2014 your menu and your loop are below. Platform admins** \u2014 how the console is locked down. Clients** \u2014 know that this console exists and what it can\/cannot do with your account. Difficulty:** Medium Time:** 15 minutes Prerequisites:** An agency account (created on the platform side). Five failed logins lock an account for 15 minutes \u2014 by design. Access model in one minute The console is **permission-gated per page**: every screen declares the permission it needs. Two people with different roles can log in to the same panel and see genuinely different menus. The **Super Admin** bypasses the per-page gates (platform staff oversight). Only the QA reviewer can launch campaigns** ( ). This is the control that makes the campaign workflow meaningful. The client workspace list is **viewable** with the view permission, **editable** with client-manage, and **not creatable or deletable from here** \u2014 client workspaces are provisioned by the platform ( ). The full page map (and the permission each page needs) Screen | Purpose | Permission | Overview** | Portfolio health at a glance. | | Setup Queue** | New client workspaces waiting for connection & setup. | | Needs Attention** | Open issues across clients (see Ads health). | + lifecycle actions | Active Campaigns** | Live campaigns with spend, attributed leads and CPL. | | QA Queue** | The 12-point QA and the launch gate. | | Support Desk** | Client support work. | | Live Chat** | Real-time client chat. | | Requests Queue** | Client requests routed to the team. | | Team Workl"},{"t":"Ads health & needs attention","u":"\/docs\/marketing\/needs-attention","s":"Marketing \/ Meta","sk":"marketing","d":"The automated watchdog for Meta connections and campaigns \u2014 what it checks, how issues appear, and the lifecycle from open to resolved.","b":"Ads health & needs attention Ads break quietly. A token expires, a campaign keeps \"running\" with zero delivery, a form stops feeding the CRM, a cost per lead doubles overnight. Waiting for a human to notice is expensive \u2014 so the platform runs a **deterministic health scanner** across every client workspace, turns real problems into **issues**, and keeps chasing them until somebody closes the loop. Who this is for Agency staff (ads specialists, account managers, support)** \u2014 the operational queue. Platform admins** \u2014 oversight of all workspaces. Clients** \u2014 what you get: fewer surprises, and your own \"needs your attention\" panel in the CRM. Difficulty:** Medium Time:** 10 minutes Prerequisites:** None to read. Acting on issues requires access to the agency console or Super Admin. What gets checked (and how often) The scanner ( ) runs **every 30 minutes** over all client workspaces and raises an issue for: Check | What it catches | CPL spike** | Cost per lead jumped \u2014 current 7 days vs the previous 7 days (needs at least 3 leads in each period to be fair). | Paused campaign, live client** | A campaign that should be running is paused while the workspace is active. | No delivery** | A campaign is active but Meta is not delivering (review rejected, budget exhausted, audience dead). | Zero leads** | Campaign running, leads not arriving. | Dead connection** | The Meta connection\/token stopped working. | Issues carry a severity \u2014 **critical**, **warning** or **info** \u2014 and are attached to the client workspace. When a condition clears, the scanner **auto-resolves** its issue; nobody has to remember to close it. The scan output is logged for operators: workspaces scanned, issues detected, auto-resolved, errors. The issue lifecycle Open \u2192 Acknowledged \u2192 Resolved** (and **Reopen** if it recurs). State | Meaning | Open** | Detected, nobody has engaged yet. | Acknowledged** | A human owns it and is working it. | Resolved** | Fixed (or deliberately accepted) \u2014 with the trail to p"},{"t":"WhatsApp Business API","u":"\/docs\/integrations\/whatsapp","s":"Integrations","sk":"integrations","d":"Connect your business WhatsApp number to the CRM through Meta's official Cloud API \u2014 credentials, webhook verification, health checks and a test message.","b":"WhatsApp Business API Zodiac Tech CRM talks to WhatsApp through Meta's official **WhatsApp Cloud API** \u2014 there is no unofficial bridge, no phone farm, and no shadow banning risk. Each Business (tenant) connects its own WhatsApp Business Account (WABA) and phone number. Once connected, messages from leads land in the WhatsApp inbox and automations can send approved templates from your own number. Who this is for Admin** (workspace owner) or **Super Admin** who manages the business's Meta assets. Anyone re-connecting after a token was rotated. Difficulty:** Medium \u00b7 **Time:** about 15 minutes \u00b7 **Prerequisites:** A **Meta Business account** with the WhatsApp Business Platform (Cloud API) enabled. A phone number that is **not currently used on the regular WhatsApp or WhatsApp Business app** (a number can only live in one place). Access to the Meta Developer App used for your workspace (or help from your provider's Super Admin). Your CRM reachable over **HTTPS** in production \u2014 Meta calls the webhook over the public internet. One Meta app can serve every client The platform usually runs on a single Meta Developer App configured by the operator at Meta Developer settings. Your workspace only supplies its own WABA ID, Phone Number ID and token \u2014 clients never need to create their own Meta app. Step 1 \u2014 Collect the credentials in Meta 1. Open \u2192 your Meta app \u2192 **WhatsApp \u2192 API Setup**. 2. Note these values: WhatsApp Business Account ID** (WABA ID) \u2014 identifies your business account. Phone Number ID** \u2014 identifies the sending number (not the phone number itself). Access token** \u2014 for production, create a **System User** token so it does not expire in 24 hours. 3. Decide a **Verify token** \u2014 any random string you invent. You will paste the same value in both Meta and the CRM. Step 2 \u2014 Fill the connection form In the CRM go to **Settings \u2192 Connections \u2192 WhatsApp** ( ). Field | Required | What it is | WABA ID** | Yes | WhatsApp Business Account ID from Meta | Phone Number ID**"},{"t":"Message templates","u":"\/docs\/integrations\/whatsapp-templates","s":"Integrations","sk":"integrations","d":"Create WhatsApp message templates in the CRM, map variables to your lead data, and get them approved by Meta \u2014 statuses are always Meta-authoritative.","b":"Message templates WhatsApp does not allow businesses to send arbitrary text to people who have not messaged them recently \u2014 outbound messages outside the 24-hour window must use a **template** that Meta has approved in advance. This page covers creating templates in the CRM, mapping their variables, submitting them to Meta, and reading their real status. If you have not connected WhatsApp yet, start with WhatsApp Business API. Who this is for Admin** or **Manager** who owns the messaging content. Super Admin** helping a business get its first templates live. Difficulty:** Medium \u00b7 **Time:** about 15 minutes per template \u00b7 **Prerequisites:** WhatsApp connected (**Settings \u2192 Connections \u2192 WhatsApp**). The permission (Admins have it; Managers can be granted it). Step 1 \u2014 Create the template 1. Open **WhatsApp \u2192 Templates** and click **New template**. 2. The editor has six sections, with a live WhatsApp-style bubble preview on the side: Section | What you set | 1. Name | The template's Meta name \u2014 lowercase letters, numbers and underscores; the field auto-converts what you type ( with ) | 2. Category | , or \u2014 this changes how Meta reviews it and how it is billed | 3. Language | , , , or | 4. Header | Optional header (text or media slot) | 5. Body | The message text with , -style placeholders | 6. Buttons | Quick reply \/ URL \/ phone number \/ Flow buttons (up to 10 total) | Category honesty matters Meta charges and reviews templates more strictly than ones. Choose the category that truthfully describes the message \u2014 misclassification is a common cause of rejection. Step 2 \u2014 Map the variables Each body placeholder ( , , \u2026) needs a data token that tells the CRM what to insert at send time. Pick from the built-in tokens: Group | Tokens | Lead | , , , , , , , , | Business | , , , , , | Appointment | , , , | Offer | , , | The mapping must line up with the body **exactly**. If your body has three placeholders you must map exactly three variables, or the CRM blocks submission wi"},{"t":"WhatsApp automations","u":"\/docs\/integrations\/whatsapp-automation","s":"Integrations","sk":"integrations","d":"Send approved WhatsApp templates automatically from the automations engine \u2014 triggers, the send_whatsapp action, guard-chain failure codes and opt-out handling.","b":"WhatsApp automations Once WhatsApp is connected and you have at least one approved message template, you can send it automatically. The automations engine supports a action that attaches a template to any trigger \u2014 a new lead, a stage change, an appointment reminder, and more. Who this is for Admin** or **Manager** building follow-up flows. Super Admin** diagnosing why an automation's WhatsApp step failed. Difficulty:** Medium \u00b7 **Time:** about 15 minutes \u00b7 **Prerequisites:** WhatsApp connected (**Settings \u2192 Connections \u2192 WhatsApp**) and healthy. An **approved** template (see Message templates). The permissions for your role. Step 1 \u2014 Create the automation 1. Open **Automations** ( ) and click **New automation**. 2. Give it a name and choose a **trigger**: Trigger | Fires when | New Lead Received | A lead is created (any source) | Lead Stage Changed | A lead moves stage in the sales process | Lead Assigned to User | Routing assigns a lead to a salesperson | Tag Added to Lead | A tag is attached | Lead Score Crosses Threshold | Score-based hand-raise | No Activity (Time-based) | A lead goes quiet for the configured period | Date Reached (birthday \/ anniversary) | A lead date field is due (checked daily at 07:00) | Form Submitted | A Meta lead form submission is ingested | Manual Trigger | Only when fired by hand \u2014 great for testing | Appointment booked | A booking is created | Appointment approaching | Swept every 5 minutes; choose the lead time \u2014 1, 3, 6, 12 or 24 hours before (default 24) | Follow-up due | Swept every 5 minutes; fires when a follow-up task reaches its due time | 3. Optional conditions (stage, tag, source\u2026) narrow when the automation runs. Step 2 \u2014 Add the send_whatsapp action 1. Add an action and choose **Send WhatsApp**. 2. Pick a template from the **template selector**. The dropdown lists only templates that are **approved** (Meta-approved, or a legacy local template that is still usable). If the list is empty, approve a template first. 3. The CR"},{"t":"Firebase phone OTP","u":"\/docs\/integrations\/firebase-otp","s":"Integrations","sk":"integrations","d":"Configure mobile login methods \u2014 Firebase phone verification for the Android app, plus server-mediated email and SMS OTP fallbacks.","b":"Firebase phone OTP The Android app signs salespeople in with a workspace-discovered login screen. You choose which methods are offered: email + password, email OTP, phone + password, or **phone OTP verified by Firebase**. Firebase gives real phone-number verification without sending SMS from your own infrastructure \u2014 Meta-style phones are verified by Google's Identity Toolkit, and the CRM then matches the verified number to the right user. No google-services.json anywhere The Android app deliberately ships **without** a . At login it fetches your workspace's Firebase options (Web API key, Project ID, App ID, Sender ID) at runtime from the CRM and initializes Firebase on the spot. That is why this integration is configured entirely in the CRM UI \u2014 there is no file to rebuild into the APK. Who this is for Admin** configuring their workspace's login methods (**Settings \u2192 Connections \u2192 Mobile App**). Super Admin** setting platform defaults for all workspaces. Developer** wiring a custom build or debugging the login flow. Difficulty:** Advanced \u00b7 **Time:** about 20 minutes (plus ~5 minutes in the Firebase console) \u00b7 **Prerequisites:** The Android app installed for at least one user (see Mobile app setup). A Google account to create a Firebase project. Optional: tenant SMTP configured for the email fallback (Email & SMTP). Step 1 \u2014 Create the Firebase project 1. Go to and create a project (e.g. ). 2. In **Project settings \u2192 General \u2192 Your apps**, click **Add app \u2192 Android**. 3. Register the app with package name ** ** (the app's application ID \u2014 it must match exactly; if you also install the demo-flavor APK, register as a second app). 4. Add the **SHA-1** of the signing keystore: Debug builds: run in the Android project. Release builds: add the SHA-1 of your release keystore. Without the matching SHA-1, phone sign-in fails with an \"app not authorized\" error before any SMS is sent. 5. In **Authentication \u2192 Sign-in method**, enable the **Phone** provider. 6. In **Project se"},{"t":"Push notifications (FCM)","u":"\/docs\/integrations\/firebase-push","s":"Integrations","sk":"integrations","d":"Send push notifications to the Android app with your own Firebase project \u2014 server-side service account, test pushes, and how devices register.","b":"Push notifications (FCM) Push notifications alert salespeople about new leads, assignments and follow-ups even when the app is closed. The CRM sends them through **Firebase Cloud Messaging (FCM) HTTP v1** using **your own Firebase project** (\"BYO Firebase\"). Push is optional \u2014 without it, users still get in-app notifications the next time they open the app. Where the Firebase connection comes from The Android app receives its Firebase **client** options at runtime from the login endpoints (see Firebase phone OTP) \u2014 there is no . The **server side** (this page) is separate: to *send* pushes the CRM needs a Firebase **service account** JSON. In-app notifications (shown above) work with no Firebase setup at all. FCM makes the phone buzz in the background \u2014 the screen looks the same.* Who this is for Admin** who wants push working for their workspace. Super Admin** setting a platform-wide default. Developer** debugging delivery or building custom integrations. Difficulty:** Medium \u00b7 **Time:** about 10 minutes \u00b7 **Prerequisites:** Firebase project from the OTP setup (same project works). The JSON **service account key**: Firebase console \u2192 **Project settings \u2192 Service accounts \u2192 Generate new private key**. The service account JSON is a secret It contains a private key. Paste it only into the CRM's encrypted settings field \u2014 never into chat, email or a ticket. The CRM encrypts it at rest and never displays it back. Step 1 \u2014 Decide where the key lives The CRM resolves the service account in this priority order: Priority | Location | Best for | 1 | Workspace setting ( ) | A client with their own Firebase project | 2 | Platform setting (Super Admin \u2192 Mobile settings, stored encrypted) | One project for all workspaces (most common) | 3 | Server environment variable | Deployments that keep secrets in | The JSON must contain at least , and . Configure exactly one layer \u2014 the first one set wins. Step 2 \u2014 Paste the service account Super Admin:** open the platform **Mobile App Log"},{"t":"Email & SMTP","u":"\/docs\/integrations\/smtp-email","s":"Integrations","sk":"integrations","d":"Route workspace email through your own SMTP server \u2014 invites, password resets, OTP emails and scheduled reports \u2014 plus the platform-level default mailer.","b":"Email & SMTP The CRM sends email for team invites, password resets, login OTP codes, notifications and scheduled report delivery. Each workspace can route all of that through **its own SMTP server** so mail comes from your domain \u2014 while the platform keeps a fallback mailer for installs that never configure one. Who this is for Admin** setting up the workspace's outgoing email. Super Admin** configuring the platform default (or changing it in terms). Difficulty:** Easy \u00b7 **Time:** about 10 minutes \u00b7 **Prerequisites:** SMTP credentials from your mail provider (host, port, username, password). The workspace's plan includes the **communications** feature. Step 1 \u2014 Enter your SMTP details (workspace) 1. Go to **Settings \u2192 Communication \u2192 Email**. 2. Fill in the form: Field | Notes | Host** | Required. e.g. | Port** | Required. Default 587 | Encryption** | (typical), , or | Username** | Usually the full mailbox address | Password** | Write-only \u2014 stored **encrypted**, never shown again | From name** | What recipients see as the sender name | From email** | The sender address (must be allowed by your SMTP server) | 3. Click **Save**. The password is write-only Once saved, the password field cannot be revealed \u2014 the CRM stores it encrypted. If you leave the field blank on a later save, the existing password is kept. If you need to replace it, paste the new one. Step 2 \u2014 Send a test email 1. Click **Test email** on the same page. 2. The recipient defaults to **your own account email** \u2014 change it if you want to test another inbox. 3. Expected result: the CRM sends a test message immediately; success or the provider's error is shown on the page. Test email is blocked in demo mode On a demo install, credential saving and the test action are disabled by the platform's demo-mode guard \u2014 that is deliberate. Step 3 \u2014 Know what uses this mailer Sender | Queued? | Notes | Team invites | No \u2014 sent immediately | Invitee sets their own password via the email | Password reset | Yes ( )"},{"t":"Calendar sync","u":"\/docs\/integrations\/calendar-sync","s":"Integrations","sk":"integrations","d":"Two-way sync between CRM appointments and your Google or Outlook calendar \u2014 connect in a click, bookings flow both ways every 15 minutes.","b":"Calendar sync Calendar sync keeps your CRM appointments and your personal calendar in step. Connect your **Google** or **Microsoft Outlook** account from Settings, and from then on: appointments booked in the CRM appear on your calendar, and events you create in your calendar come back into the CRM \u2014 checked every 15 minutes. Who this is for Anyone who owns appointments \u2014 sales agents, managers, admins. Each person connects their **own** calendar; sync is per user, not per workspace. Difficulty:** Easy \u00b7 **Time:** under 5 minutes (client side) \u00b7 **Prerequisites:** The platform operator has registered the calendar app with Google\/Microsoft and set the client credentials (see \"For the operator\" below). If the provider row shows as unavailable, ask your Super Admin. Access to the calendar account you want to connect. Step 1 \u2014 Open the calendar settings Go to **Settings \u2192 Communication \u2192 Calendar**. You will see a card per provider \u2014 **Google Calendar** and **Microsoft Outlook** \u2014 each with a **Connect** button. Step 2 \u2014 Connect 1. Click **Connect** next to the provider you use. 2. You are sent to that provider's official consent screen (Google or Microsoft). Sign in and grant the calendar permissions shown. 3. You return to the CRM's callback and the row flips to **connected**. What the permissions mean The CRM asks for read\/write access to calendar events plus your email address, so it can tell which calendar belongs to you. It does not read your mail, contacts or files. You can revoke access at any time from your Google\/Microsoft account security page \u2014 or use **Disconnect** here. Step 3 \u2014 Verify and forget about it 1. The card shows the connection as connected. 2. Book a test appointment in the CRM on your own behalf (Appointments & calendar) and give sync a minute \u2014 the event should appear on your calendar (the account's primary\/default calendar). What syncs in each direction Direction | What happens | CRM \u2192 calendar** | An appointment ( ) created in the CRM is pos"},{"t":"Outbound webhooks & API keys","u":"\/docs\/integrations\/outbound-webhooks","s":"Integrations","sk":"integrations","d":"Push CRM events to your own systems with signed webhooks, and let external apps read data through scoped API keys.","b":"Outbound webhooks & API keys Two ways to connect the CRM to other systems: Outbound webhooks** \u2014 the CRM calls *your* URL whenever something happens (a lead is created, a stage changes\u2026) with a signed JSON payload. API keys** \u2014 *your* systems call the CRM's REST API with a scoped key. Both live in the **Advanced** group of Settings and are gated by your plan (features and ). Who this is for Admin** who subscribes to CRM events. Developer** integrating an ERP, ad platform, call tool or data warehouse. Super Admin** auditing what a workspace has connected. Difficulty:** Advanced \u00b7 **Time:** about 15 minutes \u00b7 **Prerequisites:** A public HTTPS endpoint on your side that can verify a signature. The plan feature enabled for webhooks \/ API access. Part 1 \u2014 Outbound webhooks Step 1 \u2014 Create the webhook Open **Settings \u2192 Advanced \u2192 Outbound Webhooks \u2192 New**, and fill: Field | Notes | Name** | Label for your own reference | URL** | Your HTTPS endpoint. Private\/loopback\/link-local and cloud-metadata addresses are **blocked** by the SSRF guard \u2014 use a public host | Events** | Any of: , , , , , | Secret** | Auto-filled with a random value \u2014 copy it into your receiver to verify signatures | Filters** (optional) | Narrow events: , , , , , . Filters combine with AND **across** fields and OR **within** a field; matches on intersection | Enabled** | Off means nothing is delivered | The secret is write-only later The secret is generated for you and stored encrypted; it is never included in API responses or listings. Copy it to your receiver when you create the webhook \u2014 you cannot read it back from the page afterwards. Step 2 \u2014 Test and watch deliveries Send test** fires a sample delivery to your URL and reports the result. View deliveries** opens the delivery log: status (pending \/ success \/ failed), response code, response body (first ~4,000 characters), latency and attempt count. Step 3 \u2014 Verify the signature in your receiver Delivery attempts carry these headers: Header | Content"},{"t":"Installation","u":"\/docs\/mobile\/installation","s":"Mobile App","sk":"mobile","d":"How the LeadHub Sales Android app gets onto a phone \u2014 where the APK comes from, installing past the \"unknown apps\" warning, and what to check on first launch.","b":"Installation The CRM has an Android app (shown in the launcher as **LeadHub Sales**) so your sales team can work leads, call, and log call outcomes from their phones. This page covers getting the app installed. Setting up your login comes next \u2014 see Login & workspace selection. Who this is for Business owners and admins who install the app for the team. Sales agents installing it on their own phone after being given the APK. Difficulty:** Easy \u00b7 **Time:** about 10 minutes \u00b7 **Prerequisites:** an Android phone (Android 13 or newer recommended) and the APK file from your operator. Step 1 \u2014 Get the APK The app is distributed directly by your CRM operator (your agency or Super Admin) as an file \u2014 it is **not** installed from the Google Play Store. Why not Play Store? The app uses call-log access ( ), which Google Play treats as a restricted permission requiring an approved core-functionality declaration. The supported distribution path today is direct install (sideload) or MDM. This is a deliberate choice, not a missing feature. Where the file comes from: Source | Location | Your operator \/ agency | Sent to you directly (WhatsApp, Drive, email) | Built from source | after running the Gradle release build | Demo \/ UI review build | \u2014 see Demo APK (UI review) | Step 2 \u2014 Install the APK 1. Copy the file onto the phone (WhatsApp to yourself, Google Drive, USB cable \u2014 any method works). 2. Open the file. Android will block the install the first time and offer a settings shortcut. 3. Allow **\"Install unknown apps\"** for whichever app opened the file (Files, Chrome, WhatsApp\u2026). This is a per-app permission and can be turned back off after installing. 4. Tap **Install**, then **Open**. The app installs as a normal app and appears in the launcher as **LeadHub Sales**. Company phones via MDM If your phones are managed with an MDM (Mobile Device Management) tool, your operator can push the APK silently and pre-approve the phone and call-log permissions \u2014 ask them instead of instal"},{"t":"Login & workspace selection","u":"\/docs\/mobile\/login","s":"Mobile App","sk":"mobile","d":"Sign in to the Android app with email or phone, password or one-time code \u2014 and how the app knows which workspace to open.","b":"Login & workspace selection The Android app signs you into the same CRM account you use on the web. This page covers the four ways to log in, how the app finds your workspace, and the two demo options built into this build. Who this is for Sales agents signing in on their phone. Admins helping a team member whose login is failing. Difficulty:** Easy \u00b7 **Time:** about 5 minutes \u00b7 **Prerequisites:** an account in the CRM (created in **Team members**) and, if OTP is used, a login method your workspace admin has enabled. Step 1 \u2014 Check the server address At the bottom of the login screen the app shows the CRM server it will contact (**Server:** \u2026). Everything else depends on this: If your business uses the operator's hosted CRM, the preconfigured address is already right. If not, tap **Advanced**, enter the correct base URL, tap **SAVE SERVER URL**, and read the confirmation line. The URL must start with or and **end with **. For a server running on your own PC (local XAMPP), a phone on the same Wi-Fi must use the PC's LAN IP, for example: What \"workspace selection\" means One CRM server can host many businesses (workspaces). The server address chooses the CRM install; your email\/phone and password then sign you into the workspace your account belongs to. If you are not sure which server hosts your workspace, ask your admin \u2014 do not guess. Step 2 \u2014 Choose how to sign in The login screen has two switches: **Email \/ Phone** and **Password \/ OTP Code**. That gives four combinations: Method | How it works | Email + Password | Your normal CRM password | Phone + Password | Same password; phone must be on your CRM profile | Email OTP | Tap **SEND CODE**, receive a one-time code by email, enter it | Phone OTP | Code by SMS \u2014 either from your workspace's SMS provider, or via the workspace's Firebase project if it has one connected | 1. Select **Email** or **Phone** and type your details (phone numbers are entered as 10 digits with a +91 prefix). 2. Select **Password** or **OTP Co"},{"t":"Permissions","u":"\/docs\/mobile\/permissions","s":"Mobile App","sk":"mobile","d":"Every permission the Android app asks for, why it needs it, and exactly what changes if you deny it.","b":"Permissions There is no \"grant everything and hope\" here. This page lists every permission the app declares, what it is for, and the honest consequence of denying it. The app is designed to stay usable when permissions are missing \u2014 it just does less. Who this is for Sales agents who saw a permission prompt and want to know what it means. Admins setting up phones for a team. Difficulty:** Easy \u00b7 **Time:** about 5 minutes \u00b7 **Prerequisites:** the app installed and a login \u2014 see Installation. The permissions, and why Permission | Asked when | Why | If you deny | Phone state** ( ) | First call feature use, or Device health \u2192 ALLOW | Know call state and enumerate active SIMs (used for the monitored-SIMs setting) | SIM count shows as unknown; all SIMs are treated as monitored | Call log** ( ) | Same prompt | Read the device call log so calls are matched to leads and logged to the CRM automatically | Call tracking stays off (\"Permission needed\" in Device health); you can still log calls manually from the lead | Phone numbers** ( ) | Same prompt | Declared alongside phone state to help identify the SIM\/phone number | No call-log sync benefit parsing; harmless | Notifications** ( , Android 13+) | First launch, and when push is set up | Show push alerts and sync-status notifications | Push arrives silently or not at all; in-app notifications still work | Battery optimization exemption** ( ) | Only when you tap **ALLOW UNRESTRICTED** in Device health | Stop Android's Doze mode from delaying background sync and recording discovery | Background uploads may be delayed until the phone next wakes | Audio settings** ( ) | No prompt (normal permission) | Mute \/ speakerphone on the optional in-app call screen | n\/a \u2014 granted at install | Answer phone calls** ( ) | No prompt until call features | \"End call\" best-effort from the in-app call screen; on modern Android the OS only lets the default dialer end calls, so this is wrapped and only used when the role is held | The call screen t"},{"t":"Calling from the CRM","u":"\/docs\/mobile\/calling","s":"Mobile App","sk":"mobile","d":"Tap-to-call from a lead, log the outcome on the post-call sheet, and let the app sync the call into the CRM automatically.","b":"Calling from the CRM Calling in the app is deliberately simple: tap a number, talk, then spend ten seconds logging the outcome. Calls are matched back to the lead and logged in the CRM automatically \u2014 as long as the phone has the call-log permission (see Permissions). Who this is for Sales agents making follow-up calls from their assigned leads. Managers who want to know calls actually reach the CRM. Difficulty:** Easy \u00b7 **Time:** about 5 minutes \u00b7 **Prerequisites:** the call-log permission granted; a lead with a phone number in your list. Step 1 \u2014 Call a lead 1. Open a lead from **Leads** (or from **Home** \/ **Follow-ups**). 2. Tap the phone number. 3. The app starts the call: If the app is allowed to place calls, it dials directly via the system call screen. Otherwise it opens your normal dialer with the number already filled in \u2014 tap the call button there. 4. Talk. The call happens on your SIM\/normal phone app; the CRM app is not a full dialer replacement by default. Optional: make LeadHub your Phone app You can opt in to **CRM Phone** by making LeadHub the default Phone app (Android's ROLE_DIALER). That adds an in-call screen with mute and speaker control served by the app. It is optional and never required for call logging. Device health shows the status and has **REQUEST** \/ **RELEASE** buttons. Note: becoming the default dialer does **not** guarantee call recording \u2014 see Call recording & what your phone supports. Step 2 \u2014 Log the outcome on the post-call sheet After the call you get the call sheet for that lead. Available outcomes (disposition chips): Chip | Meaning | Connected** | You spoke with the lead ( ) | Voicemail** | Reached voicemail ( ) | No answer** | Rang out ( ) | Not interested** | Lead declined ( ) | Callback** | Lead asked to be called back ( ) | 1. Tap the chip that matches what happened. 2. Add notes (a line or two is fine). 3. Optionally create a follow-up right there \u2014 it becomes a task on the lead. 4. Save. These are the same five outcome"},{"t":"Call recording & what your phone supports","u":"\/docs\/mobile\/recording","s":"Mobile App","sk":"mobile","d":"The honest truth about call recording on Android \u2014 three capability levels detected per device, where to see yours, and what to do at each level.","b":"Call recording & what your phone supports Call recording is the most over-promised feature in every CRM. It will not be over-promised here. Android and phone manufacturers restrict recording in different ways on different devices, so the app **detects what your exact phone can do** and tells you honestly. Some phones can record; some can only import recordings made by the phone's own app; some can only track call metadata. All three are useful; only the first two produce an audio file. The Recording row on your own phone is the answer for your device \u2014 the level shown above is only what this test device reported.* Who this is for Sales agents wondering why recording is or isn't available on their phone. Admins answering \"does the app record calls?\" per device. Difficulty:** Medium \u00b7 **Time:** about 7 minutes \u00b7 **Prerequisites:** the app installed and logged in. The three capability levels Open **More \u2192 Device health** and find the row titled **Recording: \u2026**. It resolves to one of four values, computed by the app's capability engine from the real state of the device: Level | Shown as | What it means | NATIVE_RECORDING** | **Recording: Native recording** | A recognised phone\/dialer app is set **and** the app found a recording folder it can actually read on this device. Native recording available. CRM recording import availability depends on your device and phone app. | IMPORTABLE_RECORDING** | **Recording: Importable recording** | Your phone can record calls, but the default dialer is not one the app recognises. Your phone can record calls, but Android\/OEM restrictions may prevent CRM access to the recording file. Calls still sync automatically. | METADATA_ONLY** | **Recording: Metadata only** | No readable recording folder on this device. Recording isn't available on this device. Call tracking is still active. | UNKNOWN** | **Recording: Unknown** | Detection itself failed on this phone. We couldn't check recording support on this device. Call tracking is still activ"},{"t":"Push notifications","u":"\/docs\/mobile\/push-notifications","s":"Mobile App","sk":"mobile","d":"How push alerts work in the Android app \u2014 bring-your-own Firebase setup, what triggers a push, deep links, and how to test it.","b":"Push notifications Push notifications let the app alert an agent the moment something happens \u2014 a new assigned lead, a due follow-up, an appointment reminder. Push is **optional**: the CRM works without it (you just won't get alerts on the lock screen), and the app is honest about which of the four states it is in. Who this is for Admins connecting the workspace's Firebase project. Agents wondering why a colleague gets alerts and they don't. Difficulty:** Easy \u00b7 **Time:** about 5 minutes \u00b7 **Prerequisites:** a workspace admin with access to the CRM's mobile settings; a Firebase project (free tier is fine). How it fits together (bring your own Firebase) Push uses Firebase Cloud Messaging (FCM). Each workspace connects **its own** Firebase project \u2014 there is no shared vendor project and no baked into the APK: 1. An admin creates a Firebase project and adds an Android app for (the app's application ID; demo flavor: ), then copies the app's Firebase options (API key, project ID, app ID, sender ID). 2. In the CRM, the admin pastes those values into the workspace's **Mobile App Login \/ push** settings (Super Admin \u2192 **Mobile & app settings**; tenant-level override in the workspace's settings \u2014 see Mobile app setup). 3. The app fetches the options automatically at login ( ) and registers this device's FCM token with the CRM ( ). If a workspace never configures Firebase, nothing breaks: the app simply stays on in-app notifications. Step 1 \u2014 Set up on the phone 1. Install and log in (see Login & workspace selection). 2. When Android asks to allow notifications (Android 13+), tap **Allow**. Declining sets the push state to **PERMISSION_DENIED** \u2014 fix it any time from **More \u2192 Device health \u2192 Push notifications (FCM) \u2192 ALLOW \/ SETTINGS**. 3. Open **More \u2192 Device health** and check the **Push notifications (FCM)** row. It shows one of four real states: State shown | Meaning | Registered** \u2014 \"Registered \u2014 this device receives push alerts.\" | All good; token posted to the CRM | P"},{"t":"Offline queue & syncing","u":"\/docs\/mobile\/offline-sync","s":"Mobile App","sk":"mobile","d":"What happens on the phone when there is no network \u2014 what queues, when it uploads, and how to check the queue is moving.","b":"Offline queue & syncing Agents work in basements, lifts and villages. The app is built for that: everything you do without a network is queued **on the phone** and uploaded automatically when a connection returns. Nothing is lost if the phone stays offline for a while. Who this is for Sales agents who noticed a \"pending\" indicator and want to know if their work is safe. Admins explaining sync behavior to the team. Difficulty:** Easy \u00b7 **Time:** about 5 minutes \u00b7 **Prerequisites:** none \u2014 this describes how the app behaves. What queues, and what doesn't Queued and uploaded later | Needs connectivity now | Call events detected from the device call log | Logging in | Notes you add to a lead | Loading fresh lead lists \/ lead details | Stage changes (moving a lead through the pipeline) | Receiving push notifications | Follow-ups you create or complete | Uploading recording audio files | Queued items are stored in an on-device database and uploaded in order by the app's sync worker. Home shows a pending badge while items are waiting; you can watch the count go down after a good connection. How the sync works 1. **Automatic, every ~15 minutes** \u2014 a periodic background worker checks the call log and pushes any queued changes. 2. **Automatic, on connection** \u2014 queued work retries with exponential backoff; a flaky network just means later, not lost. 3. **On demand** \u2014 force it any time: More \u2192 Device health \u2192 Background sync \u2192 SYNC NOW**, or More \u2192 Settings \u2192 Sync \u2192 SYNC NOW**. 4. **Failed items** \u2014 if an item is rejected after retries, it stays visible in **Settings \u2192 Sync**, where **RETRY FAILED** re-sends it. Step 1 \u2014 Check the queue state 1. Open **More \u2192 Device health** and read the **Background sync** row: \"Last sync: 5 Oct, 9:41 am\" \u2014 a successful upload has happened. \"Uploading now\u2026\" \u2014 the sync worker is running. \"Waiting for a connection\" \u2014 queued, waiting for network. \"Some changes couldn't sync \u2014 we'll retry automatically.\" \u2014 backing off after a failure. \"No succes"},{"t":"Device health","u":"\/docs\/mobile\/device-health","s":"Mobile App","sk":"mobile","d":"The on-phone checklist that proves what each Android device supports \u2014 permissions, sync, recording capability, battery \u2014 and how admins see it in the CRM.","b":"Device health Device health is the app's honesty screen. Instead of guessing why calls, push or recording aren't working, open it and read the exact state of this phone \u2014 then fix it with one tap where a fix exists. Every phone shows its own results \u2014 the rows above come from a test device; yours will differ.* Who this is for Agents checking their own phone before reporting a problem. Admins reviewing what a specific team phone supports. Difficulty:** Easy \u00b7 **Time:** about 5 minutes \u00b7 **Prerequisites:** the app installed and logged in. Step 1 \u2014 Open it More \u2192 Device health** (from the bottom navigation), or More \u2192 Settings \u2192 Device \u2192 CHECK DEVICE**. The screen re-runs the device check and pushes a fresh capability snapshot to the CRM every time it opens (quietly \u2014 if the phone is offline it just saves locally and sends later). Step 2 \u2014 Read the rows This device** \u2014 manufacturer, model, Android version and app version. Health check** rows, each with \u2713 \/ \u26a0 \/ \u2717 and, when possible, an action button: Row | What it tells you | Actions | Call tracking** | Whether the call-log permission is granted \u2014 the permission calls sync depends on | **ALLOW** re-requests phone\/call-log permissions | Notifications** | Whether Android allows this app to notify | **ALLOW** (Android 13+), **SETTINGS** | Push notifications (FCM)** | Registered \/ Permission denied \/ Not configured \/ Pending | **ALLOW**, **SETTINGS**, **RETRY** | Background sync** | Last successful sync and current activity (\"Uploading now\u2026\", \"Waiting for a connection\", backing off) | **SYNC NOW** | Recording: \u2026** | This phone's recording capability level with a plain-language explanation | \u2014 | Battery optimization** | Whether uploads can be delayed by Android's Doze | **ALLOW UNRESTRICTED** | SIM count** | How many active SIMs were detected (managed in Settings \u2192 Call tracking) | \u2014 | Default dialer** | Which phone app is set as default on this device | \u2014 | CRM Phone (default dialer)** | Whether LeadHub holds the optional d"},{"t":"Demo APK (UI review)","u":"\/docs\/mobile\/demo-apk","s":"Mobile App","sk":"mobile","d":"A shareable, server-free build of the Android app for reviewing the UI and checking call-recording capability on a real phone.","b":"Demo APK (UI review) Before a client commits their sales team to the app, send them the **demo APK**. It is a full build of the real app that runs with **no server and no login**, filled with bundled sample data captured from the ABC Realty demo workspace. Recipients can browse every screen and \u2014 most usefully \u2014 check what their own phone supports for call recording. Who this is for Super admins and agency staff demoing the product to a client. Business admins reviewing the app before rolling it out. Support staff asking a client to check a specific phone's capability. Difficulty:** Easy \u00b7 **Time:** about 5 minutes \u00b7 **Prerequisites:** the APK file ( ) shared by your operator; an Android phone. Two ways in \u2014 and which to use The login screen of this build has both demo entry points: Button | What it does | Needs a server? | \ud83d\udd0d EXPLORE DEMO \u2014 NO SERVER NEEDED** | Opens the app with sample data already inside (offline mode) \u2014 Home, Leads, Follow-ups, Calls, WhatsApp click-to-chat, Appointments, Notifications, Device health, Settings | No | TRY THE DEMO ACCOUNT** | Signs into the seeded demo workspace ( ) on a real server | Yes | For pure UI review, use **EXPLORE DEMO**. It flips the app into demo mode: an internal flag plus a stub token, with an interceptor that answers every API call from bundled fixtures \u2014 the same screens, DTO parsing and state handling as the real app, so what a reviewer sees is the real UI. Step 1 \u2014 Install and open 1. Send the APK to the reviewer (WhatsApp, Drive, email). 2. They open the file and allow \"install unknown apps\" when prompted \u2014 same as any sideloaded APK; see Installation. 3. Tap **\ud83d\udd0d EXPLORE DEMO \u2014 NO SERVER NEEDED**. 4. Mutating actions (call notes, dispositions, stage changes, follow-ups) succeed locally with the same optimistic UI as the real app. A **Demo mode** notice appears in Settings; **LOG OUT \u2014 EXIT DEMO** returns to the login screen. Step 2 \u2014 Review checklist Walk through each screen and confirm it works for the client's"},{"t":"Mobile troubleshooting","u":"\/docs\/mobile\/troubleshooting","s":"Mobile App","sk":"mobile","d":"Symptom-first fixes for the Android app \u2014 login, missing leads, calls not syncing, push, recording, and a slow app.","b":"Mobile troubleshooting Work through the problem that matches your symptom. Almost every mobile issue has exactly one of three causes: a permission, the server address, or a connection\/sync delay. Device health is where the evidence lives \u2014 start there when in doubt. Who this is for Agents fixing their own phone. Admins and support staff walking a user through a fix. Difficulty:** Easy \u00b7 **Time:** about 10 minutes per problem \u00b7 **Prerequisites:** the app installed (Installation). Quick map Symptom | Most likely cause | Jump to | Cannot log in | Wrong server URL, disabled login method, or lockout | Login problems | No leads in the app | Lead not assigned, or sync pending | No leads | Calls not reaching the CRM | Call-log permission denied or battery restriction | Calls not syncing | Push not arriving | Firebase not configured, notifications denied, or token pending | Push problems | Recording unavailable | Phone capability \u2014 honest metadata-only state | Recording problems | App feels slow \/ stuck | Large call-log backlog draining; recording scan in progress | Slow app | Cannot log in Quick fix:** check the **Server:** line at the bottom of the login screen. If it is wrong, **Advanced \u2192 Server URL** \u2192 correct URL (must end with ) \u2192 **SAVE SERVER URL** \u2192 try again. On a local server, use the PC's LAN IP, not . Then:** confirm the login method is enabled by the workspace admin (email\/phone, password or OTP), and that 5 failed attempts haven't locked the account for 15 minutes \u2014 while locked, the API answers with a retry-time message (wait, or ask an admin to reset). Escalate when:** the server line is correct, no lockout, and the server returns an error you don't recognize \u2014 send the exact message. See Login & workspace selection and Cannot log in. No leads appear Quick fix:** pull the latest data with **More \u2192 Device health \u2192 SYNC NOW**, then reopen Home. Check the **Background sync** row for \"Last sync\". Then:** confirm in the CRM (web) that the lead is assigned to thi"},{"t":"Architecture overview","u":"\/docs\/developer\/architecture","s":"Developer","sk":"developer","d":"How the platform is put together \u2014 Laravel 13 + Filament v4, three panels, the services layer, observers, jobs and the request lifecycle.","b":"Architecture overview The platform is a single Laravel application that serves four surfaces \u2014 three Filament panels, a REST\/mobile API, and the public marketing + docs site \u2014 over one MySQL database with tenant isolation at the model layer. This page is the map; the detailed pages are linked at the bottom. Who this is for Developers and hosting admins who will maintain, extend or debug the install. Difficulty:** Medium \u00b7 **Time:** about 10 minutes \u00b7 **Prerequisites:** familiarity with Laravel and a checkout of the repository. The stack Concern | Choice | Framework | Laravel 13 (PHP 8.4+) | Admin UI | Filament v4 (Livewire under the hood) | Database | MySQL ( locally; any MySQL 8-compatible server in production) | Queue | locally; + worker in production \u2014 see Queues, jobs & scheduler | Scheduler | Laravel's scheduler driven by one cron entry ( every minute) | Deployment target | Shared cPanel\/Apache hosting (subdomain install), not Docker | Surfaces and panel providers Surface | Path | Provider \/ entry | Tenant CRM | | (panel id ) | Super Admin | | (id ) | Agency (Meta Ops) | | (id ) | REST API | | API-key authenticated controllers ( ) | Mobile API | | Device-token authenticated controllers ( ) | Marketing + docs | , , | Blade controllers\/views | OpenAPI viewer | | | Request lifecycle is the single wiring point: middleware groups, alias list ( , , , , , Spatie role\/permission), CSRF exceptions for token-authenticated inbound endpoints, and the API\/mobile error-envelope renderers. Key middleware on every web request \u2014 trusts nothing by default; opt in via . \u2014 resolves and binds the workspace for web requests. , , . API and mobile requests bind their tenant from the credential instead \u2014 see Authentication. The services layer Business logic lives in and is called by controllers, jobs and Filament actions \u2014 controllers stay thin. Representative services: Area | Services | Lead capture | , , , | Messaging | (MetaCloudWhatsAppProvider, template\/message\/media services) | B"},{"t":"Authentication","u":"\/docs\/developer\/authentication","s":"Developer","sk":"developer","d":"The three credential systems \u2014 web sessions, REST API keys and mobile device tokens \u2014 plus OTP flows and where each is enforced.","b":"Authentication The platform has exactly three authentication mechanisms, each for a different caller. They are deliberately independent: API keys cannot log into panels, device tokens cannot call the REST API, and sessions are never used for machine callers. Who this is for Developers integrating with the API, debugging login failures, or extending auth. Difficulty:** Advanced \u00b7 **Time:** about 12 minutes. The three mechanisms Mechanism | Credential | Who uses it | Middleware | Where | Web session** | Email\/phone + password via Filament login form | Humans in , , | Filament auth + panel access checks | Panel routes | API key** | | Server-to-server integrations | \u2192 | | Device token** | | The Android app | | (except login\/OTP\/config) | Web sessions (Filament panels) Login lives on the panel's own login page; credentials are submitted via Livewire. Login lockout**: 5 failed attempts \u2192 15 minutes. Failures are recorded in ( ). Because Filament 4 submits through (not the panel login URL), panels enforce the lockout inside , which hooks Livewire's . The alias ( ) exists for any custom non-Filament login route. Super Admin access additionally has the optional IP allowlist \u2014 \u2192 . Guests hitting an expired non-panel URL are redirected to the panel login (configured in ). OTP login for the mobile app (pre-device-auth endpoints) Endpoint | Purpose | Which login methods this workspace supports (password\/email OTP\/phone OTP, Firebase options when configured) | Email or phone + password + \u2192 device token | Send a one-time code (email, workspace SMS, or Firebase) | Verify code or Firebase ID token \u2192 device token | Details enforced in and its rate limiters: OTP codes are stored **HMAC-SHA256-hashed with a random salt** \u2014 the plaintext is never persisted. Verify attempts are capped (5 per code); issuance is limited per identifier (3 per 10 minutes) and per IP (10 per 10 minutes), on top of a coarse route throttle ( ). Phone OTP via the workspace's Firebase project is verified **server"},{"t":"Multi-tenancy & isolation","u":"\/docs\/developer\/multi-tenancy","s":"Developer","sk":"developer","d":"How one install serves many businesses safely \u2014 the fail-closed BelongsToTenant scope, current_tenant binding, the SA HQ workspace, and the rules that keep data apart.","b":"Multi-tenancy & isolation This product is single-database multi-tenant: every business (\"workspace\"; the table) shares the schema, and a **fail-closed** global scope keeps their rows apart. The design rule is simple: if the code cannot prove which tenant a request belongs to, queries return **nothing** \u2014 they never fall back to \"all tenants\". Who this is for Developers adding models, queries, endpoints or panel pages \u2014 and anyone debugging \"why is this list empty?\" or a data-visible-only-to-the-wrong-team bug. Difficulty:** Advanced \u00b7 **Time:** about 12 minutes. The pieces Piece | Role | table | One row per business (plus the internal HQ row). UI calls it \"Business\" | Global scope + auto-stamp for tenant-owned models | The per-request binding the scope reads | Web: resolves and binds the workspace (skips ) | (alias ) | Logs out a non-SA user who has no workspace | Super Admin panel: binds the internal \"LeadHub HQ\" workspace | The explicit opt-in for cross-tenant SA queries | How a request gets its tenant The scope itself does three things: 1. **Filter**: adds global scope \u2192 . 2. **Fail closed**: when no tenant resolves **and** the user is not a Super Admin \u2192 (empty result, no leak). 3. **Auto-stamp**: on , fills from the resolved context when the caller didn't set it. Resolution order: first, then . A Super Admin context **without** a bound tenant is intentionally unfiltered (that is what powers cross-tenant SA tables) \u2014 SA code that only wants one workspace must bind it or filter explicitly. The \"LeadHub HQ\" special case deliberately skips , so tenant-scoped queries there would otherwise run unfiltered \u2014 fine for cross-tenant admin lists, wrong for the SA panel's own CRM-shaped pages. (registered as **persistent** panel middleware, so Livewire requests keep the binding) solves that: Only for super-admin users; a no-op everywhere else. Finds the internal workspace via the marker (created by ). Caches the id under for 60 seconds; caches for \"not provisioned yet\"; nev"},{"t":"Roles & permissions (RBAC)","u":"\/docs\/developer\/rbac","s":"Developer","sk":"developer","d":"Spatie roles, the HasRolePermissions gate with its pivot fallback, real permission prefixes, and the roles across tenant, agency and platform panels.","b":"Roles & permissions (RBAC) Authorization is Spatie permissions on top of the tenant pivot, wrapped by one trait so every Filament resource answers the same way. This page maps the system: the traits, the real permission names, the roles, and the two things that are *not* authorization. Who this is for Developers adding resources, changing role behavior, or debugging \"why can this user not see that page?\". Difficulty:** Advanced \u00b7 **Time:** about 10 minutes. The roles Panel | Roles | Tenant ( ) | (owner), , (sales agent) \u2014 stored on the pivot | Platform | | Agency ( ) | , , , (only role that can **launch** campaigns), | The canonical super-admin check Always use: The legacy column **and** the Spatie role both count. Do not test the column directly. The resource gate: HasRolePermissions Every tenant-facing Filament resource declares a prefix and inherits the gates: Gate | Required permission | or** | (view-only roles cannot save) | \/ | **or** | resolves in this order: 1. **Super Admin bypass** \u2014 grants everything. 2. **Role-admin bypass** \u2014 any user holding the Spatie role (the workspace owner; wires every tenant permission to this role). 3. **Spatie permission** \u2014 . 4. ** pivot fallback** \u2014 for legacy workspaces whose owner never got Spatie roles synced: pivot role \u2192 everything; pivot role \u2192 permissions ending , , , , , (never \/ ). Resources with nuanced policies override individual gates \u2014 the trait's methods are plain statics, not final. Real prefixes in use Prefix values found on tenant resources (a representative inventory): Prefix | Example uses | Generated permissions | LeadResource, LeadCallResource, tags, custom fields, scoring rules, invoices | | FormResource, LandingPageResource, LeadCaptureWidgetResource, ChatbotConfigResource | | PipelineResource | | AutomationResource, EmailSequenceResource, EmailTemplateResource, AiSdrAgentResource | | IntegrationResource, LeadSourceConnectionResource, OutboundWebhookResource | | ApiKeyResource | | Prefixes are more coa"},{"t":"Database & migrations","u":"\/docs\/developer\/database","s":"Developer","sk":"developer","d":"Migration conventions, the tables that matter most, and how the schema is organised \u2014 with an ER map of the core relationships.","b":"Database & migrations The schema is plain MySQL managed entirely by Laravel migrations ( , currently 177 files). This page gives you the conventions and the map of the tables you will actually touch; the migrations themselves are the source of truth for columns. Who this is for Developers writing migrations, debugging data, or preparing a fresh install. For the tenancy mechanics behind , read Multi-tenancy & isolation first. Difficulty:** Medium \u00b7 **Time:** about 10 minutes. Conventions 1. **Every tenant-owned table carries ** (FK to , indexed) and its model uses the trait. 2. **Uniqueness is composite, not global** \u2014 natural keys are scoped: on ; on . The same external object can exist for two businesses. 3. **Migrations are chronological and additive** \u2014 later migrations add columns\/indexes ( , , \u2026). Do not rewrite history; add a new migration. 4. **Soft deletes for businesses** \u2014 (and login-adjacent tables) use soft deletes; GDPR erasure hard-deletes after a cool-off (see Security model). 5. **JSON columns** for per-tenant configuration ( , ) instead of wide nullable columns. 6. **No SQLite-specific SQL in app code** \u2014 JSON-path checks are done in PHP (see ) so MySQL\/SQLite test runs behave the same. Core ER map Tables you will meet first Tenancy & users (name, slug, owner_id, domain\/subdomain, max_seats\/seat_count, subscription_status, plan, settings JSON, branding JSON, active, soft deletes) \u00b7 \u00b7 (pivot; defaults to ) \u00b7 \u00b7 \u00b7 . Leads & sales (source, source_id, source_connection_id, form_id, names, email, phone, phone_normalized, status default , is_duplicate, raw_data, custom_fields, assigned_to, notes, contacted_at, consented_at) \u00b7 (follow-ups) \u00b7 \u00b7 \u00b7 \u00b7 \u00b7 \/ \u00b7 \u00b7 \u00b7 \u00b7 . Capture & messaging (per-tenant Meta\/other connectors; unique 64 chars, credentials\/settings, status, last_received_at, last_error) \u00b7 (WABA\/phone, encrypted tokens, health fields, unique) \u00b7 \/ \/ \/ \u00b7 + WhatsApp message tables \u00b7 . Onboarding + (the guided 12-step client journey; see Roles & who does wha"},{"t":"Queues, jobs & scheduler","u":"\/docs\/developer\/queues-cron","s":"Developer","sk":"developer","d":"The complete scheduled-task inventory, the queue configuration for local and production, and how failures surface.","b":"Queues, jobs & scheduler Almost everything \"automatic\" in the product \u2014 WhatsApp appointment reminders, follow-up sweeps, Meta lead health, billing lifecycle, retention, backups \u2014 rides on two mechanisms: **queued jobs** and **the Laravel scheduler**. The entire schedule is declared in ; this page transcribes it in full. Who this is for Hosting admins and developers who must configure cron\/queues and reason about background behavior. Difficulty:** Medium \u00b7 **Time:** about 12 minutes. Queue configuration Environment | | What runs the queue | Local XAMPP (default in ) | | Nothing \u2014 jobs run inline during the request | Production (recommended) | | A long-lived worker: | With , deferred behaviors still work because the product is **sweep-based**: checks run on a schedule and query state, rather than relying on delayed jobs being processed at a precise moment. Production worker (one is enough on a small cPanel install; keep it alive via cron or a process manager): Failed jobs land in (Laravel default). Inspect ( ), retry ( ), or flush ( ). Jobs may target a named queue; for example push delivery ( ) runs on the queue with 2 tries and 30\/120-second backoff. Scheduler setup One cron entry drives everything: Every task below runs inside Laravel's scheduler, so a single missed cron minute only delays tasks, and prevents pile-ups. The complete schedule (routes\/console.php) All entries use (10 minutes unless noted) and logging a structured error. Task | Cadence | Purpose | 1 | | every 5 min | Poll connected mailboxes for inbound email | 2 | | hourly | Fire no-activity automations | 3 | | every 5 min | WhatsApp appointment reminders inside each tenant's window (dedupe key prevents repeats) | 4 | | every 5 min | Fire automations for overdue lead tasks | 5 | | daily 07:00 | Birthday\/anniversary greetings from date custom fields | 6 | | every 15 min | Advance email sequence enrollments | 7 | | every 15 min | One AI SDR decision\/action per due enrollment (no-op in demo mode) | 8 | "},{"t":"Webhooks (inbound)","u":"\/docs\/developer\/webhooks","s":"Developer","sk":"developer","d":"Every inbound webhook \u2014 lead sources, WhatsApp\/SMS messaging, and commercial billing \u2014 with verification, idempotency and failure behavior.","b":"Webhooks (inbound) Three families of external systems push data into the platform: **lead sources** (Meta lead ads and friends), **messaging channels** (WhatsApp\/SMS\/\u2026), and **payment providers** (Razorpay\/Cashfree). All are tokenized or signature-verified, CSRF-exempt, and designed to fail safely \u2014 a webhook must never create duplicates, and an invalid caller must learn nothing. Who this is for Developers debugging \"leads stopped arriving\" \/ \"delivery statuses missing\", or integrating a new source. Difficulty:** Advanced \u00b7 **Time:** about 15 minutes. Route inventory Webhook | Method(s) | Route | Handler | Generic lead source | (verification) + | | | Messaging (WhatsApp\/SMS\/Telegram\/Viber) | (verification) + | | | Commercial billing \u2014 Razorpay | | | | Commercial billing \u2014 Cashfree | | | idem | Legacy gateway billing | | | | CSRF exemptions are registered in for , , and the embeddable form widget ( ) \u2014 these callers cannot carry a session token. Lead-source webhooks is the workspace slug; is the per-connection secret on (unique column; generated as a random secret when the connection is created). 1. **Verification (GET)** \u2014 once the connection resolves, a challenge handshake (Meta, or Twitter's CRC) gets echoed back; malformed verification requests just get . 2. **Delivery (POST)** \u2014 the connector's handler parses and verifies the payload: Meta: HMAC \u2014 validated with the connection's stored credential, falling back to the platform-wide secret from (Super Admin \u2192 **Meta Developer** settings). A row is created with status , then is queued and updates it (including a human-readable error when a Graph fetch fails, so the log is retryable from the UI). Rejected deliveries (inactive connection, unregistered source, signature mismatch) are still **recorded** in with \/ status and acknowledged with a 200 \u2014 operators can see them, while attackers probing tokens learn nothing (unknown tenant\/source\/token gets a silent 200 and only a redacted log line). 3. **Ingest** \u2014 the queue"},{"t":"Storage & file handling","u":"\/docs\/developer\/storage","s":"Developer","sk":"developer","d":"Where files live in the platform \u2014 private recordings, the streaming playback route, generated tenant branding CSS, and retention.","b":"Storage & file handling Files fall into two very different buckets: **private business data** (call recordings) that must never be publicly reachable, and **generated public assets** (per-tenant branding CSS) that browsers fetch anonymously. This page covers both, plus the retention job that cleans up. Who this is for Developers touching uploads\/downloads, and hosting admins sizing\/mounting storage on cPanel. Difficulty:** Medium \u00b7 **Time:** about 10 minutes. Private recordings (never public) Mobile recordings are uploaded to the **private disk** (Laravel's disk rooted at , outside the web root): Upload: (multipart, device-token authenticated). Max size **20 MB** ( ). Content must be **audio\/*** \u2014 server-side mime detection with a client-declared-mime fallback for containers PHP cannot sniff (e.g. some \/ ). The call is resolved **within the requesting tenant** (a call from another workspace 404s with ). Excluded numbers are a hard backstop** \u2014 audio for an excluded number is rejected (422 ). Re-uploading for the same call is idempotent: the existing stored recording is returned with . Layout: . Playback: streams the file ( ). No public URL exists by design. The model is tenant-scoped, so another tenant's id is a 404. A purged\/expired recording returns **410 GONE**; a missing file returns 404 . If transcription is configured for the workspace, a new upload dispatches (the same gate as the manual web action). Retention Each recording gets ( ). runs **daily at 03:15** (see Queues, jobs & scheduler): deletes files past expiry from the disk; keeps the metadata row, marked expired with set to null, so call history\/reporting stays intact; supports to preview candidates. Public branding CSS (generated per tenant) The white-label theme is a generated stylesheet, not a database-driven runtime paint: writes when branding\/settings change (public\/ must be writable; a write failure is logged as a warning and never breaks saving). injects the stylesheet into the tenant panel's pag"},{"t":"Security model","u":"\/docs\/developer\/security","s":"Developer","sk":"developer","d":"Password hashing, encrypted settings, CSRF and signatures, audit logging, lockouts, and the data-privacy commands \u2014 the platform's defensive posture in one place.","b":"Security model This page collects the security-relevant mechanics that are spread across the codebase. Each item cites the real class or command; nothing here is aspirational. Who this is for Developers doing a security review, and hosting admins hardening a production install. Difficulty:** Advanced \u00b7 **Time:** about 15 minutes. Credentials and secrets at rest Data | Protection | User passwords | Laravel's password hashing ( ), never stored reversibly | Meta app secret (platform) | with ; never rendered back in the SA form \u2014 fills a masked field | Billing provider keys | \u2014 provider key fields (SA \u2192 Billing \u2192 Providers & Settings) | WhatsApp tokens | casts , , as | Calendar OAuth tokens | casts , as | Outbound webhook signing secrets | casts as | 2FA secrets | casts as | Mobile device tokens | Only is stored \u2014 the plaintext token never lands in the database | OTP codes | Stored HMAC-SHA256-hashed with a random salt; 5 verify attempts; issuance rate-limited per identifier and IP | Encryption uses Laravel's \u2014 losing\/rotating it without re-encrypting makes these values unreadable. Back it up with the database. Transport and request integrity CSRF** is on by default for web routes. The explicit exemptions (registered in ) are exactly the token\/signature-authenticated inbound surfaces: , , , . Inbound webhook verification**: Meta: HMAC (connection credential or platform ). WhatsApp: when the connection has an ; token mismatches return the same anonymous . Billing: provider signature verified against the **raw body**; invalid \u2192 400; idempotent keyed + payload SHA-256. See Webhooks (inbound). Trusted proxies** are opt-in ( ; default trusts nothing) so lockout\/audit IPs cannot be spoofed by header injection. Security headers** ( middleware) add X-Frame-Options, X-Content-Type-Options and Referrer-Policy to every web response; the embeddable widget opts out per-route deliberately. Signed links**: guided-onboarding client links are signed URLs valid for 72 hours ( ), so they "},{"t":"Testing the platform","u":"\/docs\/developer\/testing","s":"Developer","sk":"developer","d":"How the PHPUnit suite is organised, how to run it on XAMPP or Linux, and how to write a feature test the house way.","b":"Testing the platform The platform ships with a large PHPUnit suite \u2014 **~700 test methods across ~90 files**, all green \u2014 organized into and . This page covers how to run it and how to add to it correctly. Who this is for Developers changing platform code, and anyone verifying an install before go-live. Difficulty:** Medium \u00b7 **Time:** about 10 minutes. Running the suite On Windows\/XAMPP (PHP may not be on PATH \u2014 call it explicitly): Anywhere else: Useful variations: The suite runs against a separate database points tests at the ** ** MySQL database (with , , , , low bcrypt rounds). That database must exist and be migrated before the first run. Connection credentials live in your local \/environment \u2014 they are intentionally not documented here, and must never be committed to docs, tickets or chat. How tests are organised Location | What lives there | Pure logic \u2014 value objects, services with fakes, helpers | HTTP + DB behavior \u2014 panels, API endpoints, jobs, webhooks | Base class (Laravel's conventions) | The house convention is ** rather than database refreshes: each test runs inside a transaction that is rolled back afterwards. The schema stays intact and tests stay fast \u2014 but it means the testing database must already be migrated, and **anything you create in a test is invisible to parallel processes**. Because every tenant-owned model is behind the fail-closed scope, tests must establish tenant context the same way real requests do \u2014 bind , sign in a user whose is set, or assert the empty-result behavior deliberately. This is the most common gotcha when a new feature test \"sees nothing\". See Multi-tenancy & isolation. Factories Model factories live in : , , , , , , . Writing a feature test (the house way) A typical feature test \u2014 factory setup, tenant context, HTTP assertion, transaction rollback: For API tests (device-token or API-key surfaces), follow \u2014 it shows the project's shape for mobile endpoints: create the tenant\/device\/user, authenticate the way the real"},{"t":"API overview","u":"\/docs\/api\/overview","s":"API Reference","sk":"api","d":"The two APIs Zodiac Tech CRM exposes \u2014 the REST API for servers and the Mobile API for the Android app \u2014 how they authenticate, version, and rate-limit.","b":"Zodiac Tech CRM exposes **two separate HTTP APIs**: API | Base path | Who it is for | Authentication | REST API** | | Servers, no-code tools (Zapier, Pabbly, n8n), custom scripts | Per-workspace **API keys** ( ) | Mobile API** | | The ZodiacTech CRM Android app ( ) | Per-user **device tokens** ( ) | They share the same Laravel application but have different auth, different response envelopes and different rate limits. Pick the one that matches your client: A server syncing leads in and out \u2192 **REST API** (REST API (API keys)). The Android app installed on a sales agent's phone \u2192 **Mobile API** (Mobile API (device tokens)). External platforms calling *you* (Meta, WhatsApp, Razorpay, Twilio) \u2192 **webhooks** (Webhook endpoints). Who this is for Developer** \u2014 building an integration against the REST API or debugging the mobile app's traffic. Admin** \u2014 creating and scoping API keys for your workspace. Super-admin** \u2014 monitoring API health and platform-level rate limits. Prerequisites:** a working install (see Go-live checklist) reachable over HTTP(S). Base URLs The exact base URL depends on how the install is deployed. When the domain's document root points at the folder (the recommended setup on cPanel), there is **no subfolder** in the URLs: If the app runs inside a subfolder \u2014 for example the XAMPP development install at , where the root bridge forwards requests into \u2014 the subfolder is part of the path: Which layout am I running? If opens the CRM directly, the document root is pointed at and no subfolder appears in API URLs. If is the CRM, include in every API URL. Versions The API version is read from , set by the environment variable (default ). The canonical surface is . Two compatibility behaviours exist for convenience: 1. **Unversioned lead aliases** \u2014 (plus ) work exactly like . These exist because some no-code platforms (Pabbly Connect, older Zapier connectors, n8n HTTP nodes) do not follow 308 redirects on . 2. **Automatic 308 redirect** \u2014 any other path under"},{"t":"Authentication","u":"\/docs\/api\/authentication","s":"API Reference","sk":"api","d":"How REST API keys and mobile device tokens are created, sent, scoped, expired and revoked \u2014 with working curl examples.","b":"Zodiac Tech CRM has **two independent credential systems**: 1. **API keys** \u2014 long-lived, per-workspace, scope-limited. For servers and no-code tools hitting . 2. **Device tokens** \u2014 per-user, minted by mobile login, 90-day life. For the Android app on . This page covers both end to end. Who this is for Admin** \u2014 creating, scoping and revoking API keys for the workspace. Developer** \u2014 wiring a server integration or diagnosing 401\/403 responses. Super-admin** \u2014 auditing which keys exist and where the limits sit. Prerequisites:** access to the admin panel at with permission to manage API keys ( permissions), and an install reachable at your base URL. Part 1 \u2014 REST API keys Step 1: Create a key 1. Log in to the tenant admin panel ( ). 2. Open **Settings \u2192 API Keys** and click **Create**. 3. Fill in: Name** \u2014 a label for the integration (max 100 characters), e.g. . Scopes** \u2014 tick exactly what the integration needs (see the scope table below). Rate limit per hour** \u2014 default , allowed range . Expires at** \u2014 optional. Leave empty for a non-expiring key. 4. Save. The **raw key is shown once** ( + 40 random characters). Copy it immediately \u2014 it is never displayed again. Under the hood the key is stored as a SHA-256 hash; the visible prefix (first 8 characters) identifies it later in the list. You can revoke a key at any time from the same screen, and delete it if no longer needed. Treat the key like a password Anyone holding the key can act as your workspace within its scopes. Store it in your integration's secret store, never in client-side code or a public repository. Step 2: Choose scopes Each route requires a specific scope (enforced per route via the middleware). Requesting more scopes than needed is the most common mistake. Scope | Grants | \/ \/ | List & view \/ create & update \/ delete leads, lead tags | \/ | Pipelines and their stages | \/ | Tags | \/ \/ | Workspace users | \/ \/ | Forms (write also covers submitting entries) | \/ \/ | Automations | \/ | Integration connectio"},{"t":"Error codes & handling","u":"\/docs\/api\/errors","s":"API Reference","sk":"api","d":"Every error envelope the REST and Mobile APIs return, the HTTP status codes behind them, and what to do about each.","b":"Both APIs return predictable JSON errors. The envelopes differ between the REST API and the Mobile API \u2014 parse the right one. Who this is for Developer** \u2014 writing retry\/backoff logic or mapping errors to user messages. Support** \u2014 reading an integration's logs and telling apart auth, scope and quota problems. Prerequisites:** basic familiarity with HTTP status codes. The two envelopes REST API ( ) is always on failure. is a stable machine-readable token (table below). appears only on 422 validation failures. Mobile API ( ) Success is ; failure is . A few mobile endpoints have their own minimal shapes (for example the capability push returns a literal ) \u2014 the endpoint docs flag these. Status codes at a glance Status | Code(s) | Meaning | Typical fix | 400 | \/ | Webhook body failed signature verification (payment webhooks) | Check the provider secret in Super Admin \u2192 Billing \u2192 Providers | 401 | , , | Missing\/invalid credential | New API key or re-login on mobile | 402 | | Workspace lead quota for the plan is exhausted | Upgrade the plan or archive old leads | 403 | , , , , | Authenticated but not allowed | Grant the scope \/ reactivate workspace \/ enable the login method | 404 | , , , | Resource missing or outside your workspace | Check the id; cross-workspace ids deliberately 404 | 410 | | Resource existed but is no longer available (expired recordings) | Nothing to retry \u2014 the file was purged | 422 | , , , , | Request understood but rejected by rules | Read the map \/ fix the payload | 429 | , | Rate limit exceeded, or password login locked after 5 failed attempts | Wait for \/ the retry time, then slow down | 500 | | Unhandled server-side failure | Check | 503 | \u2014 | Health check found a degraded subsystem | See Monitoring & alerts | REST API codes in detail Defined in : Code | HTTP | Message you will see | Resolution | 401 | | Send the Bearer header | 401 | | Key revoked\/expired \u2014 create a new one | 403 | | Billing issue on the workspace | 403 | | Add the scope to th"},{"t":"REST API (API keys)","u":"\/docs\/api\/rest-endpoints","s":"API Reference","sk":"api","d":"Complete reference for every \/api\/v1 endpoint \u2014 method, path, required scope, key parameters and response summary, grouped by resource.","b":"This is the complete REST API surface. Every endpoint lives under (plus a friendly unversioned alias for lead CRUD), authenticates with an API key, and enforces one scope per route. Base URL in production. On a subfolder install the subfolder is part of the path ( ). Append the path from the tables below. All requests need: List responses use the pagination envelope ( + + ); single-record responses are ; errors follow Error codes & handling. Who this is for Developer** \u2014 integrating a system, no-code tool or script against the CRM. Admin** \u2014 checking which scope a key needs before creating it. Prerequisites:** an API key with the relevant scopes (Authentication). Health Method | Path | Scope | Purpose | none (public) | DB\/cache\/storage\/queue check, version, timestamp. 200 or 503 | Leads Scopes: , , . Method | Path | Scope | Purpose | List leads (paginated, filterable) | Create a lead \u2014 201 on success; 402 if the plan's lead quota is exhausted | Single lead with tags, assigned user, pipeline stage | \/ | | | Update a lead | Delete a lead (soft delete) | Attach tags (creates missing tags) | Detach one tag by id **or** name | List filters** (query string): , , , , , (name), (matches first\/last name, email, phone), , , , (one of , , , , , ; default ), ( \/ , default ), (default 15, max 100). Create body** (real fields): is required; max 255, max 50, \/ max 80\/50. , and are validated to **belong to this workspace** (cross-tenant ids fail 422). Tag attach body:** \u2192 . Tag detach accepts an id or a name in the URL segment. Unversioned aliases The same lead CRUD is also exposed **without** the version prefix for tools that mishandle 308 redirects: , , , . Same scopes, same behaviour. Pipelines & stages Scopes: , (stage routes are covered by the pipelines scope). Method | Path | Purpose | List pipelines | Create \u2014 body: (required, max 100), (optional), (bool) | Pipeline detail | \/ | | Update | Delete | List stages of a pipeline | Create stage \u2014 body: (required, max 100), , , , |"},{"t":"Mobile API (device tokens)","u":"\/docs\/api\/mobile-endpoints","s":"API Reference","sk":"api","d":"Every \/api\/v1\/mobile endpoint used by the Android sales app \u2014 auth, request bodies with real field names, responses and errors.","b":"The Mobile API powers the ZodiacTech CRM Android app ( ). It is a separate surface from the REST API: **per-user device tokens** instead of API keys, and a \/ envelope. Base URL in production. The XAMPP dev default baked into the app is , and the agent can override the server URL on the login screen under **Advanced \u2192 Server URL** (must start with \/ and end with ). Auth flow and token lifecycle: Authentication. Endpoint list below is the exact set from and the app's Retrofit contract. Who this is for Developer** \u2014 extending the Android app or building another mobile client. Support** \u2014 confirming what the app sends before blaming \"the app\" for a sync issue. Prerequisites:** a device token (or the ability to log in and mint one). Envelopes Success: \u2014 paginated lists add a object. Failure: . Exception: the capability push returns a literal (documented below). Public endpoints (no token) Password login. Throttled 10\/min\/IP. accepts e-mail **or** phone. A legacy field is also accepted. is required; re-login on the same UUID rebinds the device record. Response data: , (90 days), , , . Errors: (401), (422), (422), (403), (403), (403), (403), (429 \u2014 locked out; message includes a retry time), (429 \u2014 only the route throttle on this path). Platform capability probe the app calls before showing login options: the **platform-default** method list (password \/ OTP) and the platform Firebase project details. It is deliberately platform-only \u2014 workspace overrides are resolved later, at login and OTP calls, once the account is known. Public (an optional device token unlocks tenant overrides). Serves the force-update gate, announcement banner and support-contact card ( ). Never returns 401. Sends a one-time code. Limits: 3 per identifier and 10 per IP per 10 minutes (in addition to the route throttle). Codes: (422), (404), (429, includes ). \/ are returned so the endpoint does not reveal whether an account exists. is required (re-login on the same UUID rebinds the device record); \/ ar"},{"t":"Webhook endpoints","u":"\/docs\/api\/webhooks","s":"API Reference","sk":"api","d":"The inbound webhooks the CRM receives \u2014 Meta lead ads, WhatsApp Cloud API, Razorpay and Cashfree \u2014 with verification, signatures, idempotency and local testing.","b":"These are the endpoints **external platforms call into**. Every one is token-scoped or signature-verified \u2014 except inbound lead intake, which authenticates with the workspace's tenant API key. Source | Method & path | Auth | Meta lead ads | and for verification | URL token + (when an app secret is configured) | WhatsApp Cloud API | \/ | URL token, verify token, when an app secret exists | Other messaging (SMS\/Telegram\/Viber) | \/ | URL token | Razorpay | | Provider signature over the raw body | Cashfree | | Provider signature over the raw body | Twilio voice | | URL token | Rate limits: generic\/webhook\/messaging routes 120\/min\/IP; payment webhooks 240\/min\/IP. Where the URLs come from The tenant id and token are generated by the CRM \u2014 you never invent them. Meta connection URLs are shown on the lead-source connection; the WhatsApp callback URL is displayed on the WhatsApp connection settings page. Full install-time wiring: Meta \/ WhatsApp \/ payment callbacks. Who this is for Developer** \u2014 implementing or debugging a webhook consumer\/provider pairing. Admin** \u2014 copying the correct URL into Meta, WhatsApp or the payment provider's dashboard. Support** \u2014 reading webhook logs to explain \"leads not arriving\" or \"payment succeeded but the invoice didn't\". Meta lead ads Verification handshake (GET) When you save the Callback URL in the Meta app dashboard, Meta sends: The CRM echoes (also accepting the dot spelling; Twitter's special case is handled too). Check the events log in the CRM if Meta reports the URL could not be validated. Lead delivery (POST) Meta sends entries with . The CRM: 1. Resolves the tenant\/source from the URL token. 2. Verifies = + HMAC-SHA256 of the **raw body** using the connection's app secret (or the platform Meta app secret from Super Admin \u2192 Meta Developer settings). If no secret is configured, verification is skipped. 3. Records a row ( , or on failure) and queues processing. For each change it then fetches the lead from the Graph API ( ) and maps "},{"t":"Server requirements","u":"\/docs\/deployment\/requirements","s":"Deployment","sk":"deployment","d":"What a Zodiac Tech CRM server needs \u2014 PHP 8.4, MySQL, Composer, extensions, disk, cron \u2014 and how the installer verifies each one.","b":"Zodiac Tech CRM runs on ordinary shared hosting. There is **no Docker and no Nginx requirement** \u2014 the supported target is cPanel (or Plesk\/DirectAdmin) on Apache\/LiteSpeed with PHP 8.4 and MySQL. This page lists exactly what the installer checks before it will proceed. Who this is for Super-admin \/ hosting admin** \u2014 preparing a server before upload. Support** \u2014 triaging \"installation fails at step 1\" tickets. Prerequisites:** cPanel (or equivalent) access with the ability to create databases, set a PHP version, and add cron jobs. Required server software Requirement | Minimum | Notes | PHP** | **8.4** | The installer refuses anything below (the bundled platform check requires ); requires | MySQL** | MySQL 8.x or MariaDB (utf8mb4-capable) | The installer validates the connection using the charset; all tables are created utf8mb4 | Web server** | Apache (or LiteSpeed) with support | required; the shipped handles routing, headers and the Authorization header | Composer** | Composer 2 *(only if you can run it)* | If cPanel has no Terminal, upload a pre-built folder instead \u2014 see cPanel deployment walkthrough | Cron** | One entry, every minute | Drives the scheduler **and** the queue drain. Without it, reminders, syncs, billing lifecycle and email sending stop | Required PHP extensions The installer ( ) hard-blocks until all of these are present: Why the notable ones: \u2014 database access (the only supported driver is MySQL). \u2014 is used for backups ( ), updates and module installs. \u2014 image handling (logos, avatars, thumbnails). \u2014 Meta Graph API, payment providers, IMAP-adjacent HTTP calls. \u2014 precise money math for billing. Most cPanel hosts enable all of these by default on PHP 8.4. Anything missing is visible under **Select PHP Version \u2192 Extensions** in cPanel. Disk space Plan for **at least ~500 MB** to start: Consumes space | Approximate | Application + | A few hundred MB | MySQL database | Grows with leads\/messages \u2014 small at first | Uploads, recordings (30-day retention"},{"t":"cPanel deployment walkthrough","u":"\/docs\/deployment\/cpanel","s":"Deployment","sk":"deployment","d":"Step-by-step production install on shared cPanel hosting \u2014 subdomain, document root, upload, installer, database, permissions, cron and first login.","b":"This walkthrough installs Zodiac Tech CRM on shared cPanel hosting (the production target: ). It uses the **browser installer** \u2014 the same flow buyers use \u2014 and documents the manual equivalents for hosts with Terminal access. Who this is for Super-admin \/ hosting admin** \u2014 doing the first install. Developer** \u2014 reproducing a customer's install problem. Prerequisites:** cPanel login that can create subdomains, databases, cron jobs and set PHP versions. The release **zip** of the application (or the project folder from your source). ~30\u201360 minutes. Two supported layouts Preferred:** point the (sub)domain's document root directly at the app's folder. URLs then have **no subfolder** \u2014 . Fallback:** upload into a folder\/subdirectory. The shipped root + bridge forward into , which is exactly how the local XAMPP install works ( ). URLs then include the subfolder, including API\/webhook URLs. Step 1 \u2014 Create the subdomain 1. cPanel \u2192 **Domains \u2192 Create A New Domain** (older panels: Subdomains). 2. Enter for (adjust to your domain). 3. **Document Root** \u2014 type the folder where the app will live, ending in , for example: If cPanel forces as the root and you cannot change it, that is fine \u2014 you are now in the **fallback layout**; keep reading, Steps 6\u20137 cover it. 4. Create. Expected result:** the subdomain resolves (it may 403\/404 until files exist). Step 2 \u2014 Set the PHP version 1. cPanel \u2192 **MultiPHP Manager** \u2192 select the subdomain \u2192 PHP **8.4**. 2. cPanel \u2192 **Select PHP Version \u2192 Extensions** (or MultiPHP INI Editor) and confirm the required extensions are enabled: , , , , , , , if offered. Expected result:** PHP 8.4 is active for the domain. ( in cPanel Terminal should also say 8.4 if you have terminal.) Step 3 \u2014 Upload the application Everything lives in **one app folder**. Upload it to the folder *above* your document root (e.g. ), so the layout becomes . 3a \u2014 What must be in the package Item | What it is | Notes | , , , , , , | Application code, migrations, translations,"},{"t":"Domain, subdomain & SSL","u":"\/docs\/deployment\/domain-ssl","s":"Deployment","sk":"deployment","d":"Point a (sub)domain at the install, issue a free certificate through cPanel AutoSSL or Let's Encrypt, force HTTPS and update APP_URL safely.","b":"HTTPS is not optional for this product: Meta OAuth requires an HTTPS redirect URI, WhatsApp webhooks are signature-checked, push and OTP flows live in browsers and mobile apps, and cPanel AutoSSL issues certificates for free. This page gets a fresh (sub)domain from DNS to a green padlock. Who this is for Super-admin \/ hosting admin** \u2014 wiring to the install. Support** \u2014 diagnosing redirect loops, mixed-content warnings and \"Meta says redirect URI invalid\". Prerequisites:** the app is already uploaded and the installer completed (cPanel deployment walkthrough). Step 1 \u2014 Create the subdomain (DNS) If your domain's nameservers already point at this host** (the usual case for cPanel): 1. cPanel \u2192 **Domains \u2192 Create A New Domain** \u2192 . 2. The DNS record is created automatically. Nothing else to do. If the domain's DNS lives elsewhere** (registrar, Cloudflare): 1. Create the subdomain in cPanel first (document root as in the walkthrough). 2. Then add a DNS record at the DNS provider: Type | Name | Value | your server's IP address | (If using Cloudflare, start with the proxy **off** (grey cloud) while you issue the certificate, then decide about proxying \u2014 see Reverse proxies below.) Expected result:** resolves to the server (a 403\/placeholder is fine at this stage). Step 2 \u2014 Issue the certificate Two free paths, both inside cPanel: Option A \u2014 AutoSSL (most cPanel hosts):** 1. cPanel \u2192 **SSL\/TLS Status**. 2. Tick the domain \u2192 **Run AutoSSL**. 3. Wait 1\u20135 minutes; refresh until the domain shows a padlock. Option B \u2014 Let's Encrypt plugin (hosts with the plugin installed):** 1. cPanel \u2192 **Let's Encrypt SSL** (or \"SSL\/TLS \u2192 Manage SSL Hosts\"). 2. Choose the domain \u2192 **Issue**. 3. Wait for issuance to complete. Expected result:** loads without a browser warning. Certificate fails to issue? The common causes are: DNS not yet resolving to this server, a Cloudflare proxy in front (the HTTP-01 challenge can be blocked), or the document root not existing yet. Fix DNS first, then re-r"},{"t":"Database setup & migrations","u":"\/docs\/deployment\/database","s":"Deployment","sk":"deployment","d":"Create the MySQL database and user on cPanel, point .env at it, run migrations and seeders, and understand the separate testing database.","b":"Zodiac Tech CRM stores everything in one MySQL database (default name , ). This page covers creating it on shared hosting, wiring , running migrations and seeders, and the separate database the automated tests use. Who this is for Super-admin \/ hosting admin** \u2014 first install or moving hosts. Developer** \u2014 running the app locally or preparing a release. Support** \u2014 \"SQLSTATE\" connection errors and migration questions. Prerequisites:** cPanel access (MySQL Databases feature) or a local MySQL\/MariaDB server. Step 1 \u2014 Create the database and a dedicated user (cPanel) 1. cPanel \u2192 **MySQL Databases**. 2. **Create New Database:** . cPanel will show the real name prefixed with your account, e.g. . 3. **Add New User:** e.g. with a strong generated password. Real username: . 4. **Add User to Database** \u2192 tick **ALL PRIVILEGES** \u2192 Make Changes. Expected result:** you hold four values: database name, username (both account-prefixed), password, and the host ( on cPanel). One database is enough The whole platform \u2014 tenants, leads, messaging, billing \u2014 lives in a single schema. Do not create a database per workspace; isolation is enforced inside the app (the global scope). Step 2 \u2014 Point at it Notes: On cPanel, and both normally work; if one fails, try the other. Some hosts require . The installer writes these values for you \u2014 edit directly only if you skipped the installer or are changing servers. Never commit ; it is blocked from web access by the shipped rules. Step 3 \u2014 Run the migrations Via installer (recommended on shared hosting):** the browser installer's migrate step does this for you. Via Terminal:** is required because ; without it Laravel asks for interactive confirmation and a cron\/CI context would hang. On a machine with the exact production config, you can also export\/import:** For importing a generated dump on cPanel without SSH, **phpMyAdmin \u2192 Import** handles multi-MB files. Files above the upload limit need splitting or CLI. Expected result:** lists every migra"},{"t":"Environment variables","u":"\/docs\/deployment\/environment","s":"Deployment","sk":"deployment","d":"Every key in .env.example explained in grouped tables \u2014 what is secret, what is safe, and the production values to set.","b":"The file is the single source of per-server configuration. ships complete: the defaults already work on shared hosting ( sessions, cache, queue). This page documents **every key** and flags its sensitivity. Who this is for Super-admin \/ hosting admin** \u2014 making a production install. Developer** \u2014 understanding what is configurable without reading the code. Prerequisites:** the app is uploaded (cPanel deployment walkthrough). Sensitivity legend Mark | Meaning | Secret** | Never commit, never share, never paste in a ticket. Rotating it breaks active sessions\/integrations | Internal** | Server-side value; not a credential, but not for public display | Safe** | Public-ish configuration; appears in the UI or generated URLs | Production baseline in production leaks stack traces, file paths and SQL to any visitor who triggers an error. The shipped already defaults to . Application Key | Default | Mark | Notes | Safe | Fallback app name (branding can be set in Super Admin) | Internal | Keep on live installs | (empty)* | **Secret** | Generated by the installer or . Changing it breaks encrypted data | Internal | **Never** in production | Safe | The final URL including scheme (and subfolder if applicable) | \/ | | Safe | UI language defaults | Internal | Keep on shared hosting | Internal | Password hashing cost; leave as is | LeadHub-specific Key | Default | Mark | Notes | Internal | Kept in sync by releases; used by the updater\/cache healer | Safe | API version segment ( ) | Safe | Branding fallback | \/ | theme colors | Safe | Branding fallbacks ( , ) | updates URL | Safe | Where the in-app updater checks for releases | Logging Key | Default | Notes | Internal | Internal | Internal \u2014 raise to temporarily when diagnosing | Database Key | Example | Mark | Internal (only MySQL is supported) | Internal | Internal | Secret-ish** (schema name; never with password in a ticket) | Secret-ish** | Secret** | Details: Database setup & migrations. Session Key | Default | Notes | Works on s"},{"t":"Cron & queue workers","u":"\/docs\/deployment\/cron-queue","s":"Deployment","sk":"deployment","d":"The one cron entry that runs everything \u2014 the full schedule table, queue configuration for shared and VPS hosting, and the cron-based worker pattern.","b":"Almost everything time-driven in Zodiac Tech CRM \u2014 reminders, WhatsApp appointment sweeps, Meta syncs, billing lifecycle, backups, e-mail sequences \u2014 rides on **one cron entry** hitting Laravel's scheduler every minute. On production installs the queue should be , drained by the same cron (or a supervised worker on VPS). Who this is for Super-admin \/ hosting admin** \u2014 wiring the cron line. Developer** \u2014 choosing queue strategy per host. Support** \u2014 \"e-mails\/reminders aren't sending\" almost always ends here. Prerequisites:** the app is installed and reachable. Step 1 \u2014 Add the cron entry Standard (Terminal\/SSH available or cPanel Cron Jobs):** Shared hosting without a usable PHP binary path:** use cPanel's shown PHP binary: No SSH and no artisan cron available \u2014 the shipped fallback runner:** drains queued jobs (up to **30 per run**, within a ~55-second budget) across all named queues, then runs \u2014 a complete replacement for both the worker and the scheduler. It requires , and if you open it in a browser it refuses to work unless you set a first. Expected result:** within two minutes, starts showing scheduled task activity, and queued e-mails\/jobs stop accumulating in the table. Step 2 \u2014 Configure the queue Behaviour | When to use | Jobs run inside the web request | Local dev \/ last resort (slower pages; no cron needed) | (recommended)* | Jobs stored in MySQL, drained by a worker | Shared hosting **and** VPS | Fastest; needs Redis + a worker | VPS\/dedicated with Redis available | The shipped already sets . Jobs are partitioned into named queues \u2014 , , , , , , , \u2014 so heavy work (exports, AI) cannot delay time-sensitive work (webhooks, mail). Step 3 \u2014 Drain the queue Shared hosting (recommended):** add a second cron entry that runs a finite worker every minute: exits when there is nothing to do; guarantees the run ends before the next minute's cron fires. Combined with the scheduler entry from Step 1, this needs no long-running process. (The fallback already does this fo"},{"t":"Meta \/ WhatsApp \/ payment callbacks","u":"\/docs\/deployment\/webhook-urls","s":"Deployment","sk":"deployment","d":"The exact URLs to paste into Meta, WhatsApp Cloud API, Razorpay, Cashfree and the Android app \u2014 where each is generated in the CRM and how to verify it.","b":"After go-live, each external platform needs one or more URLs pointing back at your install. Every URL below is **generated or displayed by the CRM** \u2014 never hand-craft the tenant ids or tokens. This page is the single checklist of \"what to paste where\". Subfolder installs If your install is in a subfolder (document root not pointed at ), every URL includes the subfolder \u2014 e.g. . The CRM generates URLs from , so set correctly first (Domain, subdomain & SSL) and copy the URLs from the screens. Who this is for Super-admin \/ hosting admin** \u2014 wiring the platform against external services. Developer** \u2014 verifying the wiring end-to-end. Support** \u2014 \"webhook rejected\" tickets. The master list Platform | URL to configure | Where the CRM shows it | Meta app \u2014 OAuth | | Super Admin \u2192 Settings \u2192 **Meta Developer** (redirect URI field + health card) | Meta lead ads \u2014 webhook | | The lead-source connection (URL built with the connection's webhook token) | WhatsApp Cloud API \u2014 callback | | Workspace \u2192 Settings \u2192 **WhatsApp connection** (copyable field) | WhatsApp Cloud API \u2014 verify token | The connection's verify token | Same WhatsApp connection page | Razorpay | | Super Admin \u2192 Billing \u2192 Providers & Settings (secret configured there) | Cashfree | | Same providers page | Twilio voice | | Generated with the workspace's voice configuration | Android app | | App build\/runtime setting (see below) | Meta (Facebook) \u2014 OAuth + lead ads OAuth redirect URI 1. Super Admin \u2192 Settings \u2192 **Meta Developer**. 2. Copy the **redirect URI** \u2014 it is , i.e.: 3. Paste it into the Meta app dashboard under the login product's **Valid OAuth Redirect URIs**. The health card on that page checks it: in production the domain must be **HTTPS** (an or URL is flagged), and the callback route must be registered. Fix issues before attempting a tenant connection \u2014 Meta surfaces redirect mismatches as a generic error. The connect flow requests these permissions: , , , . Lead ads webhook Each lead-source connection"},{"t":"Backups & restore","u":"\/docs\/deployment\/backups","s":"Deployment","sk":"deployment","d":"The built-in leadhub:backup command, the nightly schedule toggle, what the archive contains, manual cPanel\/mysqldump backups, and how to restore safely.","b":"Zodiac Tech CRM ships a native backup system \u2014 no extra packages, no Redis, no cloud account. One command produces a single zip containing the full database and all uploaded files. This page covers running it, scheduling it, restoring from it, and the cPanel-side belt-and-braces. Who this is for Super-admin \/ hosting admin** \u2014 owning the backup routine. Support** \u2014 performing a restore during an incident. Prerequisites:** the app is installed; Terminal access makes life easier (the Super Admin UI covers the rest). What a backup contains creates containing: Entry | Content | Full database dump \u2014 the **mysqldump** binary when reachable (fast, includes routines\/triggers\/events), otherwise a pure-PHP PDO dump (table-only; works where is disabled) | Uploaded public files (branding assets, tenant branding, WhatsApp\/Meta media) | Call recordings** ( ) and support attachments \u2014 added 2026-10-06; archives from earlier versions do not contain this entry | , app version, Laravel\/PHP versions, which parts were included | It does **not** include your or the application code \u2014 keep those separately ( in your password manager; code in your release zip\/git). Step 1 \u2014 Take a backup now Or via the UI: **Super Admin \u2192 Backups \u2192 Create backup**. Expected result:** a line like and the archive listed on the Backups page. Step 2 \u2014 Verify the archive The Backups page can smoke-test an archive without restoring it (checks the zip is well-formed, exists with content, and roughly counts SQL statements). Do this at least once so you know your backups are restorable *before* the day you need one. First rule of backups A backup you have never restored is a hope, not a backup. Run one restore drill on a staging copy. Step 3 \u2014 Schedule it (nightly toggle) 1. Super Admin \u2192 **Script Settings** \u2192 enable **Automatic nightly backup** ( ). 2. The scheduler already contains the job: runs **daily at 02:00**, and only executes when either that toggle or ( env) is on. 3. Ensure your cron entry is live \u2014 wit"},{"t":"Go-live checklist","u":"\/docs\/deployment\/go-live","s":"Deployment","sk":"deployment","d":"The final pre-launch checklist \u2014 server, security, email, Meta, WhatsApp, payments, mobile, cron, backups and monitoring \u2014 before real leads flow.","b":"Work through this list top to bottom on a fresh production install before handing it to a client or pointing real ad spend at it. Every item is verifiable from the app or the server; nothing here is theoretical. Who this is for Super-admin \/ hosting admin** \u2014 running the launch. Support \/ account manager** \u2014 auditing a deployment someone else built. Prerequisites:** completed cPanel deployment walkthrough and Domain, subdomain & SSL. 1. Application & server PHP **8.4** selected for the domain; all required extensions green in the installer \/ Document root points at \u2014 **or** the subfolder bridge works ( loads) and in matches the real HTTPS URL exactly (no trailing slash, includes subfolder if any) set (installer did it; changing it later breaks encrypted data) ran \u2014 logos\/attachments\/recordings serve correctly and writable (775), no permission errors in run after the last edit 2. Database Dedicated DB user with rights on **only** this database Migrations all ( or installer finished) Base seeders applied (roles\/permissions\/plans); **no demo seeders** on production shows 3. Security HTTPS certificate live; **Force HTTPS** on Session hardening enabled on HTTPS: , , set correctly if behind Cloudflare\/host proxy considered for the platform panels (optional but recommended) decision made for platform staff All default\/demo passwords changed; owner account uses a strong password off** not readable over HTTP (dotfile blocks active) present (installer cannot re-run) 4. Email SMTP configured in Settings (host, port, user, password, from-address) Test e-mail sends **and arrives** (check the spam folder; SPF\/DKIM at the domain if it lands there) A test invitation reaches a real inbox 5. Meta (Facebook) lead ads Platform app credentials saved in Super Admin \u2192 Settings \u2192 Meta Developer (health card green) OAuth redirect URI pasted into the Meta app dashboard Test tenant connected via OAuth; Page + Ad Account selected Lead forms selected (only selected forms ingest) and field mappi"},{"t":"Updates & rollback","u":"\/docs\/deployment\/updates","s":"Deployment","sk":"deployment","d":"How to update a production install safely \u2014 backup first, in-app updater or manual files, composer, migrations, cache and Filament commands, queue restart, verification and rollback.","b":"Updating a live CRM touches code, the database, caches and long-running workers. The order below is the production-safe order: **backup \u2192 update code \u2192 dependencies \u2192 migrate \u2192 caches \u2192 workers \u2192 verify**, with a rollback plan in hand before you start. Who this is for Super-admin \/ hosting admin** \u2014 applying releases. Developer** \u2014 preparing a release or recovering from a bad one. Prerequisites:** Backups & restore understood, cron running, a maintenance window. Step 0 \u2014 Backup first (non-negotiable) 1. **Super Admin \u2192 Backups \u2192 Create backup** (or ). 2. Verify it (the smoke-test action) and download it off-site. 3. If your host offers one-click full-account backups, take one of those too \u2014 code + files + DB in one. No backup, no update Migrations are generally additive, but a rollback that needs data back is impossible without a dump. Two minutes of backup beats a day of incident response. Step 1 \u2014 Check what you're updating to In-app: the update screen checks and compares against . Terminal: . Read the release notes for the version span (especially: new migrations, changed Filament pages, new env keys \u2014 new keys are the usual cause of post-update warnings). Step 2 \u2014 Put the app into maintenance (optional but kind) You can keep working with ; visitors see a maintenance page. Skip this only if the release is explicitly zero-downtime. Step 3 \u2014 Apply the update Route A \u2014 In-app updater (recommended on shared hosting) Run the update from the Super Admin update screen. The updater applies the release zip and then automatically: clears compiled views\/routes\/config, republishes Filament assets ( ) \u2014 important because zip updates skip Composer's , so the framework's never fired during the copy, refreshes classmap metadata (classmap-authoritative installs) and resets opcache where the host allows. Route B \u2014 Manual (file upload or git) Never overwrite or Release zips contain and the skeleton \u2014 never let an extraction clobber your live , or your symlink. Extract carefully or "},{"t":"Daily checks","u":"\/docs\/operations\/daily-checks","s":"Operations","sk":"operations","d":"The ten-minute daily routine for whoever runs a live Zodiac Tech CRM install \u2014 health endpoint, backups, queue, leads and payments.","b":"Daily checks A live install has a small number of moving parts: the web app, the queue worker, the scheduler and the nightly jobs. Ten minutes each morning is enough to catch almost everything before your team notices. Work down this page in order \u2014 each step links to the page that explains the fix when something is off. Who this is for The super admin (or whoever is on point) for a live install. Developers covering support for a client workspace. Difficulty:** Easy \u00b7 **Time:** about 10 minutes \u00b7 **Prerequisites:** Super Admin access and, ideally, the ability to run on the server (or reach the cron runner). Step 1 \u2014 Read the health endpoint Open . It returns HTTP 200 with , or HTTP 503 with when a core check fails: If it is degraded, note which of , or failed \u2014 the same failure is written to the log as , or . Point an uptime monitor at this URL and at your login page; see Monitoring & alerts. Step 2 \u2014 Skim Super Admin \u2192 System Health Open **Super Admin \u2192 Settings \u2192 System Health** ( ). On a healthy morning: Queue driver** is not on production. With , jobs run inline inside web requests \u2014 slow integrations then block page loads, and System Health warns about it when you restart the queue. Debug mode** is off. Disk usage** has headroom (recordings and backups grow over time). The **WhatsApp health card** shows connections as connected, templates where you expect them, and at 0. That count comes from failed jobs for . The page also carries the one-click actions you will want on a bad day \u2014 Clear caches, Run migrations, Rebuild caches, Storage link and Restart queue. Incident response says when to use each. Step 3 \u2014 Confirm last night's jobs ran This is what runs every night (server time): Time | Job | Where you see it | 02:00 | | **Super Admin \u2192 Settings \u2192 Backups** \u2014 newest entry is from last night; run **Verify** | 03:00 | | Old audit rows gone; see Data retention & privacy (GDPR) | 03:15 | | Old recordings' audio deleted; rows kept with = expired | 03:30 | | Benchma"},{"t":"Weekly & monthly reviews","u":"\/docs\/operations\/weekly-monthly","s":"Operations","sk":"operations","d":"The weekly and monthly maintenance rhythm for a live install \u2014 drifts to catch, a restore drill, updates and retention to confirm.","b":"Weekly & monthly reviews Daily checks catch today's problems. This page catches the slow drifts: a webhook that has been rejecting for a week, a backup that has never been restore-tested, an update that has been pending for a month. The weekly pass takes about 15 minutes; the monthly pass is a longer, calm walk-through \u2014 better done at a quiet time, not during an incident. Who this is for The super admin responsible for a live install. The developer on support for the install. Difficulty:** Easy \u00b7 **Time:** about 30 minutes (weekly part ~15 min, monthly part ~15 min) \u00b7 **Prerequisites:** Super Admin access and shell access or hosting-panel access for the command-line checks. Weekly review 1. Webhooks and lead sources Admin \u2192 Webhook Logs** ( ): filter to the last 7 days. A healthy picture is all . means the connection was inactive; means the App Secret and the provider no longer agree \u2014 see Meta won't connect. Admin \u2192 Lead Source Health Report** ( ): every connection is (or has an obvious explanation, like a paused campaign). Reconnect anything that says it needs it. Super Admin \u2192 Meta Ads \u2192 Needs Attention** ( ): resolve anything already fixed, acknowledge anything you are working on. The nav badge counts open CRITICAL issues so nothing hides. 2. WhatsApp and Meta health runs every 6 hours and logs a warning when it finds unhealthy connections ( ). Connection statuses to expect: , or as a warning \u2014 , , and all need a reconnect. System Health** WhatsApp card: templates where you expect them ( \/ ones need attention in Meta), and back at 0 after any retry. 3. Failed jobs \u2014 clear out anything old you have triaged, with (this deletes all failed-job records; check them first). If the same job keeps failing, it is a symptom, not a housekeeping item \u2014 chase the cause from the matching troubleshooting page. 4. Payments and reconciliation Super Admin \u2192 Billing \u2192 Commercial** ( ): the , , and cards should hold no surprises. Payment reconciliation runs every 30 minutes and rai"},{"t":"Monitoring & alerts","u":"\/docs\/operations\/monitoring","s":"Operations","sk":"operations","d":"What to watch on a live install, where each signal lives, and which signal maps to which runbook \u2014 health endpoint, Meta, WhatsApp, billing and the scheduler.","b":"Monitoring & alerts Zodiac Tech CRM is deliberately pragmatic about monitoring: there is one public health endpoint you can point any uptime monitor at, plus in-app health surfaces that already do the deeper checking for you. This page is the map \u2014 every built-in signal, where it lives, and which runbook to open when it fires. Who this is for The person who owns uptime for a live install. Developers wiring an external monitor or an on-call rota. Difficulty:** Easy \u00b7 **Time:** 15 minutes to read and wire up \u00b7 **Prerequisites:** Super Admin access; access to whatever uptime-monitoring tool you use. The one endpoint to monitor externally is public and designed for monitors: HTTP 200** with \u2014 web app up, and the , and checks passed. HTTP 503** with \u2014 one of those checks failed; the payload's object shows which. Alert on non-200 and on the literal string . Also monitor the login page itself ( ) \u2014 a monitor should prove the app renders, not just that PHP answers. Suggested cadence: every 1\u20135 minutes for the health URL, every 5\u201315 minutes for the login page. The in-app signal table Signal | Where it lives | Healthy looks like | When it fires, go to | System health, disk, queue driver, debug mode | **Super Admin \u2192 Settings \u2192 System Health** ( ) | Queue driver not , debug off, disk headroom | Incident response | Meta connection problems | (every 6 h) + **Super Admin \u2192 Meta Ads \u2192 Needs Attention** ( ) | All connections ; no open CRITICAL issues | Meta won't connect | Meta connection statuses | Health report + connection record | (or as an early warning only) | Meta won't connect | WhatsApp connection, templates, message volume | System Health \u2192 WhatsApp card | Connections connected, templates approved, 0 | WhatsApp not sending | Inbound webhook rejects | **Admin \u2192 Webhook Logs** ( ) | All rows | Leads not entering the CRM | Lead source health | **Admin \u2192 Lead Source Health Report** ( ) | Every connection healthy or explainably paused | Meta won't connect | Payment failures an"},{"t":"Incident response","u":"\/docs\/operations\/incident-response","s":"Operations","sk":"operations","d":"A calm, ordered way to handle a live incident \u2014 severity levels, the first five minutes, runbooks for the common failures, and how to restart what stopped.","b":"Incident response Something is wrong on a live install: pages 500, leads stopped, payments are not flowing, the queue is backed up. This page is the calm version of those moments. Read the severity table, do the first five minutes, then jump to the matching runbook. Everything here uses tools that already exist in the app \u2014 no improvisation required. Who this is for Super admins and developers handling a live incident. Whoever is on call when the support ticket lands. Difficulty:** Medium \u00b7 **Time:** 20 minutes to read; runbooks are minutes each \u00b7 **Prerequisites:** Super Admin access, shell\/hosting access, and a way to reach the workspace owner. Step 0 \u2014 Set the severity Severity | Examples | Response | SEV1 | App down for everyone; data loss suspected; payment webhooks failing across tenants | Drop everything; work it live; communicate | SEV2 | Leads stopped for one workspace; WhatsApp messages failing; login broken for a team | Fix within hours; keep the affected owner updated | SEV3 | One user cannot log in; one report looks wrong | Normal ticket flow; see Troubleshooting | The first five minutes (any severity) 1. **Confirm what users see** \u2014 open and the login page. Degraded or 503 tells you it is infrastructure; 200 tells you it is application logic. 2. **Look at the log** \u2014 tail . The newest ERROR lines usually name the exact class or integration. Keep the lines; they are evidence. 3. **Check the boring things** \u2014 disk space (System Health shows total\/free\/used), database reachable ( ), and whether a deployment or update happened recently (**Super Admin \u2192 Settings \u2192 Updates**). 4. **Check the queue** \u2014 ; is the worker running; is the driver when it should not be? 5. **Write down the timeline** \u2014 when it started, what you tried, what changed. You will need it for the post-incident note, and it stops you retrying the same fix. Runbook \u2014 the app is down or 500s 1. Put the site into maintenance mode while you work: (this shows a clean maintenance page instead of "},{"t":"Data retention & privacy (GDPR)","u":"\/docs\/operations\/data-privacy","s":"Operations","sk":"operations","d":"How long the CRM keeps audit logs, login attempts, billing events and recordings \u2014 plus tenant data export, the 30-day erasure countdown and who can do what.","b":"Data retention & privacy (GDPR) Zodiac Tech CRM stores personal data (leads, contacts, calls, recordings, messages) on behalf of the business that owns the workspace. This page is the operator's view: what is kept, for how long, which jobs delete it, and how an export or erasure request is handled. Who this is for Workspace owners and admins answering a data request. Super admins and developers configuring retention on a live install. Difficulty:** Medium \u00b7 **Time:** 20 min \u00b7 **Prerequisites:** Admin access for the workspace-level flows; shell access for the commands. What is kept, and for how long Data | Retention | Deleted by | Audit log entries (admin and sensitive actions) | 180 days (default) | , daily at 03:00 | Login attempts ( ) | 30 days (default) | , daily at 03:00 | Processed billing events (idempotency records) | 90 days (default) | , daily at 03:00 | Call recording audio | Per the install's recording retention | , daily at 03:15 | Leads, contacts, messages, call metadata | Until the workspace deletes them or executes erasure | App actions \/ erasure job | Retention windows are configurable per install with the environment variables , and (see ). Change them deliberately \u2014 shortening audit retention weakens your own incident forensics. Recordings keep their metadata deletes the audio file and clears the stored path, but keeps the call record itself with = expired. The history that a call happened survives; the audio does not. The deletion jobs (and how to dry-run them) Always preview before purging: \u2014 overlays for a one-off run with different windows than the configured defaults. \u2014 audio-only cleanup; metadata stays. \u2014 executes scheduled tenant deletions whose 30-day countdown has passed. Runs daily at 04:00. Tenant data export (access requests) When someone asks \"what do you hold about me \/ us\": 1. The workspace owner opens **Admin \u2192 Data & Privacy** ( ). 2. They press the export button. The CRM builds a ZIP of the tenant's data as JSON. 3. The download "},{"t":"Cannot log in","u":"\/docs\/troubleshooting\/login","s":"Troubleshooting","sk":"troubleshooting","d":"Fix sign-in failures on the web panels and the Android app \u2014 wrong credentials, lockouts, disabled login methods and suspended workspaces.","b":"Cannot log in A person cannot sign in \u2014 on the web panels ( , , ) or in the Android app. This page separates the four really different causes: wrong details, a lockout, a login method that is not enabled, and an account or workspace that is blocked. Find the message in \"What you see\" first \u2014 it names the cause. Who this is for:** the person locked out, and the admin helping them. Problem Sign-in is rejected, or the app bounces back to the login screen. The same account may work on one surface and fail on another (web works, phone does not \u2014 or the reverse). What you see Message \/ behavior | What it means | \"Invalid credentials\"** | Wrong email\/phone or password \u2014 or a lockout in progress | A lockout message with minutes remaining ( ) | 5 failed attempts; locked for 15 minutes | \"This login method is not enabled\"** | The workspace has not enabled that login method for the app | App shows with | The device token is missing, revoked or expired | \"This user account is not active.\"** | The user is suspended | Mobile error , or | User suspended \/ no workspace attached \/ workspace inactive | Redirect to | Workspace suspended (billing) \u2014 not a login problem | Redirect to | Workspace is in its 30-day deletion countdown \u2014 only the owner can sign in | Likely causes Simple typos, or using an email when the account is registered under a phone number (or the reverse). Five failed attempts \u2014 lockout, 15 minutes, applies to web and mobile. The person is a contact\/lead in the CRM, not a user with a login account. On mobile: wrong server address (the field must end with ), or the login method is not enabled for the workspace. The account or workspace is suspended, or the workspace is in its deletion countdown. The device token expired (90 days) or the user logged out elsewhere. Quick fix 1. Wait 15 minutes if there was a lockout, then retry with the exact email or the 10-digit phone registered on the profile. 2. On mobile, check the **Server:** line at the bottom of the login screen "},{"t":"Email or OTP not received","u":"\/docs\/troubleshooting\/email-otp","s":"Troubleshooting","sk":"troubleshooting","d":"Fix missing transactional emails, email OTP codes and phone OTP\/SMS codes \u2014 SMTP configuration, login-method switches, rate limits and Firebase.","b":"Email or OTP not received \"Send code\" does nothing, or an email the CRM claims to have sent never arrives. This covers all three channels: transactional email (invites, digests, sequences), email OTP for mobile sign-in, and phone OTP\/SMS (Firebase or the workspace's SMS provider). The first question is always the same: did the CRM hand the message to a real sender, or to a mailbox that pretends to send? Who this is for:** workspace admins and super admins handling delivery complaints. Problem An expected email or one-time code does not arrive \u2014 or arrives so late it has expired. The app's screen may look successful (\"code sent\") while nothing was delivered. What you see Symptom | Where | Mobile login errors: , (with ), | Android app | \"This login method is not enabled\"** | Android app login screen | A message about incomplete Firebase configuration | Android app when phone OTP goes through Firebase | Test email from the CRM never arrives | Admin \u2192 Email settings | Digests\/sequences silent for the whole workspace | Admin inboxes | Likely causes Mail is configured to a non-delivering mailer.** If global mail is set to or , the CRM \"sends\" perfectly and nothing leaves the server. This is the most common cause of \"the CRM says it emailed me\". SMTP credentials wrong or blocked** (host, port, encryption, username\/password, from-address rejected by the provider). Wrong switch, not wrong pipe:** email OTP ( ) is on by default, phone OTP ( ) is **off** by default \u2014 a workspace may simply not have enabled the method the user is trying. Rate limits are doing their job:** OTP issuance is capped (3 codes per identifier, 10 per IP, per 10-minute window) and verification is capped at 5 attempts; the code itself expires (~10 minutes by default). Phone OTP needs a working channel:** either the workspace's Firebase project (verified server-side) or a configured SMS provider (Twilio\/Plivo\/custom) \u2014 neither means no code. Spam filtering, greylisting, or a provider-side block on the rec"},{"t":"Meta won't connect","u":"\/docs\/troubleshooting\/meta","s":"Troubleshooting","sk":"troubleshooting","d":"Fix Facebook\/Meta connection failures \u2014 expired OAuth sessions, missing page tokens, app permission gaps and webhook signature problems.","b":"Meta won't connect Connecting a Facebook Page to the CRM fails, or a previously working connection has gone unhealthy \u2014 tokens expire, pages change hands, app permissions drift. Every one of those states has a specific symptom. Read \"What you see\", match it, then work down. Who this is for:** workspace admins connecting Meta, and super admins who own the platform's Meta app settings. Problem The OAuth flow errors out, the connection lands but shows unhealthy, or Meta settings show a failing health check. Leads will not flow until this is fixed \u2014 but this page is about the *connection*; the deeper \"lead didn't arrive\" path is on Leads not entering the CRM. What you see Symptom | Where | OAuth error flash (session expired) and you land back on the connections list | Admin \u2192 Lead Source Connections ( ) | \"No Page access token is stored for this connection. Reconnect the Facebook Page so LeadHub can read the lead.\"** | On a lead read attempt | Connection shows needs attention \/ disconnected | **Admin \u2192 Lead Source Health Report** ( ) | A health check is red on the developer settings page | **Super Admin \u2192 Settings \u2192 Meta Developer Settings** ( ) | logs | | Open CRITICAL issue with a badge on the nav | **Super Admin \u2192 Meta Ads \u2192 Needs Attention** ( ) | Likely causes Expired or revoked user token** \u2014 the OAuth session timed out mid-flow, or the Facebook user's authorisation was removed. No Page selected** \u2014 the account authorised but no Page was chosen, so no page token was stored. Missing app permissions** \u2014 , , , are required. App configuration drift** \u2014 wrong\/blank Meta App Secret, wrong OAuth callback URL, domain mismatch, or the Meta app in the wrong mode (development vs production). Webhook wiring** \u2014 the app-side callback must be reachable at the CRM's webhook URL; the platform reports this as a health check. Quick fix 1. Reconnect: **Admin \u2192 Lead Source Connections** \u2192 the connection \u2192 **Connect with OAuth** again, and then use **Select Page** to store the page to"},{"t":"Leads not entering the CRM","u":"\/docs\/troubleshooting\/leads-not-arriving","s":"Troubleshooting","sk":"troubleshooting","d":"The full guided path for a Meta lead that never becomes a CRM lead \u2014 connection, page access, ad account, form allowlist, webhook, permissions, test lead and assignment.","b":"Leads not entering the CRM Meta says the lead happened; the CRM says nothing did. This is the flagship troubleshooting path \u2014 follow it top to bottom and you will find the exact stage where the lead stopped: the connection, the page's access, the ad account, the form allowlist, the webhook, the app permissions, or assignment inside the CRM. Who this is for:** the admin or ad specialist who owns lead flow, with the super admin on standby for platform-level checks. Problem A lead exists in Meta (Lead Center, a form's results, or a notification) but never appears in the CRM \u2014 or it appears unassigned, or under the wrong owner. What you see Symptom | Most likely stage | Nothing at all in **Webhook Logs** for the time of the lead | The lead never reached the CRM \u2014 connection, page, ad account or webhook | A row in Webhook Logs | The connection was inactive or the source is not registered | An row | The app secret and the connector disagree | Webhook rows , but no lead | Allowlist filter, permissions on the page read, or assignment\/visibility | The lead exists but \"no one owns it\" | Routing\/assignment rules | Everything worked yesterday | Tokens expire; start at the top of the diagram | The decision path Likely causes In the order to check them: 1. **Meta connection** unhealthy, expired or disconnected \u2014 the most common cause. 2. **No page token** \u2014 the Page was never selected after OAuth (the CRM tells you this explicitly when it tries to read the lead). 3. **Wrong Page or ad account** \u2014 the form belongs to a different Page\/ad account than the one connected; those leads go elsewhere. 4. **Allowlist** \u2014 the connection is set to selected forms only, and this form is not selected. 5. **Webhook not reaching the CRM** \u2014 wrong URL, wrong verify token, or Meta's webhook subscription changed. 6. **Signature mismatch** \u2014 app secret changed on one side only. 7. **Permissions** \u2014 the page read needs and friends (see Meta won't connect). 8. **Assignment** \u2014 the lead arrived, but rou"},{"t":"WhatsApp not sending","u":"\/docs\/troubleshooting\/whatsapp","s":"Troubleshooting","sk":"troubleshooting","d":"Fix failed WhatsApp sends \u2014 map the failure code (templates, opt-outs, connection, phone, variables, media) and get messages flowing again.","b":"WhatsApp not sending WhatsApp messages are failing, or they \"send\" but the customer never gets them. The CRM refuses sends for a small, well-defined set of reasons and records the exact one on the message. Find the failure code, fix its cause, resend. Almost nothing here is guesswork \u2014 the system tells you what is wrong. Who this is for:** workspace admins managing the WhatsApp channel, and super admins who own the platform WhatsApp configuration. Problem Messages stuck or failed in an automation, an inbox reply that never delivers, or templates that cannot be sent at all. What you see Symptom | Where | A failed message with a | Lead message record \/ conversation view | Connection not connected \/ needs reconnect | **Admin \u2192 Settings \u2192 WhatsApp** ( ), and the System Health WhatsApp card | Templates stuck or marked | **Admin \u2192 WhatsApp templates** ( ) | The composer hint about the 24-hour window | **Admin \u2192 Conversations** ( ) | above zero | System Health WhatsApp card (counts failed jobs) | The failure codes, decoded Failure code | Meaning | Fix | The workspace has no working WhatsApp connection | Reconnect under Admin \u2192 Settings \u2192 WhatsApp | The named template does not exist on the connection | Sync templates, then pick a template the CRM actually has | Template exists but Meta has not approved it | Wait for approval or choose an approved template; chase rejects in Meta | The contact sent a stop keyword (exact match) | Respect it \u2014 see the opt-out section below | The contact's number is missing or not sendable | Fix the phone number on the contact (10-digit Indian format) | The template needs variables the message did not supply | Fill the template variables in the automation\/message | Template has a media header, but the referenced file is gone | Re-upload the media (or send without the media header) | The checks run in that order \u2014 the first failing gate is the code you get, so fixing one code may reveal the next. Work through them until the message sends. Likely "},{"t":"Calls & recording issues","u":"\/docs\/troubleshooting\/calls-recording","s":"Troubleshooting","sk":"troubleshooting","d":"Fix calls not reaching the CRM and recordings that never appear \u2014 phone capability states, permissions, battery restrictions and retention purges.","b":"Calls & recording issues Calls are missing from the CRM, or recordings are missing from the calls that did arrive. The Android app is capability-first: it reports what the *phone* can actually do (some devices simply cannot record calls) and never fakes a recording. So the fix usually starts with reading the phone's own capability state, then the phone's permissions, then the CRM. Who this is for:** agents who use the dialer, and admins supporting them. Problem After a phone call you expect a call record in the CRM, a recording (or a recording link), and the call mapped to the right lead. One or more of those is missing. What you see Symptom | Where | Capability mode shown as or | Device Health screen | Recording mode \/ unavailable | Device Health screen | Tracking shown as (never ) | Device Health screen \u2014 means call data flows are partially restricted | Permission rows: Registered \/ Permission denied \/ Not configured \/ Pending | **More \u2192 Device health** | Calls appear without any audio | CRM call record | Old recordings disappeared | Possibly retention, not a fault \u2014 audio is purged on schedule | Likely causes The phone cannot record.** Android 10+ and many OEMs block call recording entirely; some allow it only with a specific dialer\/SIM. This is a device fact, not a CRM bug. Play-distributed build limitations:** call-log access ( ) is a restricted permission \u2014 the Play build cannot use it the way a sideloaded build may, so call-log scanning is limited. Permissions not granted:** phone\/SIM\/call-log permissions, plus **notification permission on Android 13+** (miss it and background work is quietly degraded). Battery optimisation** killed or throttled the background call-log scan (it runs roughly every 15 minutes). Call tracking settings wrong:** Monitored SIMs not set, or the recordings folder not pointed at where the phone actually writes files (**Settings \u2192 Call tracking**: Monitored SIMs, Additional recordings folder, Excluded numbers). The number is excluded**"},{"t":"Mobile not syncing \/ push not arriving","u":"\/docs\/troubleshooting\/mobile-sync","s":"Troubleshooting","sk":"troubleshooting","d":"Fix Android sync stalls and missing push notifications \u2014 device tokens, sync queue counts, FCM configuration, permissions and battery restrictions.","b":"Mobile not syncing \/ push not arriving Two related complaints: the app shows stale data (or a stuck sync queue), and notifications never arrive on the phone. Both have clear diagnostics on the device itself \u2014 the Sync queue page and the Device Health screen \u2014 plus a server-side test push. Work in that order; almost every case is solved on the phone or in the workspace's app settings, not by changing code. Who this is for:** agents with a misbehaving app, and admins\/super admins supporting them. Problem Data in the app is old; actions taken offline stay \"waiting\"; the number \"N waiting \u00b7 N retrying\" will not go down. Push notifications (new lead, assignment) never appear \u2014 even though the lead exists in the CRM. What you see Symptom | Where | \"N waiting \u00b7 N retrying\"** above zero | Sync queue page in the app | \"Retry failed\"** needed repeatedly | Sync queue page | A sync error, or the app bounces to login | In-app error \/ from the API | Push notifications (FCM):** Permission denied \/ Not configured \/ Pending | **More \u2192 Device health** | No notifications at all, no error shown | Android notification settings \/ battery optimisation | App shows a maintenance message | Platform or workspace maintenance mode | Likely causes Device token gone:** tokens last up to 90 days; they are revoked on logout or expiry. An old session gets on every call \u2014 the app looks \"not syncing\" when it is actually signed out server-side. No network \/ flaky network:** items queue up correctly and will flush; a very long queue just needs connectivity and time. Redelivery backoff:** failed uploads retry with exponential backoff \u2014 a \"retrying\" count is not failure, but a *growing* one is. Push not wired:** the workspace must connect its own Firebase project (BYO-Firebase \u2014 there is no bundled ; the app initialises Firebase at runtime). Not configured = no push, cleanly reported as such. Notification permission (Android 13+)** missing, or notifications disabled for the app channel ( ). Battery optimi"},{"t":"Payments failing","u":"\/docs\/troubleshooting\/payments","s":"Troubleshooting","sk":"troubleshooting","d":"Fix failed payments and billing states \u2014 AutoPay problems, provider configuration, webhook delivery, reconciliation alerts and the grace-to-suspension lifecycle.","b":"Payments failing A payment failed, AutoPay will not set up, or a workspace got restricted\/suspended over billing. The commercial billing stack has two sides: the workspace (paying, fixing a failed method) and the super admin (provider configuration, webhook health, reconciliation). Identify which side the problem is on before changing anything. Who this is for:** workspace admins getting billing right, and super admins running commercial billing. Problem A charge did not go through, a subscription state changed against expectations, or the tenant portal shows a payment problem that will not clear. What you see Symptom | Where | Payment-failed messaging and a retry\/re-check flow | Tenant **Admin \u2192 Billing** ( ) | Redirect to ( ) | Tenant users after suspension | Restriction to the billing page only | Tenant during restriction (e.g. trial expired) | AutoPay shows unapproved, or **REQUIRES_NEW_AUTHORIZATION** | **Admin \u2192 Billing \u2192 Agreement** ( ) | \/ \/ \/ counts rising | Super Admin **Billing \u2192 Commercial** ( ) | A reconciliation alert on the billing overview | Billing overview \u2192 **Needs Attention** ( , raised every 30 minutes) | Webhook deliveries absent or rejected | Provider dashboard \/ server log | Likely causes The payment method itself**: card declined, expired, insufficient limit, or bank-side block. AutoPay mandate not approved** \u2014 a mandate that needs a new authorisation shows as **REQUIRES_NEW_AUTHORIZATION** and must be re-authorised, not \"retried\". Provider configuration drift** (super admin): wrong environment ( vs ), wrong or rotated keys, or a webhook secret that no longer matches \u2014 the classic cause of \"money moved but the CRM does not know\". Webhooks not delivered**: provider cannot reach or (firewall, DNS, cron.php\/ weirdness on shared hosts). Status drift**: provider and CRM disagree \u2014 exactly what the reconciliation alert exists to flag. Lifecycle timing**: even a fixed payment does not teleport the workspace out of suspension instantly \u2014 lifecycle j"},{"t":"Deployment & server errors","u":"\/docs\/troubleshooting\/deployment","s":"Troubleshooting","sk":"troubleshooting","d":"Fix 500s, broken uploads, dead queues and failed cron after a deploy \u2014 caches, migrations, storage links, the cron.php entry point and safe rollback.","b":"Deployment & server errors Something broke after a deploy, an update or a server change: white screens, 500s, uploads that 404, a queue that stopped draining, or cron that silently is not running. On shared hosting (cPanel\/Apache) most of these come down to five things: caches built for the wrong environment, migrations not run, the storage symlink missing, the cron entry point not wired, or a that did not travel. Work down this page; each step is a check you can actually perform. Who this is for:** the super admin performing the deploy or update, and developers supporting one. Problem The app is up but unhealthy, or unhealthy after a change you just made \u2014 and you need to get back to a known-good state without guessing. What you see Symptom | First suspect | White page \/ HTTP 500 for all pages | Environment or caches built elsewhere, missing , permission errors | errors | Migrations not run, or wrong database credentials | Uploads and images broken (404) | Missing symlink | Queue never processes; driver in production | Worker not running \/ driver misconfigured | Scheduled jobs never fire | Cron entry missing or unreachable | Errors only after an update | Cache staleness or a failed migration \u2014 rollback path below | \"Please provide a valid cache path\" \/ view errors | directories missing or not writable | Likely causes Deployed files without running the migration step, or without clearing\/rebuilding caches \u2014 a cached config from the old release is the classic post-deploy 500. and not writable by the web user on the new host. No after a fresh deployment or move. The single entry point (shared hosting) or the cron line (VPS) missing \u2014 everything \"scheduled\" then quietly stops. Queue worker not running, or running without the full queue list. missing or still holding development values ( , wrong , too noisy to find anything). Quick fix The one-click recovery pass \u2014 on **Super Admin \u2192 Settings \u2192 System Health** ( ), in this order: 1. **Clear caches** ( ) \u2014 the first thin"},{"t":"How a Meta lead becomes a CRM lead","u":"\/docs\/workflows\/meta-lead-to-crm","s":"How It Works","sk":"workflows","d":"The full trace \u2014 from a Facebook lead form submission to a lead row in the CRM, assigned and notified, with the real services and jobs involved.","b":"How a Meta lead becomes a CRM lead Someone fills in your Facebook lead form. Seconds later, a lead card sits in your CRM with an owner, a follow-up task, and a notification. This page follows that journey end to end \u2014 the happy path first, then the real names, then how to debug it when a lead goes missing. The journey in plain language 1. A person submits your **Meta Instant Form** on Facebook or Instagram. 2. Meta calls **your workspace's webhook** \u2014 a private address unique to your workspace and connection. 3. The CRM **verifies the call really came from Meta** (digital signature), then queues it. 4. A background worker **checks the form against your allowlist** \u2014 only forms you ticked in Lead forms & mapping are accepted. 5. The CRM **fetches the full lead from Meta** (form answers, ad id, created time). 6. Answers are **mapped to CRM fields**, checked for duplicates, and written as a **Lead**. 7. The lead's creation triggers the rest of the chain: **scoring, activity log, automations, assignment, notifications**. The technical trace 1. **Submission.** The person completes a form attached to an ad, on your selected Page. 2. **Webhook call.** Meta delivers with to , handled by . The raw body's header is validated as an HMAC of the payload using the app secret (skipped only when no secret is configured \u2014 a misconfiguration worth fixing). 3. **Queued processing.** The controller stores the webhook log and dispatches to the ** queue** (3 tries, 30-second backoff; the log records success or failure). 4. **Allowlist gate.** extracts the and checks its against on the row. Unselected forms are skipped by design and recorded with *\"Skipped: lead form {id} is not one of the forms selected\u2026\"*. 5. **Graph fetch.** The lead is pulled from the Graph API: (default version , configurable). is the raw question\/answer array. 6. **Mapping + creation.** The confirmed field mapping converts answers into CRM fields; writes the Lead (source , plus the ad id for attribution). applies du"},{"t":"How guided onboarding works","u":"\/docs\/workflows\/guided-onboarding","s":"How It Works","sk":"workflows","d":"The onboarding state machine \u2014 how each wizard step derives from real app state, how skips auto-upgrade, and what Super Admin can see.","b":"How guided onboarding works The guided setup wizard is not a checklist that trusts you \u2014 it is a **state resolver**. Every step is recalculated from real system state, so \"done\" can only mean \"the thing actually exists\". That design choice explains almost every behaviour you will observe, including why some steps you thought you finished can flip back, and why skipped steps complete themselves later. The idea in plain language The wizard walks a workspace through the **12 frozen client steps** (Client onboarding from zero). Behind the scenes, a resolver asks the database one question per step: *\"is the real condition for this step true right now?\"* The answer becomes a status: , , , (you chose to skip) or (Meta needs attention). Completion is **one-way**: once the resolver sees real state, the step stays completed. Zodiac Tech sees the whole picture on the **client onboarding dashboard** \u2014 including skips and stuck steps \u2014 and the workspace is notified when you finish. The 12 client steps and their real conditions Step key | Completes when\u2026 | Required \/ Skippable | 1 | | Business name **and** business type are set | Required \u00b7 not skippable | 2 | | Industry is set **and** a pipeline exists | Required \u00b7 not skippable | 3 | | A Meta connection exists (BLOCKED if error\/needs-reauth) | Required \u00b7 not skippable | 4 | | A Page **and** an ad account are stored on the connection | Required \u00b7 not skippable | 5 | | Form ids are selected **and** the mapping is confirmed | Required \u00b7 **skippable** | 6 | | The largest pipeline has \u2265 2 stages | Required \u00b7 not skippable | 7 | | Assignment mode is off\/specific\/round-robin | Required \u00b7 not skippable | 8 | | An enabled automation exists | Required \u00b7 not skippable | 9 | | The workspace has more than one user | Optional \u00b7 **skippable** | 10 | | A WhatsApp connection is in state connected | Optional \u00b7 **skippable** | 11 | | A device registered **or** manual confirmation stored | Optional \u00b7 **skippable** | 12 | | is set by the test run |"},{"t":"How WhatsApp messages are delivered","u":"\/docs\/workflows\/whatsapp-delivery","s":"How It Works","sk":"workflows","d":"The status ladder from queued to read, the 24-hour reply window, template vs free-form messages, and how Meta's webhooks update every message.","b":"How WhatsApp messages are delivered Every WhatsApp message in the CRM carries a status: it was queued, it is sending, Meta accepted it, the phone received it, the person read it \u2014 or it failed, with a reason. This page traces one message from the inbox (or an automation) to the customer's phone and back, and explains the rule that trips everyone up: the **24-hour reply window**. The status ladder in plain language Status | Meaning | Queued** | The CRM has accepted the message and it is waiting to be sent | Sending** | The provider call is in flight | Sent** | Meta accepted the message for delivery | Delivered** | The recipient's phone received it | Read** | The recipient opened the chat (when Meta reports it) | Failed** | Something went wrong \u2014 the reason is stored on the message | Statuses only ever move **forward**. A late \"delivered\" webhook cannot overwrite a \"read\"; nothing downgrades. is terminal. The 24-hour reply window WhatsApp is strict about who may start a conversation: Inside the window** (within 24 hours of the customer's last incoming message): you can send **free-form** messages \u2014 anything your team types in the inbox. Outside the window**: you can only send an **approved message template** (marketing\/utility\/authentication). Attempting free-form outside the window fails with Meta error **131047** (\"re-engagement message\"). The CRM tells you which mode you are in: The **WhatsApp inbox** flags conversations where the window has closed (the composer switches to templates). Automations** that send WhatsApp messages describe the template they use; the send path prefers a template descriptor when present. The connection's **approved templates** are managed under Message templates. \"Failed: 131047\" is not a bug If a free-form message failed with 131047, the customer has not written to you in 24 hours. Send an approved template instead \u2014 the message failed by WhatsApp's design, not by fault of the CRM. The technical trace 1. **Queued.** Something wants to s"},{"t":"How Firebase OTP works","u":"\/docs\/workflows\/firebase-otp","s":"How It Works","sk":"workflows","d":"From the app asking which sign-in methods exist to a verified Firebase phone token and an issued device token \u2014 with the SMS fallback explained.","b":"How Firebase OTP works Signing in to the mobile app with a phone number does not go through the CRM's own SMS stack by default \u2014 it goes through **Firebase Phone Authentication**. Firebase proves the person owns the number; the CRM then verifies that proof server-side and issues the device its own token. Here is the full loop, including the SMS fallback for workspaces that prefer their own provider. The loop in plain language 1. The app asks the CRM **which sign-in methods this workspace allows**. 2. The person chooses phone sign-in and enters their number. 3. Firebase sends the OTP by SMS; the person types the code. 4. Firebase hands the app a **signed proof** (an ID token) that the number was verified. 5. The app gives that proof to the CRM. The **server verifies it against Google's servers** \u2014 the app cannot fake it. 6. The CRM checks the person belongs to an active workspace, then issues a **device token** and registers the phone. 7. Every later API call uses that device token. The technical trace 1. **Auth config.** resolves capabilities through : platform defaults from the panel (settings group ), overridden per tenant by . Flags: , , , . The app renders only the methods enabled for this workspace. 2. **OTP start.** with the identifier: Email OTP** \u2014 the server generates the code and mails it through the **tenant's SMTP** configuration. Phone OTP** \u2014 either Firebase sends the SMS client-side (Firebase phone sign-in), or the workspace's **SMS provider** (tenant messaging settings) delivers a server-side code. If neither is configured, the API answers : *\"Phone OTP is not configured for this workspace.\"* 3. **Limits.** Starts are capped at **3 per identifier and 10 per IP per 10 minutes**; verification allows **5 attempts**. Rate-limit responses are deliberate safety, not errors. 4. **Verification.** . For Firebase, the server validates the app-provided ID token against Google's **Identity Toolkit ** endpoint \u2014 no Admin SDK, no (the Android app initialises Fireb"},{"t":"How push notifications work","u":"\/docs\/workflows\/push-notifications","s":"How It Works","sk":"workflows","d":"From a CRM event to a notification on a sales agent's phone \u2014 the database notification bridge, FCM delivery, and the crm:\/\/ deep link that opens the right screen.","b":"How push notifications work When something happens in the CRM that a person must know about \u2014 a lead is assigned, a call is logged, an appointment approaches \u2014 the CRM sends them a notification. In the browser it appears in the notification bell. On the Android app, the same notification also arrives as a **push**, and tapping it opens the exact screen the notification is about. Push is **optional per workspace**: it works out of the box through the platform's Firebase configuration, and a workspace can bring its own Firebase project for full control. The trace in plain language 1. **An event happens.** The CRM creates a **database notification** for a user (this is the same notification you see under the bell in the web app). 2. **A bridge notices.** The listener reacts to the event \u2014 only for notifications that went to the database channel. 3. **A payload is built.** decides whether the notification has a linked entity and builds the payload, including a **deep link** in the form . 4. **A job is queued.** runs on the queue and hands the message to the FCM provider ( , Firebase Cloud Messaging **v1** API), as a **data-only** message \u2014 the app, not Google, decides how to present it. 5. **The phone receives it.** The Android app's maps the payload to the correct deep link and shows the notification. 6. **Tapping navigates.** The deep link opens the right screen \u2014 lead, call, appointment or task. What deep-links to what Entity key in the payload | Opens | The lead's record (Lead 360) | \/ | The call record | The appointment | \/ | The follow-up task | Notifications without an entity still arrive Notifications that are not tied to a record (for example a general announcement) are still pushed \u2014 they just open the app's notifications screen instead of a record. Where Firebase credentials come from Push resolution is layered \u2014 the first configured source wins: 1. The **workspace's own** Firebase service account ( ) \u2014 bring-your-own-Firebase. 2. The **platform's** configure"},{"t":"How a phone call becomes a CRM record","u":"\/docs\/workflows\/call-recording","s":"How It Works","sk":"workflows","d":"Call log ingestion, device capability resolution, and the honest truth about recording \u2014 what works on which phones, and what the CRM can never record.","b":"How a phone call becomes a CRM record Your team calls from their phones all day. Where do those calls end up? Every call the app can see becomes a CRM record \u2014 who called whom, when, which direction, how long \u2014 matched to the lead where possible. **Recording is a different story**: Android allows it on some phones, not others, and this page is honest about exactly which. The call journey in plain language 1. **A call happens** on the salesperson's phone \u2014 incoming, outgoing or missed. 2. **The app collects it.** For normal SIM calls the app scans the phone's call log periodically (about every 15 minutes); in **CRM Phone mode** (app set as the default dialer) events come live. 3. **A batch is uploaded** to the mobile API \u2014 up to 100 events per batch, each with an idempotency key so retries never double-create. 4. **Exclusions and direction** are respected: numbers the user excluded (personal calls) never leave the phone's filter; directions are incoming \/ outgoing \/ missed \/ unknown. 5. **The CRM matches and stores.** A call record is created, matched to a lead where the number matches, and written to the timeline. 6. **Recording \u2014 only where the phone allows.** The app resolves the phone's capability and works within it (see below). If recording is possible and enabled, the audio is uploaded through the recordings endpoint and retained for **30 days** by default ( ). Device capability \u2014 the honest matrix Mode | Meaning | The phone can record calls for the app (some OEM dialers allow it) \u2014 recording may be available | Another recorder on the phone writes files the app can import | Only call details (who\/when\/duration) \u2014 **no audio**, by platform design | Not yet determined \u2014 the app resolves it as it learns the device | Tracking is also graded: **FULL** (call log access granted, everything flows) or **LIMITED** (some events unavailable). The app cannot record on stock Android 10+ Android itself blocks third-party call recording on stock Android 10 and newer. On those"},{"t":"How billing & renewals work","u":"\/docs\/workflows\/billing-lifecycle","s":"How It Works","sk":"workflows","d":"Agreement states, automatic renewals, payment failures, grace and restriction \u2014 and why price and entitlements are deliberately separate.","b":"How billing & renewals work Commercial billing is the quiet machinery behind every workspace: an **agreement** is signed, a **mandate** is authorized with a payment provider, invoices are raised automatically on each renewal, and if a payment fails the workspace degrades **gracefully** \u2014 never instantly. This page follows that lifecycle and explains the one invariant that keeps everything sane: **price and entitlements are separate**. The lifecycle in plain language 1. **Agreement.** You agree commercial terms (price, billing cycle, what is included). The agreement moves through approval and payment-authorization states. 2. **Mandate.** You authorize the payment provider (Razorpay or Cashfree) to debit on schedule. Once authorized, the agreement is **ACTIVE**. 3. **Renewal.** On each billing date the CRM raises the renewal invoice, and the provider debits using the mandate. 4. **Failure path.** A failed debit never locks you out immediately: the agreement moves to a **grace period** (default 7 days) with full access, then **PAST_DUE**, then **RESTRICTED** (premium features paused; data is never deleted; lead capture and read access continue), and only after 7 more days **SUSPENDED** (all access denied). 5. **Recovery.** A successful payment at **any** point in the failure path returns the agreement to **ACTIVE**. What each degraded state allows State | Effect on the workspace | GRACE_PERIOD** | Full access while you fix the payment \u2014 nothing is paused | PAST_DUE** | Still working; the restriction clock is running | RESTRICTED** | Premium features paused. Allowed: , , , . Data is never deleted | SUSPENDED** | All access denied until payment is recovered | The invariant: price \u2260 entitlements What you **pay** and what your workspace is **allowed to use** are stored and applied separately. Changing your price never silently changes your entitlements, and restoring access after a failure never requires renegotiating price. That separation is what makes the grace \u2192 restri"},{"t":"How mobile login finds your workspace","u":"\/docs\/workflows\/mobile-login","s":"How It Works","sk":"workflows","d":"What happens between typing your credentials in the Android app and the device token that scopes every later API call \u2014 including the workspace checks in between.","b":"How mobile login finds your workspace The Android app never asks you for a workspace address or an ID. You sign in as **you**, and the server figures out which workspace you belong to, whether that workspace is in good standing, and issues your phone its own access token. This page traces that resolution \u2014 and why the app can never be pointed at the wrong workspace. The trace in plain language 1. **The app asks what is allowed.** returns which sign-in methods this installation\/workspace enables \u2014 email+password, phone+password, email OTP, phone OTP \u2014 so the login screen only shows methods that can actually work. 2. **You authenticate.** Either: Email + password** via , or OTP** via + (How Firebase OTP works). 3. **The workspace is resolved \u2014 server-side.** The server looks up **the found user's own workspace** ( ). A workspace id sent by the app is **never** accepted; there is no way to type your way into someone else's workspace. 4. **Capability checks.** If the method is disabled for that workspace, the API answers clearly: *\"Email sign-in is disabled for this workspace. Please use another sign-in method.\"* (or the phone equivalent). 5. **Subscription check.** The workspace must be active \u2014 \u2014 or the API answers : *\"This workspace is not active. Renew the subscription to use the app.\"* 6. **Device token issued.** registers the phone (a row) and mints a **64-character token with a 90-day TTL**. The app stores it securely. 7. **Scoped calls.** Every later request sends . The token identifies **you, your workspace and this device** \u2014 all data is scoped to the workspace automatically. What the login screen never shows There is no \"workspace selector\" to mis-configure \u2014 the server resolves the workspace from your account. Multi-workspace staff simply sign in with the account whose workspace they need. Troubleshooting notes Symptom | Likely cause | Fix | \"Email sign-in is disabled for this workspace\" | The workspace's mobile sign-in capability | Ask your admin to enable "},{"t":"General & client FAQ","u":"\/docs\/faq\/general","s":"FAQ","sk":"faq","d":"Straight answers for clients and end users \u2014 what the CRM is, what it needs, what it costs, data safety, the mobile app, and getting help.","b":"General & client FAQ The questions clients, owners and salespeople ask most \u2014 answered from how the product actually works. Every answer links to the deeper guide. Setup & basics <details> <summary><strong>What exactly is Zodiac Tech CRM?<\/strong><\/summary> A multi-tenant (multi-business) CRM built around **Meta\/Facebook lead generation**: it captures leads from your Facebook pages and forms, assigns them to salespeople, drives follow-ups by call and WhatsApp, and reports on the whole funnel. The same platform runs many businesses side by side \u2014 yours is one isolated \"Business\" (workspace) with your own users, leads and settings. Start with What is Zodiac CRM?. <\/details> <details> <summary><strong>Do I need my own Facebook\/Meta developer app?<\/strong><\/summary> No.** Your provider configures **one Meta app** for the platform and it serves every client server-side. You connect with the normal \"Continue with Facebook\" flow \u2014 you never create a developer app or paste an App ID\/Secret. If you do want your own Meta app, it can still be used through the same connection settings. Details: Meta Developer settings. <\/details> <details> <summary><strong>Is my Facebook password ever entered into the CRM?<\/strong><\/summary> Never. Connecting uses Facebook's official OAuth login \u2014 the password is typed into Facebook's own window, and the CRM only receives a permission token. You can revoke the app's access any time from your Facebook settings, and the CRM's **Disconnect** action removes the connection. See Connect Meta (Facebook). <\/details> <details> <summary><strong>How long does setup take?<\/strong><\/summary> The core path \u2014 connect Meta, choose your Page, pick lead forms, set up stages, add team, test a lead \u2014 is designed to be done in an afternoon; the guided setup walks you through 12 steps. See Quick start (15 minutes) and Client onboarding from zero. <\/details> <details> <summary><strong>Do I need WhatsApp to use the CRM?<\/strong><\/summary> No. WhatsApp is an integratio"},{"t":"Admin, Meta & WhatsApp FAQ","u":"\/docs\/faq\/admin","s":"FAQ","sk":"faq","d":"The operational questions admins ask most \u2014 Meta app credentials, WhatsApp windows and tokens, template rejections, lead form allowlists, notifications and billing states.","b":"Admin, Meta & WhatsApp FAQ The questions workspace admins and Super Admins hit while running Meta lead capture and WhatsApp messaging \u2014 answered with the real limits and error codes. Meta & lead capture <details> <summary><strong>Do I need to create a Meta developer app?<\/strong><\/summary> No.** The platform provides one Meta app configured by the operator; your connections fall back to it server-side. Clients connect with the normal Facebook login and never touch App IDs or secrets. Operators manage this at Meta Developer settings. <\/details> <details> <summary><strong>Can one Meta app serve multiple businesses?<\/strong><\/summary> Yes \u2014 that is the intended design. One platform Meta app handles many tenants; each business connects its own Facebook account and selects its own Page and Ad Account. Workspaces stay isolated; the shared app is only the API credential. See Connect Meta (Facebook) and Choose your Page & Ad Account. <\/details> <details> <summary><strong>Why do I see \"Page access expired \u2014 reconnect\"?<\/strong><\/summary> Facebook invalidates Page access tokens when permissions change, a password changes, or the app is removed from the account. The fix is in **Lead Sources**: click **Refresh Pages** to re-read what the account can see, then **Reconnect** if the token is dead. Leads stop flowing while the token is invalid, so reconnect the same day. More detail in Meta won't connect. <\/details> <details> <summary><strong>Can I limit which lead forms enter the CRM?<\/strong><\/summary> Yes. The CRM uses an **allowlist**: only the forms you explicitly select are ingested \u2014 forms on the Page that you did not select are ignored. Review or change the selection from the lead source connection in the guided setup; the ingest path is with your selected forms. See Lead forms & mapping. <\/details> WhatsApp <details> <summary><strong>Why did my WhatsApp send fail with \"re-engagement message\" \/ error 131047?<\/strong><\/summary> You tried to send **free-form text** to a conta"},{"t":"Mobile, developer & deployment FAQ","u":"\/docs\/faq\/mobile-developer","s":"FAQ","sk":"faq","d":"Technical answers about the Android app, Firebase without google-services.json, queues and cron on cPanel, tenant isolation, API access, updates and backups.","b":"Mobile, developer & deployment FAQ The technical questions developers, integrators and operators ask most \u2014 with the real file, command and permission names. Mobile app <details> <summary><strong>Does the Android app need a google-services.json file?<\/strong><\/summary> No \u2014 deliberately not.** The app ships without one. At login it fetches the workspace's Firebase options from the CRM's mobile endpoints ( \/ ), caches them securely on the device, initializes Firebase at runtime, and only then requests an FCM token. That is what makes per-workspace \"bring your own Firebase\" possible without shipping per-client builds. See Firebase phone OTP. <\/details> <details> <summary><strong>Which Android versions and package does the app target?<\/strong><\/summary> Application ID ** ** (demo flavor ; the internal Kotlin namespace remains and appears only in code class paths); **minSdk 26** (Android 8.0), **targetSdk 35**; current version 1.0.0 (versionCode 1). Firebase phone auth must be registered with exactly this application ID plus your signing SHA-1. See Installation. <\/details> <details> <summary><strong>Why is the app sideloaded instead of published on Google Play?<\/strong><\/summary> The app uses the **call log** permission ( ) to match phone calls to CRM leads \u2014 a permission Google restricts for Play distribution. The current distribution model is sideload\/MDM (e.g. for sales teams provisioned centrally). A **demo APK** exists for UI review: Demo APK. <\/details> <details> <summary><strong>How do deep links into the app work?<\/strong><\/summary> Push notifications and taps use URIs that the app resolves to screens: , , , , . The server only attaches a deep link when the payload carries the matching entity id. See Push notifications. <\/details> <details> <summary><strong>How long do mobile sessions last, and how are device tokens secured?<\/strong><\/summary> Device tokens use against , have a **90-day TTL**, and are stored **hashed** at rest ( ) \u2014 the raw token is shown once t"},{"t":"Glossary","u":"\/docs\/glossary\/index","s":"Glossary","sk":"glossary","d":"Every term used across this documentation, defined twice \u2014 first in plain language, then in its technical sense \u2014 with links to the guide that covers it.","b":"Glossary Every term you will meet in this documentation, defined first in **plain words**, then in the **technical** sense the system actually implements, and finally **where it is used** with a link to the full guide. A Ad Account In plain words:** The billing container inside Meta that pays for and runs your Facebook\/Instagram ads. Technical:** entity under a Meta Business; the CRM selects one per lead source connection and uses it for campaign reporting and management. Where you'll see it:** Campaigns API key In plain words:** A long password that lets another system read or write your CRM data \u2014 with only the permissions you grant it. Technical:** Bearer credential created at **Settings \u2192 Advanced \u2192 API Keys**, with scopes ( , , \u2026), an hourly rate limit (default 1,000, max 100,000) and an optional expiry; stored hashed, shown once at creation. Where you'll see it:** Authentication App Secret In plain words:** The private password of a Meta app; whoever has it can act as the app. Technical:** The Meta Developer App secret, stored encrypted ( , ) and used to verify webhook signatures ( ) and OAuth exchanges. Where you'll see it:** Meta Developer settings B Business In plain words:** Your company's workspace in the CRM \u2014 your leads, users and settings, invisible to other companies. Technical:** A row in the table; every tenant-owned record carries enforced by the fail-closed global scope. \"Business\" is the UI word for \"tenant\". Where you'll see it:** Businesses (tenants) C Capability snapshot In plain words:** A report from a phone saying what it can actually do (record calls natively, import recordings, or only log call metadata). Technical:** Append-only rows in describing the device's mode (NATIVE_RECORDING \/ IMPORTABLE_RECORDING \/ METADATA_ONLY \/ UNKNOWN), one of the latest 20 kept per device; posted via . Where you'll see it:** Device health Commercial Agreement In plain words:** The service contract behind a workspace \u2014 what is being paid, how often, and whet"}]