215 lines
6.2 KiB
Markdown
215 lines
6.2 KiB
Markdown
# Zoho CRM Setup Guide for Queue North Admins
|
||
|
||
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 ~5–10 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 ~5–10 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`
|
||
- Edit the field mapping in `server/zoho/` 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.
|