Overview
The Chatlane API provides a RESTful interface for accessing and managing conversations, messages, contacts, and custom entity records. The API uses API Key authentication via Laravel Sanctum.
Base URL
All API endpoints are prefixed with /api/v1/:
https://chatlane.io/api/v1/
Authentication
The API uses Bearer token authentication. Include your API token in the Authorization header:
Authorization: Bearer {your-api-token}
Generating API Tokens
- Log in to your Chatlane account
- Navigate to Settings → API Tokens
- Click "Create Token"
- Enter a name for your token (e.g., "Zapier Integration")
- Select the team to scope the token to
- Copy the token value immediately (it will not be shown again)
Important: API tokens are scoped to a specific team. The token can only access data from that team.
Rate Limiting
API requests are rate-limited. Contact support if you need higher limits.
Response Format
Success Response
All successful responses return JSON with the following structure:
Single Resource:
{
"data": {
"id": 1,
"name": "Example",
"created_at": "2026-01-26T10:00:00Z"
}
}
Collection (Paginated):
{
"data": [
{
"id": 1,
"name": "Example 1"
},
{
"id": 2,
"name": "Example 2"
}
],
"links": {
"first": "https://chatlane.io/api/v1/resource?page=1",
"last": "https://chatlane.io/api/v1/resource?page=2",
"prev": null,
"next": "https://chatlane.io/api/v1/resource?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 2,
"path": "https://chatlane.io/api/v1/resource",
"per_page": 50,
"to": 50,
"total": 100
}
}
Error Response
Error responses follow this format:
{
"error": "Error message",
"code": "ERROR_CODE",
"details": {}
}
HTTP Status Codes
200- Success201- Created400- Bad Request401- Unauthenticated403- Forbidden404- Not Found422- Validation Error500- Server Error
Endpoints
Conversations
List Conversations
GET /api/v1/conversations
List conversations with optional filtering.
Query Parameters:
created_after(string, ISO 8601) - Filter conversations created after this timestamp (for polling)inbox_id(integer) - Filter by inbox IDstatus(string) - Filter by status:active,pending,closedlimit(integer, default: 50, max: 100) - Number of results per pageoffset(integer) - Pagination offset
Example Request:
curl -X GET "https://chatlane.io/api/v1/conversations?created_after=2026-01-26T00:00:00Z&status=active" \
-H "Authorization: Bearer {your-token}"
Example Response:
{
"data": [
{
"id": 1,
"subject": "Customer inquiry",
"status": "active",
"is_read": false,
"is_archived": false,
"is_starred": false,
"last_message_at": "2026-01-26T10:30:00Z",
"inbox": {
"id": 1,
"name": "Support",
"type": "standard"
},
"participant": {
"id": 1,
"name": "John Doe",
"email": "[email protected]"
},
"assignee": null,
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T10:30:00Z"
}
],
"links": {...},
"meta": {...}
}
Get Single Conversation
GET /api/v1/conversations/{id}
Get detailed information about a specific conversation, including messages.
Example Request:
curl -X GET "https://chatlane.io/api/v1/conversations/1" \
-H "Authorization: Bearer {your-token}"
Example Response:
{
"data": {
"id": 1,
"subject": "Customer inquiry",
"status": "active",
"inbox": {...},
"participant": {...},
"messages": [
{
"id": 1,
"body": "Hello, I need help with...",
"type": "email",
"delivery_status": "sent",
"created_at": "2026-01-26T10:00:00Z"
}
],
"assignee": {...},
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T10:30:00Z"
}
}
Create Conversation
POST /api/v1/conversations
Create a new conversation.
Request Body:
{
"inbox_id": 1,
"contact_id": 123,
"subject": "New conversation",
"body": "Initial message content",
"status": "active",
"tags": ["vip", "billing", "priority"]
}
For Entity Inboxes:
{
"inbox_id": 2,
"custom_entity_record_id": 456,
"subject": "New conversation",
"body": "Initial message content",
"status": "active",
"tags": ["shipment", "high_value"]
}
Example Request:
curl -X POST "https://chatlane.io/api/v1/conversations" \
-H "Authorization: Bearer {your-token}" \
-H "Content-Type: application/json" \
-d '{
"inbox_id": 1,
"contact_id": 123,
"subject": "New conversation",
"tags": ["vip", "billing"]
}'
Notes:
- The
bodyfield is optional on conversation creation. - If
bodyis provided, an initial email message is created automatically with that content. - For full control over message delivery (type, draft status, channel, attachments, etc.), the recommended pattern is:
- Create the conversation (with or without
body). - Then create one or more messages using the Message endpoint:
POST /api/v1/conversations/{conversationId}/messages.
- Create the conversation (with or without
Example Response:
{
"data": {
"id": 1,
"subject": "New conversation",
"status": "active",
"tags": [
{
"id": 10,
"name": "vip",
"color": "#3b82f6"
},
{
"id": 11,
"name": "billing",
"color": "#3b82f6"
}
],
"created_at": "2026-01-26T10:00:00Z"
}
}
Messages
List Messages
GET /api/v1/messages
List messages with optional filtering.
Query Parameters:
created_after(string, ISO 8601) - Filter messages created after this timestamp (for polling)conversation_id(integer) - Filter by conversation IDinbox_id(integer) - Filter by inbox IDtype(string) - Filter by message type:email,sms,whatsapp,note,phone_call,facebook,instagramlimit(integer, default: 50, max: 100) - Number of results per page
Example Request:
curl -X GET "https://chatlane.io/api/v1/messages?conversation_id=1&type=email" \
-H "Authorization: Bearer {your-token}"
Example Response:
{
"data": [
{
"id": 1,
"body": "Hello, I need help with...",
"type": "email",
"delivery_status": "sent",
"is_read": false,
"conversation": {
"id": 1,
"subject": "Customer inquiry"
},
"sender": {
"id": 1,
"name": "John Doe",
"email": "[email protected]"
},
"created_at": "2026-01-26T10:00:00Z"
}
],
"links": {...},
"meta": {...}
}
Get Single Message
GET /api/v1/messages/{id}
Get detailed information about a specific message.
Example Request:
curl -X GET "https://chatlane.io/api/v1/messages/1" \
-H "Authorization: Bearer {your-token}"
Example Response:
{
"data": {
"id": 1,
"body": "Hello, I need help with...",
"type": "email",
"delivery_status": "sent",
"is_read": false,
"external_message_id": null,
"attachments": [],
"conversation": {
"id": 1,
"subject": "Customer inquiry",
"status": "active"
},
"channel": {
"id": 1,
"name": "Email Channel",
"type": "email",
"is_active": true
},
"sender": {
"id": 1,
"name": "John Doe",
"email": "[email protected]"
},
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T10:00:00Z"
}
}
Create Message
POST /api/v1/conversations/{conversationId}/messages
Create a new message in a conversation.
Request Body:
{
"body": "Message content",
"type": "email",
"is_draft": false,
"inbox_channel_id": 123,
"file_urls": [
"https://example.com/file1.pdf",
"https://example.com/file2.jpg"
],
"cc": "[email protected]",
"bcc": "[email protected]",
"sender_type": "contact",
"sender_id": 456
}
Parameters:
body(required, string) - Message contenttype(required, string) - Message type:email,sms,whatsapp,note,phone_call,facebook,instagramis_draft(boolean, default: false) - Iftrue, message is saved as draft. Iffalse, message is sent immediately.inbox_channel_id(integer, optional) - Specific channel to use. If not provided, uses first active channel of the specified type.file_urls(array, optional) - Array of publicly accessible file URLs to download and attachcontact_id(integer, optional) - Required for entity record conversationscc(string, optional) - CC recipients (comma-separated)bcc(string, optional) - BCC recipients (comma-separated)sender_type(string, optional) - Type of sender:user,contact, oragent. If omitted, the sender defaults to the authenticated user.sender_id(integer, optional) - ID of the sender model. Must belong to the same team. Required whensender_typeis provided.
Example Request:
curl -X POST "https://chatlane.io/api/v1/conversations/1/messages" \
-H "Authorization: Bearer {your-token}" \
-H "Content-Type: application/json" \
-d '{
"body": "Thank you for your inquiry!",
"type": "email",
"is_draft": false,
"sender_type": "contact",
"sender_id": 456
}'
Notes:
- If
sender_typeandsender_idare not provided, the message sender defaults to the authenticated user associated with the API token. - When specifying a custom sender:
- Both
sender_typeandsender_idare required. sender_type: "user"→sender_idmust be a user that belongs to the same team.sender_type: "contact"→sender_idmust be a contact in the same team.sender_type: "agent"→sender_idmust be an agent in the same team.
- Both
Example Response:
{
"data": {
"id": 1,
"body": "Thank you for your inquiry!",
"type": "email",
"delivery_status": "sending",
"is_read": true,
"external_message_id": null,
"attachments": [],
"conversation": {
"id": 1,
"subject": "Customer inquiry",
"status": "active"
},
"channel": {
"id": 1,
"name": "Email Channel",
"type": "email",
"is_active": true
},
"sender": {
"id": 2,
"name": "Support Agent",
"email": "[email protected]"
},
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T10:00:00Z"
}
}
Contacts
List Contacts
GET /api/v1/contacts
List contacts with optional filtering.
Query Parameters:
created_after(string, ISO 8601) - Filter contacts created after this timestamp (for polling)limit(integer, default: 50, max: 100) - Number of results per pageemail(string, optional) - Filter contacts by exact email addressphone_number(string, optional) - Filter contacts by phone number. The number will be normalized to E.164 format before matching.
Example Request:
curl -X GET "https://chatlane.io/api/v1/contacts" \
-H "Authorization: Bearer {your-token}"
Example: Find Contact by Email
curl -X GET "https://chatlane.io/api/v1/[email protected]" \
-H "Authorization: Bearer {your-token}"
Example: Find Contact by Phone Number
curl -X GET "https://chatlane.io/api/v1/contacts?phone_number=+441234567890" \
-H "Authorization: Bearer {your-token}"
Both filters can be combined; results are always scoped to the authenticated token's team and returned as a paginated list (even if only a single contact matches).
Get Single Contact
GET /api/v1/contacts/{id}
Get detailed information about a specific contact.
Example Request:
curl -X GET "https://chatlane.io/api/v1/contacts/1" \
-H "Authorization: Bearer {your-token}"
Create Contact
POST /api/v1/contacts
Create a new contact.
Request Body:
{
"name": "John Doe",
"email": "[email protected]",
"phone_number": "+1234567890",
"custom_attributes": {
"company": "Acme Corp",
"role": "Manager"
}
}
Example Request:
curl -X POST "https://chatlane.io/api/v1/contacts" \
-H "Authorization: Bearer {your-token}" \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "[email protected]"
}'
Update Contact
PUT/PATCH /api/v1/contacts/{id}
Update an existing contact. All fields are optional - only provided fields will be updated.
Request Body:
{
"name": "Jane Doe",
"email": "[email protected]",
"phone_number": "+1987654321",
"custom_attributes": {
"company": "New Corp",
"role": "Director",
"department": "Engineering"
}
}
Example Request:
curl -X PUT "https://chatlane.io/api/v1/contacts/1" \
-H "Authorization: Bearer {your-token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "[email protected]",
"custom_attributes": {
"company": "New Corp",
"role": "Director"
}
}'
Example Response:
{
"data": {
"id": 1,
"name": "Jane Doe",
"email": "[email protected]",
"phone_number": "+1987654321",
"custom_attributes": {
"company": "New Corp",
"role": "Director",
"department": "Engineering"
},
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T11:00:00Z"
}
}
Note: If you update the email or phone number to a value that already exists for another contact in your team, you will receive a 422 error with code DUPLICATE_EMAIL or DUPLICATE_PHONE.
Custom Entity Records
List Custom Entity Records
GET /api/v1/custom-entity-records
List custom entity records with optional filtering.
Query Parameters:
created_after(string, ISO 8601) - Filter records created after this timestamp (for polling)custom_entity_id(integer) - Filter by custom entity IDlimit(integer, default: 50, max: 100) - Number of results per page
Example Request:
curl -X GET "https://chatlane.io/api/v1/custom-entity-records?custom_entity_id=1" \
-H "Authorization: Bearer {your-token}"
Example Response:
{
"data": [
{
"id": 1,
"custom_entity_id": 1,
"external_id": "EXT-12345",
"values": {
"name": "Order #12345",
"status": "pending"
},
"custom_entity": {
"id": 1,
"name": "Orders",
"slug": "orders"
},
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T10:00:00Z"
}
],
"links": {...},
"meta": {...}
}
Get Single Custom Entity Record
GET /api/v1/custom-entity-records/{id}
Get detailed information about a specific custom entity record.
Example Request:
curl -X GET "https://chatlane.io/api/v1/custom-entity-records/1" \
-H "Authorization: Bearer {your-token}"
Example Response:
{
"data": {
"id": 1,
"custom_entity_id": 1,
"external_id": "EXT-12345",
"values": {
"name": "Order #12345",
"status": "pending",
"amount": 99.99
},
"custom_entity": {
"id": 1,
"name": "Orders",
"slug": "orders",
"attributes": [...]
},
"conversations": [...],
"contacts": [...],
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T10:00:00Z"
}
}
Create Custom Entity Record
POST /api/v1/custom-entity-records
Create a new custom entity record. The custom_entity_id is required to specify which custom entity type this record belongs to.
Request Body:
{
"custom_entity_id": 1,
"external_id": "EXT-12345",
"values": {
"name": "Order #12345",
"status": "pending",
"amount": 99.99
}
}
Parameters:
custom_entity_id(required, integer) - The ID of the custom entity this record belongs to. Must exist and belong to your team.external_id(optional, string) - An external identifier for the record. If not provided and the custom entity has an external_id attribute defined, it will be extracted from thevaluesobject.values(required, object) - The record's attribute values. Must match the custom entity's attribute definitions.
Example Request:
curl -X POST "https://chatlane.io/api/v1/custom-entity-records" \
-H "Authorization: Bearer {your-token}" \
-H "Content-Type: application/json" \
-d '{
"custom_entity_id": 1,
"values": {
"name": "Order #12345",
"status": "pending"
}
}'
Example Response:
{
"data": {
"id": 1,
"custom_entity_id": 1,
"external_id": "Order #12345",
"values": {
"name": "Order #12345",
"status": "pending"
},
"custom_entity": {
"id": 1,
"name": "Orders",
"slug": "orders"
},
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T10:00:00Z"
}
}
Note: The custom_entity_id is always included in the response, even when the custom_entity relationship is not loaded. This allows you to identify which custom entity type the record belongs to without needing to load the full relationship.
Update Custom Entity Record
PUT/PATCH /api/v1/custom-entity-records/{id}
Update an existing custom entity record. You can update the values object and/or the external_id.
Request Body:
{
"external_id": "EXT-12345-UPDATED",
"values": {
"name": "Order #12345",
"status": "completed",
"amount": 149.99
}
}
Parameters:
external_id(optional, string) - Update the external identifier for the record.values(optional, object) - Update the record's attribute values. If provided, must match the custom entity's attribute definitions. If the custom entity has an external_id attribute defined and you update that value invalues, theexternal_idfield will be automatically updated.
Example Request:
curl -X PUT "https://chatlane.io/api/v1/custom-entity-records/1" \
-H "Authorization: Bearer {your-token}" \
-H "Content-Type: application/json" \
-d '{
"values": {
"name": "Order #12345",
"status": "completed",
"amount": 149.99
}
}'
Example Response:
{
"data": {
"id": 1,
"custom_entity_id": 1,
"external_id": "EXT-12345",
"values": {
"name": "Order #12345",
"status": "completed",
"amount": 149.99
},
"custom_entity": {
"id": 1,
"name": "Orders",
"slug": "orders"
},
"created_at": "2026-01-26T10:00:00Z",
"updated_at": "2026-01-26T11:00:00Z"
}
}
Note: When updating values, you can provide a partial update (only the fields you want to change) or a complete update (all fields). The custom_entity_id cannot be changed after creation.
Inboxes (Read-Only)
List Inboxes
GET /api/v1/inboxes
List all inboxes for reference (read-only).
Example Request:
curl -X GET "https://chatlane.io/api/v1/inboxes" \
-H "Authorization: Bearer {your-token}"
Get Single Inbox
GET /api/v1/inboxes/{id}
Get information about a specific inbox (read-only).
Example Request:
curl -X GET "https://chatlane.io/api/v1/inboxes/1" \
-H "Authorization: Bearer {your-token}"
Zapier Integration
Setting Up Zapier
Generate API Token:
- Log in to Chatlane
- Go to Settings → API Tokens
- Create a new token for your Zapier integration
- Copy the token value
Configure Zapier:
- In your Zapier app, add API Key authentication
- Use the token as the API key
- Set the Base URL to:
https://chatlane.io/api/v1
Create Triggers:
- Use polling triggers with
created_afterparameter - Example:
GET /api/v1/conversations?created_after={last_poll_time}
- Use polling triggers with
Create Actions:
- Use POST endpoints to create resources
- Example:
POST /api/v1/conversations/{id}/messagesto send messages
Example Zapier Trigger (New Conversations)
Polling URL: https://chatlane.io/api/v1/conversations
Query Parameters:
created_after: Use the timestamp from your last pollstatus:active(optional)
Sample Response:
{
"data": [
{
"id": 1,
"subject": "New customer inquiry",
"status": "active",
"participant": {
"name": "John Doe",
"email": "[email protected]"
}
}
]
}
Example Zapier Action (Send Message)
Action URL: https://chatlane.io/api/v1/conversations/{conversation_id}/messages
Method: POST
Headers:
Authorization: Bearer {your-token}
Content-Type: application/json
Body:
{
"body": "{{message_body}}",
"type": "email",
"is_draft": false
}
Error Codes
| Code | Description |
|---|---|
UNAUTHENTICATED |
No valid API token provided |
UNAUTHORIZED |
Token is valid but user lacks permission |
NOT_FOUND |
Resource not found |
VALIDATION_ERROR |
Request validation failed |
TEAM_ACCESS_DENIED |
Token is not valid for the requested team |
INVALID_CHANNEL |
Specified channel is not active or does not match message type |
NO_CHANNEL_FOUND |
No active channel of the specified type found |
CONTACT_REQUIRED |
Contact must be specified for entity record conversations |
CONTACT_NOT_ASSOCIATED |
Specified contact is not associated with the entity record |
NO_EMAIL_ADDRESS |
Contact does not have an email address |
NOTE_CANNOT_BE_DRAFT |
Notes cannot be saved as drafts |
MESSAGE_TOO_LONG |
Message exceeds maximum length (e.g., 1600 chars for WhatsApp) |
DUPLICATE_EMAIL |
Contact with this email already exists |
DUPLICATE_PHONE |
Contact with this phone number already exists |
Best Practices
- Polling: Use
created_afterparameter with ISO 8601 timestamps for efficient polling - Pagination: Always handle pagination using
linksandmetain responses - Error Handling: Check HTTP status codes and error response structure
- Rate Limiting: Implement exponential backoff for rate limit errors
- Token Security: Store tokens securely and never expose them in client-side code
- Team Scoping: Remember that tokens are scoped to specific teams
Support
For API support, contact [email protected] or browse the help center.