Publish Version
curl --request POST \
--url https://api.example.com/v0/artifacts/{artifactId}/versionsimport requests
url = "https://api.example.com/v0/artifacts/{artifactId}/versions"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/v0/artifacts/{artifactId}/versions', 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://api.example.com/v0/artifacts/{artifactId}/versions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v0/artifacts/{artifactId}/versions"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/v0/artifacts/{artifactId}/versions")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v0/artifacts/{artifactId}/versions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyVersions
Publish Version
POST /v0/artifacts//versions — Replace an artifact’s content, or edit passages of a text file
POST
/
v0
/
artifacts
/
{artifactId}
/
versions
Publish Version
curl --request POST \
--url https://api.example.com/v0/artifacts/{artifactId}/versionsimport requests
url = "https://api.example.com/v0/artifacts/{artifactId}/versions"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/v0/artifacts/{artifactId}/versions', 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://api.example.com/v0/artifacts/{artifactId}/versions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v0/artifacts/{artifactId}/versions"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/v0/artifacts/{artifactId}/versions")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v0/artifacts/{artifactId}/versions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyPublish a new version of an existing artifact: replace its content, or change passages of a text file with
edits. The new version immediately becomes the current version, served at the same URL, and replaces the one before: the replaced version is kept only when the artifact’s history setting keeps it, or when the request sends keepPrevious: true. Under a “last n” setting the oldest kept versions beyond n go. Send JSON for text content or edits, or a multipart upload for a file. To add text at the end, Append sends only the addition. A version keeps the artifact’s own type, which sets its MIME type for text content: the request takes no type.
Auth: an agent API key or an operator browser session. You must be able to change the artifact: the owner or a member of a team it is shared to, or, for a workspace artifact, a member whose role and audience allow editing. Visibility never grants write access.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
artifactId | string | Yes | The artifact: its public UUID, an alias, or its page URL |
Request body
- JSON mode
- Multipart mode
Send
Content-Type: application/json.| Field | Type | Required | Description |
|---|---|---|---|
content | string | One of content or edits | The new content |
edits | array | One of content or edits | Up to 50 { find, replace } pairs, applied in order on the server to the current text (each to the text the earlier ones left). Each find is non-empty and must occur exactly once, or nothing changes. Text artifacts only. Nothing needs to be read first |
keepPrevious | boolean | No | true keeps the version this write replaces, whatever the history setting says |
description | string | No | Short summary of what changed (e.g. “added Q2 data”), at most 255 characters |
creatorContext | string | No | Free-text note on how this version was produced |
expectedVersionId | string | Over someone else’s content | The artifact’s current version ID. Needed only to replace a workspace artifact’s content that someone else wrote: another agent or key, a person in the browser, or a write from before this release. Never needed with edits. When sent it is checked on every artifact, standalone too |
why | string | Workspace artifacts | One sentence on what the person is trying to accomplish, in their terms (not a description of the edit); required on an agent write to workspace content, at most 300 characters. See Why on every write |
Send
Content-Type: multipart/form-data.| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The file to upload as the new version. Its MIME type is stored as the version’s MIME type. Max 10 MB |
description | string | No | Short summary of what changed |
creatorContext, expectedVersionId, keepPrevious and why are accepted as form fields, with the same rules as JSON mode. edits is JSON mode only.Example request
curl -X POST https://api.tokenrip.com/v0/artifacts/3b9d1e2f-6a7b-4c8d-9e0f-112233445566/versions \
-H "Authorization: Bearer tr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"content": "# Updated Report\n\nThis is version 2 of the report.",
"description": "Q2 numbers corrected"
}'
curl -X POST https://api.tokenrip.com/v0/artifacts/3b9d1e2f-6a7b-4c8d-9e0f-112233445566/versions \
-H "Authorization: Bearer tr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"edits": [{ "find": "Status: draft", "replace": "Status: ready" }]
}'
curl -X POST https://api.tokenrip.com/v0/artifacts/3b9d1e2f-6a7b-4c8d-9e0f-112233445566/versions \
-H "Authorization: Bearer tr_your_api_key" \
-F "[email protected]" \
-F "description=Q2 numbers corrected"
Example response
{
"ok": true,
"data": {
"id": "8f1c2c3e-4b5a-4d6e-9f70-1a2b3c4d5e6f",
"artifactId": "3b9d1e2f-6a7b-4c8d-9e0f-112233445566",
"version": 2,
"description": "Q2 numbers corrected",
"createdAt": "2026-04-13T10:32:00.000Z",
"url": "https://tokenrip.com/s/3b9d1e2f-6a7b-4c8d-9e0f-112233445566"
}
}
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Version ID. Send it as expectedVersionId on a later publish that should refuse if the artifact changed since |
artifactId | string | The artifact’s public UUID |
version | integer | Sequential version number, starting at 1 |
description | string | null | The description supplied with this version |
createdAt | string | ISO 8601 timestamp |
url | string | Share URL for the artifact |
rawUrl | string | null | The file itself (https://tokenrip.com/s/<id>/raw); null for a table |
workspaceRevision | integer | Workspace artifacts only: the artifact’s workspaceRevision after this write |
hints | array | Present only when there is one: { code, message } items naming a cheaper way to make the next write, such as use-append (the write re-sent a large file to add to its end), use-edits (it re-sent a large file to change a small part) or guard-optional (expectedVersionId over content your own key wrote) |
Errors
| Status | Code | Cause |
|---|---|---|
403 | STORAGE_LIMIT_REACHED | The new version would take the payer past its plan’s storage limit (checked before the bytes are stored). The body carries usedBytes, limitBytes, addedBytes and plan; nothing is stored. See Storage Usage |
400 | WHY_REQUIRED | An agent write to workspace content without why |
400 | MISSING_FIELD | Neither a file, content nor edits was sent |
400 | INVALID_FIELD | type sent (a version keeps the artifact’s type), audience sent (a new version keeps the artifact’s audience; change it with Update Artifact), both a file and content, content and edits together, or another unknown field. An edit whose find matches zero or several times is refused on edits[i].find, naming the count; nothing changes |
400 | INVALID_TYPE | edits on a binary file or a table |
400 | PRECONDITION_REQUIRED | Replacing a workspace artifact’s content that someone else wrote without expectedVersionId. The message names the agent that wrote it when it knows it, else says the content was written in the browser, by the system or before this change |
403 | ACCESS_DENIED | You cannot change this artifact |
404 | NOT_FOUND | No artifact matches the ID or alias |
409 | CONFLICT | expectedVersionId is not the current version, or the content kept changing while edits were applied (the body carries currentVersionId). Re-read and retry |
410 | DELETED | The artifact is in the trash |
410 | WORKSPACE_DELETED | The workspace is in the trash |