Skip to content

Examples

Copy, paste, publish.

Each example runs against this server as written. Set API_KEY to a key from Connect first.

curl: draft to live page

Shell
BASE="https://bloting.com"

# 1. Find the publication to publish into
curl -s "$BASE/v1/publications" -H "Authorization: Bearer $API_KEY"

# 2. Create a draft
curl -s "$BASE/v1/content" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"publication_id":"pub_...","markdown":"# Release notes\n\nWhat changed this week..."}'

# 3. Check it
curl -s "$BASE/v1/publishing/preview" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -d '{"content_id":"art_..."}'

# 4. Publish it (returns 200 with a url, or 202 with an approve_url)
curl -s "$BASE/v1/publishing/publish" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  -H "Idempotency-Key: release-notes-week-41" \
  -d '{"content_id":"art_..."}'

TypeScript: publish a Markdown file

Uses the built-in fetch; no SDK needed. Run with Node.js 22 or later.

publish.ts
import { readFile } from "node:fs/promises";

const BASE = "https://bloting.com";
const KEY = process.env.API_KEY!;

async function api<T>(method: string, path: string, body?: unknown, idempotencyKey?: string): Promise<{ status: number; data: T }> {
  const res = await fetch(BASE + path, {
    method,
    headers: {
      Authorization: `Bearer ${KEY}`,
      ...(body ? { "Content-Type": "application/json" } : {}),
      ...(idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}),
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  const data = res.status === 204 ? null : await res.json();
  if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
  return { status: res.status, data };
}

const file = process.argv[2]!;
const markdown = await readFile(file, "utf8");

const pubs = await api<{ data: { id: string; name: string }[] }>("GET", "/v1/publications");
const publication = pubs.data.data[0];
if (!publication) throw new Error("Create a publication first.");

const draft = await api<{ id: string }>("POST", "/v1/content", { publication_id: publication.id, markdown }, `draft:${file}`);

const preview = await api<{ requires_approval: boolean; validation: { checks: { id: string; label: string; state: string; notes: string[] }[] } }>(
  "POST", "/v1/publishing/preview", { content_id: draft.data.id });
for (const check of preview.data.validation.checks) for (const note of check.notes) console.log(`${check.label}: ${note}`);
// A key without publish permission is "blocked" only by that check; it can still ask for approval.
const blocking = preview.data.validation.checks.filter((c) => c.state === "block" && c.id !== "publishing_permissions");
if (blocking.length) process.exit(1);

const result = await api<{ status: string; url?: string; approve_url?: string }>(
  "POST", "/v1/publishing/publish", { content_id: draft.data.id }, `publish:${draft.data.id}`);

console.log(result.status === 202 ? `Waiting for approval: ${result.data.approve_url}` : `Live: ${result.data.url}`);

Python: list everything you've published

list_published.py
import os
import requests

BASE = "https://bloting.com"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['API_KEY']}"

cursor = None
while True:
    params = {"status": "published", "limit": 100}
    if cursor:
        params["cursor"] = cursor
    res = session.get(f"{BASE}/v1/content", params=params, timeout=30)
    if res.status_code == 429:
        raise SystemExit(f"Rate limited. Retry in {res.headers['Retry-After']}s.")
    res.raise_for_status()
    page = res.json()
    for item in page["data"]:
        print(item["published_at"], item["url"], item["title"], sep="\t")
    if not page["has_more"]:
        break
    cursor = page["next_cursor"]

In a conversation

With the MCP server connected, publishing can happen without leaving your assistant. An illustration:

  1. YouPublish my latest article.
  2. AssistantWhich publication should I use?
  3. YouMy Technology Blog.
  4. AssistantI've prepared the page. Would you like to publish it?
  5. YouYes.
  6. AssistantPublished. Here's your link.

This is an example, not a transcript. It depends on your AI client supporting remote MCP servers and asking before it calls tools, and on the connection having permission to publish. Without that permission the last step is a link for you to approve instead.

Behind those turns the assistant calls publication_list, content_create, content_preview and, after you say yes, content_publish.