Propose an article edit or new draft for editor review

:::openapi-operation POST /api/v1/workspaces/{workspace}/proposals AUTH bearerAuth :::

Files a proposal that changes nothing until an editor approves it. A change to an article takes edits or markdown, base_revision and allow_shrink with the rules of updateArticle, and records the current revision as its base. A new article takes title, markdown and section_key, the section it goes into on approval.

:::codesamples open Code examples

curl -X POST "https://contextowl.co/api/v1/workspaces/string/proposals" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  --data '{
  "markdown": "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/proposals"))
        .header("Accept", "application/json")
        .header("Authorization", "Bearer <token>")
        .header("Content-Type", "application/json")
        .method("POST", HttpRequest.BodyPublishers.ofString("{\n  \"markdown\": \"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/proposals"
headers = {
    "Accept": "application/json",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json",
}
data = "{\n  \"markdown\": \"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/proposals", {
  method: "POST",
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "markdown": "string"
  })
});

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

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

func main() {
	body := strings.NewReader(`{
  "markdown": "string"
}`)
	req, err := http.NewRequest("POST", "https://contextowl.co/api/v1/workspaces/string/proposals", 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/proposals")
        .header("Accept", "application/json")
        .header("Authorization", "Bearer <token>")
        .header("Content-Type", "application/json")
        .body("{\n  \"markdown\": \"string\"\n}")
        .send()?;

    println!("{}", response.status());
    println!("{}", response.text()?);
    Ok(())
}

:::

:::details open Parameters (1)

NAME IN TYPE REQUIRED DESCRIPTION
workspace path string yes Workspace id, or - for the key's bound workspace

:::

:::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 in the current body, applied in order. Only for a change to an existing article. Send markdown or edits, not both.
markdown string no Proposed body in Markdown. It replaces the whole body. Send markdown or edits, not both.
note string no Note for the reviewer: what changed and why
section_key string no Key of the sidebar section that a new article goes into when a reviewer approves it. Only for a new article.
slug string no Slug of the article to change. Leave it out to propose a new article.
title string no Proposed title. A new article needs one. A change keeps the current title when you leave it out.
{
  "markdown": "string"
}

:::

:::details open Success responses (201)

201

Success

Content-Type: application/json

FIELD TYPE REQUIRED DESCRIPTION
baseRevision string yes -
id integer yes -
reviewUrl string yes -
slug string yes -
status string yes -
{
  "baseRevision": "string",
  "id": 0,
  "reviewUrl": "string",
  "slug": "string",
  "status": "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: a section_key of 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
  }
}

409

stale_revision: base_revision does not match the current content. openapi_generated: detach the generated page before you propose a change.

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.

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
  }
}

:::