Skip to main content
Preview. Part of the Migration API — in active design and not yet generally available. Endpoints and payloads may change. See the overview.
POST https://app.vern.so/api/v1/companies/{id}/imports
Pushes a customer’s files into the company and replays the source’s import plan to produce validated rows. The call is asynchronous: it returns a run you poll until it finishes. {id} is the company.id from provisioning.

Authentication

Requires an x-api-key header. See Authentication.

Uploading files

You have two options:
  • Signed upload (any size). Request a signed upload URL, PUT the file’s bytes to it, then pass the returned reference as upload_ref. Use this for real customer files.
  • Inline rows (small sets). Skip the upload and pass tabular data directly as rows. Convenient for small or already-parsed data.

Signed upload

A two-step handshake. First, ask for a signed URL, declaring the file’s name, type, and size:
curl -X POST https://app.vern.so/api/v1/companies/{id}/uploads \
  -H "x-api-key: $VERN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "contacts.csv", "content_type": "text/csv", "size": 184320 }'
{
  "upload_url": "https://storage.vern.so/...&token=...",
  "upload_ref": "workbook-files/.../contacts.csv"
}
Then PUT the raw bytes to upload_url with a Content-Type matching what you declared, and pass the upload_ref to the import call:
curl -X PUT "$UPLOAD_URL" -H "Content-Type: text/csv" --data-binary @contacts.csv
The signed URL is short-lived (about an hour) and single-use — request a fresh one for each file you intend to import.

Request body

files
object[]
Files to import. Each entry is { "name": "contacts.csv", "upload_ref": "..." }, where upload_ref comes from a signed upload. Provide either files or rows.
rows
object[]
Inline tabular data for small sets — an array of row objects. An alternative to files.
idempotency_key
string
A key you choose to make this import safe to retry. Re-sending the same key for the same company returns the existing run instead of starting a second one. See Errors & idempotency.

Response

201 Created
{
  "run_id": "d4c3b2a1-9f8e-47d6-b5a4-c3d2e1f0a9b8",
  "status": "queued",
  "poll_url": "/api/v1/companies/c0a8012e-4f1b-4d3a-9b2c-7e6f5a4b3c2d/imports/d4c3b2a1-9f8e-47d6-b5a4-c3d2e1f0a9b8"
}
Poll poll_url until the run reaches a terminal status. See Poll an import.

How the import behaves

Your plan was authored against a particular file shape, but real customer exports drift — renamed headers, reordered columns, stray formats. The import self-heals through that drift wherever it can, so a frozen plan survives files it didn’t see at authoring time. When rows still fail validation, the run pauses at needs_attention with a proposed fix for your approval; approving it produces a new plan version and re-runs. If you’d rather not gate on review, the surviving invalid cells are reported in the run’s report so you can download only the valid rows (see Export CSV) or fix the source data and re-import. See Poll an import for both paths.

Errors

StatusMeaning
400Neither files nor rows provided, or the payload is malformed.
401API key missing or invalid.
404No company with that {id} in your account.
409Another import is already running for this company, or an idempotency_key conflict (same key, different payload). Only one import runs at a time per company — wait for the active run to reach a terminal state.
429Rate limit hit — back off and retry.
500Server error.

Example

curl -X POST https://app.vern.so/api/v1/companies/c0a8012e-4f1b-4d3a-9b2c-7e6f5a4b3c2d/imports \
  -H "x-api-key: $VERN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "files": [{ "name": "contacts.csv", "upload_ref": "<from-signed-upload>" }],
    "idempotency_key": "acme-001-imp-1"
  }'

Next