Snapshot API

Overview

The Snapshot API exports an AI Agent’s configuration as one archive file that you keep. It then imports that archive, whole or in parts, into any Agent, including the one it came from. A snapshot is the configuration at that moment; the archive is the file that holds it.

  • Save it. An export captures the whole Agent exactly as it is right now. There is no partial export.
  • Move it. An import applies the archive to another Agent, or back to the same one.
  • Move part of it. An import can take only the sections you name, for example Playbooks. Anything those Playbooks use comes with them.

Three things follow from that design:

  1. A snapshot is a moment in time. Nothing stays in sync after the export.
  2. An import replaces the sections you import. In each section you ask for, the target ends up matching the archive. Items the archive does not carry are deleted. Sections pulled in by reference are only added to.
  3. There is no undo on Ada’s side. Ada keeps no copy you can download or import. Export the target Agent first, so you have an archive to import back.

How it works

Export and import run as background jobs: you start one, get a job_id, and poll until it finishes.

Source AgentThe archiveTarget Agent
What happensExport jobOne .tar.gz you downloadImport job
What you doStart, poll, downloadKeep it safePrepare the target, validate, apply, test

The target Agent must already exist. An import fills an Agent; it does not create one.

An import request runs in validate mode unless you ask for apply. Validate writes nothing, apart from any secret values you send with it. It reports what an apply would create, update, and delete, by name. Run it with the same archive and the same include before every apply.

Three calls do all of this: GET /v2/config/ starts an export, PUT /v2/config/ starts an import, and GET /v2/config/jobs/{job_id} checks a job. Each call goes to the Agent it concerns, at the host you use to open its dashboard plus /api, with that Agent’s API key. See Endpoints for the details and Getting started for the procedure.

In API paths and error messages this feature appears as config, for example /v2/config/.

Limitations

Read this section before the first import. Several limits are silent: the import succeeds and the Agent looks right, but a skipped step only shows up in a conversation.

Scope of a snapshot

A snapshot carries how the Agent behaves: persona, languages, variable definitions, API tools, Handoffs, Processes, Greetings, Playbooks and Playbooks Classic, Coaching, Custom instructions, and Glossary. It also carries Knowledge sources and articles, CSAT settings, custom redaction patterns, the list of enabled integrations, and web chat settings.

It never carries credentials, API keys, secret values, customer login, webhooks, or conversation data. Nor does it carry channels other than web chat settings, tags, code tools, MCP tools, Schedules, built-in PII redaction switches, or change sets. Set those up on the target Agent by hand.

What a snapshot includes lists every area of the dashboard and how an import treats it.

Import behavior

  • Replace within the sections you import. Items the archive does not carry are deleted from those sections. Four exceptions:
    • Persona and the other settings pages are updated field by field.
    • Custom instructions are only added to.
    • Integrations that Ada always keeps on are not disabled.
    • Sections pulled in by reference are only added to.
  • No limit on deletions. Nothing stops a large deletion, in Knowledge or anywhere else. The changes block on a validate is the only advance warning. Read knowledge.articles.delete before every apply. Leaving knowledge out of include stops every article deletion. Articles that your listed sections reference are still added or updated.
  • A failed import can stop halfway. Items are written one at a time, so the Agent is left partly updated. Whether to re-run depends on the failure reason, see Failure reasons.
  • No undo. Export the target Agent before importing into it.
  • One import at a time. A second import request for the same Agent is refused with 409 while one is queued or running.
  • One export at a time. A second export request returns the export already running instead of starting another.
  • MCP does not travel. MCP server connections, MCP tools, and the Playbook steps that call them are not in a snapshot. The Playbook imports, but the step points at a tool the target does not have. Reconnect the server and re-select the tool.
  • Primary language is read-only. A different primary language in the archive is skipped with a warning. Change it in the dashboard.
  • Article limit. An import cannot take the Agent above its article limit, which is 50,000 articles unless your plan sets a different limit.
  • Search catches up later. Imported articles are re-indexed after the job completes, so the Agent may not find them for a while. That is not a failed import.
  • Large imports take hours. Plan for it.

Limits

ItemLimit
Download link for an export1 hour. Poll the job again for a fresh link.
Upload link for an import1 hour from when it is issued. The job waits about 90 minutes for the archive, then fails with upload_not_received.
Archive size4 GB. A larger archive fails with upload_too_large.
Job record7 days. Download the archive before then.
Rate limitsThe standard Ada API limits apply.

Use cases

Four ways to use a snapshot, in order of risk. All four are the same calls; what changes is what you include and what you check first.

Use caseWhenRisk
1Save a copy before a changeBefore a large configuration change on the same Agent. Fine on a live Agent.Lowest. Restoring puts the Agent back to the moment of the export, so later changes are lost too.
2Move part of an AgentMove the Playbooks you built in a sandbox into another Agent that is not live, with include.Low. Only the sections you name are replaced. Everything they use is added to the target, never removed from it. Into a live Agent, treat it as use case 4.
3Copy into an empty AgentA new production Agent, a new region, or a fresh sandbox.Low. Nothing on the target to lose, but nothing stops an incomplete setup either.
4Overwrite an Agent that has contentRefreshing a sandbox from production, or consolidating two Agents.Highest, and silent. Export the target first. Not recommended on a live Agent; see Best practices.

You can keep archives in your own version control as dated files. They are sealed snapshots for restoring or moving, not documents to edit or diff.

When this is the right tool

You want toUse
Set up a whole Agent from another oneSnapshot API
Move one part of an Agent, such as its PlaybooksSnapshot API with include
Have a way back before a large changeSnapshot API
Change one thing on a live AgentThe dashboard
Test a change before it goes liveChange sets
Keep two Agents in sync over timeNot available

Capabilities & configuration

Three endpoints and one archive. This section covers each call, the job lifecycle, the archive, the import request, the checks, and what an import changes elsewhere in the dashboard.

Endpoints

Method and pathPurposeBody
GET /v2/config/Start an export. Returns job_id and status.None
PUT /v2/config/Start an import. Returns job_id, status, and upload with a temporary link.JSON, see Import request
PUT <upload.url>Send the archive to that link as raw bytes, in one request, with no Authorization header. Returns 200 with an empty body.The .tar.gz
GET /v2/config/jobs/{job_id}Check a job.None

The base URL is the host you use to open the Agent’s dashboard, plus /api. Every call except the upload carries that Agent’s key:

Header keyHeader value
AuthorizationBearer <your_api_key>
Content-Typeapplication/json (import request only)

Copying between two Agents therefore uses two keys. The source key covers the export and its job checks. The target key covers the import and its job checks.

Every Agent also serves its own API documentation at https://<handle>.ada.support/api/v2/docs and its OpenAPI specification at https://<handle>.ada.support/api/v2/spec, on the same host. Import the specification into an API client to get every request ready-made; see Export and import with Postman.

Error responses

StatusWhen
400The import request body is malformed, or carries an unknown field. Or mode is not validate or apply, or an include entry is not a section name. A typo is refused here, before any upload. Archive problems are reported on the job, not here.
401Missing or invalid API key.
404Unknown job_id, or a job that belongs to another Agent.
409An import is already queued or running for this Agent. A job still waiting_for_upload does not conflict; submitting again replaces it, and the replaced job ends as failed with superseded.
429Rate limit exceeded. See API limits.

Job lifecycle

Poll GET /v2/config/jobs/{job_id} every 5 seconds for the first minute, then every 15 seconds, until the status is completed or failed.

StatusMeaning
waiting_for_uploadImport only. Waiting for the archive. Allow up to two minutes here after the upload arrives.
queuedWaiting to start.
in_progressRunning.
completedDone. Read result, and for an import warnings.
failedStopped. failure_reason is a short code you can act on. failure_detail is a sentence you can show someone.

Other fields on the job:

FieldWhat it holds
typeexport or import. Both import modes report import.
progress0 to 100, or null before counting starts. It measures how far through the Knowledge the job is, not work remaining. 100 can appear while packing, uploading, or final steps still run. Only status means done.
resultEmpty until completed, or a list of blocking issues when failure_reason is preflight_failed. Contents depend on the job, see below. Only a validate result carries result.status.
warningsImport only. Findings that did not stop the import, each naming the section and the problem.
failure_reasonSet when failed. One of the codes in Failure reasons.
failure_detailA sentence explaining the failure. Empty when the code already says everything.
created_at, started_at, completed_atTimestamps.
Jobresult contains
Exporturl (the download link), expires_at, and secrets: the names of secret values the target must have, each with a null value.
Validatestatus (valid or blocked), blockers, warnings, changes (see Change counts), articles.found, and selection (see Choosing sections).
Applyarticles (upserted, deleted), indexing, selection, and post_apply_blockers: anything the checks still flag after the changes. Empty is the healthy answer.

Failure reasons

failure_reasonWhat happenedWhat to do
archive_expiredExport only. The archive was removed from storage before you downloaded it. The export itself had succeeded.Export again and download promptly.
upload_not_receivedNo archive reached the upload link within about 90 minutes.Request the import again and upload within the hour.
upload_too_largeThe archive is over 4 GB.Contact your Ada team.
source_unreadableThe archive could not be read: missing, damaged, or not a .tar.gz.Upload the archive exactly as exported.
invalid_snapshotThe archive was read but cannot be applied: a schema error, an export cut short by an article limit, or more articles than this Agent allows. Nothing was written.Fix what failure_detail names, then export again.
preflight_failedThe target cannot serve the snapshot; result.blockers lists each blocking issue. Nothing was written, except that integrations the snapshot lists were enabled before the checks ran.Fix each blocking issue on the target, check Apps, then request a new import.
supersededA later import request replaced this job while it was waiting for its archive.Poll the newer job. This is expected, not an error.
partially_appliedThe apply stopped after part of the configuration was written. The Agent holds part of the snapshot.Do not simply retry. Check the Agent in the dashboard, then import an archive you know is good.
incomplete_knowledgeThe import wrote fewer article files than the archive holds, so it refused to delete any articles. The configuration sections were already applied, including their deletions.Request the same import again and upload the same archive. It resumes where it stopped.
ref_key_already_mappedAn item’s stable identifier is already used by a different item on this Agent.Contact your Ada team with the job_id.
timeoutThe job hit its time limit.Request it again. An import resumes where it stopped.
stalledThe job stopped making progress.Request it again. If it happens twice, contact your Ada team with the job_id.
internal_errorAn unexpected fault, retried and still failing. failure_detail is empty.Request it again. If it recurs, contact your Ada team with the job_id.
agent_not_foundThe Agent no longer exists.Nothing.

Archive contents

The export is one timestamped file, for example config_20260904-145213.tar.gz, containing:

  • config.json: the configuration document, everything except article bodies. It also records the export time, the source Agent’s handle, and the names of the secrets the snapshot needs. It names the Zendesk or Salesforce accounts the Handoffs were built against.
  • articles/articles_*.jsonl: the Knowledge articles, one per line, split across files.
  • manifest.json: an index, including the article count, the archive format version (1.x), and whether an article limit cut the export short.

Do not edit or repack the archive.

Import request

The import request body:

FieldValuesDefaultPurpose
modevalidate, applyvalidatevalidate reports; apply writes. Both report the same blocking issues, so an apply fails on exactly what a validate showed.
secrets{ "name": "value" }noneValues for the secrets the snapshot names. Values never travel in the archive; the names come from result.secrets on the export job. A missing secret is a warning, not a failure. The values are stored on the Agent as soon as the request is accepted, in either mode, even if the upload never arrives.
includeA list of section names, see belowall sectionsImport only these sections. Anything they reference comes with them.
allow_unsafe_importtrue, falsefalseTurns the safety checks off. See Unsafe imports before you use it.
mode defaults to validate, which writes nothing except the secret values in the request. You have to send mode: "apply" for an import to make any changes. Send mode every time, so the intent is on the request.

Each import request gets its own upload link, so the apply needs a fresh upload of the same archive.

Choosing sections

include takes one or more of these section names:

persona, variables, actions (API tools), handoffs, processes, greetings, languages, playbooks, coaching, custom_instructions, glossary, knowledge, csat_settings, custom_redactions, integrations, web_chat

Every section ends up in one of three states:

SectionWhat happens
Listed in includeReplaced. Items of that type the archive does not carry are deleted.
Pulled in because a listed section references itAdded to, never pruned. Only the referenced items come over.
NeitherUntouched. Not read, not written.

For example, include: ["playbooks"] replaces the Agent’s Playbooks. The articles, variables, API tools, and Handoffs those Playbooks use come with them and are added to the target. The target’s other variables and API tools are not affected.

result.selection on the job reports what happened:

FieldMeaning
requestedThe sections you listed.
includedEvery section that was applied, once references were followed.
pulledHow many items came over per section you did not list. For knowledge, sources and articles.
unresolvedReferences the import could not follow, each with kind, reference, parameter, and reason. Each one is a link that only works if the target already has that item.
  • include: ["knowledge"] brings every article and pulls in all variable definitions, so article availability rules resolve.
  • A whole-snapshot import reports selection: null.

Unsafe imports

allow_unsafe_import: true applies a snapshot with its safety checks off and leaves the Agent needing repair by hand. Never use it on a live Agent.

With the flag on, three things change:

  • Nothing is pulled in. Only the sections in include are applied. A Playbook arrives without the API tools, variables, Handoffs, or articles it uses, unless the target already has them.
  • Blocking issues become warnings. A Handoff whose platform is not connected, or a feature the Agent lacks, no longer stops the import. It is reported under warnings and the import proceeds.
  • Broken Playbooks are written. An active Playbook whose references do not resolve is imported as is, and those steps do nothing at runtime.

Nothing repairs the result later. You fix each reference by hand, or import the missing sections afterwards.

Use it for one purpose: rebuilding a scratch or test Agent from one slice of a snapshot, when a half-wired Agent is more useful than a refused import. Always run mode: "validate" with the same flag first. result.selection.unresolved lists every reference the import will break, and result.warnings lists every blocking issue it will ignore.

Archive checks

These run first and fail the job with a failure_reason before anything is written:

  • The archive is a readable .tar.gz within the size limits. It holds manifest.json, config.json, and every article file the manifest lists, and nothing else, in format version 1.x.
  • config.json matches the configuration schema. Every section is one this API manages. Names and handles are unique, and there is exactly one default Greeting. References between items resolve. Every custom redaction is a valid regular expression, and every language is one Ada supports. A section this API no longer manages is skipped with a warning.
  • The Agent’s limits are respected: live Custom instructions, Glossary terms, and the article limit. The limit on enabled API tools is checked separately, as a blocking issue.
  • The archive was not cut short by an article limit. If it was, ask your Ada team to lift the limit and export again. Or leave knowledge out of include to apply the rest of the snapshot.

Pre-import checks

Before an import writes anything, it reads the target Agent and checks that it can serve the snapshot. validate reports what it finds; apply refuses on any blocking issue and reports the rest as warnings. Each finding has these fields:

FieldWhat it holds
codeA code you can act on.
entityThe section the finding concerns.
parameterA path into the archive’s config.json.
messageA plain-language explanation.
referenceWhere useful, the integration, variable, or account involved.

The checks on connections run again right before the import deletes anything, and again after the apply completes. If one fails at the first point, the job stops with preflight_failed before anything is deleted; updates already made stay. Anything found after the apply is reported as post_apply_blockers. With allow_unsafe_import, blocking issues are reported as warnings instead and the import proceeds.

Blocking issues

CodeWhat it meansWhat to do on the target
handoff_connection_missingA Handoff block routes to a live-agent platform or a named handoff integration that is not connected, is disabled, or has no credentials on this Agent. Live-agent platforms are Zendesk Chat, Zendesk Support, Zendesk Messaging, and Salesforce Chat.Connect it under Handoffs > Integrations or Apps, then re-run.
handoff_integration_label_unresolvedA block hands off to a custom integration built on the Handoffs API, and that integration is not connected here.Connect the custom integration.
handoff_integration_unknownA block names a handoff integration that does not exist in this region.Rebuild the Handoff against an integration available here.
handoff_tenant_mismatchThe snapshot’s Handoffs were built against a different Zendesk subdomain or Salesforce org than the one this Agent is connected to. Their routing ids would point at nothing, or at the wrong team.Connect this Agent to the same account, or rebuild those Handoffs here.
client_feature_missingA Handoff block needs a feature that is not enabled for this Agent.Ask your Ada team to enable it.
action_integrations_feature_offA block calls an integration, but this Agent does not have the integrations feature. When nothing in the snapshot calls one, the same code is a warning instead; see Warnings.Ask your Ada team to enable it.
action_integration_not_enabledA block calls an integration that would not be enabled after the import.Enable it on Apps.
action_integration_not_connectedThe integration is enabled but has no credentials, so every call would fail.Connect it on Apps.
action_limit_exceededThe snapshot would enable more API tools than this Agent’s limit allows.Disable some API tools in the source before exporting, or ask your Ada team about the limit.

Warnings

CodeWhat it meansWhat to do
client_secret_missingThe snapshot names a secret that is not defined on this Agent, and no value was supplied. Anything that reads it fails until you set it.Pass it in secrets, or enter it in the dashboard after the import.
variable_ref_unresolvedA field references a variable this Agent does not have. Often a metavariable that exists only when a channel or feature is enabled. The reference is left as literal text.Enable the channel or feature, or edit the field after the import.
untranslated_entity_idA Handoff’s off-hours response is referenced by an internal id that only resolves on the Agent it came from.On a different Agent, re-select the off-hours response after the import.
integration_connectivity_unverifiedCredentials could not be verified: the check could not reach the integration service, or the integration is only being enabled by this import. An apply re-checks it.Re-run validate later, or check Apps after the apply.
action_integrations_feature_offThe snapshot lists enabled integrations, nothing in it calls one, and this Agent does not have the integrations feature. The list is skipped.Ask your Ada team to enable the feature if you need those integrations.

Three warnings carry no code:

  • A section in the archive that this API no longer manages. It is skipped.
  • On a selective import, the integrations it needs could not be merged with the ones already enabled. The integration service could not be read, so no integration was switched on or off. Enable them on Apps, or run the import again.
  • The import succeeded, but the enabled integrations could not be read back, so integrations is missing from the response. Do not run the import again.

Change counts

A validate also returns changes. For every section the archive carries, it says how many items the apply would create, update, and delete, and names them. Names are capped at 50 per list. Where a count is higher, a created_truncated, updated_truncated, or deleted_truncated flag says so. The counts are always exact.

  • Items are matched by a stable identifier assigned at export. An item renamed on the source therefore still updates the same item on the target. An item the target has not received by import before is matched by its name instead:
    • API tools, variables (within their scope), and Playbooks: by name.
    • Handoffs, Processes, and Greetings: by handle.
    • Glossary terms, Knowledge sources, and articles: by external id.
    • Custom instructions: by title. Custom redactions: by name.
    • Coaching entries have no name, so a snapshot from a different Agent creates new entries instead of updating matching ones.
  • knowledge.articles.delete is the number to check before applying to an Agent with live Knowledge. It appears on a validate result only; a refused apply does not pre-scan Knowledge.
  • Persona, languages, CSAT settings, and web chat are single settings pages. They report create: 0 and delete: 0, and update counts the fields that would change.
  • Handoffs, Processes, and Greetings share one item type, so their deletions are reported once. Custom instructions never report a deletion. A section pulled in by reference reports delete: 0.

Effects on Reports, Conversations, and the audit log

An import changes configuration, never history. What you see afterward in Reports, in the Conversation View, and in the Audit log:

Reports and Conversations

  • Items the import updates keep their identity. An API tool, Handoff, Process, Greeting, Playbook, variable, or article matched by its stable identifier is updated in place. Existing filters and past conversations still point at the same item, under its new name if it was renamed.
  • Items the import deletes stop appearing in filters for new conversations. Past conversations that used them are unchanged.
  • Items the import creates are new, with no history. On an empty Agent everything is new: nothing from the source Agent’s Reports or conversations comes with it.

Audit log

If the Audit log is not enabled for the Agent, none of these rows are written.

  • Requesting an import writes one row immediately: entity Config Apply or Config Validate, activity Executed, Interface API. The actor is the API key’s owner, with the key’s name. A selective import writes the same single row. Secret values supplied in the request are logged at the same time, as variable rows.
  • When the apply runs, each item it writes gets its own row: Created, Updated, or Deleted. That covers variables, API tools, Handoffs, Processes, Greetings, Playbooks, Coaching entries, Glossary terms, and Knowledge sources. These rows show System as the actor and as the Interface, because the import job made the change rather than a person. Use the Config Apply row’s timestamp to find them.
  • Persona, languages, Custom instructions, CSAT settings, custom redactions, enabled integrations, and web chat settings get no rows of their own. The Config Apply row is the only record that they changed.
  • Articles are not logged individually. Their Knowledge source gets one row, including when deleting a source removes its articles.
  • Exports are not logged.

Best practices

Habits that keep imports predictable.

  • Export before every large change, and put the date in the filename. Those archives are the only version history you have.
  • Validate before every apply, with the same archive and the same include. Read changes by name, and warnings, even when the result is valid.
  • Import the smallest set of sections that does the job. include limits what an import can delete.
  • Run your first import into an Agent that is not live, even when you are confident.
  • Do not import another Agent’s configuration, whole or in part, into a live Agent. The checks confirm that connections exist, not that they match the source. If you must, complete every prerequisite, then test each flow that uses an integration.
  • Refresh sandboxes from production with the same procedure. The target is not serving anyone, so it is the safe way to practice.
  • If something is missing after an import, check enabled features first with your Ada team. A feature mismatch never shows up as an error.
  • Keep secret values in your own secrets manager and pass them per environment in the apply request. They never belong in the archive or in version control.
  • What a snapshot includes: every dashboard area, and how an import treats it.
  • Getting started: the prerequisites checklist and the step-by-step export, validate, and apply procedure.
  • Authentication: generate and manage API keys.
  • API limits: rate limits that apply to every call.
  • Audit log: where imports and the changes they make are recorded.
  • Playbooks API: edit individual Playbooks instead of moving a whole configuration.
  • Data export: export conversation data, which a snapshot never carries.

FAQs

No. The archive is a sealed snapshot. Edits either fail the archive checks or change what the import deletes. To change configuration, use the dashboard or the individual APIs, then export again.

Yes. Send include: [“playbooks”]. What those Playbooks use comes with them and is only added to the target. See Choosing sections.

No. An export always captures the whole Agent. You choose what to import.

Your own export of the target Agent, taken before the import. Ada does not keep a copy you can access. Importing that archive puts the Agent back to the moment you exported it.

It can. Items are written one at a time, so a conversation that is running while the import applies can see the configuration change part-way. Import during a quiet period, or into an Agent that is not live.

The step calls a tool connected through an MCP server. MCP servers and their tools do not travel. Reconnect the server on the target and re-select the tool in the Playbook.

Rebuilding a test Agent from one slice of a snapshot, when a half-wired Agent is more useful than a refused import. It skips the pull-in of referenced items and turns blocking issues into warnings. Never use it on a live Agent.

A snapshot is a copy of a whole Agent at one moment, for moving it or restoring it. Change sets test and promote a set of edits on the same Agent. Use change sets for day-to-day changes, and a snapshot before a large one. An export reads live configuration only, so promote or discard staged changes first.

An Agent with a handful of articles completes in under a minute. Time scales with the number of articles; tens of thousands can take hours. Poll the job rather than waiting on the request.

That is the feature’s internal name. config in a path or message means the Snapshot API.

The archive checks fail the job before anything is written, and failure_reason says why. Request the import again and upload the right archive.