curl --request PATCH \
--url https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"baseRev": 123,
"deletes": [
"<string>"
],
"writes": [
{
"contentBase64": "<string>",
"path": "<string>"
}
]
}
'import requests
url = "https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files"
payload = {
"baseRev": 123,
"deletes": ["<string>"],
"writes": [
{
"contentBase64": "<string>",
"path": "<string>"
}
]
}
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
baseRev: 123,
deletes: ['<string>'],
writes: [{contentBase64: '<string>', path: '<string>'}]
})
};
fetch('https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'baseRev' => 123,
'deletes' => [
'<string>'
],
'writes' => [
[
'contentBase64' => '<string>',
'path' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files"
payload := strings.NewReader("{\n \"baseRev\": 123,\n \"deletes\": [\n \"<string>\"\n ],\n \"writes\": [\n {\n \"contentBase64\": \"<string>\",\n \"path\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"baseRev\": 123,\n \"deletes\": [\n \"<string>\"\n ],\n \"writes\": [\n {\n \"contentBase64\": \"<string>\",\n \"path\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"baseRev\": 123,\n \"deletes\": [\n \"<string>\"\n ],\n \"writes\": [\n {\n \"contentBase64\": \"<string>\",\n \"path\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"agentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z",
"files": [
{
"createdAt": "2023-11-07T05:31:56Z",
"fileName": "<string>",
"filePath": "<string>",
"fileSize": 123,
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"updatedAt": "2023-11-07T05:31:56Z",
"checksum": "<string>",
"mimeType": "<string>"
}
],
"graph": {
"nodes": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"properties": {
"type": "start"
},
"type": "start",
"description": "<string>",
"position": {
"x": 123,
"y": 123
}
}
],
"sticky_notes": [
{
"content": "<string>",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"color": "<string>",
"position": {
"x": 123,
"y": 123
},
"size": {
"height": 123,
"width": 123
}
}
],
"transitions": [
{
"from": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"properties": {
"type": "iris"
},
"require_confirmation": true,
"to": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "iris",
"description": "<string>",
"schema": {}
}
]
},
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"inputs": [
{
"name": "<string>",
"required": true,
"schema": {},
"defaultValue": "<unknown>",
"description": "<string>"
}
],
"isPublished": true,
"rev": 123,
"rules": "<string>",
"settings": {
"max_timeout_mins": 123,
"viewport_height": 123,
"viewport_width": 123
},
"version": 123,
"author": "<string>",
"environmentTemplate": {
"config": {
"provider": "anchor"
},
"type": "browser"
},
"parentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}{
"code": 400,
"message": "<string>"
}{
"code": 401,
"message": "<string>"
}{
"code": 403,
"message": "<string>"
}{
"code": 404,
"message": "<string>"
}{
"code": 409,
"message": "<string>"
}{
"code": 500,
"message": "<string>"
}Patch workflow head files
Patch the editable head’s file representation in place: apply file writes/deletes, re-derive the structured workflow, and persist it. Structural files re-derive the graph; agent files go to the blob store. Agent-file writes overlay the current head even when baseRev is stale. Structural-file writes still require a matching baseRev. When the head is frozen (published or executed) the edit forks a fresh version behind the scenes.
curl --request PATCH \
--url https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: <api-key>' \
--data '
{
"baseRev": 123,
"deletes": [
"<string>"
],
"writes": [
{
"contentBase64": "<string>",
"path": "<string>"
}
]
}
'import requests
url = "https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files"
payload = {
"baseRev": 123,
"deletes": ["<string>"],
"writes": [
{
"contentBase64": "<string>",
"path": "<string>"
}
]
}
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
baseRev: 123,
deletes: ['<string>'],
writes: [{contentBase64: '<string>', path: '<string>'}]
})
};
fetch('https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'baseRev' => 123,
'deletes' => [
'<string>'
],
'writes' => [
[
'contentBase64' => '<string>',
'path' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files"
payload := strings.NewReader("{\n \"baseRev\": 123,\n \"deletes\": [\n \"<string>\"\n ],\n \"writes\": [\n {\n \"contentBase64\": \"<string>\",\n \"path\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"baseRev\": 123,\n \"deletes\": [\n \"<string>\"\n ],\n \"writes\": [\n {\n \"contentBase64\": \"<string>\",\n \"path\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://odyssey.asteroid.ai/agents/v2/agents/{agentId}/workflow-head/files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"baseRev\": 123,\n \"deletes\": [\n \"<string>\"\n ],\n \"writes\": [\n {\n \"contentBase64\": \"<string>\",\n \"path\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"agentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z",
"files": [
{
"createdAt": "2023-11-07T05:31:56Z",
"fileName": "<string>",
"filePath": "<string>",
"fileSize": 123,
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"updatedAt": "2023-11-07T05:31:56Z",
"checksum": "<string>",
"mimeType": "<string>"
}
],
"graph": {
"nodes": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"properties": {
"type": "start"
},
"type": "start",
"description": "<string>",
"position": {
"x": 123,
"y": 123
}
}
],
"sticky_notes": [
{
"content": "<string>",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"color": "<string>",
"position": {
"x": 123,
"y": 123
},
"size": {
"height": 123,
"width": 123
}
}
],
"transitions": [
{
"from": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"properties": {
"type": "iris"
},
"require_confirmation": true,
"to": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"type": "iris",
"description": "<string>",
"schema": {}
}
]
},
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"inputs": [
{
"name": "<string>",
"required": true,
"schema": {},
"defaultValue": "<unknown>",
"description": "<string>"
}
],
"isPublished": true,
"rev": 123,
"rules": "<string>",
"settings": {
"max_timeout_mins": 123,
"viewport_height": 123,
"viewport_width": 123
},
"version": 123,
"author": "<string>",
"environmentTemplate": {
"config": {
"provider": "anchor"
},
"type": "browser"
},
"parentId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}{
"code": 400,
"message": "<string>"
}{
"code": 401,
"message": "<string>"
}{
"code": 403,
"message": "<string>"
}{
"code": 404,
"message": "<string>"
}{
"code": 409,
"message": "<string>"
}{
"code": 500,
"message": "<string>"
}Authorizations
Path Parameters
The ID of the agent
Body
The file writes and deletes to apply
Request to patch the editable head's file representation. The server classifies each path: structural files re-derive the structured workflow, the agent's own files (memory, uploads, node scripts) go to their blob store. Agent-file writes overlay the head resolved under the edit lock, so a stale baseRev is not rejected. Structural-file writes still require a matching baseRev; a stale value is rejected with 409.
The revision this edit is based on. Agent-file-only patches overlay the current head even when this is stale. A structural-file patch is rejected with 409 when it does not match the stored head revision.
Paths of files to delete.
Files to upsert.
Show child attributes
Show child attributes
Response
The request has succeeded.
A workflow (commit) representing an immutable snapshot of agent configuration
The agent ID this workflow belongs to
When this workflow was created. For the editable head this is restamped on each in-place edit, so it doubles as the last-edited time.
The files stored on this workflow version. Empty when the workflow has no files.
Show child attributes
Show child attributes
The workflow graph
Show child attributes
Show child attributes
The unique ID of this workflow
Typed input definitions for workflow execution. Includes names referenced in prompts, which default to optional strings.
Show child attributes
Show child attributes
Whether this snapshot is the agent's published version (the API default). At most one snapshot per agent is published.
Monotonic optimistic-concurrency revision. Only meaningful for the editable head: supply it as baseRev on the next head patch. Agent-file-only patches overlay the current head if it has moved; structural-file patches are rejected with 409 when stale. Frozen snapshots never receive in-place patches.
The rules/instructions for this workflow
The settings for this workflow
Show child attributes
Show child attributes
The monotonic per-agent snapshot version number.
The email of the user who created this workflow.
Optional environment template. Defaults to browser/anchor if not provided. Omits admin-only OS fields.
Show child attributes
Show child attributes
The ID of the parent workflow this was derived from (for lineage tracking)

