Import an exported workflow as a draft, or fork and synchronize workspaces through the v2 preview-and-apply protocol. Preview the destination bindings, apply those exact choices, then poll the returned operation to verify copies and deployment readiness. The CLI workflow guide uses the same protocol.
Choose the interface
HTTP paths below are relative to /api/v2. {workspaceId} is the current workspace you explicitly selected.
| CLI command | HTTP request |
|---|---|
sim workflows export <id> --include-references | GET /workflows/{workflowId}/export?includeReferences=true |
sim workflows import-preview / sim workflows import | POST /workflows/import/preview / POST /workflows/import |
sim workspaces fork-availability / sim workspaces lineage | GET /workspaces/{workspaceId}/fork/availability / .../fork/lineage |
sim workspaces children / sim workspaces fork-resources | GET /workspaces/{workspaceId}/fork/children / .../fork/resources?kind=tables |
sim workspaces fork-preview / sim workspaces fork | POST /workspaces/{workspaceId}/fork/preview / .../fork |
sim workspaces push-preview / sim workspaces push --yes | POST /workspaces/{workspaceId}/fork/push/preview / .../fork/push |
sim workspaces pull-preview / sim workspaces pull --yes | POST /workspaces/{workspaceId}/fork/pull/preview / .../fork/pull |
sim workspaces mappings get / sim workspaces mappings update | GET / PUT /workspaces/{workspaceId}/fork/mappings |
sim selectors list / sim selectors get | POST /selectors/list / POST /selectors/get |
sim workspaces operations get <id> / sim workspaces operations wait <id> | GET /workspaces/{workspaceId}/operations/{operationId}; wait polls this endpoint |
sim workspaces operations list | GET /workspaces/{workspaceId}/operations |
The sync reference documents fields and includes rollback, unlink, and exclusions. Children, resource discovery, mappings, and operations are paginated: follow nextCursor with the same scope and filters.
Prerequisites and access
Set BASE_URL to your deployment origin, without /api/v2. Use a personal API key in X-API-Key, or an OAuth token in Authorization: Bearer. Examples use separate authorized source/destination keys where applicable. Replace all example resource IDs with IDs from your export and destination.
| Operation | Required access |
|---|---|
| Export | Workflow read access |
| Import preview/apply | Destination write access; binding credentials also requires an acting user with credential access |
| Fork discovery, preview, creation | Source workspace Admin; creation policy must allow a new workspace |
| Sync preview/apply and mapping read/update | Admin on both workspaces on a direct parent/child fork edge |
| Rollback / unlink | Target Admin / acting-side Admin, respectively |
| Selector discovery | Read access in the discovery workspace and access to the selected credential |
| Operation get/list | Read access in the receipt workspace |
Workspace keys can import where authoring policy allows, but cannot bind credentials, administer forks, or execute selectors. The key owner is not a substitute for an acting user. Workspace policies, permission groups, credential access, and workspace creation limits still apply.
OAuth import/fork/sync previews require api:write, even though previews do not commit changes. Export, fork discovery, mapping reads, selectors, and operation reads use api:read.
Forking and sync require the owning organization's Enterprise entitlement on billing-enabled deployments. On billing-disabled deployments, deployment configuration must enable forking. Check Fork availability before starting. Imports, selector discovery, and operation reports have their own access rules and do not inherit the fork-specific gate.
Import a portable workflow
Export and inspect the source
Default exports clear registered credential fields and workspace bindings. includeReferences=true adds a versioned manifest of resource IDs and their source occurrences, including nested tools. The manifest contains identities, not secret values. Unresolved environment-variable references remain, and ordinary workflow variable values or literal configuration can remain in the full export. Inspect the payload before sharing it.
Source IDs and imported provenance are labels; they do not grant access to an alleged source workspace. includeWorkspaceBindings=true can retain non-secret bindings for a same-workspace round trip; otherwise configure any required bindings reported by import.
Raw HTTP wraps the result in data; the CLI unwraps a single resource. Extract that payload before saving it:
curl -sS --fail-with-body \
-H "X-API-Key: $SOURCE_API_KEY" \
"$BASE_URL/api/v2/workflows/$WORKFLOW_ID/export?includeReferences=true" \
| jq '.data' > workflow.jsonMap destination resources
Save import-mappings.json, using source IDs from the manifest and authorized destination IDs:
[
{ "kind": "credential", "sourceId": "source-connection", "targetId": "destination-connection" },
{ "kind": "sandbox", "sourceId": "source-sandbox", "targetId": "destination-sandbox" }
]mappings applies to every occurrence of a resource's kind and sourceId. Destination type, provider, and parent/child compatibility are validated. targetId:null requests clearing and cannot satisfy a required binding. Conflicting instructions for one occurrence are rejected.
For older exports, bindings addresses individual registered occurrences. Entries are flat objects, without sourceId or an occurrence wrapper:
[
{
"kind": "credential",
"blockId": "source-agent",
"subBlockKey": "tools",
"valuePath": [0, "params", "oauthCredential"],
"encoding": "scalar",
"targetId": "destination-connection"
}
]A top-level field uses valuePath:[]. Other registered encodings are array, csv, files, and environment; multi-value occurrences can include positions. Use a returned registered occurrence rather than inventing a path.
Preview and complete configuration
Build one request file and preview it:
jq -n --arg workspaceId "$DESTINATION_WORKSPACE" \
--slurpfile workflow workflow.json --slurpfile mappings import-mappings.json \
'{workspaceId: $workspaceId, workflow: $workflow[0], mappings: $mappings[0]}' \
> import-request.json
curl -sS --fail-with-body -H "X-API-Key: $DESTINATION_API_KEY" \
-H 'Content-Type: application/json' --data @import-request.json \
"$BASE_URL/api/v2/workflows/import/preview" > import-preview.jsonInspect data.unresolvedBindings, data.configuration, data.unresolvedConfiguration, and data.discovery. Dependent configuration choices have a different shape from bindings:
[
{ "blockId": "source-agent", "subBlockKey": "tools[0].folder", "value": "destination-label" }
]Add them as dependentValues to the request and preview again. A multiSelect:true field uses a comma-separated string of selected IDs.
For credential-backed selectors, use the import destination workspace and the preview's selectorKey and context to discover options:
curl -sS --fail-with-body -H "X-API-Key: $DESTINATION_API_KEY" \
-H 'Content-Type: application/json' \
--data "$(jq -n --arg workspaceId "$DESTINATION_WORKSPACE" \
'{workspaceId: $workspaceId, selectorKey: "gmail.labels", context: {oauthCredential: "destination-connection"}, limit: 50}')" \
"$BASE_URL/api/v2/selectors/list"Selector lists return { "data": [...], "nextCursor": null, "truncated": false }; check pagination and truncation. Detail uses /selectors/get with the same workspace/key/context and an id. MCP tool discovery uses mcp.tools with mcpServerId. A missing OAuth connection can require human authorization; changing a resource ID cannot create the connection.
Keep selector workspace, key, context, and search unchanged when paging. A changed provider page can return 409, requiring discovery to restart. Detail can return data:null for a missing choice or 413 when verification exceeds provider bounds. See List selector and Get selector.
Apply the reviewed import
When data.ready is true, choose a stable IMPORT_REQUEST_ID for this mutation and retain it with the complete request. Apply the exact reviewed choices and fingerprint:
jq --arg requestId "$IMPORT_REQUEST_ID" \
--arg fingerprint "$(jq -er '.data.previewFingerprint' import-preview.json)" \
'. + {requestId: $requestId, previewFingerprint: $fingerprint}' \
import-request.json > import-apply.json
curl -sS --fail-with-body -H "X-API-Key: $DESTINATION_API_KEY" \
-H 'Content-Type: application/json' --data @import-apply.json \
"$BASE_URL/api/v2/workflows/import" > import-result.jsonMapped import atomically creates the draft, graph, variables, required inline custom tools, and receipt. Remapping happens before graph ID regeneration; the result includes idMap. Plain imports without mapping options retain their earlier behavior and return no operation receipt. Supplying mapping options, even empty arrays, requires requestId and previewFingerprint.
Imported workflows remain drafts. Check reported configuration and deploy before using ordinary deployed execution.
Fork a workspace
Fork preview and apply start with the same choices:
{
"name": "Review environment",
"copy": { "tables": ["source-table"] }
}POST the request to /workspaces/{workspaceId}/fork/preview. Inspect its plan and fingerprint, then POST the same choices to /workspaces/{workspaceId}/fork with a stable requestId and the returned previewFingerprint.
Eligible deployed source workflows become child drafts. Resources are copied only when selected explicitly. Fork creation uses copy; sync uses copyResources. Fork copy.files contains workspace file IDs, while sync copyResources.files contains storage keys. Credentials and secret values are not copied. Inspect destination configuration before deploying a fork's workflows.
Push or pull a sync
Push sends deployed workflows from the current workspace to otherWorkspaceId. Pull brings them from otherWorkspaceId into the current workspace. Either endpoint can run from either side of a direct parent/child edge, with Admin access to both.
Sync can create target workflows, replace mapped target workflows, and archive mapped targets whose source was deleted or archived. It schedules deployments of the admitted snapshots. An undeployed source alone does not archive its mapped target. Excluded workflows remain excluded; review target replacements and retiring trigger URLs before apply.
Select mappings and copies
For a pull into the workspace in the URL, save sync-request.json:
{
"otherWorkspaceId": "source-workspace",
"mappings": [
{ "resourceType": "oauth_credential", "sourceId": "source-connection", "targetId": "destination-connection" }
],
"dependentValues": [
{ "sourceWorkflowId": "source-workflow", "sourceBlockId": "source-agent", "subBlockKey": "tools[0].folder", "value": "destination-label" }
],
"copyResources": { "tables": ["source-table"] }
}Sync mappings use edge resourceType names such as oauth_credential, service_account_credential, knowledge_base, custom_tool, and sandbox. Imports instead use kind names such as credential, knowledge-base, and custom-tool. Workflow identity is system-managed. Choose a knowledge document through its parent knowledge base's dependent selector instead of writing a knowledge_document edge mapping.
Mapping inspection requires otherWorkspaceId and direction query fields. Read rows include a storage id; writes accept only resourceType, sourceId, and targetId. Project a read page with jq '[.data[] | {resourceType, sourceId, targetId}]' before reusing it, and follow nextCursor for further pages.
Preview does not persist inline mappings. Apply saves them in the sync transaction. Dependent overrides use source workflow/block/field identities, including original nested-tool indices. Omitting dependentValues reuses saved choices; supplying it replaces choices for affected workflows, and [] clears them. Values in a target draft alone are not saved sync configuration.
dropReferences acknowledges references deleted in the source; it cannot discard live source resources.
Preview and inspect trigger choices
curl -sS --fail-with-body -H "X-API-Key: $SIM_API_KEY" \
-H 'Content-Type: application/json' --data @sync-request.json \
"$BASE_URL/api/v2/workspaces/$CURRENT_WORKSPACE/fork/pull/preview" > sync-preview.jsonReview unresolvedBindings, configuration, planned workflow actions, and retiring URLs. For selector discovery, use each configuration field's discoveryWorkspaceId: the source when its parent will be copied, the destination when mapped. Pass the returned context and preview any changed choices again. ready:true means the apply plan is ready, not that all destination deployments will be ready.
triggerSlots uses stable sourceWorkflowId and sourceBlockId identities and includes ownPath, adoptablePaths, and defaultAdoptPath:
- A slot with
ownPathpreserves that URL and accepts no override. - An arriving trigger can adopt an offered retiring path, or request a new URL with
adoptPath:null. - Unknown identities, duplicate choices, or paths outside the slot's candidates are rejected. Candidates stay within the same target workflow and provider.
Include the same triggerMappings choices on preview and apply:
[
{ "sourceWorkflowId": "source-workflow", "sourceBlockId": "source-trigger", "adoptPath": "retiring-trigger-path" }
]Apply the sync
Choose a stable SYNC_REQUEST_ID and preserve the exact reviewed request:
jq --arg requestId "$SYNC_REQUEST_ID" \
--arg fingerprint "$(jq -er '.data.previewFingerprint' sync-preview.json)" \
'. + {requestId: $requestId, previewFingerprint: $fingerprint, confirm: true}' \
sync-request.json > sync-apply.json
curl -sS --fail-with-body -H "X-API-Key: $SIM_API_KEY" \
-H 'Content-Type: application/json' --data @sync-apply.json \
"$BASE_URL/api/v2/workspaces/$CURRENT_WORKSPACE/fork/pull" > sync-result.jsonFor push, use /fork/push/preview and /fork/push with the same direction-relative rules. confirm:true acknowledges target replacement. Changes to mappings or trigger choices require another preview before apply.
Verify operations and recover
Apply returns a single-resource envelope. A completed sync report can look like:
{
"data": {
"operationId": "operation-id",
"requestId": "release-2026-10-13",
"workspaceId": "current-workspace",
"kind": "workspace_pull",
"applied": true,
"status": "completed",
"resourceIds": ["destination-workflow"],
"issues": [],
"deployments": [
{
"operationId": "deployment-id",
"workflowId": "destination-workflow",
"version": 2,
"status": "active",
"ready": true,
"pendingComponents": []
}
]
}
}Poll under the returned workspaceId:
| Mutation | Receipt workspace |
|---|---|
| Import | Destination |
| Fork creation | Source workspace on which /fork ran |
| Push/pull | Current workspace in the request URL, including a push that changes the other workspace |
OPERATION_ID=$(jq -er '.data.operationId' sync-result.json)
OPERATION_WORKSPACE=$(jq -er '.data.workspaceId' sync-result.json)
curl -sS --fail-with-body -H "X-API-Key: $SIM_API_KEY" \
"$BASE_URL/api/v2/workspaces/$OPERATION_WORKSPACE/operations/$OPERATION_ID"Poll with a delay while status is processing. Terminal outcomes are completed, completed_with_warnings, requires_configuration, and failed. Inspect issues, copyProgress, deployments[].ready, pendingComponents, and triggerUrlChanges.
applied:true stays true after a follow-up failure: the transaction committed. Completed imports and forks remain drafts. For sync, check the exact admitted deployments in the receipt before treating the destination as ready.
Retry an uncertain response
Request IDs deduplicate within the receipt workspace. Retain the complete apply request and original ID. Identical authorized retries return the original operation before preview-freshness checks. A changed payload under the same ID, stale preview, or blocked apply returns HTTP 409 with the v2 error envelope; other invalid input can return 400. Follow-up failures appear on a committed operation.
After an uncertain response, retry the identical request with its original ID, or query GET /workspaces/{workspaceId}/operations?requestId=.... Lists return { "data": [...], "nextCursor": ... }; use operation get for refreshed copy/deployment status.
If a stale preview is refused before commit, obtain a new preview and use a new request ID for the revised request. Do not replace a lost-response request with a fresh ID just to retry; that can create another mutation.
Rollback, unlink, and exclusions
Rollback restores the latest inbound sync's prior deployed versions. It can archive sync-created workflows and restore archived targets, but does not promise to restore arbitrary target drafts or undo all resource copies. Inspect pendingActivations; another rollback attempt may be needed to finish activation.
Unlink removes the direct relationship and its mappings while retaining workspace content. Exclusions keep selected workflows out of later syncs.
Related docs
- CLI workflow sync
- Workspace forking
- Import preview
- Operation status
- Workflow-sync repository harness for
bun run test:workflow-sync, disposable PostgreSQL, fixture boundaries, and contributor prerequisites