Skip to main content
POST
/
api
/
lists
/
{id}
/
companies
/
import
Preview a company CSV/XLSX import
curl --request POST \
  --url https://app.puffle.ai/api/lists/{id}/companies/import \
  --header 'Authorization: Bearer <token>'
{
  "columns": [
    "<string>"
  ],
  "auto_mapping": {},
  "preview_rows": [
    {}
  ],
  "total_rows": 4503599627370495,
  "csv_text": "<string>",
  "existing_columns": [
    "<string>"
  ]
}

Overview

The company importer is a two-step flow so the caller can review (and edit) the auto-detected column mapping before any rows are written.
StepMethodWhat it does
1POST /api/lists/{id}/companies/importUpload the file, parse it, auto-detect a column mapping, return a preview. No rows written.
2PUT /api/lists/{id}/companies/importRe-send the parsed csv_text plus the final mapping; server upserts by domain.
This page documents step 1. See updateListCompanyImport for step 2.

File formats

Accepts multipart/form-data with a single file field:
  • .csv — parsed with a quote-aware CSV reader that handles multiline quoted fields and Windows line endings.
  • .xlsx / .xls — parsed with SheetJS. Only the first sheet is read; it is also converted to CSV so step 2 can be CSV-only.
Max size is 10 MB. Files larger than that return 400 before any parsing.

Auto-detection pipeline

The detection runs in three passes, in order:
  1. Pattern matching on header names — the 13 built-in company fields (domain, name, linkedin_url, industry, employee_count, founded_year, funding_stage, location, city, state, country, website, description) are matched against a hand-curated synonym list. Exact (lowercased) hits win.
  2. LLM fallback — any built-in field still unmapped is handed to an OpenRouter model (csvColumnMapping) with the unmatched headers plus 3 sample rows. Used only when OPENROUTER_API_KEY is set.
  3. Custom columns — any header that didn’t match a built-in field becomes either column:<name> (if it matches an existing company-subject column on the list) or new:<name> (to be created at confirm time).
The returned auto_mapping is a flat target → source map — edit it client-side before calling step 2.

AI agent notes

Nothing is persisted in step 1. Calling POST without a follow-up PUT is a no-op as far as the list is concerned. Safe to call repeatedly to refine the mapping.csv_text round-trip. The csv_text returned by step 1 must be passed back verbatim to step 2. XLSX files are normalized to CSV in step 1 so the PUT handler never needs to touch a binary.Mapping edits. The mapping returned here is advisory. You can drop built-in field keys, swap source columns, or change new:column: before the confirm. Unknown fields in the mapping object are ignored by step 2.Blocklist applies at step 2, not here. skipExistingCustomers is a PUT-only flag. Expect the preview row count to be higher than the eventual imported + updated count.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Path Parameters

id
string<uuid>
required

List UUID

Pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$

Response

Import preview with detected column mapping.

Column-mapping preview for a CSV/XLSX company import.

columns
string[]
required

Header names extracted from the uploaded file.

auto_mapping
object
required

Detected mapping from target company field → source column name. Keys include the 13 built-in fields (domain, name, linkedin_url, industry, employee_count, founded_year, funding_stage, location, city, state, country, website, description), plus custom-column keys prefixed with new: (new column to create) or column: (match to an existing custom column). Unmapped fields are null.

preview_rows
object[]
required

First five rows of the parsed file for preview.

total_rows
integer
required

Number of non-empty data rows detected in the file.

Required range: 0 <= x <= 9007199254740991
csv_text
string
required

Normalized CSV string. XLSX/XLS uploads are converted here so the PUT confirm step can be CSV-only.

existing_columns
string[]
required

Names of existing company-subject columns already on this list, used by the confirm step to dedupe custom-column creation.