Skip to main content

Importing Data

The Import API allows you to bulk import data from CSV files into Terros. Imports are asynchronous — you initiate an import, upload a file, then poll for status until processing completes.

Supported Entity Types

You can import the following entity types:

  • Account — customer accounts
  • Contact — contacts associated with accounts
  • CalendarEvent — calendar events
  • User — users in your organization
  • Task — tasks assigned to users
  • Recruit — recruit records

Import Flow

Importing data is a three-step process:

Step 1: Initiate the Import

Call Add Import to create an import job. The response includes a pre-signed S3 URL for uploading your CSV file.

curl -X POST "https://api.terros.com/import/add" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $TERROS_API_KEY" \
-d '{
"entity": "Account",
"name": "Q1 Account Import"
}'

Response:

{
"type": "success",
"url": "https://s3.amazonaws.com/terros-imports/imports/Import:abc123/upload.csv?X-Amz-Signature=...",
"importData": {
"importId": "Import:abc123",
"entity": "Account",
"name": "Q1 Account Import",
"importStatus": "New"
}
}

Save the importId from the response — you will need it to check status and fetch errors.

Step 2: Upload the CSV File

Upload your CSV file to the pre-signed URL returned in Step 1 using a PUT request. The upload URL is valid for 1 hour — you do not need to construct the path yourself, just upload directly to the URL returned by the API.

curl -X PUT \
-H "Content-Type: text/csv" \
--data-binary @accounts.csv \
"https://s3.amazonaws.com/terros-imports/imports/Import:abc123/upload.csv?X-Amz-Signature=..."

Once the file is uploaded, processing begins automatically. The import transitions through these statuses:

StatusDescription
NewImport created, waiting for file upload
UploadedFile received, queuing records
QueuedRecords enqueued for processing
ProcessingRecords are being processed
PostProcessingFinalizing results
CompletedImport finished successfully
FailedImport failed — check reason field for details

Step 3: Poll for Status

Call Get Import to check the current status of your import:

curl -X POST "https://api.terros.com/import/get" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $TERROS_API_KEY" \
-d '{ "importId": "Import:abc123" }'

Response:

{
"type": "success",
"log": {
"importId": "Import:abc123",
"entity": "Account",
"importStatus": "Completed",
"successes": 150,
"errors": 3,
"totalMessages": 153,
"completedAt": 1772665914046
}
}

Poll until importStatus is Completed or Failed. We recommend using exponential backoff (e.g. 5s, 10s, 20s, 40s) to avoid unnecessary requests for larger imports that take longer to process.

Fetching Errors

If the import has errors (errors > 0), call Get Import Errors to download the error details:

curl -X POST "https://api.terros.com/import/errors" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $TERROS_API_KEY" \
-d '{ "importId": "Import:abc123" }'

Response:

{
"type": "success",
"records": [
{
"key": "imports/Import:abc123/errors/row-42.json",
"signedUrl": "https://s3.amazonaws.com/terros-imports/errors/row-42.json?X-Amz-Signature=..."
}
]
}

Each record contains a signedUrl — a temporary download link for the error file, valid for 12 hours. Download these files to see which rows failed and why.

Import Options

When initiating an import, you can pass these optional fields:

FieldTypeDefaultApplies ToDescription
entitystringAllRequired. The entity type to import
namestringAllA friendly name for the import
disableGeocodingbooleanfalseAccount, CalendarEvent, Contact, RecruitSkip location resolution for addresses
addMissingUsersbooleanfalseAccount, Contact, Recruit, UserAutomatically create users if they don't exist
createCustomLocationsbooleanfalseAccount, CalendarEvent, Contact, RecruitCreate locations for new addresses
notifyUsersbooleanfalseUserSend welcome emails to newly imported users
workflowIdstringAccountWorkflow to apply to imported records
columnMappingobjectAllMaps CSV column names to the expected header names the parser should read them as

Listing Imports

Call List Imports to see all imports for your company:

curl -X POST "https://api.terros.com/import/list" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $TERROS_API_KEY" \
-d '{}'

Cleanup

After an import completes, you can call Cleanup Import to remove temporary data. Do not invoke cleanup while an import is still in progress — wait until the status reaches Completed or Failed.

curl -X POST "https://api.terros.com/import/cleanup" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey $TERROS_API_KEY" \
-d '{ "importId": "Import:abc123" }'