Queue-North-Website/docs/architecture/zoho-setup.md

235 lines
7.1 KiB
Markdown
Raw Permalink Normal View History

# Zoho CRM Setup Guide for Queue North Admins
docs: adopt project template, retire the markdown backlog This repository is the one the template's README describes: 205 issues, zero milestones, and severity labels spelled "P0 Critical" / "P1 High" / "P2 Medium", which privacyllc.dev reports as NOT ADOPTED rather than as 87% complete. Six markdown records described the same work and none pointed at the tracker. Two of them said the project was in "Phase 5" while the code was at 0.9.3. Migrated, then deleted in this commit: FUTURE.md -> docs/history/BATCH_LEDGER.md (Archived). Its open items were all already filed as issues, so nothing needed migrating into the tracker HISTORY.md -> docs/history/DEVELOPMENT_LOG.md, verbatim, 0 lines lost DEVELOPMENT_LOG.md -> the same file, as a second labelled block. Not interleaved: the changelog has three duplicated version headings, so one date order would have implied more than the record supports PROJECT.md -> docs/planning/PROJECT_PLAN.md STRUCTURE.md -> the agent pipeline into README.md; its versioning rules retired BUILD_SUMMARY.md -> BATCH_LEDGER.md. Its embedded SQL schema deliberately NOT carried: it predated the UNIQUE constraint on leads.email, and server/index.js owns the schema SCRIPTS.md -> docs/TOOLS.md, corrected for the SSR + prerender build Moved with history (git detects all four as renames): OVERHAUL_PLAN.md, review.md, project-requirements.md, docs/zoho-setup.md Kept because this project earned them: the five-agent pipeline, the design system in OVERHAUL_PLAN.md (Status: Current, with a front-note saying which half is history), the positioning argument in REDESIGN_REVIEW.md, and REQUIREMENTS.md whole, including its change policy. Deleted from the template because they do not apply, each said out loud in DOC_TRUST_MAP.md: QA pass I (no money moves), the authorisation checklist group and the session-token row (no accounts, no sessions), and one PRECAUTIONARY paragraph in SECURITY.md about holding credentials on behalf of users — there are none, and PROJECT_PLAN.md records accounts as out of scope. Pass H was kept and rewritten: its authorisation half does not apply, its what-a-stranger-can- reach half is the most exposed surface here. Also removed: main.js, the old static site's hash router, referenced by nothing and preserved in .drop/; and test-results/.last-run.json, a May Playwright artifact reading {"status":"failed"} for a suite that does not exist. The repository was made private on Forgejo before this commit. That is what let the internal history be committed rather than exempted — null/fruit-fall is already private and reports normally. Two defects found on the way in and fixed here: zoho-setup.md told admins to edit `server/zoho/`, a directory that has never existed in any commit (the mapping is in server/index.js), and README.md's route list still advertised /8x8, removed at 0.6.6, while omitting /privacy-policy. Branding: icon.webp and logo.webp converted from this project's own marks in assets/. banner.webp is absent and is filed as an issue rather than faked. Verified: verify.sh 3/3, doc-claims 71 claimed paths all present, backup and a first-ever restore of the live leads database (2 tables, 3 rows, under 1s). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 01:19:02 -05:00
```
Status: Current
Owner: _null
Last reviewed: 2026-08-18
Governs: server/index.js, .env.example — the Zoho CRM integration: app setup,
OAuth credentials, environment variables, and how to test that leads
arrive
Review trigger: Any change to ZOHO_* environment variables, the forwarding mode,
the field mapping, or the datacenter; any Zoho API version change
```
> **Read the mode first.** This guide documents the OAuth/REST path. Production
> currently runs `ZOHO_FORWARDING_MODE=webtolead`, which needs none of the OAuth
> setup below — the REST path is kept as a configured standby. `.env.example`
> shows both. The reasoning behind the current shape is in
> `docs/history/BATCH_LEDGER.md`.
This guide walks you through the current Zoho CRM integration. Contact leads use the legacy Zoho WebToLead form tokens, while the OAuth/API integration remains available as a standby option for future lead upserts or support cases.
---
## Prerequisites
Before you begin, ensure you have:
- A Zoho CRM account (admin access required)
- The WebToLead hidden field values from the old Zoho form
---
## Step 1: Gather WebToLead Values
The current integration needs the old Zoho form's hidden fields:
```text
xnQsjsdp
xmIwtLD
actionType
returnURL
zc_gad
```
These values are stored locally in `zoho.md`, which is ignored by git.
---
## Optional Standby: Create a Zoho Self-Client App
Only use these OAuth steps if switching `ZOHO_FORWARDING_MODE=api`.
1. Go to **https://api-console.zoho.com**
2. Click **"Create Self Client"**
3. Fill in:
- **Client Name**: Queue-North-Zoho-Integration
- **Description**: Auto-capture leads and cases from Queue North website
- **Redirect URI**: `https://www.zoho.com` (required for Self-Client, not used)
4. Click **Create**
5. **Copy and save**:
- **Client ID**
- **Client Secret**
> ⚠️ Store these securely — they're like a username and password.
---
## Optional Standby: Generate an Authorization Code
1. In the Self Client tab, click **"Generate Code"**
2. Set the **Scope** to:
```
ZohoCRM.modules.leads.CREATE,ZohoCRM.modules.leads.READ,ZohoCRM.modules.cases.CREATE,ZohoCRM.modules.cases.READ
```
3. Set **Expiry** to **10 minutes** (use it quickly)
4. Click **Generate**
5. **Copy the authorization code** — it expires in 10 minutes
---
## Optional Standby: Exchange Auth Code for Tokens
Run this `curl` command (replace placeholders):
```bash
curl -X POST https://accounts.zoho.com/oauth/v2/token \
-d "code=<YOUR_AUTH_CODE>" \
-d "client_id=<YOUR_CLIENT_ID>" \
-d "client_secret=<YOUR_CLIENT_SECRET>" \
-d "grant_type=authorization_code" \
-d "redirect_uri=https://www.zoho.com"
```
**Response will include:**
```json
{
"access_token": "1000.xxxxx.xxxxx",
"refresh_token": "1000.yyyyy.yyyyy",
"expires_in": 3600,
"token_type": "bearer"
}
```
**Save the `refresh_token`** — this never expires and must be kept secret.
---
## Step 2: Configure Environment Variables
The current production-friendly setup uses the legacy Zoho WebToLead form tokens for contact leads while keeping the OAuth API integration available as a standby option.
Add these to your `.env` file for WebToLead lead forwarding:
```env
ZOHO_FORWARDING_MODE=webtolead
ZOHO_WEBTOLEAD_ENABLED=true
ZOHO_WEBTOLEAD_URL=https://crm.zoho.com/crm/WebToLeadForm
ZOHO_WEBTOLEAD_XNQSJSDP=<from Zoho WebToLead hidden field>
ZOHO_WEBTOLEAD_XMIWTLD=<from Zoho WebToLead hidden field>
ZOHO_WEBTOLEAD_ACTION_TYPE=TGVhZHM=
ZOHO_WEBTOLEAD_RETURN_URL=null
ZOHO_WEBTOLEAD_ZC_GAD=
```
Use these only if switching back to the Zoho CRM REST API/OAuth integration:
```env
ZOHO_FORWARDING_MODE=api
ZOHO_ENABLED=false
ZOHO_API_DOMAIN=https://www.zohoapis.com
ZOHO_ACCOUNTS_DOMAIN=https://accounts.zoho.com
ZOHO_CLIENT_ID=<from Step 1>
ZOHO_CLIENT_SECRET=<from Step 1>
ZOHO_REFRESH_TOKEN=<from Step 3>
# Cases forwarding is also OFF by default
ZOHO_CASES_ENABLED=false
```
> **Note:** `ZOHO_CASES_ENABLED` only applies to the OAuth/API path. The WebToLead values found in the old site are for lead capture only.
### Datacenter Variants
If your Zoho datacenter is **outside the US**, adjust the domains:
| Region | API Domain | Accounts Domain |
|--------|-----------|-----------------|
| US | `www.zohoapis.com` | `accounts.zoho.com` |
| EU | `www.zohoapis.eu` | `accounts.zoho.eu` |
| IN | `www.zohoapis.in` | `accounts.zoho.in` |
| AU | `www.zohoapis.com.au` | `accounts.zoho.com.au` |
---
## Step 3: Test the Integration
### Test Lead Capture
1. Submit a lead on the contact form (name, email, phone, message)
2. Wait ~510 seconds
3. Log in to Zoho CRM → Leads tab
4. Verify the new lead appears with correct data
### Test Case Capture
1. Submit a support request (e.g., booking inquiry, technical question)
2. Wait ~510 seconds
3. Log in to Zoho CRM → Cases tab
4. Verify the new case appears with correct data
---
## Troubleshooting
### Token Errors
- **"invalid_grant"**: Your authorization code expired. Generate a new one in Step 2 and repeat Step 3.
- **"invalid_client"**: Double-check Client ID and Secret — no extra spaces.
- **"invalid_scope"**: Re-run Step 2 with the exact scopes listed above.
### Field Mismatches
- If leads/cases don't appear, check if Zoho requires custom fields like `Service_Interest`
docs: adopt project template, retire the markdown backlog This repository is the one the template's README describes: 205 issues, zero milestones, and severity labels spelled "P0 Critical" / "P1 High" / "P2 Medium", which privacyllc.dev reports as NOT ADOPTED rather than as 87% complete. Six markdown records described the same work and none pointed at the tracker. Two of them said the project was in "Phase 5" while the code was at 0.9.3. Migrated, then deleted in this commit: FUTURE.md -> docs/history/BATCH_LEDGER.md (Archived). Its open items were all already filed as issues, so nothing needed migrating into the tracker HISTORY.md -> docs/history/DEVELOPMENT_LOG.md, verbatim, 0 lines lost DEVELOPMENT_LOG.md -> the same file, as a second labelled block. Not interleaved: the changelog has three duplicated version headings, so one date order would have implied more than the record supports PROJECT.md -> docs/planning/PROJECT_PLAN.md STRUCTURE.md -> the agent pipeline into README.md; its versioning rules retired BUILD_SUMMARY.md -> BATCH_LEDGER.md. Its embedded SQL schema deliberately NOT carried: it predated the UNIQUE constraint on leads.email, and server/index.js owns the schema SCRIPTS.md -> docs/TOOLS.md, corrected for the SSR + prerender build Moved with history (git detects all four as renames): OVERHAUL_PLAN.md, review.md, project-requirements.md, docs/zoho-setup.md Kept because this project earned them: the five-agent pipeline, the design system in OVERHAUL_PLAN.md (Status: Current, with a front-note saying which half is history), the positioning argument in REDESIGN_REVIEW.md, and REQUIREMENTS.md whole, including its change policy. Deleted from the template because they do not apply, each said out loud in DOC_TRUST_MAP.md: QA pass I (no money moves), the authorisation checklist group and the session-token row (no accounts, no sessions), and one PRECAUTIONARY paragraph in SECURITY.md about holding credentials on behalf of users — there are none, and PROJECT_PLAN.md records accounts as out of scope. Pass H was kept and rewritten: its authorisation half does not apply, its what-a-stranger-can- reach half is the most exposed surface here. Also removed: main.js, the old static site's hash router, referenced by nothing and preserved in .drop/; and test-results/.last-run.json, a May Playwright artifact reading {"status":"failed"} for a suite that does not exist. The repository was made private on Forgejo before this commit. That is what let the internal history be committed rather than exempted — null/fruit-fall is already private and reports normally. Two defects found on the way in and fixed here: zoho-setup.md told admins to edit `server/zoho/`, a directory that has never existed in any commit (the mapping is in server/index.js), and README.md's route list still advertised /8x8, removed at 0.6.6, while omitting /privacy-policy. Branding: icon.webp and logo.webp converted from this project's own marks in assets/. banner.webp is absent and is filed as an issue rather than faked. Verified: verify.sh 3/3, doc-claims 71 claimed paths all present, backup and a first-ever restore of the live leads database (2 tables, 3 rows, under 1s). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 01:19:02 -05:00
- Edit the field mapping in `server/index.js``forwardToZoho()` builds the
`First_Name` / `Last_Name` / `Lead_Source` payload, and
`forwardToZohoWebToLead()` builds the form fields — to match your Zoho CRM
field API names
### Cases Not Appearing
- Ensure `ZOHO_CASES_ENABLED=true` is set
- Verify the Cases tab is enabled in your Zoho CRM plan
- Check that your Zoho CRM user has **Cases CREATE** permissions
### Lead Upsert Behavior
- Leads are **upserted by email**: duplicate email = update existing lead
- Cases are **always inserted** (new ticket each time)
- If you see duplicate leads, check for slight email variations (e.g., `test@` vs `test+1@`)
---
## Architecture Notes
### Flow Overview
```
Website Contact Form → SQLite (always saved)
Zoho CRM (best-effort)
Fire-and-forget (no failure blocking)
```
### OAuth2 Refresh Token Flow
1. Use `refresh_token` to get a new `access_token` when expired
2. `access_token` expires in 1 hour
3. `refresh_token` never expires — store it securely
### Upsert Logic
- **Leads**: WebToLead creates leads through the legacy Zoho form endpoint. API mode uses email-based upsert.
- **Cases**: Always insert (new case per submission)
### Fire-and-Forget Design
- Zoho failures **do not block** form submissions
- All data is saved to SQLite first
- Zoho attempts happen in the background
- No retry logic needed — users won't wait for Zoho
---
## What Happens Next?
After configuration:
1. Deploy the environment variables to production
2. Set `ZOHO_WEBTOLEAD_ENABLED=true` in production `.env`
3. Restart the application
4. Submit a test lead and support case to verify data flows to Zoho CRM
5. Check Zoho CRM Leads and Cases tabs to confirm both appear
---
**Need help?** Contact your site administrator.