Import & Export API
Bulk import records from CSV/Excel files and export data to various formats
The Import & Export API enables bulk data operations, allowing you to import records from external files and export your data in multiple formats.
Import Overview
The import process follows a four-step workflow:
- Upload - Parse the file and get a preview of the data
- Map - Map source columns to module fields (with optional AI suggestions)
- Validate - Check data for errors before importing
- Execute - Run the import with configurable duplicate handling
This approach allows you to review and adjust mappings before committing any changes.
Import Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /modules/{module}/import/parse | Upload and parse file |
| POST | /modules/{module}/import/suggest-mapping | Get AI mapping suggestions |
| POST | /modules/{module}/import/validate | Validate mapped data |
| POST | /modules/{module}/import/execute | Execute the import |
| GET | /modules/{module}/import/jobs | List import history |
| GET | /modules/{module}/import/jobs/{jobId} | Get job status |
| DELETE | /modules/{module}/import/jobs/{jobId} | Rollback import |
Step 1: Upload and Parse File
Upload a CSV or Excel file to parse its contents and get a preview.
curl -X POST "https://api.getcoherence.io/v1/modules/contacts/import/parse" \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "[email protected]"Supported File Types
| Format | MIME Type | Extensions |
|---|---|---|
| CSV | text/csv, text/plain | .csv |
| Excel | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | .xlsx |
| Excel (Legacy) | application/vnd.ms-excel | .xls |
Response
{
"success": true,
"data": {
"sourceColumns": ["Name", "Email", "Phone", "Company"],
"sampleRows": [
{
"Name": "John Smith",
"Email": "[email protected]",
"Phone": "555-0100",
"Company": "Acme Corp"
},
{
"Name": "Jane Doe",
"Email": "[email protected]",
"Phone": "555-0101",
"Company": "TechStart Inc"
}
],
"totalRows": 1500,
"fileType": "csv",
"fileName": "contacts.csv",
"encoding": "utf-8"
}
}The preview includes up to 50 sample rows. Use this data to verify the file was parsed correctly before proceeding.
File Size Limits
- Maximum file size: 100 MB
- Maximum rows: No hard limit, but large files process asynchronously
Step 2: Get Column Mapping Suggestions
Get AI-powered suggestions for mapping source columns to module fields.
curl -X POST "https://api.getcoherence.io/v1/modules/contacts/import/suggest-mapping" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sourceColumns": ["Name", "Email", "Phone", "Company"],
"sampleData": [
{
"Name": "John Smith",
"Email": "[email protected]",
"Phone": "555-0100",
"Company": "Acme Corp"
}
]
}'Request Body
{
sourceColumns: string[]; // Column headers from the file
sampleData?: object[]; // Sample rows for better AI matching
}Response
{
"success": true,
"data": {
"suggestions": [
{
"sourceColumn": "Name",
"targetFieldSlug": "displayName",
"confidence": 0.95
},
{
"sourceColumn": "Email",
"targetFieldSlug": "email",
"confidence": 0.98
},
{
"sourceColumn": "Phone",
"targetFieldSlug": "phone",
"confidence": 0.92
},
{
"sourceColumn": "Company",
"targetFieldSlug": "account",
"confidence": 0.85
}
],
"aiUsed": true,
"targetFields": [
{
"fieldSlug": "displayName",
"label": "Name",
"dataType": "text"
},
{
"fieldSlug": "email",
"label": "Email",
"dataType": "email"
},
{
"fieldSlug": "phone",
"label": "Phone",
"dataType": "phone"
},
{
"fieldSlug": "account",
"label": "Account",
"dataType": "reference"
}
]
}
}Step 3: Validate Import Data
Validate your mapped data before executing the import.
curl -X POST "https://api.getcoherence.io/v1/modules/contacts/import/validate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{"Name": "John Smith", "Email": "[email protected]"},
{"Name": "Jane Doe", "Email": "invalid-email"}
],
"columnMapping": [
{"sourceColumn": "Name", "targetFieldSlug": "displayName"},
{"sourceColumn": "Email", "targetFieldSlug": "email"}
]
}'Request Body
{
rows: object[]; // All rows from the parsed file
columnMapping: ColumnMapping[];
}
interface ColumnMapping {
sourceColumn: string; // Header name from file
targetFieldSlug: string | null; // Module field to map to
ignored?: boolean; // Skip this column
valueType?: string; // For multi-value fields (e.g., "Mobile", "Work")
addressPart?: "street" | "street2" | "city" | "state" | "zip" | "country";
}Response
{
"success": true,
"data": {
"isValid": false,
"totalRows": 2,
"validRows": 1,
"errorRows": 1,
"errors": [
{
"row": 2,
"field": "email",
"value": "invalid-email",
"error": "Invalid email format"
}
],
"warnings": [
{
"row": 1,
"field": "phone",
"message": "Required field \"Phone\" is not mapped"
}
]
}
}Step 4: Execute Import
Run the import with your configured options.
curl -X POST "https://api.getcoherence.io/v1/modules/contacts/import/execute" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rows": [...],
"columnMapping": [
{"sourceColumn": "Name", "targetFieldSlug": "displayName"},
{"sourceColumn": "Email", "targetFieldSlug": "email"}
],
"duplicateStrategy": "update",
"duplicateMatchFields": ["email"],
"mergeMode": "prefer_import"
}'Request Body
{
rows: object[]; // All rows to import
columnMapping: ColumnMapping[]; // Field mappings
duplicateStrategy?: "skip" | "update" | "create"; // Default: "skip"
duplicateMatchFields?: string[]; // Fields to match duplicates
mergeMode?: "fill_empty" | "overwrite" | "prefer_import"; // Default: "prefer_import"
aiMappingUsed?: boolean; // Track AI usage for analytics
skipValidation?: boolean; // Skip validation (not recommended)
createMissingReferences?: boolean; // Auto-create referenced records
staticValues?: Record<string, string>; // Values to apply to all records
}Duplicate Handling Options
| Strategy | Behavior |
|---|---|
skip | Skip rows that match existing records |
update | Update existing records with new data |
create | Always create new records (allows duplicates) |
Merge Modes (for update strategy)
| Mode | Behavior |
|---|---|
fill_empty | Only update fields that are empty on the existing record |
overwrite | Replace all fields with import values (including nulls) |
prefer_import | Update with import values, but keep existing if import is empty |
Response
{
"success": true,
"data": {
"importJobId": "job_abc123",
"status": "completed",
"processingMode": "sync",
"successRows": 1498,
"errorRows": 2,
"skippedRows": 50,
"createdRecordIds": ["rec_1", "rec_2", "..."],
"errors": [
{
"row": 156,
"error": "Duplicate email found"
}
],
"referenceWarnings": [
{
"fieldSlug": "account",
"fieldLabel": "Account",
"unresolvedValues": ["Unknown Company"],
"targetModuleSlug": "accounts"
}
]
}
}Processing Modes
Imports automatically select a processing mode based on row count:
| Rows | Mode | Behavior |
|---|---|---|
| Up to 5,000 | sync | Processes immediately, returns when complete |
| 5,001 - 50,000 | stream | Processes with progress updates |
| 50,000+ | background | Returns immediately, poll for status |
For large imports, use the job status endpoint to poll for completion.
Import Job Status
Get the status and progress of an import job.
curl -X GET "https://api.getcoherence.io/v1/modules/contacts/import/jobs/job_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"success": true,
"data": {
"importJobId": "job_abc123",
"accountId": "acc_xyz",
"moduleId": "mod_contacts",
"status": "processing",
"processingMode": "background",
"fileName": "contacts.csv",
"fileType": "csv",
"totalRows": 75000,
"processedRows": 45000,
"successRows": 44950,
"errorRows": 50,
"skippedRows": 0,
"aiMappingUsed": true,
"duplicateStrategy": "skip",
"createdDateTime": "2024-01-15T10:30:00Z",
"startedDateTime": "2024-01-15T10:30:01Z",
"completedDateTime": null,
"expiresDateTime": "2024-01-22T10:30:00Z"
}
}Job Status Values
| Status | Description |
|---|---|
pending | Job created, waiting to start |
processing | Import in progress |
completed | Import finished successfully |
failed | Import failed with errors |
cancelled | Import was rolled back |
List Import History
Get a list of past imports for a module.
curl -X GET "https://api.getcoherence.io/v1/modules/contacts/import/jobs?limit=25" \
-H "Authorization: Bearer YOUR_API_KEY"Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Maximum jobs to return (1-100) |
Rollback Import
Undo an import by deleting all created records.
curl -X DELETE "https://api.getcoherence.io/v1/modules/contacts/import/jobs/job_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"success": true,
"data": {
"deletedCount": 1498
}
}Rollback permanently deletes all records created by the import. This cannot be undone.
Export Overview
Export records from any module to CSV or PDF format. Exports can be performed synchronously for small datasets or asynchronously for large exports.
Export Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /modules/{module}/export | Export module records |
| POST | /reports/{reportId}/export | Export report results |
| GET | /export-jobs | List export jobs |
| GET | /export-jobs/{exportJobId} | Get export job status |
Export Module Records
Export records from a module to CSV or PDF.
curl -X POST "https://api.getcoherence.io/v1/modules/contacts/export" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"format": "csv",
"config": {
"columns": ["displayName", "email", "phone", "createdDateTime"],
"includeHeaders": true,
"sortField": "createdDateTime",
"sortDirection": "desc",
"limit": 1000
}
}' \
--output contacts-export.csvRequest Body
{
format: "csv" | "pdf";
config?: {
columns?: string[]; // Fields to include (default: name, owner, dates)
columnLabels?: Record<string, string>; // Custom header labels
includeHeaders?: boolean; // Include header row (default: true)
dateFormat?: string; // Date format string
title?: string; // PDF title
description?: string; // PDF description
sortField?: string; // Field to sort by
sortDirection?: "asc" | "desc"; // Sort order
limit?: number; // Maximum records (up to 100,000)
}
}Export Formats
| Format | Content-Type | Description |
|---|---|---|
csv | text/csv | Comma-separated values, UTF-8 encoded |
pdf | application/pdf | Formatted table with headers and pagination |
Response
For immediate exports, the response is the file content with appropriate headers:
Content-Type: text/csv; charset=utf-8
Content-Disposition: attachment; filename="contacts-export-2024-01-15.csv"
Export Report Results
Export the results of a saved report.
curl -X POST "https://api.getcoherence.io/v1/reports/rpt_abc123/export" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"format": "pdf",
"config": {
"title": "Q4 Sales Report",
"description": "Generated for quarterly review"
}
}' \
--output sales-report.pdfExport Jobs
For large exports, create an async export job.
List Export Jobs
curl -X GET "https://api.getcoherence.io/v1/export-jobs?limit=25" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"jobs": [
{
"exportJobId": "exp_abc123",
"accountId": "acc_xyz",
"sourceId": "mod_contacts",
"sourceType": "module",
"format": "csv",
"status": "completed",
"progress": 100,
"fileName": "contacts-export-2024-01-15.csv",
"fileUrl": "https://storage.getcoherence.io/exports/exp_abc123.csv",
"fileSizeBytes": 1048576,
"contentType": "text/csv",
"requestedDateTime": "2024-01-15T10:30:00Z",
"completedDateTime": "2024-01-15T10:32:00Z",
"expiresDateTime": "2024-01-16T10:30:00Z"
}
]
}Get Export Job Status
curl -X GET "https://api.getcoherence.io/v1/export-jobs/exp_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"Export files are available for 24 hours after completion. Download or save them before expiration.
Best Practices
Batch Size Recommendations
| Operation | Recommended Size | Notes |
|---|---|---|
| Import (sync) | Up to 5,000 rows | Fastest for small datasets |
| Import (streaming) | 5,000-50,000 rows | Progress updates available |
| Import (background) | 50,000+ rows | Poll for completion |
| Export (direct) | Up to 10,000 records | Immediate download |
| Export (async) | 10,000+ records | Use export jobs |
Error Handling
Always validate before executing:
// 1. Parse the file
const parseResult = await api.post(`/modules/${module}/import/parse`, file);
// 2. Get mapping suggestions
const mappings = await api.post(`/modules/${module}/import/suggest-mapping`, {
sourceColumns: parseResult.data.sourceColumns,
sampleData: parseResult.data.sampleRows.slice(0, 5)
});
// 3. Validate with mappings
const validation = await api.post(`/modules/${module}/import/validate`, {
rows: allRows,
columnMapping: mappings.data.suggestions
});
// 4. Check validation results
if (!validation.data.isValid) {
console.error("Validation errors:", validation.data.errors);
return;
}
// 5. Execute import
const result = await api.post(`/modules/${module}/import/execute`, {
rows: allRows,
columnMapping: mappings.data.suggestions,
duplicateStrategy: "update",
duplicateMatchFields: ["email"]
});Progress Tracking for Large Imports
async function importWithProgress(module: string, rows: object[], mapping: object[]) {
// Start the import
const result = await api.post(`/modules/${module}/import/execute`, {
rows,
columnMapping: mapping
});
// For background imports, poll for status
if (result.data.processingMode === "background") {
const jobId = result.data.importJobId;
while (true) {
const status = await api.get(`/modules/${module}/import/jobs/${jobId}`);
const progress = Math.round(
(status.data.processedRows / status.data.totalRows) * 100
);
console.log(`Import progress: ${progress}%`);
if (status.data.status === "completed" || status.data.status === "failed") {
return status.data;
}
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
return result.data;
}Handling Reference Fields
When importing data with references to other modules:
{
"columnMapping": [
{
"sourceColumn": "Company Name",
"targetFieldSlug": "account"
}
],
"createMissingReferences": true
}With createMissingReferences: true, new records are automatically created in the referenced module if no match is found.
Multi-Value Fields
Map multiple columns to the same multi-value field:
{
"columnMapping": [
{
"sourceColumn": "Mobile Phone",
"targetFieldSlug": "phone",
"valueType": "Mobile"
},
{
"sourceColumn": "Work Phone",
"targetFieldSlug": "phone",
"valueType": "Work"
}
]
}Address Fields
Map address components separately:
{
"columnMapping": [
{
"sourceColumn": "Street Address",
"targetFieldSlug": "address",
"addressPart": "street"
},
{
"sourceColumn": "City",
"targetFieldSlug": "address",
"addressPart": "city"
},
{
"sourceColumn": "State",
"targetFieldSlug": "address",
"addressPart": "state"
},
{
"sourceColumn": "Postal Code",
"targetFieldSlug": "address",
"addressPart": "zip"
}
]
}Error Codes
| Code | Message | Solution |
|---|---|---|
| 400 | No file uploaded | Include file in multipart request |
| 400 | Unsupported file type | Use CSV or Excel format |
| 400 | File too large | Split file into smaller batches |
| 404 | Module not found | Check module slug is correct |
| 404 | Import job not found | Verify job ID exists |
| 403 | Access denied | Check user has import permission |
Related: API Overview | Authentication