Contacts API
This guide covers the API endpoints for managing contacts in the Revenue Recognition System. Contacts represent individuals associated with your entities (customers, vendors, partners) who serve as points of contact for business relationships and communications.
All contact data is isolated by organization context, ensuring that each organization can only access and modify its own contact records.
Overview
Contacts are individual people who represent or work for entities in your system. They can be associated with companies (customers, vendors, partners) and have hierarchical relationships (reporting structures). Each contact can have multiple communication channels and metadata about their role and preferences.
Base URL
https://api.example.com/api/v1
Authentication
All contact API endpoints require authentication with a valid JWT bearer token. The token must include an organization context, which determines which contacts are visible and modifiable.
Authorization: Bearer <your-jwt-token>
Schema
Field | Type | Description | Required |
---|---|---|---|
id | UUID | Unique identifier (system-generated) | Read-only |
organizationId | String | Organization this contact belongs to | Read-only |
name | String | Full name of the contact | Yes |
displayName | String | Display name for the contact | No |
code | String | Optional code identifier | No |
entityTypes | Array | Entity types (always includes 'Contact') | Read-only |
String | Email address of the contact | No | |
phone | String | Primary phone number | No |
website | String | Website URL | No |
address | Object | Physical address details (see below) | No |
parentEntityId | UUID | ID of parent entity (e.g., company) | No |
primaryContactId | UUID | ID of primary contact (for companies) | No |
taxId | String | Tax identification number | No |
description | String | Brief description of the contact | No |
notes | String | Additional notes | No |
customFields | Object | Custom fields for the contact | No |
metadata | Object | Contact metadata (see below) | No |
status | String | Status: 'active', 'inactive', or 'archived' | Yes |
isActive | Boolean | Whether the contact is active | Yes |
createdAt | DateTime | When the record was created | Read-only |
updatedAt | DateTime | When the record was last updated | Read-only |
Address Object
Field | Type | Description | Required |
---|---|---|---|
id | UUID | Unique identifier for the address | No |
addressee | String | Name of addressee | No |
companyName | String | Company name for address | No |
attention | String | Attention line | No |
phoneNumber | String | Phone number for address | No |
line1 | String | Address line 1 | No |
line2 | String | Address line 2 | No |
city | String | City | No |
stateProvince | String | State or province | No |
postalCode | String | Postal or ZIP code | No |
countryCode | String | Two-letter ISO country code | No |
Contact Metadata Object
Field | Type | Description | Required |
---|---|---|---|
title | String | Job title of the contact | No |
department | String | Department the contact belongs to | No |
reportsTo | UUID | ID of the contact this person reports to | No |
mobilePhone | String | Mobile phone number | No |
workPhone | String | Work phone number | No |
preferredContactMethod | String | Preferred method: 'email', 'phone', 'mobile' | No |
Endpoints
Create Contact
Create a new contact within your organization.
- Name
Endpoint
- Type
- POST /contacts
- Description
- Name
Content-Type
- Type
- application/json
- Description
Request Body
- Name
name
- Type
- string
- Required
- Description
Full name of the contact
- Name
displayName
- Type
- string
- Description
Display name for the contact
- Name
code
- Type
- string
- Description
Optional code identifier
- Name
entityTypes
- Type
- array
- Description
Entity types (should include 'Contact' for contacts)
- Name
email
- Type
- string
- Description
Email address of the contact
- Name
phone
- Type
- string
- Description
Primary phone number
- Name
website
- Type
- string
- Description
Website URL
- Name
address
- Type
- object
- Description
Physical address details
- Name
parentEntityId
- Type
- string (UUID)
- Description
ID of parent entity (e.g., company) this contact belongs to
- Name
taxId
- Type
- string
- Description
Tax identification number
- Name
description
- Type
- string
- Description
Brief description of the contact
- Name
notes
- Type
- string
- Description
Additional notes
- Name
customFields
- Type
- object
- Description
Custom fields for the contact
- Name
metadata
- Type
- object
- Description
Contact metadata including job title, department, etc.
- Name
status
- Type
- string
- Description
Status: 'active', 'inactive', or 'archived'
- Name
isActive
- Type
- boolean
- Description
Whether the contact is active
Request
curl -X POST https://api.example.com/api/v1/contacts \
-H "Authorization: Bearer <your-jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "John Smith",
"displayName": "John",
"email": "john.smith@acme.com",
"phone": "555-123-4567",
"entityTypes": ["Contact"],
"parentEntityId": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a",
"address": {
"line1": "123 Main St",
"city": "San Francisco",
"stateProvince": "CA",
"postalCode": "94105",
"countryCode": "US"
},
"metadata": {
"title": "Sales Director",
"department": "Sales",
"workPhone": "555-123-4568",
"preferredContactMethod": "email"
},
"status": "active"
}'
Response
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"organizationId": "org_123456789",
"name": "John Smith",
"displayName": "John",
"code": null,
"entityTypes": ["Contact"],
"email": "john.smith@acme.com",
"phone": "555-123-4567",
"website": null,
"address": {
"id": "addr_987654321",
"line1": "123 Main St",
"line2": null,
"city": "San Francisco",
"stateProvince": "CA",
"postalCode": "94105",
"countryCode": "US"
},
"parentEntityId": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a",
"primaryContactId": null,
"taxId": null,
"description": null,
"notes": null,
"customFields": null,
"metadata": {
"title": "Sales Director",
"department": "Sales",
"reportsTo": null,
"mobilePhone": null,
"workPhone": "555-123-4568",
"preferredContactMethod": "email"
},
"status": "active",
"isActive": true,
"createdAt": "2025-06-03T10:15:30.000Z",
"updatedAt": "2025-06-03T10:15:30.000Z"
}
List Contacts
Retrieve a paginated list of contacts in your organization.
- Name
Endpoint
- Type
- GET /contacts
- Description
Query Parameters
- Name
page
- Type
- number
- Description
Page number for pagination
- Name
limit
- Type
- number
- Description
Number of items per page (max: 100)
- Name
orderBy
- Type
- string
- Description
Field to sort by (name, createdAt, updatedAt)
- Name
orderDirection
- Type
- string
- Description
Sort direction (asc, desc)
- Name
status
- Type
- string
- Description
Filter by status (active, inactive, archived)
- Name
search
- Type
- string
- Description
Search query string (searches in name, email, phone)
- Name
parentEntityId
- Type
- string (UUID)
- Description
Filter by parent entity ID
- Name
isActive
- Type
- boolean
- Description
Filter by active status
Request
curl -X GET "https://api.example.com/api/v1/contacts?page=1&limit=20&status=active&search=john" \
-H "Authorization: Bearer <your-jwt-token>"
Response
{
"data": [
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"organizationId": "org_123456789",
"name": "John Smith",
"displayName": "John",
"code": null,
"entityTypes": ["Contact"],
"email": "john.smith@acme.com",
"phone": "555-123-4567",
"website": null,
"address": {
"line1": "123 Main St",
"city": "San Francisco",
"stateProvince": "CA",
"postalCode": "94105",
"countryCode": "US"
},
"parentEntityId": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a",
"primaryContactId": null,
"metadata": {
"title": "Sales Director",
"department": "Sales",
"preferredContactMethod": "email"
},
"status": "active",
"isActive": true,
"createdAt": "2025-06-03T10:15:30.000Z",
"updatedAt": "2025-06-03T10:15:30.000Z"
}
],
"total": 1,
"page": 1,
"limit": 20,
"totalPages": 1
}
Get Contact
Retrieve a specific contact by ID.
- Name
Endpoint
- Type
- GET /contacts/{id}
- Description
Path Parameters
- Name
id
- Type
- string (UUID)
- Required
- Description
ID of the contact to retrieve
Request
curl -X GET https://api.example.com/api/v1/contacts/c12f8e21-4ab2-4589-ae0d-9c12654b8e7a \
-H "Authorization: Bearer <your-jwt-token>"
Response
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"organizationId": "org_123456789",
"name": "John Smith",
"displayName": "John",
"code": null,
"entityTypes": ["Contact"],
"email": "john.smith@acme.com",
"phone": "555-123-4567",
"website": null,
"address": {
"id": "addr_987654321",
"line1": "123 Main St",
"line2": null,
"city": "San Francisco",
"stateProvince": "CA",
"postalCode": "94105",
"countryCode": "US"
},
"parentEntityId": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a",
"primaryContactId": null,
"taxId": null,
"description": null,
"notes": null,
"customFields": null,
"metadata": {
"title": "Sales Director",
"department": "Sales",
"reportsTo": null,
"mobilePhone": null,
"workPhone": "555-123-4568",
"preferredContactMethod": "email"
},
"status": "active",
"isActive": true,
"createdAt": "2025-06-03T10:15:30.000Z",
"updatedAt": "2025-06-03T10:15:30.000Z"
}
Update Contact
Update an existing contact.
- Name
Endpoint
- Type
- PUT /contacts/{id}
- Description
- Name
Content-Type
- Type
- application/json
- Description
Path Parameters
- Name
id
- Type
- string (UUID)
- Required
- Description
ID of the contact to update
Request Body
All fields are optional. Only include fields you want to update.
- Name
name
- Type
- string
- Description
Full name of the contact
- Name
displayName
- Type
- string
- Description
Display name for the contact
- Name
code
- Type
- string
- Description
Optional code identifier
- Name
email
- Type
- string
- Description
Email address of the contact
- Name
phone
- Type
- string
- Description
Primary phone number
- Name
website
- Type
- string
- Description
Website URL
- Name
address
- Type
- object
- Description
Physical address details
- Name
parentEntityId
- Type
- string (UUID)
- Description
ID of parent entity
- Name
taxId
- Type
- string
- Description
Tax identification number
- Name
description
- Type
- string
- Description
Brief description of the contact
- Name
notes
- Type
- string
- Description
Additional notes
- Name
customFields
- Type
- object
- Description
Custom fields for the contact
- Name
metadata
- Type
- object
- Description
Contact metadata
- Name
status
- Type
- string
- Description
Status: 'active', 'inactive', or 'archived'
- Name
isActive
- Type
- boolean
- Description
Whether the contact is active
Request
curl -X PUT https://api.example.com/api/v1/contacts/c12f8e21-4ab2-4589-ae0d-9c12654b8e7a \
-H "Authorization: Bearer <your-jwt-token>" \
-H "Content-Type: application/json" \
-d '{
"displayName": "Johnny",
"metadata": {
"title": "VP of Sales",
"mobilePhone": "555-999-8888",
"preferredContactMethod": "mobile"
}
}'
Response
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"organizationId": "org_123456789",
"name": "John Smith",
"displayName": "Johnny",
"code": null,
"entityTypes": ["Contact"],
"email": "john.smith@acme.com",
"phone": "555-123-4567",
"website": null,
"address": {
"id": "addr_987654321",
"line1": "123 Main St",
"line2": null,
"city": "San Francisco",
"stateProvince": "CA",
"postalCode": "94105",
"countryCode": "US"
},
"parentEntityId": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a",
"primaryContactId": null,
"taxId": null,
"description": null,
"notes": null,
"customFields": null,
"metadata": {
"title": "VP of Sales",
"department": "Sales",
"reportsTo": null,
"mobilePhone": "555-999-8888",
"workPhone": "555-123-4568",
"preferredContactMethod": "mobile"
},
"status": "active",
"isActive": true,
"createdAt": "2025-06-03T10:15:30.000Z",
"updatedAt": "2025-06-03T11:30:45.000Z"
}
Delete Contact
Delete a contact.
- Name
Endpoint
- Type
- DELETE /contacts/{id}
- Description
Path Parameters
- Name
id
- Type
- string (UUID)
- Required
- Description
ID of the contact to delete
Request
curl -X DELETE https://api.example.com/api/v1/contacts/c12f8e21-4ab2-4589-ae0d-9c12654b8e7a \
-H "Authorization: Bearer <your-jwt-token>"
Response
HTTP/1.1 204 No Content
Get Contact Hierarchy
Returns a hierarchy map showing which contacts report to whom.
- Name
Endpoint
- Type
- GET /contacts/hierarchy
- Description
Request
curl -X GET https://api.example.com/api/v1/contacts/hierarchy \
-H "Authorization: Bearer <your-jwt-token>"
Response
{
"a23f8e21-3bb2-4589-be0d-8c32654b8e7b": [
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"name": "John Smith",
"displayName": "John",
"metadata": {
"title": "Sales Manager",
"department": "Sales"
}
},
{
"id": "d34f9e32-5cc3-4690-cf1e-9d43765c9f8c",
"name": "Jane Doe",
"displayName": "Jane",
"metadata": {
"title": "Account Executive",
"department": "Sales"
}
}
]
}
Find Contacts by Company
Get all contacts associated with a specific company/entity.
- Name
Endpoint
- Type
- GET /contacts/company/{companyId}
- Description
Path Parameters
- Name
companyId
- Type
- string (UUID)
- Required
- Description
ID of the company
Request
curl -X GET https://api.example.com/api/v1/contacts/company/d45f8e21-3ab2-4389-9e0d-9c12654b8e7a \
-H "Authorization: Bearer <your-jwt-token>"
Response
{
"data": [
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"name": "John Smith",
"displayName": "John",
"email": "john.smith@acme.com",
"phone": "555-123-4567",
"metadata": {
"title": "Sales Director",
"department": "Sales"
},
"status": "active"
},
{
"id": "e45f0e43-6dd4-4701-df2f-0e54876d0g9d",
"name": "Sarah Johnson",
"displayName": "Sarah",
"email": "sarah.johnson@acme.com",
"phone": "555-234-5678",
"metadata": {
"title": "Marketing Manager",
"department": "Marketing"
},
"status": "active"
}
]
}
Find Contacts by Department
Get all contacts in a specific department.
- Name
Endpoint
- Type
- GET /contacts/department/{department}
- Description
Path Parameters
- Name
department
- Type
- string
- Required
- Description
Department name
Request
curl -X GET https://api.example.com/api/v1/contacts/department/Sales \
-H "Authorization: Bearer <your-jwt-token>"
Response
{
"data": [
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"name": "John Smith",
"displayName": "John",
"email": "john.smith@acme.com",
"metadata": {
"title": "Sales Director",
"department": "Sales"
}
},
{
"id": "d34f9e32-5cc3-4690-cf1e-9d43765c9f8c",
"name": "Jane Doe",
"displayName": "Jane",
"email": "jane.doe@acme.com",
"metadata": {
"title": "Account Executive",
"department": "Sales"
}
}
]
}
Set Primary Contact
Designate a contact as the primary contact for a specific company.
- Name
Endpoint
- Type
- POST /contacts/{id}/set-primary/{companyId}
- Description
Path Parameters
- Name
id
- Type
- string (UUID)
- Required
- Description
ID of the contact
- Name
companyId
- Type
- string (UUID)
- Required
- Description
ID of the company
Request
curl -X POST https://api.example.com/api/v1/contacts/c12f8e21-4ab2-4589-ae0d-9c12654b8e7a/set-primary/d45f8e21-3ab2-4389-9e0d-9c12654b8e7a \
-H "Authorization: Bearer <your-jwt-token>"
Response
{
"contact": {
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"name": "John Smith",
"displayName": "John",
"email": "john.smith@acme.com",
"parentEntityId": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a"
},
"company": {
"id": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a",
"name": "Acme Corporation",
"primaryContactId": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a"
}
}
Find Contacts by Preferred Contact Method
Get all contacts with a specific preferred contact method.
- Name
Endpoint
- Type
- GET /contacts/contact-method/{method}
- Description
Path Parameters
- Name
method
- Type
- string
- Required
- Description
Contact method: 'email', 'phone', or 'mobile'
Request
curl -X GET https://api.example.com/api/v1/contacts/contact-method/email \
-H "Authorization: Bearer <your-jwt-token>"
Response
{
"data": [
{
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"name": "John Smith",
"email": "john.smith@acme.com",
"phone": "555-123-4567",
"metadata": {
"preferredContactMethod": "email"
}
},
{
"id": "f56g1f54-7ee5-4812-eg3g-1f65987e1h0e",
"name": "Emily Chen",
"email": "emily.chen@globex.com",
"phone": "555-345-6789",
"metadata": {
"preferredContactMethod": "email"
}
}
]
}
Error Responses
The API returns standard HTTP status codes and error messages in a consistent format.
{
"error": "ERROR_CODE",
"message": "Human-readable error description",
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
Common errors include:
Status Code | Error Code | Description |
---|---|---|
400 | VALIDATION_ERROR | Request data failed validation |
400 | INVALID_ENTITY_TYPE | Contact does not belong to the specified company |
401 | UNAUTHORIZED | Missing or invalid authentication token |
404 | CONTACT_NOT_FOUND | The requested contact was not found |
404 | COMPANY_NOT_FOUND | The specified company was not found |
500 | INTERNAL_SERVER_ERROR | An unexpected error occurred |
Rate Limiting
The contacts API is rate-limited to ensure fair usage:
- Rate limit: 1000 requests per hour per organization
- Burst limit: 100 requests per minute
- Headers returned:
X-RateLimit-Limit
: Maximum requests per hourX-RateLimit-Remaining
: Remaining requests in current windowX-RateLimit-Reset
: Unix timestamp when the limit resets
When rate limited, the API returns a 429 Too Many Requests
status code.
Code Examples
JavaScript/TypeScript
// Using fetch API
const baseUrl = 'https://api.example.com/api/v1';
const token = 'your-jwt-token';
// Create a contact
async function createContact(contactData) {
const response = await fetch(`${baseUrl}/contacts`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(contactData)
});
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
return response.json();
}
// List contacts for a company
async function getCompanyContacts(companyId) {
const response = await fetch(`${baseUrl}/contacts/company/${companyId}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
return response.json();
}
// Update contact
async function updateContact(contactId, updates) {
const response = await fetch(`${baseUrl}/contacts/${contactId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
});
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
return response.json();
}
// Example usage
const newContact = await createContact({
name: 'John Smith',
email: 'john.smith@acme.com',
entityTypes: ['Contact'],
parentEntityId: 'd45f8e21-3ab2-4389-9e0d-9c12654b8e7a',
metadata: {
title: 'Sales Director',
department: 'Sales',
preferredContactMethod: 'email'
}
});
console.log('Created contact:', newContact);
Python
import requests
import json
base_url = 'https://api.example.com/api/v1'
headers = {
'Authorization': 'Bearer your-jwt-token',
'Content-Type': 'application/json'
}
# Create a contact
def create_contact(contact_data):
response = requests.post(
f'{base_url}/contacts',
headers=headers,
json=contact_data
)
response.raise_for_status()
return response.json()
# List contacts with filters
def list_contacts(page=1, limit=20, status='active', search=None):
params = {
'page': page,
'limit': limit,
'status': status
}
if search:
params['search'] = search
response = requests.get(
f'{base_url}/contacts',
headers=headers,
params=params
)
response.raise_for_status()
return response.json()
# Get contact hierarchy
def get_contact_hierarchy():
response = requests.get(
f'{base_url}/contacts/hierarchy',
headers=headers
)
response.raise_for_status()
return response.json()
# Set primary contact for company
def set_primary_contact(contact_id, company_id):
response = requests.post(
f'{base_url}/contacts/{contact_id}/set-primary/{company_id}',
headers=headers
)
response.raise_for_status()
return response.json()
# Example usage
new_contact = create_contact({
'name': 'Jane Doe',
'email': 'jane.doe@example.com',
'entityTypes': ['Contact'],
'phone': '555-987-6543',
'metadata': {
'title': 'Product Manager',
'department': 'Product',
'preferredContactMethod': 'email'
}
})
print(f"Created contact: {new_contact['id']}")
# List all active contacts
contacts = list_contacts(status='active')
print(f"Found {contacts['total']} active contacts")
Webhooks
The contacts API supports webhooks for real-time notifications of contact events. To configure webhooks, see the Webhooks documentation.
Available webhook events:
contact.created
- Fired when a new contact is createdcontact.updated
- Fired when a contact is updatedcontact.deleted
- Fired when a contact is deletedcontact.status_changed
- Fired when a contact's status changescontact.primary_set
- Fired when a contact is set as primary for a company
Example webhook payload:
{
"event": "contact.created",
"timestamp": "2025-06-03T10:15:30.000Z",
"data": {
"id": "c12f8e21-4ab2-4589-ae0d-9c12654b8e7a",
"organizationId": "org_123456789",
"name": "John Smith",
"email": "john.smith@acme.com",
"parentEntityId": "d45f8e21-3ab2-4389-9e0d-9c12654b8e7a",
"status": "active"
}
}
Best Practices
Contact Management
-
Use meaningful display names: Set display names that are commonly used in communication to make contacts easier to identify.
-
Link contacts to companies: Always set the
parentEntityId
to associate contacts with their companies for better organization. -
Track reporting structures: Use the
metadata.reportsTo
field to build organizational hierarchies within companies. -
Set preferred contact methods: Always specify the preferred contact method to ensure communications are sent through the right channel.
Data Quality
-
Validate email addresses: Ensure email addresses are valid before creating or updating contacts.
-
Use consistent naming: Establish naming conventions for contacts to maintain consistency.
-
Keep contact information current: Regularly update contact information, especially when employees change roles or companies.
-
Archive instead of delete: Use the 'archived' status instead of deleting contacts to maintain historical records.
Performance
-
Use pagination: Always paginate results when listing contacts to avoid performance issues.
-
Filter efficiently: Use specific filters (status, parentEntityId) to reduce the result set.
-
Cache frequently accessed data: Cache contact data that doesn't change often to reduce API calls.
Changelog
For the latest updates and changes to the contacts API, see the API Changelog.