Contacts API
The Contacts API allows you to manage customer contacts and leads in your ISAO system. You can list, create, update, and search contacts programmatically.
📋 Table of Contents
- Authentication
- Endpoints Overview
- List Contacts
- Get Contact by ID
- Create Contact
- Update Contact
- Search and Filtering
- Error Handling
- Code Examples
🔐 Authentication
All contacts endpoints require the contacts:read or contacts:write permissions:
- Read operations:
contacts:readpermission - Write operations:
contacts:writepermission
Authorization: Bearer YOUR_API_KEY
🔗 Endpoints Overview
| Method | Endpoint | Permission | Description |
|---|---|---|---|
GET | /contacts | contacts:read | List all contacts with pagination |
GET | /contacts/:id | contacts:read | Get specific contact by ID |
POST | /contacts | contacts:write | Create new contact |
PUT | /contacts/:id | contacts:write | Update existing contact |
Base URL: https://staging.isao.io/api/external
📑 List Contacts
Retrieve a paginated list of contacts from your company.
Request
GET /contacts
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (minimum: 1) |
limit | integer | 50 | Items per page (maximum: 200) |
search | string | - | Search in name, email, or phone number |
createdSince | string | - | ISO 8601 date, contacts created after this date |
updatedSince | string | - | ISO 8601 date, contacts updated after this date |
Example Request
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/contacts?page=1&limit=10&search=john"
Response
{
"success": true,
"data": [
{
"id": "contact_123",
"name": "John Smith",
"firstName": "John",
"lastName": "Smith",
"phoneNumber": "+33123456789",
"email": "john.smith@example.com",
"position": "CEO",
"currentCompany": "Tech Corp",
"industrySector": "Technology",
"city": "Paris",
"country": "France",
"tags": ["vip", "enterprise"],
"createdAt": "2024-11-01T10:30:00.000Z",
"updatedAt": "2024-11-08T09:15:00.000Z"
}
],
"meta": {
"page": 1,
"limit": 10,
"total": 1,
"totalPages": 1
}
}
👤 Get Contact by ID
Retrieve a specific contact by its ID.
Request
GET /contacts/:id
Example Request
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://staging.isao.io/api/external/contacts/contact_123
Response
{
"success": true,
"data": {
"id": "contact_123",
"name": "John Smith",
"firstName": "John",
"lastName": "Smith",
"phoneNumber": "+33123456789",
"email": "john.smith@example.com",
"position": "CEO",
"currentCompany": "Tech Corp",
"industrySector": "Technology",
"city": "Paris",
"country": "France",
"tags": ["vip", "enterprise"],
"createdAt": "2024-11-01T10:30:00.000Z",
"updatedAt": "2024-11-08T09:15:00.000Z"
}
}
➕ Create Contact
Create a new contact in your system.
Request
POST /contacts
Content-Type: application/json
Required Fields
| Field | Type | Description |
|---|---|---|
name | string | Full name of the contact (max 255 chars) |
phoneNumber | string | Phone number (required, must be unique) |
Optional Fields
| Field | Type | Description |
|---|---|---|
firstName | string | First name (max 100 chars) |
lastName | string | Last name (max 100 chars) |
email | string | Email address (valid email format) |
position | string | Job title or position (max 100 chars) |
currentCompany | string | Current company (max 255 chars) |
industrySector | string | Industry sector (max 100 chars) |
city | string | City (max 100 chars) |
country | string | Country (max 100 chars) |
tags | array | Array of strings for categorization |
Example Request
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"firstName": "Jane",
"lastName": "Doe",
"phoneNumber": "+33987654321",
"email": "jane.doe@example.com",
"position": "Marketing Manager",
"currentCompany": "Marketing Pro",
"industrySector": "Marketing",
"city": "Lyon",
"country": "France",
"tags": ["lead", "marketing"]
}' \
https://staging.isao.io/api/external/contacts
Success Response (201 Created)
{
"success": true,
"data": {
"id": "contact_456",
"name": "Jane Doe",
"firstName": "Jane",
"lastName": "Doe",
"phoneNumber": "+33987654321",
"email": "jane.doe@example.com",
"position": "Marketing Manager",
"currentCompany": "Marketing Pro",
"industrySector": "Marketing",
"city": "Lyon",
"country": "France",
"tags": ["lead", "marketing"],
"createdAt": "2024-11-08T10:30:00.000Z",
"updatedAt": "2024-11-08T10:30:00.000Z"
}
}
Error Response (409 Conflict)
If a contact with the same phone number already exists:
{
"success": false,
"error": "Contact with this phone number already exists",
"existingContactId": "contact_123"
}
✏️ Update Contact
Update an existing contact's information.
Request
PUT /contacts/:id
Content-Type: application/json
Example Request
curl -X PUT \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"position": "Senior Marketing Manager",
"city": "Marseille",
"tags": ["lead", "marketing", "senior"]
}' \
https://staging.isao.io/api/external/contacts/contact_456
Response
{
"success": true,
"data": {
"id": "contact_456",
"name": "Jane Doe",
"firstName": "Jane",
"lastName": "Doe",
"phoneNumber": "+33987654321",
"email": "jane.doe@example.com",
"position": "Senior Marketing Manager",
"currentCompany": "Marketing Pro",
"industrySector": "Marketing",
"city": "Marseille",
"country": "France",
"tags": ["lead", "marketing", "senior"],
"createdAt": "2024-11-08T10:30:00.000Z",
"updatedAt": "2024-11-08T11:45:00.000Z"
}
}
🔍 Search and Filtering
The contacts API provides powerful search and filtering capabilities.
Search by Text
Search across name, email, and phone number fields:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/contacts?search=jane"
Filter by Creation Date
Get contacts created since a specific date:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/contacts?createdSince=2024-11-01T00:00:00.000Z"
Filter by Update Date
Get contacts updated since a specific date:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/contacts?updatedSince=2024-11-07T00:00:00.000Z"
Pagination
Navigate through large datasets:
# Get page 2 with 25 items per page
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/contacts?page=2&limit=25"
Combined Filtering
Combine multiple filters:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://staging.isao.io/api/external/contacts?search=manager&createdSince=2024-11-01T00:00:00.000Z&limit=20"
❌ Error Handling
Common Error Responses
401 Unauthorized
{
"success": false,
"error": "API key required in Authorization header",
"message": "Please provide a valid API key in the format: Authorization: Bearer YOUR_API_KEY"
}
403 Forbidden
{
"success": false,
"error": "Permission denied: contacts:read required",
"message": "This API key does not have the required permission: contacts:read",
"requiredPermission": "contacts:read",
"availablePermissions": ["webhooks:write"]
}
404 Not Found
{
"success": false,
"error": "Contact not found"
}
409 Conflict
{
"success": false,
"error": "Contact with this phone number already exists",
"existingContactId": "contact_123"
}
422 Validation Error
{
"success": false,
"error": "Validation failed",
"details": {
"phoneNumber": "Phone number is required",
"email": "Invalid email format"
}
}
💻 Code Examples
JavaScript/Node.js
const axios = require('axios');
class ContactsAPI {
constructor(apiKey) {
this.client = axios.create({
baseURL: 'https://staging.isao.io/api/external',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
});
}
// List all contacts with pagination
async listContacts(options = {}) {
const params = {
page: options.page || 1,
limit: options.limit || 50,
search: options.search,
createdSince: options.createdSince,
updatedSince: options.updatedSince
};
const response = await this.client.get('/contacts', { params });
return response.data;
}
// Get contact by ID
async getContact(contactId) {
const response = await this.client.get(`/contacts/${contactId}`);
return response.data;
}
// Create new contact
async createContact(contactData) {
const response = await this.client.post('/contacts', contactData);
return response.data;
}
// Update contact
async updateContact(contactId, updateData) {
const response = await this.client.put(`/contacts/${contactId}`, updateData);
return response.data;
}
// Search contacts
async searchContacts(searchTerm, limit = 50) {
return this.listContacts({ search: searchTerm, limit });
}
}
// Usage example
const contactsAPI = new ContactsAPI(process.env.ISAO_API_KEY);
async function example() {
try {
// Create a contact
const newContact = await contactsAPI.createContact({
name: "Alice Johnson",
phoneNumber: "+33111222333",
email: "alice@example.com",
position: "Developer",
tags: ["developer", "new"]
});
console.log('Created contact:', newContact);
// List contacts
const contacts = await contactsAPI.listContacts({ page: 1, limit: 10 });
console.log('Contacts:', contacts);
// Search contacts
const searchResults = await contactsAPI.searchContacts("alice");
console.log('Search results:', searchResults);
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
Python
import requests
from typing import Optional, Dict, List
class ContactsAPI:
def __init__(self, api_key: str):
self.base_url = "https://staging.isao.io/api/external"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def list_contacts(self, page: int = 1, limit: int = 50,
search: Optional[str] = None,
created_since: Optional[str] = None,
updated_since: Optional[str] = None) -> Dict:
params = {
"page": page,
"limit": limit,
"search": search,
"createdSince": created_since,
"updatedSince": updated_since
}
# Remove None values
params = {k: v for k, v in params.items() if v is not None}
response = requests.get(f"{self.base_url}/contacts",
headers=self.headers, params=params)
response.raise_for_status()
return response.json()
def get_contact(self, contact_id: str) -> Dict:
response = requests.get(f"{self.base_url}/contacts/{contact_id}",
headers=self.headers)
response.raise_for_status()
return response.json()
def create_contact(self, contact_data: Dict) -> Dict:
response = requests.post(f"{self.base_url}/contacts",
json=contact_data, headers=self.headers)
response.raise_for_status()
return response.json()
def update_contact(self, contact_id: str, update_data: Dict) -> Dict:
response = requests.put(f"{self.base_url}/contacts/{contact_id}",
json=update_data, headers=self.headers)
response.raise_for_status()
return response.json()
def search_contacts(self, search_term: str, limit: int = 50) -> Dict:
return self.list_contacts(search=search_term, limit=limit)
# Usage example
import os
contacts_api = ContactsAPI(os.getenv("ISAO_API_KEY"))
try:
# Create a contact
new_contact = contacts_api.create_contact({
"name": "Bob Wilson",
"phoneNumber": "+33444555666",
"email": "bob@example.com",
"position": "Designer",
"tags": ["designer", "creative"]
})
print("Created contact:", new_contact)
# List contacts
contacts = contacts_api.list_contacts(page=1, limit=10)
print(f"Found {contacts['meta']['total']} contacts")
# Search contacts
search_results = contacts_api.search_contacts("bob")
print("Search results:", search_results)
except requests.exceptions.HTTPError as e:
print(f"HTTP Error: {e.response.status_code}")
print(f"Error details: {e.response.json()}")
PHP
<?php
class ContactsAPI {
private $baseUrl = 'https://staging.isao.io/api/external';
private $headers;
public function __construct($apiKey) {
$this->headers = [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
];
}
private function makeRequest($method, $endpoint, $data = null, $params = []) {
$url = $this->baseUrl . $endpoint;
if (!empty($params)) {
$url .= '?' . http_build_query(array_filter($params));
}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $this->headers,
]);
if ($data) {
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
$result = json_decode($response, true);
if ($httpCode >= 400) {
throw new Exception("API Error ({$httpCode}): " . ($result['error'] ?? 'Unknown error'));
}
return $result;
}
public function listContacts($options = []) {
$params = [
'page' => $options['page'] ?? 1,
'limit' => $options['limit'] ?? 50,
'search' => $options['search'] ?? null,
'createdSince' => $options['createdSince'] ?? null,
'updatedSince' => $options['updatedSince'] ?? null
];
return $this->makeRequest('GET', '/contacts', null, $params);
}
public function getContact($contactId) {
return $this->makeRequest('GET', "/contacts/{$contactId}");
}
public function createContact($contactData) {
return $this->makeRequest('POST', '/contacts', $contactData);
}
public function updateContact($contactId, $updateData) {
return $this->makeRequest('PUT', "/contacts/{$contactId}", $updateData);
}
public function searchContacts($searchTerm, $limit = 50) {
return $this->listContacts(['search' => $searchTerm, 'limit' => $limit]);
}
}
// Usage example
try {
$contactsAPI = new ContactsAPI(getenv('ISAO_API_KEY'));
// Create a contact
$newContact = $contactsAPI->createContact([
'name' => 'Charlie Brown',
'phoneNumber' => '+33777888999',
'email' => 'charlie@example.com',
'position' => 'Manager',
'tags' => ['manager', 'leadership']
]);
echo "Created contact: " . json_encode($newContact) . "\n";
// List contacts
$contacts = $contactsAPI->listContacts(['page' => 1, 'limit' => 10]);
echo "Found " . $contacts['meta']['total'] . " contacts\n";
// Search contacts
$searchResults = $contactsAPI->searchContacts('charlie');
echo "Search results: " . json_encode($searchResults) . "\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>
🔗 Related Documentation
- Authentication - API key setup and security
- Webhooks - Real-time contact notifications
- Deals API - Link contacts to sales opportunities
- Error Handling - Comprehensive error reference
✅ Best Practices
- Validate phone numbers before sending to avoid conflicts
- Use pagination when fetching large datasets
- Implement search to help users find contacts quickly
- Handle duplicate contacts gracefully with proper error handling
- Use tags for categorization and filtering
- Set up webhooks to get real-time contact updates