Update an article (status needs article.publish; restricted visibility needs a paid plan)

:::openapi-operation PATCH /api/v1/workspaces/{workspace}/articles/{slug} AUTH bearerAuth :::

Changes only the fields in the body. Send edits for exact text replacements, or markdown for a full body, not both. base_revision makes the call fail with 409 stale_revision when the article changed. A markdown body that removes more than half of the text and more than 2,000 characters returns 422 large_removal unless allow_shrink is true. A status change to a published status places an unplaced article in the sidebar, and the response then has placed true. When the org reviews changes from agent keys, a change to a published article, or a status that publishes a draft, answers 202 with the proposal that holds it. A change that makes the pending proposal of the key unneeded withdraws it, and withdrawnProposal names that proposal.

:::codesamples open Code examples

curl -X PATCH "https://contextowl.co/api/v1/workspaces/string/articles/string" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  --data '{
  "allow_shrink": true,
  "base_revision": "string",
  "edits": [
    {
      "new": "string",
      "old": "string"
    }
  ],
  "markdown": "string",
  "note": "string",
  "section": "string",
  "status": "string",
  "title": "string",
  "visibility": "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"))
        .header("Accept", "application/json")
        .header("Authorization", "Bearer <token>")
        .header("Content-Type", "application/json")
        .method("PATCH", HttpRequest.BodyPublishers.ofString("{\n  \"allow_shrink\": true,\n  \"base_revision\": \"string\",\n  \"edits\": [\n    {\n      \"new\": \"string\",\n      \"old\": \"string\"\n    }\n  ],\n  \"markdown\": \"string\",\n  \"note\": \"string\",\n  \"section\": \"string\",\n  \"status\": \"string\",\n  \"title\": \"string\",\n  \"visibility\": \"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"
headers = {
    "Accept": "application/json",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json",
}
data = "{\n  \"allow_shrink\": true,\n  \"base_revision\": \"string\",\n  \"edits\": [\n    {\n      \"new\": \"string\",\n      \"old\": \"string\"\n    }\n  ],\n  \"markdown\": \"string\",\n  \"note\": \"string\",\n  \"section\": \"string\",\n  \"status\": \"string\",\n  \"title\": \"string\",\n  \"visibility\": \"string\"\n}".encode("utf-8")
req = urllib.request.Request(url, data=data, headers=headers, method="PATCH")
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", {
  method: "PATCH",
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "allow_shrink": true,
    "base_revision": "string",
    "edits": [
      {
        "new": "string",
        "old": "string"
      }
    ],
    "markdown": "string",
    "note": "string",
    "section": "string",
    "status": "string",
    "title": "string",
    "visibility": "string"
  })
});

console.log(response.status);
console.log(await response.json());
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"
)

func main() {
	body := strings.NewReader(`{
  "allow_shrink": true,
  "base_revision": "string",
  "edits": [
    {
      "new": "string",
      "old": "string"
    }
  ],
  "markdown": "string",
  "note": "string",
  "section": "string",
  "status": "string",
  "title": "string",
  "visibility": "string"
}`)
	req, err := http.NewRequest("PATCH", "https://contextowl.co/api/v1/workspaces/string/articles/string", 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::PATCH, "https://contextowl.co/api/v1/workspaces/string/articles/string")
        .header("Accept", "application/json")
        .header("Authorization", "Bearer <token>")
        .header("Content-Type", "application/json")
        .body("{\n  \"allow_shrink\": true,\n  \"base_revision\": \"string\",\n  \"edits\": [\n    {\n      \"new\": \"string\",\n      \"old\": \"string\"\n    }\n  ],\n  \"markdown\": \"string\",\n  \"note\": \"string\",\n  \"section\": \"string\",\n  \"status\": \"string\",\n  \"title\": \"string\",\n  \"visibility\": \"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
allow_shrink boolean no Accept a markdown body that removes more than half of the text and more than 2,000 characters. The default is false.
base_revision string no Revision of the article that the change starts from, as getArticle returns it. A different current revision returns 409 stale_revision.
edits array items: ArticleEdit object no 1 to 20 exact text replacements, applied in order. Do not send them together with markdown.
markdown string no New body in Markdown. It replaces the whole body. Do not send it together with edits.
note string no Note for the reviewer when the org reviews agent changes: what the change does and why. A direct write ignores it.
section string no New display label of the section. It does not move the article in the sidebar.
status string no DRAFT, IN REVIEW, BETA, STABLE or DEPRECATED. A status change needs the article.publish permission.
title string no New title
visibility string no public, internal or private. internal and private need a paid plan or an active trial.
{
  "allow_shrink": true,
  "base_revision": "string",
  "edits": [
    {
      "new": "string",
      "old": "string"
    }
  ],
  "markdown": "string",
  "note": "string",
  "section": "string",
  "status": "string",
  "title": "string",
  "visibility": "string"
}

:::

:::details open Success responses (200, 202)

200

Success

Content-Type: application/json

FIELD TYPE REQUIRED DESCRIPTION
changed array items: string yes -
nav string yes -
placed boolean no -
previousRevision string yes -
revision string yes -
slug string yes -
status string yes -
updatedAt string (date-time) yes -
url string yes -
withdrawnProposal WithdrawnProposal object no -
{
  "changed": [
    "string"
  ],
  "nav": "string",
  "placed": true,
  "previousRevision": "string",
  "revision": "string",
  "slug": "string",
  "status": "string",
  "updatedAt": "string",
  "url": "string",
  "withdrawnProposal": {
    "id": 0,
    "reason": "string"
  }
}

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, 409, 422, 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: internal and private visibility need 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
  }
}

409

stale_revision: base_revision does not match the current content. openapi_generated: detach the generated page before you edit it.

Content-Type: application/json

FIELD TYPE REQUIRED DESCRIPTION
error object yes -
{
  "error": {
    "code": "string",
    "details": null,
    "message": "string",
    "status": 0
  }
}

422

encrypted, edit_not_found, edit_ambiguous or large_removal: the change does not apply to the current text. When the edits apply to the pending proposal of the key, details.proposalId names 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
  }
}

:::