The FirstQuadrant API provides powerful filtering capabilities to help you find exactly the data you need. This guide covers search queries, advanced filters, and field selection.
Quick start
# Search contacts by name or email
curl "https://api.us.firstquadrant.ai/v5/contacts?query=john" \
-H "Authorization: Bearer YOUR_API_KEY"
# Filter by email domain
curl "https://api.us.firstquadrant.ai/v5/[email protected] " \
-H "Authorization: Bearer YOUR_API_KEY"
# Select specific fields
curl "https://api.us.firstquadrant.ai/v5/contacts?select[]=id&select[]=email&select[]=firstName" \
-H "Authorization: Bearer YOUR_API_KEY"
Search with query parameter
The query
parameter performs full-text search across relevant fields:
# Search contacts
GET /v5/contacts?query=john
# Search campaigns
GET /v5/campaigns?query=welcome
# Combine with other filters
GET /v5/contacts?query=john & filter.tags.has =customer
The search is case-insensitive and searches across multiple fields depending on the resource type.
Advanced filtering
Filter syntax
Filters use the format: filter.field.operator=value
# Single filter
filter.email.equals [email protected]
# Multiple filters (AND logic)
filter.firstName.equals =John & filter.lastName.contains =Doe
# Nested field filters
filter.customProperties.industry.equals =technology
Available operators
String operators
Operator Description Example equals
Exact match (case-sensitive) [email protected]
not
Not equal to filter.status.not=inactive
contains
Contains substring [email protected]
startsWith
Starts with string filter.name.startsWith=John
endsWith
Ends with string filter.email.endsWith=.edu
in
Value in array filter.status.in=active,pending
notIn
Value not in array filter.status.notIn=deleted,archived
Number operators
Operator Description Example equals
Equal to filter.score.equals=100
not
Not equal to filter.score.not=0
gt
Greater than filter.score.gt=50
gte
Greater than or equal filter.score.gte=50
lt
Less than filter.score.lt=100
lte
Less than or equal filter.score.lte=100
in
Value in array filter.priority.in=1,2,3
Date operators
Operator Description Example equals
Exact date match filter.createdAt.equals=2024-01-15
gt
After date filter.createdAt.gt=2024-01-01
gte
On or after date filter.lastActivityAt.gte=2024-01-01
lt
Before date filter.createdAt.lt=2024-12-31
lte
On or before date filter.updatedAt.lte=2024-12-31
Array operators
Operator Description Example has
Array contains value filter.tags.has=customer
hasEvery
Array contains all values filter.tags.hasEvery=customer,vip
hasSome
Array contains any value filter.tags.hasSome=lead,prospect
isEmpty
Array is empty filter.tags.isEmpty=true
Boolean operators
Operator Description Example equals
Boolean value filter.isActive.equals=true
not
Opposite boolean filter.isVerified.not=true
Filtering examples
JavaScript
Python
TypeScript
// Advanced filtering with multiple conditions
const params = new URLSearchParams ({
"filter.status.equals" : "active" ,
"filter.createdAt.gte" : "2024-01-01" ,
"filter.tags.hasSome" : "customer,lead" ,
"filter.customProperties.score.gt" : "50" ,
query: "john" ,
});
const response = await fetch ( `https://api.us.firstquadrant.ai/v5/contacts? ${ params } ` , {
headers: {
Authorization: "Bearer YOUR_API_KEY" ,
"FirstQuadrant-Organization-ID" : "org_YOUR_ORG_ID" ,
},
});
const contacts = await response . json ();
Field selection
Use the select[]
parameter to specify which fields to include in the response:
Basic field selection
# Select only id, email, and name fields
GET /v5/contacts?select[]=id &select[]=email&select[]=firstName&select[]=lastName
# Response includes only selected fields
[
{
"id" : "con_abc123" ,
"email" : "[email protected] " ,
"firstName" : "John" ,
"lastName" : "Doe"
}
]
Nested field selection
Use dot notation for nested fields:
# Select nested fields
GET /v5/contacts?select[]=id &select[]=email&select[]=company.name&select[]=customProperties.score
# Response
[
{
"id" : "con_abc123" ,
"email" : "[email protected] " ,
"company" : {
"name" : "Acme Corp"
},
"customProperties" : {
"score" : 85
}
}
]
Field selection reduces payload size and improves performance:
// Fetch only essential fields for a list view
const listParams = new URLSearchParams ({
"select[]" : [ "id" , "email" , "firstName" , "lastName" , "company.name" ],
limit: "100" ,
});
// Fetch all fields for a detail view
const detailResponse = await fetch ( `https://api.us.firstquadrant.ai/v5/contacts/ ${ contactId } ` );
Complex filter combinations
Example 1: Sales qualified leads
Find high-value leads from specific industries:
GET /v5/contacts?
filter.customProperties.leadScore.gte =80 &
filter.customProperties.industry.in =technology,finance,healthcare &
filter.tags.has =qualified &
filter.lastActivityAt.gte =2024-01-01 &
orderBy = customProperties.leadScore &
sort = desc
Example 2: Email campaign targets
Find contacts for an email campaign:
GET /v5/contacts?
filter.email.endsWith =.com &
filter.emailOptOut.equals = false &
filter.tags.hasEvery =customer,active &
filter.customProperties.lastPurchaseDate.gte =2023-01-01 &
select[] =id &
select[] =email &
select[] =firstName
Example 3: Data cleanup
Find potentially duplicate contacts:
GET /v5/contacts?
filter.email.contains [email protected] &
filter.createdAt.gte =2024-01-01 &
orderBy = email &
sort = asc
Special filters
Null and empty values
# Find contacts without a company
filter.companyId.equals =null
# Find contacts with no tags
filter.tags.isEmpty = true
# Find contacts with any tags
filter.tags.isEmpty = false
Date ranges
// Contacts created this month
const startOfMonth = new Date ();
startOfMonth . setDate ( 1 );
startOfMonth . setHours ( 0 , 0 , 0 , 0 );
const params = new URLSearchParams ({
"filter.createdAt.gte" : startOfMonth . toISOString (),
"filter.createdAt.lt" : new Date (). toISOString (),
});
Pattern matching
# Email domains
filter.email.endsWith [email protected]
# Phone numbers with area code
filter.phone.startsWith =+1415
# Names containing substring
filter.firstName.contains =john
Best practices
Use indexes : Filter on indexed fields (id, email, createdAt) for better performance
Limit results : Always use pagination with filters
Select fields : Only request fields you need
Combine wisely : Too many filters can slow queries
// ❌ Inefficient: Fetching all fields for large dataset
const response = await fetch ( "/v5/contacts?limit=100" );
// ✅ Efficient: Select only needed fields with filters
const response = await fetch (
"/v5/contacts?" + "filter.status.equals=active&" + "select[]=id&select[]=email&select[]=name&" + "limit=50" ,
);
Common use cases
1. Segmentation
// VIP customers in California
const vipCA = {
"filter.tags.has" : "vip" ,
"filter.customProperties.state.equals" : "CA" ,
"filter.customProperties.lifetimeValue.gt" : "10000" ,
};
2. Time-based queries
// Contacts inactive for 90 days
const ninetyDaysAgo = new Date ();
ninetyDaysAgo . setDate ( ninetyDaysAgo . getDate () - 90 );
const inactive = {
"filter.lastActivityAt.lt" : ninetyDaysAgo . toISOString (),
"filter.status.equals" : "active" ,
};
3. Data export
// Export specific fields with filters
async function exportContacts ( filters ) {
const params = new URLSearchParams ({
... filters ,
"select[]" : [ "id" , "email" , "firstName" , "lastName" , "createdAt" ],
limit: "100" ,
});
// Paginate through all results
let allContacts = [];
let hasMore = true ;
let cursor = null ;
while ( hasMore ) {
if ( cursor ) params . set ( "startingAfter" , cursor );
const response = await fetch ( `/v5/contacts? ${ params } ` );
const page = await response . json ();
allContacts = allContacts . concat ( page );
hasMore = page . length === 100 ;
if ( hasMore ) cursor = page [ page . length - 1 ]. id ;
}
return allContacts ;
}
Troubleshooting
Common issues
Invalid operator : Ensure the operator is valid for the field type
Field not found : Check field names and nested paths
Type mismatch : Ensure filter values match the field type
Special characters : URL-encode special characters in filter values
Debugging tips
// Log the exact URL being called
const params = new URLSearchParams ( filters );
console . log ( `API URL: https://api.us.firstquadrant.ai/v5/contacts? ${ params } ` );
// Check response headers for debugging info
const response = await fetch ( url );
console . log ( "Request ID:" , response . headers . get ( "X-Request-Id" ));