Skip to main content
GET   https://app.vern.so/api/v1/migrations/{migration_id}/runs/{run_id}
PATCH https://app.vern.so/api/v1/migrations/{migration_id}/runs/{run_id}
Reads the state of a run. Poll it on an interval (≈2s, backing off) until status is terminal for its phase. For live progress, prefer the thread stream.

Authentication

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

Response by status

Every response carries run_id, status, and created_at. The rest depends on status:
status
string
One of queued, running, blocked, awaiting_approval, completed, failed, or canceled.
statusExtra fields
queued / runningmessage — a human-readable update (e.g. "Cleaning your data", "Retrying (attempt 2 of 5)"), or null.
blockedquestions[] — the agent hit a genuinely ambiguous decision and is waiting on you. Answer via the messages sub-resource.
awaiting_approval(none) — a generate/update run produced a preview. Fetch it from GET /preview.
completedreport for an execute run (see below); nothing extra for a clarify run.
failederror — the agent couldn’t produce a working result even after self-healing. For an execute, no rows were inserted.
canceled(none) — the run was stopped before it finished.
A completed execute carries a report:
{
  "run_id": "e5d4c3b2-...",
  "status": "completed",
  "created_at": "2026-06-19T15:40:02.000Z",
  "report": {
    "inserted": 1450,
    "perSheet": [
      { "templateName": "Contacts", "sheetId": "7a1c2b3d-...", "rowCount": 1450 }
    ],
    "invalidCellCount": 12,
    "coverage": null
  }
}
report.inserted
number
Total rows imported across all sheets.
report.perSheet
object[]
Per-template counts — { templateName, sheetId, rowCount }.
report.invalidCellCount
number
The number of rows that still have at least one cell that failed validation — not a count of individual cells. The import succeeded; those rows are simply flagged. The default CSV download (?filter=valid) excludes any flagged row entirely, so a single bad cell drops its whole row. See Export CSV.
report.coverage
object | null
An optional value-completeness profile — per-column fill/distinct stats for the source inputs and the imported outputs — so a hollow import (right row count, dropped fields) is detectable programmatically. null when profiling wasn’t available for the run.

A blocked run

When a run is blocked, the poll response carries the questions you need to render in your own UI. Each question is self-describing — { id, question, context?, options[], allowCustom }:
{
  "run_id": "d4c3b2a1-...",
  "status": "blocked",
  "created_at": "2026-06-19T15:32:11.000Z",
  "questions": [
    {
      "id": "q1",
      "question": "Some Status values aren't one of the allowed options (Open, Closed, Pending). How should I handle them?",
      "options": [
        { "id": "a", "label": "Map them all to 'Open'" },
        { "id": "b", "label": "Drop those rows" }
      ],
      "allowCustom": true
    }
  ]
}
Answer through the run’s messages sub-resource — not the poll. The agent resumes and may block again with a fresh question.

Recovering a run

If you lose a run_id (a crash, a dropped response, a page reload), re-issue the same run you were running. Because only one run runs at a time per migration, the call returns 409 with the active run’s ID:
{ "error": "A run is already in progress for this migration.", "run_id": "d4c3b2a1-..." }
Poll that run_id as usual.
A run whose engine dies without writing a terminal status is swept to failed (“Import timed out”) once it goes stale — so a lookup never reports a zombie run as forever-running.

Cancel a run

PATCH https://app.vern.so/api/v1/migrations/{migration_id}/runs/{run_id}
Cancels an in-flight run — it stops the durable workflow and any active import task. The only accepted body is:
{ "status": "cancel_requested" }
The response is the run in its updated (canceled) shape.
curl -X PATCH https://app.vern.so/api/v1/migrations/c0a8012e-.../runs/d4c3b2a1-... \
  -H "x-api-key: $VERN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "cancel_requested" }'

Errors

StatusMeaning
400(PATCH) body isn’t { "status": "cancel_requested" }.
401API key missing or invalid.
404No such run, or the migration isn’t in your account.
429Rate limit hit — back off and retry.
500Server error.

Example

curl https://app.vern.so/api/v1/migrations/c0a8012e-.../runs/d4c3b2a1-... \
  -H "x-api-key: $VERN_API_KEY"

Next