API Overview
Integrate with the Kantos REST API.
The Kantos API provides programmatic access to your CRM data. Build integrations, automate workflows, sync with external systems, and create custom applications using our RESTful API.
API-First Design
Everything you can do in the Kantos dashboard is also available via the API. This includes managing records, objects, automations, users, and more.
Base URL
All API requests are made to:
https://kantos.ai/apiAuthentication
All API requests require authentication using an API key. Include your key in the X-Api-Key header with every request:
curl -X GET "https://kantos.ai/api/crm/records/query" \
-H "X-Api-Key: sk_live_your_secret_key" \
-H "Content-Type: application/json"API Key Types
| Key Type | Prefix | Use Case | Permissions |
|---|---|---|---|
| Secret Key | sk_live_ | Server-side integrations | Full read/write access |
| Publishable Key | pk_live_ | Client-side form capture | Write-only to intake endpoint |
| Intake Key | kantos_ | Smart Intake integration | Write-only to ingest endpoint |
Keep Secret Keys Secure
Secret keys (sk_live_...) provide full access to your CRM data. Never expose them in client-side code, public repositories, or browser requests. Use publishable keys for frontend integrations.
Creating API Keys
Go to Settings → API Keys
Navigate to the API Keys section in your Kantos dashboard.
Click "Create Key"
Choose the key type based on your use case.
Name Your Key
Give it a descriptive name like "Production Server" or "Marketing Website".
Copy and Store Securely
The full key is only shown once. Store it securely in environment variables.
Request Format
The API accepts JSON request bodies and returns JSON responses. Always include the appropriate headers:
curl -X POST "https://kantos.ai/api/crm/record" \
-H "X-Api-Key: sk_live_your_secret_key" \
-H "Content-Type: application/json" \
-d '{
"object_id": "obj_contacts",
"field_values": {
"name": "John Doe",
"email": "john@example.com"
}
}'Response Format
Successful responses return the requested data directly. The response format varies by endpoint:
Single Record Response
{
"id": "rec_abc123",
"object_id": "obj_contacts",
"field_values": {
"name": "John Doe",
"email": "john@example.com",
"phone": "+1 (555) 123-4567",
"company": "rec_company_456"
},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"created_by": "user_789"
}List Response (Paginated)
{
"data": [
{ "id": "rec_abc123", ... },
{ "id": "rec_def456", ... }
],
"pagination": {
"total": 156,
"page": 1,
"per_page": 25,
"total_pages": 7
}
}Error Handling
Errors return appropriate HTTP status codes with a JSON body describing the issue:
{
"error": "Record not found",
"code": "NOT_FOUND",
"status": 404,
"details": {
"record_id": "rec_invalid123"
}
}Common Error Codes
| Status | Code | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid request body or parameters |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN | API key lacks required permissions |
| 404 | NOT_FOUND | Resource does not exist |
| 409 | CONFLICT | Duplicate record or constraint violation |
| 422 | VALIDATION_ERROR | Field validation failed |
| 429 | RATE_LIMITED | Too many requests |
| 500 | INTERNAL_ERROR | Server error (contact support) |
Records API
The Records API is the primary way to read and write CRM data.
Query Records
Retrieve records with optional filtering, sorting, and pagination:
GET /api/crm/records/query?object_id=obj_contacts&page=1&per_page=25
# With filters
GET /api/crm/records/query?object_id=obj_contacts&filters={"status":"active"}
# With sorting
GET /api/crm/records/query?object_id=obj_contacts&sort=created_at&order=descQuery Parameters
| Parameter | Type | Description |
|---|---|---|
object_id | string | Required. The object to query |
filters | JSON | Field filters (see Filter Syntax below) |
sort | string | Field to sort by |
order | string | "asc" or "desc" (default: "asc") |
page | number | Page number (default: 1) |
per_page | number | Results per page (default: 25, max: 100) |
Filter Syntax
{
// Exact match
"status": "active",
// Comparison operators
"deal_value": { "$gte": 10000 },
"created_at": { "$lt": "2024-01-01" },
// Multiple conditions (AND)
"status": "active",
"source": "website",
// Contains (text search)
"name": { "$contains": "John" },
// In array
"category": { "$in": ["Enterprise", "SMB"] },
// Is empty / not empty
"phone": { "$empty": false }
}Get Single Record
GET /api/crm/record/{record_id}Create Record
POST /api/crm/record
Content-Type: application/json
{
"object_id": "obj_contacts",
"field_values": {
"name": "Jane Smith",
"email": "jane@example.com",
"phone": "+1 (555) 987-6543",
"status": "new",
"source": "api"
}
}Update Record
PATCH /api/crm/record/{record_id}
Content-Type: application/json
{
"field_values": {
"status": "qualified",
"notes": "Spoke on phone, interested in enterprise plan"
}
}Delete Record
DELETE /api/crm/record/{record_id}Objects API
Manage your CRM schema programmatically.
List Objects
GET /api/crm/objects
# Response
{
"data": [
{
"id": "obj_contacts",
"name": "Contacts",
"slug": "contacts",
"icon": "user",
"field_count": 12
},
{
"id": "obj_companies",
"name": "Companies",
"slug": "companies",
"icon": "building",
"field_count": 8
}
]
}Get Object Schema
GET /api/crm/objects/{object_id}
# Response includes all fields
{
"id": "obj_contacts",
"name": "Contacts",
"slug": "contacts",
"fields": [
{
"id": "fld_name",
"name": "Name",
"slug": "name",
"type": "text",
"required": true
},
{
"id": "fld_email",
"name": "Email",
"slug": "email",
"type": "email",
"required": true,
"unique": true
}
]
}Create Object
POST /api/crm/objects
Content-Type: application/json
{
"name": "Projects",
"icon": "folder",
"fields": [
{
"name": "Project Name",
"type": "text",
"required": true
},
{
"name": "Status",
"type": "status",
"options": {
"stages": ["Planning", "In Progress", "Review", "Complete"]
}
},
{
"name": "Budget",
"type": "currency"
}
]
}Intake API
The Intake API receives form submissions from websites and external sources.
Ingest Endpoint
POST /api/ingest
X-Api-Key: kantos_your_intake_key
Content-Type: application/json
{
"source": "website_contact_form",
"fields": {
"name": "John Doe",
"email": "john@example.com",
"message": "I'm interested in your services"
},
"metadata": {
"page_url": "https://example.com/contact",
"referrer": "https://google.com",
"user_agent": "Mozilla/5.0..."
}
}Use Smart Intake
For website form capture, use the Smart Intake Universal Script which handles all the details automatically.
Webhooks
Configure webhooks to receive real-time notifications when records change.
Webhook Events
| Event | Triggered When |
|---|---|
record.created | A new record is created |
record.updated | A record is modified |
record.deleted | A record is deleted |
intake.received | A form submission is received |
Webhook Payload
{
"event": "record.created",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"id": "rec_abc123",
"object_id": "obj_contacts",
"field_values": {
"name": "John Doe",
"email": "john@example.com"
}
},
"signature": "sha256=..."
}Rate Limits
API requests are rate limited to ensure fair usage and platform stability.
| Plan | Requests/Minute | Requests/Day |
|---|---|---|
| Free | 100 | 10,000 |
| Pro | 1,000 | 100,000 |
| Enterprise | Custom | Custom |
Rate limit information is included in response headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1705312800Exceeding Limits
When rate limited, you'll receive a 429 response. Implement exponential backoff in your integration to handle this gracefully.
SDKs & Libraries
Official and community SDKs make integration easier:
JavaScript / TypeScript
npm install @kantos/sdkimport { Kantos } from '@kantos/sdk';
const kantos = new Kantos({
apiKey: process.env.KANTOS_API_KEY
});
// Create a contact
const contact = await kantos.records.create({
objectId: 'obj_contacts',
fieldValues: {
name: 'John Doe',
email: 'john@example.com'
}
});
// Query records
const leads = await kantos.records.query({
objectId: 'obj_contacts',
filters: { status: 'new' },
sort: 'created_at',
order: 'desc'
});Python
pip install kantosfrom kantos import Kantos
client = Kantos(api_key=os.environ['KANTOS_API_KEY'])
# Create a contact
contact = client.records.create(
object_id='obj_contacts',
field_values={
'name': 'John Doe',
'email': 'john@example.com'
}
)
# Query records
leads = client.records.query(
object_id='obj_contacts',
filters={'status': 'new'},
sort='created_at',
order='desc'
)Best Practices
Security
- Store API keys in environment variables, never in code
- Use secret keys only on the server, publishable keys for client-side
- Rotate keys periodically and after any suspected compromise
- Use HTTPS for all API requests
Performance
- Batch operations when possible to reduce API calls
- Use pagination for large datasets
- Cache responses where appropriate
- Implement retry logic with exponential backoff
Error Handling
- Always check response status codes
- Log errors for debugging
- Handle rate limits gracefully
- Validate data before sending to the API
Next Steps
- Data Model Guide - Understand objects and fields
- Smart Intake - Set up form capture
- Automations - Trigger workflows on API events