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}/exports
Pushes the company’s validated rows into a destination system using your published export writer for that destination and the company’s destination connection. A writer isn’t tied to a source — it maps your templates to a destination API. Like import, it’s asynchronous — it returns a run you poll. Export is a deterministic replay of your published writer; there’s no agent in the loop.

Authentication

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

Request body

mode
string
default:"full"
full exports every validated row. canary exports the first row of each template — a safe smoke test against the destination before a full run.
selection
object
Optional narrowing, e.g. { "template_ids": ["..."], "row_filter": { } }. Omit to export everything validated.
idempotency_key
string
Makes export run creation safe to retry. See the duplicate-write note below.

Response

201 Created
{
  "run_id": "e5d4c3b2-1a09-4f8e-9d7c-6b5a4d3c2e1f",
  "status": "queued",
  "poll_url": "/api/v1/companies/c0a8012e-4f1b-4d3a-9b2c-7e6f5a4b3c2d/exports/e5d4c3b2-1a09-4f8e-9d7c-6b5a4d3c2e1f"
}
Poll GET /api/v1/companies/{id}/exports/{run_id} until terminal. A completed report partitions every write:
{
  "status": "completed",
  "report": {
    "mode": "full",
    "total": 1450,
    "succeeded": 1438,
    "failed": 12,
    "results": [
      {
        "template_id": "9e8d7c6b-5a4f-4321-8b2c-1d0e9f8a7b6c",
        "path": "/v3/contacts",
        "status": 422,
        "ok": false,
        "error": "email: already exists",
        "fields_confirmed": null
      }
    ]
  }
}
A run completes even with partial failures: every write lands in results[] with its ok flag, the destination’s HTTP status, and an error on the ones that failed (ok: false). Only job-level problems (bad credentials, destination down) mark the whole run failed. When the destination’s schema drifts, the fix is to re-author the writer in the UI, publish a new version, and re-run — not an in-flight agent.
Hollow writes. When a writer authors a read-back verify, each row carries fields_confirmed: true if a mapped field was found in the written record, false if it came back empty (a hollow write — a 2xx the destination accepted but that didn’t actually stick), or null when no verify ran. A 2xx with fields_confirmed: false is a silent drop worth alerting on.
Avoiding duplicate writes. idempotency_key only dedupes run creation — it does not prevent a retried write from creating a second record in the destination. Writers require a natural key (or a by-key upsert) so re-runs upsert instead of double-writing into a customer’s live system.

Next