Import a full configuration snapshot, including knowledge articles

Applies a snapshot produced by `GET /v2/config/` — the whole configuration document *and* the Agent's knowledge articles — reading it from an archive you upload rather than from a request body. Use it to restore an Agent, or to clone one Agent's configuration onto another. ## Two calls 1. `PUT /v2/config/` returns a `job_id` and an `upload` block holding a short-lived `url`. 2. `PUT` the raw `.tar.gz` to that `url` in one request — no form encoding, no `Content-Type` needed. Then poll `job_id` at `GET /v2/config/jobs/{job_id}`. The job waits in `waiting_for_upload` until the archive appears and starts on its own. The bytes never pass through this API, so the archive may be far larger than a request body allows, and a snapshot from an Agent on one region imports onto an Agent on another with no access between them. ## `mode` defaults to `validate` **An omitted `mode` is a dry run. Send `mode: "apply"` to write anything.** `validate` reads the archive and reports what an apply would do, without writing — including `changes["knowledge.articles"]["delete"]`, the number of articles the full replace would remove. It is the only place the destructive half is enumerated beforehand, so run it before every apply. ## Narrowing what is applied `include` lists the sections to import; omit it for the whole snapshot. Anything a listed section references travels with it, whichever section you name. Ask for `playbooks`, for example, and the articles, variables, actions and handoffs those playbooks use come too; ask for `handoffs` and the variables their messages interpolate come with them. That leaves every section in one of three states. | Section | What happens | |---|---| | **Listed** in `include` | Replaced. Entities of that type the snapshot does not carry are deleted. | | **Pulled in** as a dependency | Added to, never pruned. | | **Neither** | Untouched — not read, not written. | Staying with `playbooks`: the Agent's playbooks are replaced, so any the snapshot does not carry are deleted. Everything they dragged in is only added to, because your selection reached some of those entities, not all. So a playbook that uses 4 variables brings those 4 over, and the target Agent's existing variables are not affected — no full replace in this case. The job's `result.selection` reports what came over and what could not be resolved. `allow_unsafe_import` turns that dependency pull off and downgrades pre-flight blockers to warnings. It leaves an Agent with dangling references that nothing repairs later — never use it on one serving traffic. Validate with the same flag first: `result.selection.unresolved` lists every reference it will break. ## Secrets Secret values never travel in the archive. Supply them in `secrets`, keyed by variable name; read the key list from the source export's `result.secrets` (or the identical block in the archive's `config.json`). They are provisioned when the import is **requested** — before the upload, and never persisted on the job — so a request whose upload never lands still leaves the values provisioned. A secret the snapshot needs that is neither supplied nor already on the target is a **warning, not a failure**. The import completes and whatever reads that secret fails at runtime until someone sets it. ## Uploading The URL is valid for one hour, measured when the upload *starts*, so a slow link finishing later is fine. **Check the status your upload returns.** Ada never sees that request, so a rejected upload is indistinguishable from one that never ran — the job waits, then fails. `curl` exits `0` on an HTTP error unless you pass `-f`. To retry, just `PUT /v2/config/` again: a job still waiting for its archive is replaced, not rejected. An archive that never arrives fails the job about 90 minutes after submission (`upload_not_received`); one over the size ceiling fails as soon as it lands (`upload_too_large`). The archive is read only when the job runs — the manifest describing it sits at the end of the file — so a malformed snapshot fails the **job** seconds after it starts, before anything is written, rather than returning a `400` here. ## What an apply does Each entity applies with the semantics the export documents: full replace matched on the natural key. Knowledge is **full replace**: an article the snapshot does not carry is deleted, however many that is. Articles created after the import started are never deleted, and articles with no knowledge source are left alone, since an import cannot recreate one. Leaving `knowledge` out of `include` stops every article deletion; articles that your listed sections reference are still added or updated.

Authentication

AuthorizationBearer

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

Request

This endpoint expects an object.
modeenumOptionalDefaults to validate

Defaults to validate. Send mode: "apply" explicitly to write anything — an omitted mode is a dry run, not an import.

validate writes nothing: it checks that the source is a readable, supported snapshot whose configuration document would apply to this Agent, and reports the create/update/delete counts the apply would produce — including how many knowledge articles the full replace would delete.

apply imports the snapshot. It is a full replace with hard deletes and it is not atomic, so the two mistakes do not cost the same: a caller who meant validate and got apply has destroyed an Agent’s knowledge, while one who meant apply and got validate has lost a round trip. The default is set accordingly.

Both are asynchronous and both need the archive uploaded: validate also returns a job_id and an upload, and its verdict is the job’s result.

secretsmap from strings to nullable stringsOptional

The Agent’s client secrets, by variable name. When the AI Agent calls your systems — an HTTP-request action hitting your order service, say — it authenticates with these. They are the client_secret-scope variables managed under Content > Authentication in the Agent.

Supply them because secret values never travel in the export archive. The names the snapshot needs are listed in the export’s own secrets block, each with a null value — fill those in and send the result here.

They are provisioned when the import is requested, before the archive is uploaded, and never stored on the job, so a request whose upload never lands still leaves the values provisioned. A secret the snapshot needs that is neither supplied nor already on the target Agent is a warning, not a failure — the actions using it fail at runtime until someone supplies it.

allow_unsafe_importbooleanOptionalDefaults to false

Applies the snapshot with its safety gates off, and leaves the Agent needing manual repair. Never use it on an Agent serving traffic.

With include, the import normally follows every reference out of the sections you named and brings the targets along, so a playbook that calls a tool arrives with that tool, a handoff arrives with the variables its messages interpolate, and a coaching entry arrives with the action it points at. allow_unsafe_import stops all of that: only the sections in include are applied, and every reference leaving them — of any kind, from any section — is left dangling unless the target Agent already has what it names.

It also drops the checks that would otherwise refuse such an import. An active playbook whose tool, variable or response references do not resolve is written anyway rather than rejected. Pre-flight blockers — a handoff whose integration is not connected on this Agent, a required client feature that is off — are reported as warnings instead of failing the job.

What lands is a broken Agent: playbooks holding unresolved {action:…} text that no-ops at runtime, handoffs pointing at integrations that do not exist, coaching entries whose target was never created. Nothing repairs it later — someone fixes each reference by hand, or imports the missing sections afterwards.

It exists for rebuilding a scratch or test Agent out of one slice of a snapshot, where a half-wired Agent is more useful than a refused import. Run mode: validate with the same flag first: every reference you are about to break is listed in selection.unresolved, and every overridden blocker appears under warnings.

includelist of enumsOptional

Import only these sections of the snapshot. Omit to import all of it.

Anything a listed section references travels with it. Importing playbooks also brings the articles, variables, API tools and handoffs those playbooks use; importing handoffs brings the variables their messages interpolate. The archive itself is not filtered — the selection is applied when it is read.

A section you list is replaced: entities of that type absent from the snapshot are deleted, exactly as a whole-snapshot import would. A section pulled in only as a dependency is added to, never pruned — importing one playbook cannot delete a variable it does not use. Sections you neither list nor reach are untouched.

The job’s result.selection reports what came over, including any reference that could not be resolved. Use mode: validate to see it before applying.

allow_unsafe_import: true turns the dependency pull off, so only the sections listed here are applied and their outbound references dangle.

Response

Accepted — for mode: validate as well, which reports its verdict as the job’s result rather than inline. Send the archive to upload.url, then poll the returned job_id at GET /v2/config/jobs/{job_id} for progress, warnings, and the result.

job_idstring
The id to poll for the job status and result
statusenum

Always waiting_for_upload: the job exists but cannot start until the archive arrives at upload.url.

uploadobject

Where to send the configuration snapshot for an import.

{url, method, expires_at} — send the raw .tar.gz bytes to url with a single PUT. expires_at is checked when the upload starts, so one begun before it and still running after completes normally.

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
409
Conflict Error
429
Too Many Requests Error
500
Internal Server Error