Publish an artifact
Publish an artifact and get back its anchor, the stable key its public URL is built from. The anchor serves the current version, so you only need to publish once, however many versions you append afterwards.
This POST has no request body. Send no JSON at all.
Requires the Applets feature and the workspace admin or owner role. See Artifacts overview.
Path parameters
slug:requiredstringThe workspace slug. It appears in your Plane URLs. In https://app.plane.so/my-team/projects/, the slug is my-team.
artifact_id:requiredstring (uuid)The artifact to publish. UUID only.
Body parameters
None. The endpoint takes no request body; anything you send is ignored.
Safe to retry
Publishing is idempotent. An artifact that is already published returns its existing anchor instead of creating a new one or returning an error. A retry after a timeout is harmless, and the anchor you get back is stable.
There is no unpublish
is_active is always true in the response. v2 has no way to withdraw an artifact once it is published, and no way to rotate its anchor. Treat publishing as a one-way step.
Scopes
workspaces.artifacts:write
Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_request | Declared by the schema; the route takes no body, so there is little to invalidate. |
401 | unauthorized | Missing or invalid credentials. |
402 | payment_required | The Applets feature isn't enabled on your plan. |
403 | forbidden | You are not a workspace admin or owner, or your token lacks the scope. |
404 | not_found | No such artifact in this workspace, or the workspace is outside your tenant. |
406 | not_acceptable | The Accept header asks for a representation the API can't produce. |
409 | conflict | Declared by the schema; publishing an already-published artifact succeeds instead. |
413 | payload_too_large | The request body is over the size limit. |
415 | unsupported_media_type | The Content-Type isn't one this endpoint accepts. |
429 | rate_limited | Throttled. Honor the Retry-After header before retrying. |
curl -X POST \
"https://api.plane.so/api/v2/workspaces/my-team/artifacts/b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53/publish/" \
-H "X-Api-Key: $PLANE_API_KEY"import requests
response = requests.post(
"https://api.plane.so/api/v2/workspaces/my-team/artifacts/b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53/publish/",
headers={"X-Api-Key": "your-api-key"},
)
print(response.json()["anchor"])const response = await fetch(
"https://api.plane.so/api/v2/workspaces/my-team/artifacts/b7e42a19-3c5d-4f80-9a26-8d1c0f4e7b53/publish/",
{
method: "POST",
headers: { "X-Api-Key": "your-api-key" },
},
);
const data = await response.json();{
"anchor": "5e2a7c81-4f39-4b60-a1d8-0c6b3e9f2d74",
"is_active": true
}{
"type": "not_found",
"code": "not_found",
"detail": "Artifact not found."
}The response status is 201, not 200
A successful publish returns 201 Created, including on a repeat call where nothing new was created. The OpenAPI document declares 200 for this operation, but that is a gap in the schema annotation, not the actual behavior. Accept any 2xx instead of matching an exact status.
Storing the anchor
Save the anchor when you get it. The detail read does not return anchor or is_published, so publishing again is currently the only way to recover an anchor you have lost. That works because publishing is idempotent, but it is not what the endpoint is for.
Artifacts share Plane's anchor system with other publishable entities, so the anchor is unique across the workspace, not just among artifacts.

