Skip to main content
POST
JavaScript
Models get deprecated. This is how you migrate off one without hand-editing every variation you have ever created. The call reassigns every agent variation in the workspace that sits on currentModelId, moving it to nextModelId. It returns immediately and the work happens in the background.
This is a workspace-wide bulk write. It touches every variation on the source model, including agents other people own and agents you forgot about. There is no dry run, no filter, and no undo beyond swapping back.Run List variations across your agents first, or check the model’s info to see how many variations sit on it.

It is asynchronous, and the response is empty

SwapModelOnVariationsResponse has no fields. No workflow ID, no count of variations moved, no handle to poll. The call returns 200 and the reassignment happens behind it. To confirm the migration landed, read the variations back:
Both ID fields accept a canonical model_... ID or the external_id: form. A variation stores the canonical ID, so a variation you wrote as external_id:claude-sonnet-4-5 still matches a swap keyed on that slug. Calling the same swap pair twice while the first is still running is safe. The workflow ID is derived from the workspace and the two model IDs, so a duplicate call collapses into the running one and returns success rather than starting a second pass.

Retire the old model in the same call

disableCurrentAfterSwap disables the source model once every variation has moved. This is the whole deprecation flow in one request.
Without it, disabling the old model separately is the safer sequence anyway, because Disable a model refuses while any variation still references it:
That guard is the reason this endpoint exists. It also means a disabled model can never be the state a running objective finds itself in: the system prevents the situation rather than handling it.

What is checked before the swap starts

  • Both models must resolve, by ID or external_id:.
  • nextModelId must be enabled. Swapping onto a disabled model is a 400 on model_swaps.next_model_id.
Nothing else. In particular, nothing checks that the two models are compatible. A variation carrying a compactionConfig tuned to a 200k-token window keeps that config after moving to a model with a smaller one, and compaction triggers as a fraction of the new model’s maxInputTokens.
A model with no maxInputTokens never triggers compaction at all, so a long objective on such a model grows until it fails. Check spec.maxInputTokens on the model you are swapping to.

The deprecation runbook

  1. Find what is affected. List your agents’ variations and group by spec.modelConfig.modelId.
  2. Pick the replacement and read its spec: maxInputTokens, maxOutputTokens, and the per-million-token prices, all on the model.
  3. Swap a canary first, by editing one variation directly rather than using this endpoint.
  4. Score the canary’s objectives. If the feedback holds up, swap the rest.
  5. Disable the old model, so nobody creates a new variation on it.
Step 3 is the one people skip. A swap rewrites the model under a prompt that was tuned for a different one, and nothing about the call tells you whether the agent still behaves.

List models

What your workspace offers, with context windows and pricing.

Create a variation

Where modelConfig.modelId is set, one variation at a time.

Disable a model

Refuses while variations still reference it.

Submit feedback

How you find out whether the new model is better.

Authorizations

Authorization
string
header
required

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

Path Parameters

workspaceId
string
required

Workspace ID.

Example:

"workspace_01HXKD2E5NQM3T9AYWCF133E3Q"

Body

application/json

Swap model on variations request. Each ModelSwap reassigns every agent variation on current_model_id to next_model_id. The work runs asynchronously.

modelSwaps
object[]

The swaps to perform.

Response

OK

Swap model on variations response. Empty: the work runs asynchronously, so no counts are returned (a large data set would make the call slow).