RoofIQ API Documentation
Complete API integration guide with enhanced leads creation, automatic duplicate detection, Google Maps validation, and intelligent agent assignment.
// Enhanced single-call lead creation
const roofiq = new RoofIQAPI(apiKey);
// Create lead with automatic contact & property creation
const result = await roofiq.leads.create({
contact: {
first_name: "John",
last_name: "Doe",
email: "john@example.com",
mobile_number: "+1234567890"
},
property: {
address: "123 Main St, Springfield, IL",
property_type: "Residential"
// Google Maps auto-fills city, state, zip, coordinates
},
pipeline_id: "pipeline-uuid",
pipeline_stage_id: "stage-uuid",
source: "Voice360"
});
// Check what was created vs reused
console.log("Contact created:", result.creation_details.contact.created);
console.log("Property created:", result.creation_details.property.created);
// 4. Schedule appointment
const appointment = await roofiq.appointments.create({
lead_id: lead.id,
title: "Estimate Consultation",
preferred_start_time: "2024-01-15T10:00:00",
timezone: "America/New_York"
// Customer info automatically retrieved from lead contact
});
Authentication
All API requests require authentication using API keys. Your API key carries many privileges, so keep it secure!
API Key Format
All RoofIQ API keys begin with roofiq_
followed by a unique identifier.
Authentication Methods
Authorization Header (Recommended)
Authorization: Bearer roofiq_your_api_key_here
X-API-Key Header
X-API-Key: roofiq_your_api_key_here
API Key Generation
Admin users can generate API keys in RoofIQ:
- Go to Settings β API Keys in your RoofIQ dashboard
- Click "Generate New API Key"
- Select the permissions you need (see below)
- Copy and securely store your API key
Required Permissions
Select the permissions you need based on which endpoints you'll use:
Quick Start Guide
Get up and running with the RoofIQ API in minutes. Follow this step-by-step guide to create your first lead.
Generate Your API Key
Admin users can generate API keys directly in RoofIQ under Settings β API Keys. Set the permissions you need for your integration.
View PermissionsTest Authentication
Verify your API key works by making a test request:
curl -X GET https://api.roofiq.net/api/v1/health \
-H "Authorization: Bearer roofiq_your_api_key_here"
Create Your First Lead
Follow the complete workflow to create a lead with automatic agent assignment:
Complete Integration Workflow
This example shows the complete end-to-end workflow for creating leads and scheduling appointments:
Step 1: Create Contact
RequiredCreate or lookup customer contact information. If a duplicate email exists, you'll get a specific error and should use the existing contact instead.
{
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@email.com",
"phone": "+1234567890",
"company": "ABC Corp"
}
Step 2: Create Property
RequiredCreate property record. If a duplicate address exists, you'll get a specific error and should search for the existing property.
{
"address": "123 Main Street",
"city": "Springfield",
"state": "IL",
"zip_code": "62701",
"property_type": "Residential",
"square_footage": 2500,
"year_built": 1995
}
Step 3: Create Lead
Auto-AssignmentCreate lead and trigger automatic agent assignment based on territory and availability.
{
"contact_id": "550e8400-e29b-41d4-a716-446655440001",
"property_id": "550e8400-e29b-41d4-a716-446655440002",
"pipeline_id": "550e8400-e29b-41d4-a716-446655440003",
"pipeline_stage_id": "550e8400-e29b-41d4-a716-446655440004",
"source": "External API Integration",
"notes": "Customer interested in roof replacement"
}
Step 4: Schedule Appointment
OptionalSchedule consultation with the automatically assigned agent.
{
"lead_id": "550e8400-e29b-41d4-a716-446655440005",
"title": "Roof Estimate Consultation",
"description": "Initial consultation for roof replacement estimate",
"preferred_start_time": "2024-01-15T10:00:00",
"duration_minutes": 60,
"timezone": "America/Chicago",
"appointment_type": "estimate_consultation",
"location": "123 Main Street, Springfield, IL 62701"
}
Contacts API
Manage customer contact information with built-in duplicate checking.
Request Body
{
"first_name": "string", // Required
"last_name": "string", // Required
"email": "string", // Required
"phone": "string", // Required
"company": "string" // Optional
}
Response
{
"results": {
"contact": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1234567890",
"company": "ABC Corp",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
},
"message": "Contact created successfully"
},
"status": 201
}
Query Parameters
Properties API
Manage property information with automatic duplicate prevention.
Request Body
{
"address": "string", // Required
"city": "string", // Required
"state": "string", // Required
"zip_code": "string", // Required
"country": "string", // Optional (default: "USA")
"property_type": "string", // Required: "Residential", "Commercial", "Industrial", "Multi-Family"
"square_footage": "integer", // Optional
"year_built": "integer", // Optional
"parcel_number": "string", // Optional
"zoning_type": "string", // Optional
"notes": "string" // Optional
}
Leads API
Create leads with automatic agent assignment based on territory and availability rules.
Automatic Agent Assignment
When you create a lead, RoofIQ automatically assigns it to the best available agent based on:
- Territory rules - Geographic proximity and coverage areas
- Load balancing - Current workload distribution
- Availability - Agent schedules and capacity
- Skills matching - Required expertise and specializations
Enhanced API Features
This API now supports optional nested contact and property creation with automatic duplicate detection and Google Maps address validation!
Traditional Request Body (Backward Compatible)
{
"contact_id": "uuid", // Required - From contacts API
"property_id": "uuid", // Optional - From properties API
"pipeline_id": "uuid", // Required - Get from account settings
"pipeline_stage_id": "uuid", // Required - Get from pipeline stages
"source": "string", // Optional - Lead source identifier
"notes": "string" // Optional - Additional notes
}
Enhanced Request Body (New)
{
"contact": { // Create contact inline
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"mobile_number": "+1234567890"
},
"property": { // Create property inline (optional)
"address": "123 Main St", // Google Maps will validate & geocode
"property_type": "Residential"
},
"pipeline_id": "uuid", // Required
"pipeline_stage_id": "uuid", // Required
"source": "Voice360", // Optional
"notes": "Customer called about roof repair"
}
Traditional Response
{
"results": {
"lead": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"contact_id": "550e8400-e29b-41d4-a716-446655440001",
"property_id": "550e8400-e29b-41d4-a716-446655440002",
"pipeline_id": "550e8400-e29b-41d4-a716-446655440003",
"pipeline_stage_id": "550e8400-e29b-41d4-a716-446655440004",
"assigned_user_id": "550e8400-e29b-41d4-a716-446655440005",
"assigned_user_name": "Sarah Johnson",
"assigned_user_email": "sarah@roofingco.com",
"created_at": "2024-01-15T10:30:00Z"
},
"message": "Lead created successfully"
}
}
Enhanced Response (with creation details)
{
"results": {
"lead": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"contact_id": "550e8400-e29b-41d4-a716-446655440001",
"property_id": "550e8400-e29b-41d4-a716-446655440002",
"pipeline_id": "550e8400-e29b-41d4-a716-446655440003",
"pipeline_stage_id": "550e8400-e29b-41d4-a716-446655440004",
"assigned_user_id": "550e8400-e29b-41d4-a716-446655440005",
"assigned_user_name": "Sarah Johnson",
"assigned_user_email": "sarah@roofingco.com",
"created_at": "2024-01-15T10:30:00Z"
},
"message": "Lead created successfully",
"creation_details": {
"contact": {
"created": true, // true = new contact created
"data": { // contact data (if created)
"id": "550e8400-e29b-41d4-a716-446655440001",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com"
}
},
"property": {
"created": false, // false = existing property used
"data": null // null when existing property used
}
}
}
}
Duplicate Detection
- Contacts: Matched by email (exact) or phone number (fuzzy matching)
- Properties: Matched by address + city + state + zip code combination
- Behavior: Returns existing records when duplicates are found
- Response: Check
creation_details
to see what was created vs reused
Google Maps Address Validation
- Automatic Validation: Addresses are validated using Google Places API
- Component Extraction: City, state, zip code auto-filled from Google data
- Geocoding: Latitude and longitude automatically populated
- Fallback: Works gracefully without Google Maps API if not configured
Enhanced Leads Integration Guide
Comprehensive examples and best practices for using the enhanced public leads API with automatic contact and property creation.
Integration Scenarios
The enhanced leads API is perfect for:
- Voice360 AI: Convert call completions to leads with customer and property data
- CRM Systems: Import leads with full contact and property information
- Web Forms: Direct form submissions without pre-processing
- Bulk Imports: Mass data migration with duplicate protection
Voice360 Call Completion β Lead Creation
{
"contact": {
"first_name": "Sarah",
"last_name": "Johnson",
"email": "sarah.johnson@example.com",
"mobile_number": "+1-555-0123"
},
"property": {
"address": "789 Pine Street, Miami, FL 33101",
"property_type": "Residential"
},
"pipeline_id": "550e8400-e29b-41d4-a716-446655440002",
"pipeline_stage_id": "550e8400-e29b-41d4-a716-446655440003",
"source": "Voice360",
"notes": "Customer interested in roof repair after storm damage. Appointment requested."
}
What Happens Automatically
- π Duplicate Check: Searches for existing contact by email/phone
- πΊοΈ Address Validation: Google Maps validates and geocodes the address
- π Property Matching: Checks for existing property at same address
- π€ Agent Assignment: Automatically assigns lead to best available agent
- π Pipeline Placement: Places lead in specified pipeline stage
External CRM β RoofIQ Lead Import
{
"contact": {
"first_name": "Michael",
"last_name": "Chen",
"email": "michael.chen@example.com",
"mobile_number": "555-0199",
"company": "Chen Construction"
},
"property": {
"address": "456 Oak Avenue, Tampa, FL 33602",
"property_type": "Commercial",
"square_footage": 5000,
"year_built": 2005,
"notes": "Large commercial building, flat roof"
},
"pipeline_id": "550e8400-e29b-41d4-a716-446655440002",
"pipeline_stage_id": "550e8400-e29b-41d4-a716-446655440003",
"source": "External CRM",
"notes": "Imported from Salesforce - high-value commercial lead"
}
Simple Contact Form β Lead
{
"contact": {
"first_name": "Emma",
"last_name": "Wilson",
"email": "emma.wilson@example.com"
},
"property": {
"address": "321 Maple Drive, Orlando, FL 32801"
// City, state, zip auto-filled by Google Maps
},
"pipeline_id": "550e8400-e29b-41d4-a716-446655440002",
"pipeline_stage_id": "550e8400-e29b-41d4-a716-446655440003"
}
Result: Google Maps will automatically fill city="Orlando", state="FL", zip_code="32801", plus latitude/longitude coordinates.
Phone Inquiry β Lead (No Property Info)
{
"contact": {
"first_name": "David",
"last_name": "Rodriguez",
"email": "david.rodriguez@example.com",
"mobile_number": "+1-555-0155"
},
// No property object - lead created without property
"pipeline_id": "550e8400-e29b-41d4-a716-446655440002",
"pipeline_stage_id": "550e8400-e29b-41d4-a716-446655440003",
"source": "Phone Inquiry",
"notes": "Customer called asking about services, needs property inspection"
}
Configuration
Required Setup
- API Key: Obtain API key with
leads:create
permission - Pipeline IDs: Get your account's pipeline and stage IDs
- Google Maps (Optional): Set
GOOGLE_MAPS_API_KEY
environment variable
Pipeline & Stage IDs
Use the Pipelines API to get your account's pipeline and stage IDs:
GET /api/public/v1/pipelines
Authorization: Bearer your-api-key
Best Practices
- Error Handling: Always check
creation_details
in responses - Duplicate Strategy: Use consistent email formats for reliable duplicate detection
- Address Quality: Provide complete addresses for best Google Maps results
- Monitoring: Log whether contacts/properties are created vs reused
- Testing: Test with real addresses to verify Google Maps integration
Error Handling
Common Error Responses
Validation Error
{
"errors": {
"error_code": "validation_error",
"errors": {
"contact": {
"email": ["Not a valid email address"]
},
"property": {
"address": ["Missing data for required field"]
}
}
}
}
Duplicate Contact Error
{
"errors": {
"error_code": "integrity_error",
"errors": {
"email": {
"message": "A contact with this email already exists in this account.",
"code": "duplicate_entry"
}
}
}
}
Note: The enhanced API prevents duplicates automatically. These errors only occur with invalid data or system issues.
Appointments API
Schedule appointments with automatically assigned agents and check availability.
Request Body
{
"lead_id": "uuid", // Required - Lead with assigned agent
"title": "string", // Required - Appointment title
"preferred_start_time": "datetime", // Required - ISO 8601 format
"duration_minutes": "integer", // Optional - Default: 60
"timezone": "string", // Optional - Default: "UTC"
"appointment_type": "string", // Optional - Default: "estimate_consultation"
"location": "string", // Optional - Meeting location
"description": "string" // Optional - Additional details
}
Customer Information
Customer details (name, email, phone) are automatically retrieved from the lead's associated contact record. This eliminates redundant data entry and ensures consistency.
Request Body
{
"start_date": "2024-01-15", // Required - YYYY-MM-DD
"end_date": "2024-01-22", // Required - YYYY-MM-DD
"duration_minutes": 60, // Optional - Default: 60
"timezone": "America/New_York", // Required
"appointment_type": "estimate_consultation", // Optional
"max_slots": 20 // Optional - Default: 20
}
Response
{
"results": {
"lead_id": "550e8400-e29b-41d4-a716-446655440000",
"assigned_agent": {
"id": "550e8400-e29b-41d4-a716-446655440005",
"name": "Sarah Johnson",
"email": "sarah@roofingco.com"
},
"availability": {
"available_slots": [
{
"start_time": "2024-01-15T10:00:00",
"end_time": "2024-01-15T11:00:00",
"duration_minutes": 60,
"timezone": "America/New_York",
"confidence_score": 0.9
}
]
}
},
"status": 200
}
Returns calendar information for the assigned agent to help understand scheduling constraints.
Pipelines API
Discover available pipelines and stages for lead management. Essential for integration setup.
Integration Setup
Use these endpoints to populate dropdown lists in your application instead of requiring users to copy/paste pipeline UUIDs.
Response
{
"results": {
"pipelines": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Residential Leads",
"description": "For house roofing jobs",
"is_default": true,
"stages": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "New Lead",
"position": 1
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Contacted",
"position": 2
},
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"name": "Estimate Scheduled",
"position": 3
}
]
},
{
"id": "550e8400-e29b-41d4-a716-446655440004",
"name": "Commercial Leads",
"description": "For commercial roofing projects",
"is_default": false,
"stages": [
{
"id": "550e8400-e29b-41d4-a716-446655440005",
"name": "Initial Contact",
"position": 1
},
{
"id": "550e8400-e29b-41d4-a716-446655440006",
"name": "Site Survey",
"position": 2
}
]
}
],
"total_count": 2,
"account_id": "550e8400-e29b-41d4-a716-446655440999"
},
"status": 200
}
Response
{
"results": {
"pipeline": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Residential Leads",
"description": "For house roofing jobs",
"is_default": true,
"stages": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "New Lead",
"position": 1,
"description": "Freshly received leads"
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Contacted",
"position": 2,
"description": "Customer has been contacted"
}
]
},
"account_id": "550e8400-e29b-41d4-a716-446655440999"
},
"status": 200
}
Integration Workflow
Step 1: User enters API key in your app
Step 2: Your app calls GET /public/v1/pipelines
Step 3: Show dropdown: "Residential Leads", "Commercial Leads"
Step 4: User selects pipeline, show stage dropdown
Step 5: Store the UUIDs for lead creation
Error Handling
The RoofIQ API uses conventional HTTP response codes and returns detailed error information in JSON format.
Error Response Format
{
"errors": {
"error": "Validation error",
"message": "Required fields missing: first_name, email",
"details": {
"first_name": ["This field is required"],
"email": ["This field is required"]
}
},
"status": 400
}
Duplicate Record Errors
When attempting to create records that already exist, you'll receive specific duplicate error responses:
Duplicate Contact (Email)
{
"errors": {
"error_code": "integrity_error",
"errors": {
"email": {
"message": "A contact with this email already exists in this account.",
"code": "duplicate_entry"
}
}
},
"status": 400
}
Duplicate Property (Address)
{
"errors": {
"error_code": "integrity_error",
"errors": {
"address": {
"message": "A property with this address already exists.",
"code": "duplicate_entry"
}
}
},
"status": 400
}
Handling Duplicates
When you receive a duplicate error:
- For Contacts: Use the GET endpoint to search by email and retrieve the existing contact ID
- For Properties: Use the GET endpoint to search by address and retrieve the existing property ID
- Then proceed with lead creation using the existing contact/property IDs
Rate Limits
API requests are rate limited to ensure fair usage and system stability.
Standard Tier
Default rate limit for all API keys
Premium Tier
Available upon request for high-volume integrations
Rate Limit Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
Support & Resources
Need help with your integration? We're here to support you.