Move an article into a section
:::openapi-operation POST /api/v1/workspaces/{workspace}/articles/{slug}/placement AUTH bearerAuth :::
Moves an article into a sidebar section, or to none to unlist it. position is a zero-based place in the section, and the default is the end. Generated OpenAPI pages are accepted, and later syncs keep their place. A move never opens an article: a published article that leaves an internal or private section for a more open place keeps that access as its own visibility, and visibilityChanged is true. To open the article, call updateArticle with visibility. The import-staging section that holds imported pages is not an access boundary, so an article that leaves it takes the access of its new section. When the org reviews changes from agent keys, a move of a published article answers 202 with the proposal that holds it.
:::codesamples open Code examples
curl -X POST "https://contextowl.co/api/v1/workspaces/string/articles/string/placement" \
-H "Accept: application/json" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
--data '{
"note": "string",
"position": 0,
"section": "string"
}'
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://contextowl.co/api/v1/workspaces/string/articles/string/placement"))
.header("Accept", "application/json")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\n \"note\": \"string\",\n \"position\": 0,\n \"section\": \"string\"\n}"))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}
import urllib.request
url = "https://contextowl.co/api/v1/workspaces/string/articles/string/placement"
headers = {
"Accept": "application/json",
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
}
data = "{\n \"note\": \"string\",\n \"position\": 0,\n \"section\": \"string\"\n}".encode("utf-8")
req = urllib.request.Request(url, data=data, headers=headers, method="POST")
with urllib.request.urlopen(req) as res:
print(res.status)
print(res.read().decode())
const response = await fetch("https://contextowl.co/api/v1/workspaces/string/articles/string/placement", {
method: "POST",
headers: {
"Accept": "application/json",
"Authorization": "Bearer <token>",
"Content-Type": "application/json",
},
body: JSON.stringify({
"note": "string",
"position": 0,
"section": "string"
})
});
console.log(response.status);
console.log(await response.json());
package main
import (
"fmt"
"io"
"net/http"
"strings"
"time"
)
func main() {
body := strings.NewReader(`{
"note": "string",
"position": 0,
"section": "string"
}`)
req, err := http.NewRequest("POST", "https://contextowl.co/api/v1/workspaces/string/articles/string/placement", body)
if err != nil {
panic(err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
res, err := client.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
bodyBytes, err := io.ReadAll(io.LimitReader(res.Body, 10<<20))
if err != nil {
panic(err)
}
fmt.Println(res.StatusCode)
fmt.Println(string(bodyBytes))
}
// cargo add reqwest --features blocking
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::blocking::Client::new();
let response = client.request(reqwest::Method::POST, "https://contextowl.co/api/v1/workspaces/string/articles/string/placement")
.header("Accept", "application/json")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"note\": \"string\",\n \"position\": 0,\n \"section\": \"string\"\n}")
.send()?;
println!("{}", response.status());
println!("{}", response.text()?);
Ok(())
}
:::
:::details open Parameters (2)
| NAME | IN | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|---|
workspace |
path | string | yes | Workspace id, or - for the key's bound workspace |
slug |
path | string | yes | - |
:::
:::details open Request body (required)
application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
note |
string | no | Note for the reviewer when the org reviews agent changes: what the change does and why. A direct write ignores it. |
position |
integer | no | Zero-based position in the section. Leave it out to add the article at the end. |
section |
string | yes | Key of the target section, or none to take the article out of the sidebar |
{
"note": "string",
"position": 0,
"section": "string"
}
:::
:::details open Success responses (200, 202)
200
Success
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
section |
string | yes | Key of the section that holds the article, or none |
slug |
string | yes | Slug of the article |
visibility |
string | yes | Visibility of the article after the move: public, internal or private |
visibilityChanged |
boolean | yes | True when the article left a stricter section and kept that access as its own visibility |
{
"section": "string",
"slug": "string",
"visibility": "string",
"visibilityChanged": true
}
202
The org reviews changes from agent keys, so the change waits in a proposal for an editor. Nothing changed for readers.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
message |
string | yes | What happened and what to tell the user |
pendingReview |
boolean | yes | True: the org reviews changes from agent keys, so the change waits in a proposal for an editor. Nothing changed for readers. |
proposal |
ReviewProposal object | yes | - |
{
"message": "string",
"pendingReview": true,
"proposal": {
"baseRevision": "string",
"entryId": 0,
"id": 0,
"objectType": "string",
"outcome": "string",
"reviewUrl": "string",
"slug": "string",
"status": "string",
"summary": "string",
"target": "string"
}
}
:::
:::details Error responses (400, 401, 402, 403, 404, 429, 500)
400
invalid_request: a parameter or the body is not valid.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
401
unauthorized: the access key is missing, invalid or expired.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
402
upgrade_required: a section that is not public needs a paid plan or an active trial.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
403
permission_denied: the key lacks the permission. two_factor_required: the org requires admins to turn on two-factor authentication.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
404
not_found: the object does not exist, or the key cannot reach it.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
429
rate_limited: too many requests. Wait for the time in the Retry-After header.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
500
internal: the server failed.
Content-Type: application/json
| FIELD | TYPE | REQUIRED | DESCRIPTION |
|---|---|---|---|
error |
object | yes | - |
{
"error": {
"code": "string",
"details": null,
"message": "string",
"status": 0
}
}
:::