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:

  1. Upload - Parse the file and get a preview of the data
  2. Map - Map source columns to module fields (with optional AI suggestions)
  3. Validate - Check data for errors before importing
  4. Execute - Run the import with configurable duplicate handling

This approach allows you to review and adjust mappings before committing any changes.

Import Endpoints

MethodEndpointDescription
POST/modules/{module}/import/parseUpload and parse file
POST/modules/{module}/import/suggest-mappingGet AI mapping suggestions
POST/modules/{module}/import/validateValidate mapped data
POST/modules/{module}/import/executeExecute the import
GET/modules/{module}/import/jobsList 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

FormatMIME TypeExtensions
CSVtext/csv, text/plain.csv
Excelapplication/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

StrategyBehavior
skipSkip rows that match existing records
updateUpdate existing records with new data
createAlways create new records (allows duplicates)

Merge Modes (for update strategy)

ModeBehavior
fill_emptyOnly update fields that are empty on the existing record
overwriteReplace all fields with import values (including nulls)
prefer_importUpdate 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:

RowsModeBehavior
Up to 5,000syncProcesses immediately, returns when complete
5,001 - 50,000streamProcesses with progress updates
50,000+backgroundReturns 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

StatusDescription
pendingJob created, waiting to start
processingImport in progress
completedImport finished successfully
failedImport failed with errors
cancelledImport 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

ParameterTypeDefaultDescription
limitnumber50Maximum 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

MethodEndpointDescription
POST/modules/{module}/exportExport module records
POST/reports/{reportId}/exportExport report results
GET/export-jobsList 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.csv

Request 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

FormatContent-TypeDescription
csvtext/csvComma-separated values, UTF-8 encoded
pdfapplication/pdfFormatted 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.pdf

Export 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

OperationRecommended SizeNotes
Import (sync)Up to 5,000 rowsFastest for small datasets
Import (streaming)5,000-50,000 rowsProgress updates available
Import (background)50,000+ rowsPoll for completion
Export (direct)Up to 10,000 recordsImmediate download
Export (async)10,000+ recordsUse 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

CodeMessageSolution
400No file uploadedInclude file in multipart request
400Unsupported file typeUse CSV or Excel format
400File too largeSplit file into smaller batches
404Module not foundCheck module slug is correct
404Import job not foundVerify job ID exists
403Access deniedCheck user has import permission

Related: API Overview | Authentication