Enhanced Public Leads API
Create leads with automatic contact and property creation, duplicate detection, and Google Maps address validation in a single API call.
What's Enhanced?
The enhanced leads API allows you to create complete leads with nested contact and property objects, eliminating the need for multiple API calls and providing intelligent duplicate handling.
Before (Traditional)
// 3 separate API calls required
const contact = await api.contacts.create({...});
const property = await api.properties.create({...});
const lead = await api.leads.create({
contact_id: contact.id,
property_id: property.id
});
After (Enhanced)
// Single API call with automatic handling
const result = await api.leads.create({
contact: {...},
property: {...},
pipeline_id: "uuid"
});
Key Features
Automatic Duplicate Detection
Smart matching prevents duplicate contacts and properties. Returns existing records when matches are found.
Google Maps Integration
Validates addresses, extracts components, and provides geocoding automatically using Google Places API.
Backward Compatible
Existing integrations continue working unchanged. Enhanced features are completely optional.
Single API Call
Create complete leads with contacts and properties in one request. No more complex orchestration.
Comprehensive Validation
Field-level validation with detailed error messages and graceful fallback handling.
Automatic Agent Assignment
Leads are automatically assigned to agents based on territory, availability, and load balancing.
Quick Start
Get Your API Key
Obtain an API key with leads:create
permission from your RoofIQ account settings.
Get Pipeline IDs
Retrieve your account's pipeline and stage IDs using the pipelines API.
GET /api/public/v1/pipelines
Authorization: Bearer your-api-key
Create Your First Enhanced Lead
const response = await fetch('/api/public/v1/leads', {
method: 'POST',
headers: {
'Authorization': 'Bearer your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
contact: {
first_name: "John",
last_name: "Doe",
email: "john@example.com",
mobile_number: "+1234567890"
},
property: {
address: "123 Main St, Miami, FL",
property_type: "Residential"
},
pipeline_id: "your-pipeline-id",
pipeline_stage_id: "your-stage-id",
source: "Your Integration"
})
});
const result = await response.json();
console.log('Lead created:', result.results.lead.id);
Duplicate Detection
How It Works
The API automatically checks for existing records before creating new ones, ensuring clean data without manual deduplication.
Contact Matching
- Email: Exact match (case-insensitive)
- Phone: Fuzzy matching (digits only)
- Scope: Within your account only
Property Matching
- Address: Exact match after Google Maps normalization
- Location: City + State + ZIP code combination
- Scope: Within your account only
Example: Duplicate Detection Response
{
"results": {
"lead": {
"id": "new-lead-uuid",
"contact_id": "existing-contact-uuid",
"property_id": "existing-property-uuid"
},
"creation_details": {
"contact": {
"created": false, // Existing contact was used
"data": null
},
"property": {
"created": false, // Existing property was used
"data": null
}
}
}
}
Google Maps Address Validation
Automatic Address Enhancement
When you provide an address, the API automatically validates it with Google Maps and extracts standardized components.
Your Input
{
"property": {
"address": "123 main st miami fl"
}
}
API Enhancement
{
"property": {
"address": "123 Main St",
"city": "Miami",
"state": "FL",
"zip_code": "33101",
"country": "USA",
"latitude": "25.7617",
"longitude": "-80.1918",
"google_validated_address": {...}
}
}
What Gets Enhanced
- β Address formatting: Standardized street address
- β Component extraction: City, state, ZIP code
- β Geocoding: Latitude and longitude coordinates
- β Validation: Confirms address exists
- β Consistency: Same format as frontend forms
Voice360 Integration Example
Call Completion
Voice360 AI completes customer call
Webhook Trigger
Your system receives call data
Lead Creation
Single API call creates complete lead
Implementation Example
// Voice360 webhook handler
app.post('/voice360/call-completed', async (req, res) => {
const { customer, property, callDetails } = req.body;
try {
const leadResponse = await fetch('/api/public/v1/leads', {
method: 'POST',
headers: {
'Authorization': `Bearer ${ROOFIQ_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
contact: {
first_name: customer.firstName,
last_name: customer.lastName,
email: customer.email,
mobile_number: customer.phone
},
property: {
address: property.address,
property_type: "Residential"
},
pipeline_id: PIPELINE_ID,
pipeline_stage_id: INITIAL_STAGE_ID,
source: "Voice360",
notes: `Call completed: ${callDetails.summary}`
})
});
const result = await leadResponse.json();
// Log creation details
console.log('Lead created:', result.results.lead.id);
console.log('Contact created:', result.results.creation_details.contact.created);
console.log('Property created:', result.results.creation_details.property.created);
res.json({ success: true, leadId: result.results.lead.id });
} catch (error) {
console.error('Lead creation failed:', error);
res.status(500).json({ error: 'Lead creation failed' });
}
});
API Reference
Request Headers
Authorization: Bearer your-api-key
Content-Type: application/json
Request Body Schema
Field | Type | Required | Description |
---|---|---|---|
contact |
object | Yes* | Contact information (alternative to contact_id) |
contact_id |
uuid | Yes* | Existing contact ID (alternative to contact object) |
property |
object | No | Property information (alternative to property_id) |
property_id |
uuid | No | Existing property ID (alternative to property object) |
pipeline_id |
uuid | Yes | Target pipeline for the lead |
pipeline_stage_id |
uuid | Yes | Initial stage in the pipeline |
source |
string | No | Lead source identifier |
notes |
string | No | Additional notes about the lead |
* Either contact or contact_id must be provided
Contact Object Schema
Field | Type | Required | Description |
---|---|---|---|
first_name |
string | Yes | Contact's first name (1-100 characters) |
last_name |
string | Yes | Contact's last name (1-100 characters) |
email |
string | Yes | Valid email address |
mobile_number |
string | No | Phone number (max 20 characters) |
company |
string | No | Company name (max 200 characters) |
Property Object Schema
Field | Type | Required | Description |
---|---|---|---|
address |
string | Yes | Street address (1-500 characters) |
city |
string | No | City name (auto-filled from Google Maps) |
state |
string | No | State code (auto-filled from Google Maps) |
zip_code |
string | No | ZIP code (auto-filled from Google Maps) |
property_type |
enum | No | Residential, Commercial, Industrial, Multi-Family |
square_footage |
integer | No | Property size in square feet |
year_built |
integer | No | Year property was built (1800-2030) |
Configuration
Environment Variables
# Optional - for Google Maps address validation
GOOGLE_MAPS_API_KEY=your-google-maps-api-key-here
Google Maps Setup
- Create a Google Cloud Platform project
- Enable the Geocoding API
- Create an API key with Geocoding API access
- Set the
GOOGLE_MAPS_API_KEY
environment variable - The API works gracefully without Google Maps if not configured
Best Practices
π Monitor Creation Details
Always check the creation_details
in responses to understand whether contacts and properties were created or existing ones were reused.
π§ Consistent Email Formats
Use consistent email formatting for reliable duplicate detection. The API is case-insensitive but exact matching works best.
π Complete Addresses
Provide complete addresses including city and state for best Google Maps validation results. Partial addresses may not validate properly.
π§ Error Handling
Implement proper error handling for validation failures, network issues, and API rate limits. Always check response status codes.
π Logging & Monitoring
Log creation details to track whether contacts/properties are being created vs reused. Monitor for unexpected duplicate rates.
π§ͺ Testing
Test with real addresses to verify Google Maps integration. Use different email addresses to test duplicate detection.