BitelioBitelio

Importing contacts from CSV

Load contacts in bulk — with their custom fields — from a CSV file, via the dashboard or the API

When streaming contacts one by one through /v1/track isn't practical — migrating off another platform, seeding a fresh list, syncing a big batch — Bitelio lets you import them in bulk from a CSV file.

CSV format

Your file needs a header row, and email is the only column that must be present. Any additional column is stored on the contact as a custom field at data.<columnName>.

A minimal file:

email
ada@example.com
grace@example.com
linus@example.com

A richer file with custom fields:

email,firstName,plan,signupDate
ada@example.com,Ada,pro,2026-01-15T00:00:00Z
grace@example.com,Grace,enterprise,2025-11-02T00:00:00Z
linus@example.com,Linus,free,2026-04-21T00:00:00Z

With this file, each imported contact gets data.firstName, data.plan, and data.signupDate.

Rules and limits

  • File size: 5 MB maximum per upload. Bigger lists should be split across several imports.
  • Encoding: UTF-8. Files in other encodings risk mangled custom field values.
  • Email column: required and validated. Any row whose email is absent or malformed comes back in the error report.
  • Reserved column names: id, subscribed, createdAt, updatedAt, and the auto-generated URL variables (unsubscribeUrl, etc.) are dropped silently — leave them out of your file.
  • Date columns: format them as ISO 8601 (2026-05-06T12:00:00Z) so Bitelio types them as dates, unlocking the within / olderThan segment operators.
  • Boolean columns: values of true, false, yes, no (any casing) become booleans and show up as a boolean toggle in segment filters.
  • Numeric columns: bare integers and decimals (42, 3.14) become numbers, usable with gt / lt segment operators. Values with leading zeros (01234), a + prefix, or scientific notation are kept as strings — this protects IDs, zip codes, and phone numbers from corruption.
  • Existing contacts: when a row's email already belongs to a contact, that contact is updated — the CSV's columns are merged into its data. No duplicate is created and the rest of the record is left intact.

Importing your CSV

  1. Go to Contacts and hit Import.
  2. Select the CSV. Bitelio checks the header and previews the first few rows for you.
  3. Confirm — the import is queued and processed in the background.
  4. Once done, the Imports page shows the outcome, including any row-level errors.

For automation, use the import API:

Step 1 — upload the CSV

curl -X POST https://api.bitelio.com/contacts/import \
  -H "Authorization: Bearer sk_..." \
  -F "file=@contacts.csv"

The response includes a jobId:

{ "jobId": "imp_abc123", "status": "queued" }

Step 2 — poll for status

curl https://api.bitelio.com/contacts/import/imp_abc123 \
  -H "Authorization: Bearer sk_..."

Keep polling at a few-second interval until status reads completed or failed. The final response carries the counts:

{
  "jobId": "imp_abc123",
  "status": "completed",
  "totalRows": 12000,
  "imported": 11985,
  "updated": 8,
  "skipped": 0,
  "errors": [
    { "row": 47,   "email": "bad@",      "reason": "invalid_email" },
    { "row": 1042, "email": "@example",  "reason": "invalid_email" }
  ]
}

imported is the number of contacts created from scratch, while updated counts existing ones whose data was patched. Each entry in errors gives you the row number and the reason, so problem rows can be corrected and re-uploaded.

Tips

  • Unsubscribed contacts: every imported contact starts out subscribed. If the CSV contains people who never opted in, either set up a workflow that filters out anyone you shouldn't be emailing, or import first and then run POST /contacts/bulk-unsubscribe so they stay on record without being mailable.
  • Custom fields appear in segments immediately: the moment the import completes, dynamic segments can filter on any of the imported columns.
  • Idempotent reruns: uploading the same CSV again updates contacts in place instead of duplicating them — so after fixing a column, a re-upload pushes the corrected value to every matching row.
  • Custom fields — how the data.<column> fields you import are typed and used.
  • Bulk operationsbulk-subscribe, bulk-unsubscribe, bulk-delete for mass actions on existing contacts (max 1,000 per call).