Skip to main content

Bulk Importing Conversations

Import many conversations at once from a single .zip archive. Use Bulk Import when you already have structured JSON chats, plain-text transcripts, and/or audio or video recordings prepared as a package — Harmony creates the conversations in the background and gives you a downloadable result report.

Bulk import (and the related Import tab) appears only when chat import is enabled for your workspace. If you only see Transcript and Recording, ask your admin whether chat import is available.

Bulk Import is driven entirely by a root manifest in the ZIP. Unlike single uploads, the dialog does not ask for Team, Contact, Owner, Medium, or Custom Fields — those values come from the manifest.

Open the upload dialog

  1. In the sidebar, go to Meetings.
  2. Open the upload dialog from any of these places:
    • The Upload option in the Quick Launch panel on the Start tab.
    • The Add Conversation action in the toolbar.
    • The global command palette (Cmd/Ctrl+K) — pick the Upload tile.

The dialog title is Upload recording. When chat import is enabled, the top tabs are Transcript, Recording, Import, and Bulk import.

Prepare your ZIP

Your archive must contain exactly one root manifest named manifest.json or manifest.csv (not both). Conversation files can sit in folders next to that manifest.

Paths inside the ZIP use forward slashes, must not contain .., and must not be absolute. Matching is case-insensitive. Every supported conversation file in the archive (.json, .txt, or a supported media file) must be listed in the manifest — unlisted files are rejected. Harmony ignores macOS junk such as .DS_Store and __MACOSX/.

Download a ready-made sample ZIP with a manifest.csv, two chat JSON files, a text transcript, and an audio recording: bulk-import-sample.zip.

The manifest uses placeholder IDs (999001, 999002, 999003) and is not upload-ready until you replace owner_id, contact_id, and team_id with values from your workspace.

A complete package can mix JSON chats, plain-text transcripts, and recordings in one archive:

manifest.csv
chats/sales-chat-001.json
chats/support-ticket-001.json
recordings/smalltalk0301.mp3
transcripts/customer-note-001.txt

Manifest fields

Use snake_case field names only (owner_id, not ownerId). For a JSON manifest, the root must be an object with a conversations array — a bare top-level array is invalid. For CSV, use the same fields as columns; empty cells are omitted; headers must be unique and non-empty; numeric IDs must be positive integers.

For each conversation you will provide:

  • source_path (required) — a unique key for this conversation in the batch (max 512 characters). Used for titles, reports, and resume identity. It does not have to match a file path on disk.
  • owner_id (required) — the Harmony user who will own the conversation.
  • contact_id (required) — the external contact linked to the conversation.
  • team_id (optional) — the workspace team. If omitted, Harmony uses the owner’s default team (or first assigned team). If the owner has no team, that item fails.
  • medium (required) — call, video, or chat.
  • Exactly one file reference (required): json_file, transcript_file, or recording_file — the path to the file inside the ZIP.
  • title (optional) — non-empty string, max 500 characters. If omitted, Harmony derives a title from the source_path basename.
  • created_at (optional) — a timestamp string (ISO-8601 recommended, for example 2026-03-01T15:30:00Z).
  • custom_fields (optional) — custom attribute values for your workspace. In CSV, this column must be a JSON object string, for example "{""region"":""EMEA""}".

Setting owner_id to someone other than yourself requires permission to create conversations for other owners. Setting team_id to a team you do not belong to requires broader create access. Without that access, those rows fail with messages such as "Per-conversation owner_id requires permission to import for another owner" or "You can only import conversations for teams you belong to."

Do not set the reserved custom field harmonyImportSource. Harmony stamps bulk imports as bulk_import_zip.

JSON conversations

Point json_file at a .json file (max 10 MB). The object must include at least one of: raw, transcript, structuredMessages, conversationTurns, or turns. You may include extractedData.participants when available.

Example conversation file:

{
"conversationTurns": [
{ "speaker": "Alex", "text": "Thanks for calling support." },
{ "speaker": "Sam", "text": "I need help with my order." }
]
}

Text transcripts

Point transcript_file at a .txt file in UTF-8. Maximum 25 MB per file.

Audio and video recordings

Point recording_file at a supported media file — including AAC, AMR, FLAC, M4A, MP3, MP4, MOV, OGG, Opus, WAV, and WebM. The manifest still requires an explicit medium (call, video, or chat).

Package size limits

  • Compressed ZIP: 500 MB
  • Total uncompressed size: 500 MB
  • Files / ZIP entries: 500
  • Conversations per import: 200
  • Concurrent imports: up to 3 per user and 10 per organization

Reports and staged archives are kept for about 30 days.

manifest.json example

The sample package uses manifest.csv, but the same conversations can be expressed as JSON:

{
"conversations": [
{
"source_path": "chats/support-ticket-001",
"title": "Support Ticket 001",
"medium": "chat",
"json_file": "chats/support-ticket-001.json",
"owner_id": 999001,
"contact_id": 999002,
"team_id": 999003
},
{
"source_path": "chats/sales-chat-001",
"title": "Sales Chat 001",
"medium": "chat",
"json_file": "chats/sales-chat-001.json",
"owner_id": 999001,
"contact_id": 999002,
"team_id": 999003
},
{
"source_path": "transcripts/customer-note-001",
"title": "Customer Note 001",
"medium": "chat",
"transcript_file": "transcripts/customer-note-001.txt",
"owner_id": 999001,
"contact_id": 999002,
"team_id": 999003
},
{
"source_path": "recordings/smalltalk0301",
"title": "Small Talk 0301",
"medium": "call",
"recording_file": "recordings/smalltalk0301.mp3",
"owner_id": 999001,
"contact_id": 999002,
"team_id": 999003
}
]
}

Replace the sample IDs with real owner_id, contact_id, and team_id values from your workspace.

manifest.csv example

The downloadable sample includes the required columns below. Optional created_at and custom_fields columns are shown here for completeness:

source_path,title,medium,json_file,transcript_file,recording_file,owner_id,contact_id,team_id,created_at,custom_fields
chats/support-ticket-001,Support Ticket 001,chat,chats/support-ticket-001.json,,,999001,999002,999003,2026-01-15T14:00:00Z,"{""ticketId"":""SUP-001"",""priority"":""medium""}"
chats/sales-chat-001,Sales Chat 001,chat,chats/sales-chat-001.json,,,999001,999002,999003,2026-01-16T09:30:00Z,"{""dealStage"":""evaluation"",""estimatedSeats"":25}"
transcripts/customer-note-001,Customer Note 001,chat,,transcripts/customer-note-001.txt,,999001,999002,999003,2026-01-17T10:00:00Z,
recordings/smalltalk0301,Small Talk 0301,call,,,recordings/smalltalk0301.mp3,999001,999002,999003,2026-03-01T15:30:00Z,

Upload a bulk package

  1. In the upload dialog, select the Bulk import tab.
  2. Under Bulk conversations (.zip), click the upload area or drag and drop your archive. The area reads "Click to upload or drag and drop" with the hint "Structured JSON, text, or media files in a .zip".
  3. Once a file is selected, you'll see "Selected: [filename]".
  4. Click Upload.

Large archives use multipart upload, with the same style of progress indicators as recording upload ("Preparing upload…", "Uploading…", and related status strings). When the archive is staged, the dialog closes and a toast confirms Bulk import started"Your conversations will appear as processing completes."

If the package is saved but not yet queued, you may see Bulk import saved but not queued, with a hint to resume later.

You do not fill Team, Contact, Owner, Medium, or Custom Fields in the dialog for Bulk import. Those values must come from the manifest.

After uploading

Harmony validates the archive, then creates conversations asynchronously. Progress and results appear as in-app toasts — Harmony does not send an email or OS notification. If you refresh the page, pending imports for the same browser session, organization, and user keep polling.

If you switch workspaces, toasts and actions apply to the active workspace. Switch back to the original workspace to resume an import or download its report.

Result toasts

ToastMeaning
Bulk import completeEvery conversation item succeeded
Bulk import completed with issuesFinished, but some items failed, need review, or remained pending
FailedThe archive or import failed as a whole
InterruptedProcessing stopped with work that can still be resumed

Toast bodies summarize counts, for example: "Created X conversation(s). Y failed, Z need review, and W remain pending." Sample failures may appear in the toast; use the report for the full detail.

Download the report

From the result toast, choose Download JSON or Download CSV. Files are named like bulk-conversation-import-{importId}.json or .csv.

Each report includes batch totals and one row (or item) per conversation with:

  • source_path, kind, and item_status (pending, processing, succeeded, failed, or needs_review)
  • conversation_id when a conversation was created
  • item_code / item_error when something failed

Reports remain available for about 30 days.

Resume an interrupted import

If an import is interrupted and still resumable, the toast includes Resume along with the download actions.

  1. Stay in (or switch back to) the workspace where you started the import.
  2. Click Resume on the interrupted-import toast.

You should see Bulk import resumed"Processing will continue for the remaining conversations."

Resume continues pending items only. Conversations that already succeeded are not created again. If the staged archive has expired (about 30 days), resume fails and you need to upload a new package.

Failed imports that are not marked interrupted cannot be resumed with this button — fix the package and upload again.

Items that need review

needs_review means the outcome was ambiguous — for example, a conversation may already exist (conversation_id is set in the report) but success was not recorded cleanly. A typical message is: "Conversation was created, but the import could not record success automatically."

Resume does not reprocess items that need review. Open the conversation from the report and verify it manually.

Troubleshooting

I don’t see Bulk import. Chat import must be enabled for your workspace. If you only see Transcript and Recording, ask your admin whether Import / Bulk import are available.

Upload rejected before processing. Confirm the file is a .zip under the package size limits, contains exactly one root manifest.json or manifest.csv, and lists every conversation file. Non-ZIP uploads show "Only .zip bulk conversation imports are allowed."

Missing or conflicting manifest. The archive needs exactly one root manifest. Both manifest.json and manifest.csv, or neither, is rejected.

Invalid owner, contact, team, or medium. IDs must exist in your workspace, medium must be call, video, or chat, and you need permission for any owner/team overrides. Field names must be snake_case.

Unlisted or missing files. Every .json, .txt, and media conversation file in the ZIP must be referenced by the manifest, and every *_file path must exist inside the archive.

Some conversations never appear. Download the CSV or JSON report and check failed or needs_review rows. Fix IDs, paths, or file types, then upload a corrected ZIP for the remaining items — or click Resume if the batch is interrupted with pending work.

I switched workspace and lost the toast. Switch back to the workspace where you started the import; Resume and Download actions are scoped to the active workspace.

Encrypted or unsafe ZIP. Harmony rejects encrypted archives and unsafe paths (absolute paths or .. traversal). Re-export a normal, unencrypted ZIP with relative paths.

Too many concurrent imports. Wait for an active import to finish. Harmony allows up to 3 active imports per user and 10 per organization.

For single-conversation uploads (file, URL, or pasted transcript), see Uploading meetings manually.