Get the status and result of a config export/import job

Poll a job submitted via `GET` or `PUT /v2/config/`. Jobs are scoped to the authenticated Agent; an unknown or unowned `job_id` returns 404. Three kinds of job are polled here. They share this response but not a lifecycle, a `result` shape, or a set of failures — so read the section for the one you submitted. | Job | Submitted by | `type` | Lifecycle | |---|---|---|---| | Export | `GET /v2/config/` | `export` | `queued` → `in_progress` → `completed` | | Import, validate | `PUT /v2/config/`, `mode: validate` (the default) | `import` | `waiting_for_upload` → `queued` → `in_progress` → `completed` | | Import, apply | `PUT /v2/config/`, `mode: apply` | `import` | `waiting_for_upload` → `queued` → `in_progress` → `completed` | Both import modes report `type: import` and the response never restates the mode. Tell them apart by `result`: only a validate carries `result.status`. Any job can also end at `failed`, from any non-terminal status. Then `failure_reason` is the slug to branch on and `failure_detail` the sentence to show a person — see `ConfigJobFailureReason` for all 14 and what to do about each. ## Export Builds the archive in the background. Nothing about the Agent changes. `completed` gives a **temporary download link** in `result.url`, minted fresh on every poll, so it is never stale — poll again rather than re-exporting if one expires. `result.secrets` lists the `client_secret` variable names the snapshot needs, each `null`; that is the list to fill in for the import, and it needs no download. The one failure peculiar to export is `archive_expired`: the export itself succeeded, but the archive was removed from storage before you polled. The job row underneath is still `completed`; this response reports `failed` rather than hand you a URL that 404s. ## Import — `mode: validate` The default, and where every import should start. **Nothing is ever written**, whatever the verdict. The job begins at `waiting_for_upload` and moves on by itself once the archive lands at the `upload.url` you were given — a validate needs the upload too, since the answer is in the archive. It reaches `completed` even when the answer is bad; the verdict is `result.status`, `valid` or `blocked`. `result.changes` reports what an apply would create, update and delete, per section and with names — including `knowledge.articles.delete`, the number of articles the full replace would remove from this Agent. On a selective import `result.selection` reports what the `include` closure actually dragged in and which references it could not resolve. Run this before every apply. It is the only place the destructive half of an import is enumerated before it happens. ## Import — `mode: apply` Writes the snapshot to the Agent. This is the destructive direction, and the one you must ask for by name. Same lifecycle as a validate: it waits at `waiting_for_upload` for the archive, and nothing is read or written before that lands — so a job sitting there has changed nothing and costs nothing to abandon. `completed` gives `result.articles` (`upserted` / `deleted`), `result.indexing`, and `result.post_apply_blockers` — **empty is the healthy answer** there; a non-empty list means the import committed but left something broken. `warnings` lists what the import did not do, without failing. Two failures need different handling from the rest. `preflight_failed` means the target Agent cannot serve the snapshot: every blocker is in `result`, and **nothing was written**. `partially_applied` means the opposite — the run died after the configuration phase committed, so the Agent holds part of the snapshot and a blind retry is unsafe. ## Polling Poll every 5 seconds for the first minute, then every 15. An import can wait minutes for its upload to be noticed and run for hours on a large knowledge base; `progress` moves while it does, and a job that keeps reporting is never timed out for being slow.

Authentication

AuthorizationBearer

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

Path parameters

job_idstringRequired

The job id returned by the export/import submit endpoint

Response

The job status, with the result once completed
job_idstring
typeenum
Which direction the job runs
statusenum

Current lifecycle status of the job. waiting_for_upload is import-only: the job exists and the archive has not arrived yet, so no work has begun and started_at stays null throughout.

created_atstring or nullOptionalformat: "date-time"
started_atstring or nullOptionalformat: "date-time"

When the job started running; null while the job is still queued or waiting for its upload. The gap from created_at is time spent waiting — for the archive, then to start — not working.

completed_atstring or nullOptionalformat: "date-time"

When the job reached a terminal status; null while it runs

progressinteger or nullOptional0-100

How far through the knowledge the job has got, as a percentage. null until the size of the work is known, which for both directions is once the job has started and read the manifest — so a queued or waiting_for_upload job always reports null.

Knowledge is the only phase whose duration scales with the Agent: an export counts the articles written to the archive, an import the archive’s article files applied.

It answers “how far”, never “is it done” — read status for that. 100 does not mean finished, and appears on three different statuses:

  • completed — reported outright, since an Agent with no articles finishes with nothing counted.
  • in_progress — the phases either side of the knowledge are not counted, so an export sits at 100 while it packs and uploads the archive, and an import while it applies the configuration document.
  • failed — an export whose scan completed but whose archive expired before you polled (failure_reason: archive_expired).

A job that fails partway keeps serving the ratio it reached, so an import that died at 4,000 of 10,000 files reports 40 from then on. One that fails before the manifest reports null.

Floored while the job runs, so a job one article short of done reports 99. It can go down: an interrupted job is restarted from the start of the knowledge, and an import resumes where it stopped rather than from what the dead attempt had merely reported.

resultobject or nullOptional

Null while the job is queued or in progress. Which shape it takes is settled by type, the submitted mode, and status:

typemodestatusresult
exportcompletedConfigExportResponse — a temporary link to the archive plus the client-secret names the snapshot needs. The URL is minted fresh on every poll, so it is never stale.
importvalidatecompletedConfigSnapshotValidation — the verdict on the snapshot. Nothing was written, whether the verdict is valid or blocked.
importapplycompletedConfigSnapshotImportResult — what was written, counted as it ran. Import deliberately does not re-export: the document would be prohibitively large for the Agent sizes this exists to serve.
importapplyfailedConfigPreflightFailure, but only for failure_reason: preflight_failed. Every other failure leaves result null and puts its sentence in failure_detail.
warningslist of objects or nullOptional

What the import did not do, without failing — see ConfigImportWarning for the five kinds. An empty array once an import completes cleanly; null for an export, and null while a job runs or after it fails.

failure_reasonenum or nullOptional

The kind of failure, as a stable slug — null unless status is failed. Branch on this rather than on failure_detail, whose wording is not part of the contract.

failure_detailstring or nullOptional

One sentence naming what actually went wrong, to show a person. Null when the job has not failed, and null on the failures whose slug says everything there is to say — preflight_failed (whose findings are in result), timeout, stalled, agent_not_found, and internal_error, whose underlying message is never returned because driver and storage errors carry internal hostnames.

Errors

401
Unauthorized Error
403
Forbidden Error
404
Not Found Error
429
Too Many Requests Error
500
Internal Server Error