Import/Export API

Import records from CSV files, export records, and track progress via real-time subscriptions.


Overview

The Import/Export API lets you bulk-import records from CSV files into a workspace, export records as CSV, and download pre-formatted CSV templates. Long-running import and export operations publish real-time progress through the subscribeToImportExportProgress subscription.

Available Operations

OperationDescriptionLink
Import RecordsBulk-import records from a CSV fileSee below
Cancel ImportCancel an in-progress importSee below
Export RecordsExport workspace records to CSVView Details →
Export CSV TemplateDownload a blank CSV template with workspace columnsView Details →

Import Records

The importTodos mutation bulk-imports records into a workspace from a CSV file that has already been uploaded to storage. The CSV is parsed in streaming chunks and records are created inside a database transaction. Progress is broadcast in real time through the subscribeToImportExportProgress subscription.

Basic Example

mutation ImportRecords {
  importTodos(
    input: {
      s3Key: "uploads/org-slug/workspace-slug/import-file.csv"
      headers: ["Title", "List", "Done", "Due Date", "Description", "Assignees", "Tags"]
      projectId: "clm4n8qwx000008l0g4oxdqn7"
    }
  )
}

Advanced Example

Import records using the optimized Rust-based importer:

mutation ImportRecordsAdvanced {
  importTodos(
    input: {
      s3Key: "uploads/org-slug/workspace-slug/import-file.csv"
      headers: [
        "Title",
        "List",
        "Done",
        "Start Date",
        "Due Date",
        "Description",
        "Assignees",
        "Created At",
        "Updated At",
        "Created By",
        "Color",
        "Project",
        "Tags",
        "Budget",
        "Priority"
      ]
      projectId: "clm4n8qwx000008l0g4oxdqn7"
      useRustImport: true
    }
  )
}

Input Parameters

ImportTodosInput

ParameterTypeRequiredDescription
s3KeyString!YesThe storage key of the uploaded CSV file
headersJSON!YesAn ordered array of column header names that maps CSV columns to record fields
projectIdString!YesID of the workspace to import records into
useRustImportBooleanNoUse the optimized Rust-based import pipeline (recommended for large files)

Recognized Header Values

The headers array tells the importer how to interpret each CSV column. The following header names are recognized:

HeaderDescription
TitleRecord title (recommended)
ListName of the list to place the record in (created if it does not exist)
DoneCompletion status (true / false)
Start DateStart date of the record
Due DateDue date of the record
DescriptionRecord description
AssigneesComma-separated assignee names or emails
Created AtOriginal creation timestamp
Updated AtOriginal last-updated timestamp
Created ByOriginal creator name or email
ColorRecord color
ProjectWorkspace name
TagsComma-separated tag names (created if they do not exist)
Custom field nameAny other header is matched to a custom field by name

Response Fields

FieldTypeDescription
importTodosBoolean!Returns true when the import has been accepted and is processing

Tracking Import Progress

Subscribe to real-time progress updates while an import is running:

subscription TrackImportProgress {
  subscribeToImportExportProgress(
    projectId: "clm4n8qwx000008l0g4oxdqn7"
    userId: "user_123"
  )
}

The subscription returns a JSON payload with the following shape:

FieldTypeDescription
typeString"IMPORT" or "EXPORT"
userIdStringID of the user who initiated the operation
usernameStringFirst name of the user
projectIdStringWorkspace slug
projectNameStringWorkspace name
statusStringIN_PROGRESS, COMPLETE, CANCELLED, or ERROR
progressFloatPercentage complete (0 - 100)
errorStringError message (only present when status is ERROR)

Cancel Import

The cancelTodoImport mutation cancels an import that is currently in progress.

Basic Example

mutation CancelImport {
  cancelTodoImport(projectId: "clm4n8qwx000008l0g4oxdqn7")
}

Input Parameters

ParameterTypeRequiredDescription
projectIdString!YesID or slug of the workspace whose import should be cancelled

Response Fields

FieldTypeDescription
cancelTodoImportBoolean!Returns true when the cancellation has been recorded

Required Permissions

OperationAccess LevelNotes
importTodosMEMBER or aboveUser must have record-creation permission in the workspace
cancelTodoImportADMIN or OWNEROnly workspace administrators can cancel imports

Error Responses

ProjectNotFoundError

{
  "errors": [{
    "message": "Project was not found.",
    "extensions": {
      "code": "PROJECT_NOT_FOUND"
    }
  }]
}

When: The specified projectId does not exist or the user does not have access to it.

TodoImportLimitError

{
  "errors": [{
    "message": "You are importing too many todos.",
    "extensions": {
      "code": "TODO_IMPORT_LIMIT"
    }
  }]
}

When: The CSV contains more than 2,500 records and the organization is not on an Enterprise plan.

ImportAlreadyInProgressError

{
  "errors": [{
    "message": "Import already in progress.",
    "extensions": {
      "code": "IMPORT_ALREADY_IN_PROGRESS"
    }
  }]
}

When: An import is already running for this workspace. Only one import can run at a time per workspace.

Important Notes

  • Record Limit: Non-enterprise organizations are limited to importing 2,500 records per CSV file. Enterprise organizations have no limit.
  • One Import at a Time: Only one import can be active per workspace. Attempting a second import while one is in progress will return an error (or silently succeed if using the Rust importer).
  • List Auto-Creation: Lists referenced in the CSV that do not already exist in the workspace are created automatically.
  • Tag Auto-Creation: Tags referenced in the CSV that do not already exist are created automatically.
  • Custom Fields: Any CSV header that does not match a built-in field name is treated as a custom field and matched by name against existing custom fields in the workspace.
  • Transaction Safety: The standard importer runs inside a database transaction. If an error occurs mid-import, all changes from the current chunk are rolled back.
  • File Upload: The CSV file must be uploaded to storage before calling importTodos. Use the file upload API to obtain the s3Key.