Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Data Import

Import records from CSV files with column mapping, duplicate handling, and progress tracking.

  1. Request upload URL — get a signed URL for your CSV file
  2. Upload file — PUT your CSV to the signed URL
  3. Complete upload — trigger processing and get a preview
  4. Confirm import — provide column mapping and start the import
  5. Monitor progress — poll the import job status

Endpoint: imports-request-upload

FieldTypeRequiredDescription
model_typestringYescontacts, companies, or sources
file_namestringYesOriginal filename
content_typestringYesMIME type (e.g., text/csv)
Terminal window
curl -X POST https://api.driftwoodapp.com/api/imports-request-upload \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model_type": "contacts",
"file_name": "leads.csv",
"content_type": "text/csv"
}'

Response:

{
"ok": true,
"result": {
"job_id": "990e8400-...",
"signed_url": "https://storage.googleapis.com/..."
}
}

Upload your CSV directly to the signed URL using a PUT request:

Terminal window
curl -X PUT "SIGNED_URL_FROM_STEP_1" \
-H "Content-Type: text/csv" \
--data-binary @leads.csv

Endpoint: imports-complete-upload

FieldTypeRequiredDescription
iduuidYesJob ID from step 1

Response includes a preview:

{
"ok": true,
"result": {
"job": { "id": "...", "status": "uploaded" },
"preview": {
"headers": ["Name", "Email", "Phone", "Company"],
"sample_rows": [
["Jane Smith", "jane@example.com", "+1-555-0100", "Acme Corp"]
],
"total_rows": 1500,
"suggested_mapping": {
"Name": "first_name",
"Email": "email",
"Phone": "phone",
"Company": "company_name"
},
"available_fields": [
{"value": "first_name", "label": "First Name"},
{"value": "last_name", "label": "Last Name"},
{"value": "email", "label": "Email"}
]
}
}
}

Endpoint: imports-confirm

FieldTypeRequiredDescription
iduuidYesJob ID
column_mappingobjectYesMap CSV columns to fields
duplicate_strategystringNoskip, merge, or overwrite (default: skip)
tag_delimiterstringNoDelimiter for tag columns (e.g., , or ;)
Terminal window
curl -X POST https://api.driftwoodapp.com/api/imports-confirm \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "990e8400-...",
"column_mapping": {
"Name": "first_name",
"Email": "email",
"Phone": "phone"
},
"duplicate_strategy": "merge"
}'

Endpoint: imports-get

FieldTypeRequiredDescription
iduuidYesJob ID

Response:

{
"ok": true,
"result": {
"id": "990e8400-...",
"status": "processing",
"total_rows": 1500,
"processed_rows": 750,
"created_count": 600,
"updated_count": 100,
"skipped_count": 45,
"failed_count": 5
}
}
StatusDescription
pendingJob created, file not yet uploaded
uploadedFile uploaded, awaiting confirmation
processingImport in progress
completedImport finished
failedImport failed

Endpoint: imports-errors

FieldTypeRequiredDescription
iduuidYesJob ID
cursorstringNoPagination cursor
limitintegerNoResults per page

Endpoint: imports-list

Terminal window
curl -X POST https://api.driftwoodapp.com/api/imports-list \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
StrategyBehavior
skipSkip rows that match an existing record
mergeUpdate existing records with non-empty imported values
overwriteReplace existing records entirely with imported data