Attach an OpenAPI spec (by url or raw spec) and generate pages

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

Validates the spec before it saves anything. When the spec and its pages are already up to date, returns unchanged true and writes nothing. When the org reviews agent changes, a spec that changes the stored spec or the pages answers 202 with an openapi proposal that holds the spec and the planned pages.

:::codesamples open Code examples

curl -X PUT "https://contextowl.co/api/v1/workspaces/string/openapi" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  --data '{
  "url": "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/openapi"))
        .header("Accept", "application/json")
        .header("Authorization", "Bearer <token>")
        .header("Content-Type", "application/json")
        .method("PUT", HttpRequest.BodyPublishers.ofString("{\n  \"url\": \"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/openapi"
headers = {
    "Accept": "application/json",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json",
}
data = "{\n  \"url\": \"string\"\n}".encode("utf-8")
req = urllib.request.Request(url, data=data, headers=headers, method="PUT")
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/openapi", {
  method: "PUT",
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "url": "string"
  })
});

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

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

func main() {
	body := strings.NewReader(`{
  "url": "string"
}`)
	req, err := http.NewRequest("PUT", "https://contextowl.co/api/v1/workspaces/string/openapi", 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::PUT, "https://contextowl.co/api/v1/workspaces/string/openapi")
        .header("Accept", "application/json")
        .header("Authorization", "Bearer <token>")
        .header("Content-Type", "application/json")
        .body("{\n  \"url\": \"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
note string no Note for the reviewer when the org reviews agent changes: what the change does and why. A direct write ignores it.
spec string no The OpenAPI document as JSON or YAML text, up to 2 MiB. Send url or spec, not both.
url string no HTTPS URL of the OpenAPI document. The server fetches it now and on every sync. Send url or spec, not both.
{
  "url": "string"
}

:::

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

200

Success

Content-Type: application/json

FIELD TYPE REQUIRED DESCRIPTION
configured boolean yes -
lastError string no -
lastSyncedAt string (date-time) no -
sourceType string no -
sourceUrl string no -
specBytes integer no -
specFormat string no -
specTitle string no -
specVersion string no -
stats OpenAPISyncStats object no -
unchanged boolean no -
updatedAt string (date-time) no -
{
  "configured": true,
  "lastError": "string",
  "lastSyncedAt": "string",
  "sourceType": "string",
  "sourceUrl": "string",
  "specBytes": 0,
  "specFormat": "string",
  "specTitle": "string",
  "specVersion": "string",
  "stats": {
    "created": 0,
    "deleted": 0,
    "unchanged": 0,
    "updated": 0
  },
  "unchanged": true,
  "updatedAt": "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, 403, 404, 409, 413, 422, 429, 500, 502)

400

invalid_openapi: the spec is not a valid OpenAPI document. invalid_openapi_source: send url or spec, not both. The stored spec and pages stay.

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

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

openapi_slug_collision: a generated page would take the slug of an article.

Content-Type: application/json

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

413

openapi_too_large: the spec is larger than 2 MiB.

Content-Type: application/json

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

422

openapi_too_complex: the schema references of the spec expand beyond the limit of the server.

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

502

openapi_fetch_failed: the server could not fetch the spec URL. The stored spec and pages stay.

Content-Type: application/json

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

:::