Full Technical Documentation & Integration Guide
Everything you need to understand, set up, and troubleshoot your HVAC booking system with detailed integration guides
When a customer submits a booking form on your website, a precise sequence of events happens:
Every booking submission sends this JSON data through your system:
{
"name": "John Smith",
"phone": "555-123-4567",
"email": "john@example.com",
"service": "AC Repair",
"lastServiced": "2026-06-15",
"urgency": "urgent",
"timestamp": "2026-08-15T10:30:00Z",
"source": "website-form"
}
Each integration processes this data differently:
Slack is a team messaging app. When a booking comes in, your team gets an instant notification in Slack instead of a phone call or email that might be missed.
When a customer books a service, this message appears instantly in your #hvac-bookings channel:
🔔 NEW HVAC BOOKING
Customer: John Smith
Phone: 555-123-4567
Service: AC Repair
Last Serviced: June 15, 2026
Urgency: URGENT ⚠️
Timestamp: Aug 15, 2026 10:30 AM
👉 Ready to accept this booking?
curl -X POST https://slack.com/api/chat.postMessage \
-H 'Authorization: Bearer xoxb-YOUR-BOT-TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"channel": "C12345678",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "🔔 *NEW HVAC BOOKING*\n\n*Customer:* John Smith"
}
}
]
}'
https://api.slack.com/appschat:write (to send messages)channels:read (to find channels)users:read (to identify users)xoxb-1234567890-1234567890-XXXXXXXXX#hvac-bookingsC12345678)Add to your .env.local:
VITE_SLACK_ACCESS_TOKEN=xoxb-YOUR-BOT-TOKEN
VITE_SLACK_CHANNEL_ID=C12345678
| Problem | Cause | Solution |
|---|---|---|
| No message in Slack | Bot not in channel | Add bot to #hvac-bookings channel |
| "Invalid token" error | Token is wrong/expired | Regenerate token at api.slack.com |
| "Channel not found" | Wrong channel ID | Copy correct ID from channel details |
| Permissions error | Bot lacks permissions | Add chat:write scope and reinstall |
Gmail sends professional email confirmations to customers. When they submit a booking, they immediately get an email confirmation saying "we received your request."
Subject: ✅ HVAC Service Booking Confirmed - ProAir HVAC
---
Hello John Smith,
Your HVAC service booking has been confirmed!
📋 Booking Details:
• Service Type: AC Repair
• Phone: 555-123-4567
• Last Service: June 15, 2026
• Urgency: URGENT
• Booked: Aug 15, 2026 10:30 AM
✓ Our team received your request
✓ We'll contact you within 1 hour
✓ Save this email for your records
---
ProAir HVAC | 24/7 Emergency Service
Gmail requires 2-step verification to create app passwords:
https://myaccount.google.comhttps://myaccount.google.com/apppasswordsAdd to your .env.local:
VITE_GMAIL_USER=booking@yourhvac.com
VITE_GMAIL_APP_PASSWORD=abcdefghijklmnop
VITE_CONTACT_EMAIL=customer@example.com
⚠️ Important:
| Problem | Cause | Solution |
|---|---|---|
| "Invalid login" error | Wrong app password | Generate new app password from Gmail |
| Email not received | Email address wrong | Check customer email in form |
| Ends up in spam | Gmail filtering | Add company email to customer's contacts |
| "Less secure apps" error | Old Gmail setting | Use app password, not regular password |
Google Sheets is a cloud spreadsheet (like Excel online). Every booking is automatically added as a new row. This creates a CRM database you can:
Timestamp Name Phone Service Urgency Email
─────────────────────────────────────────────────────────────────────────────
8/15/2026 10:30 AM John Smith 555-123-4567 AC Repair URGENT john@ex.com
8/15/2026 10:45 AM Jane Doe 555-987-6543 Heating NORMAL jane@ex.com
8/15/2026 11:00 AM Bob Wilson 555-456-7890 Maintenance URGENT bob@ex.com
https://sheets.google.comA: Timestamp
B: Name
C: Phone
D: Service
E: Urgency
F: Email
https://docs.google.com/spreadsheets/d/[SHEET_ID]/edit
1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6Phttps://console.cloud.google.comhttps://console.cloud.google.com/iam-admin/serviceaccountsclient_email valuehvac-app@project-123.iam.gserviceaccount.comhttps://console.cloud.google.com/apis/libraryAdd to your .env.local:
VITE_GOOGLE_SHEETS_ID=1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P
VITE_GOOGLE_SHEETS_SERVICE_ACCOUNT={full-json-content-here}
| Problem | Cause | Solution |
|---|---|---|
| "Permission denied" | Sheet not shared with service account | Share sheet with service account email |
| "Spreadsheet not found" | Wrong sheet ID | Copy correct ID from URL |
| "Invalid range" | Column headers don't match | Match column names to code |
| No data appears | API key not enabled | Enable Google Sheets API in console |
Twilio sends SMS text messages. When a booking comes in, the customer gets a text confirmation immediately.
ProAir HVAC: Thanks for booking AC Repair! We got your request.
Our team will call you at 555-123-4567 within 1 hour.
Confirmation details: bit.ly/hvac-confirm
https://www.twilio.com/consolehttps://www.twilio.com/consoleACxxxxxxxxxxxxxxxxxxxxx)your-auth-token-here)Two Options:
Option A: Free Trial Number (Limited)
Option B: Buy Dedicated Number ($1/month)
https://www.twilio.com/console/phone-numbersAdd to your .env.local:
VITE_TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxx
VITE_TWILIO_AUTH_TOKEN=your-auth-token-here
VITE_TWILIO_PHONE=+12025551234
| Problem | Cause | Solution |
|---|---|---|
| "Permission denied" | Credentials wrong | Check Account SID and Auth Token |
| SMS doesn't arrive | On trial, number not verified | Verify phone in Twilio console first |
| Wrong number | Twilio number not set | Set Twilio phone number in config |
| Invalid recipient | Formatting wrong | Use full format: +15551234567 |
// server.js (Express backend)
app.post('/webhook/hvac', async (req, res) => {
const { name, phone, email, service, lastServiced, urgency } = req.body;
try {
// Start all integrations in parallel
await Promise.all([
// 1. Send to Slack
slack.chat.postMessage({
channel: process.env.SLACK_CHANNEL_ID,
text: `🔔 New booking: ${name} - ${service} (${urgency})`
}),
// 2. Send to Gmail
nodemailer.createTransport({...}).sendMail({
to: email,
subject: 'Booking Confirmed',
html: emailTemplate(name, service, phone)
}),
// 3. Add to Google Sheets
sheetsAPI.spreadsheets.values.append({
spreadsheetId: SHEETS_ID,
range: 'Sheet1!A:F',
values: [[
new Date().toLocaleString(),
name,
phone,
service,
urgency,
email
]]
}),
// 4. Send SMS via Twilio
twilio.messages.create({
from: TWILIO_NUMBER,
to: phone,
body: `Thanks for booking! We'll contact you soon.`
})
]);
res.json({ success: true, message: 'Booking processed' });
} catch (error) {
console.error('Integration error:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
See what errors occurred when the form was submitted:
# Terminal - see error messages
tail -f logs/error.log
# Or watch console output
npm run dev
# Look for error messages when submitting form
Test each credential individually:
# Test Slack token
curl -H 'Authorization: Bearer YOUR_TOKEN' \
https://slack.com/api/auth.test
# Test Gmail (try sending email manually)
# Test Sheets (try editing manually)
# Test Twilio
curl -u 'SID:TOKEN' \
https://api.twilio.com/2010-04-01/Accounts/SID
Cause: Environment variable not set
Fix: Check `.env.local` has all credentials and restart server
Cause: Bot not in channel or wrong ID
Fix: Invite bot manually to #hvac-bookings channel
Cause: Service account not shared with sheet
Fix: Open sheet → Share → Add service account email
Cause: Phone format wrong for Twilio
Fix: Use format: +15551234567