$ cli-blog docs

Quickstart

Create an API key, then publish with the CLI, API, Node SDK, or an agent.

Start in the dashboard, create keys, then publish one draft through the CLI, API, Node SDK, or agent skill.

Choose your quickstart

Start with the surface that matches the work you want to complete:

Get an API key

Create a public key for delivery reads and a private key for trusted publishing.

  1. Open API keys in the dashboard.
  2. Create a public key with read access for your blog frontend.
  3. Create a private key with only the write permissions this quickstart needs.
  4. Save the private value immediately in your shell or secret manager; it is shown only when created.

See API keys before choosing permissions for production.

Use the CLI

Configure a trusted key.

cli-blog config set --api-key "$CLI_BLOG_API_KEY"

Create a draft.

AUTHOR_ID=$(cli-blog authors create --public-name "Maya Chen" --slug maya-chen --json | jq -r '.id')
CATEGORY_ID=$(cli-blog categories create --name "Engineering" --slug engineering --locale en-US --json | jq -r '.id')
TAG_ID=$(cli-blog tags create --name "Launch Notes" --slug launch-notes --locale en-US --json | jq -r '.id')

POST_JSON=$(cli-blog posts create \
  --title "Shipping an API-first blog" \
  --body-markdown "## What shipped

We added a durable publishing workflow to our product." \
  --author-ids "$AUTHOR_ID" \
  --category-ids "$CATEGORY_ID" \
  --tag-ids "$TAG_ID" \
  --json)

POST_ID=$(printf '%s' "$POST_JSON" | jq -r '.id')
POST_VERSION=$(printf '%s' "$POST_JSON" | jq -r '.version')

printf 'Draft created: %s\n' "$POST_ID"

Publish after review.

cli-blog posts publish "$POST_ID" --expected-version "$POST_VERSION" --json

Publishing is a status change under the hood. The command above is a shortcut for:

cli-blog posts update "$POST_ID" --status published --expected-version "$POST_VERSION" --json

You can also publish immediately on create by passing --status published, though draft-first is safer for human or agent review.

Use public keys for published-content reads. Use private keys for create, update, publish, schedule, and delete commands. Read API keys for storage, permissions, and rotation guidance.

Call the API

Read published posts with a public key.

curl -sS "https://api.cli-blog.com/v1/posts?locale=en-US&fields=summary&include=authors,tags" \
  -H "x-api-key: $CLI_BLOG_PUBLIC_KEY"

Create a complete draft with a private key. This terminal example uses jq to pass each returned ID into the next request.

AUTHOR_ID=$(curl -sS "https://api.cli-blog.com/v1/authors" \
  -H "content-type: application/json" \
  -H "x-api-key: $CLI_BLOG_API_KEY" \
  -d '{
    "public_name": "Maya Chen",
    "slug": "maya-chen"
  }' | jq -r '.id')

CATEGORY_ID=$(curl -sS "https://api.cli-blog.com/v1/categories" \
  -H "content-type: application/json" \
  -H "x-api-key: $CLI_BLOG_API_KEY" \
  -d '{ "name": "Engineering", "slug": "engineering", "locale": "en-US" }' | jq -r '.id')

TAG_ID=$(curl -sS "https://api.cli-blog.com/v1/tags" \
  -H "content-type: application/json" \
  -H "x-api-key: $CLI_BLOG_API_KEY" \
  -d '{ "name": "Launch Notes", "slug": "launch-notes", "locale": "en-US" }' | jq -r '.id')

POST_JSON=$(curl -sS "https://api.cli-blog.com/v1/posts" \
  -H "content-type: application/json" \
  -H "x-api-key: $CLI_BLOG_API_KEY" \
  -d "$(jq -n \
    --arg author "$AUTHOR_ID" \
    --arg category "$CATEGORY_ID" \
    --arg tag "$TAG_ID" \
    '{
      title: "Shipping an API-first blog",
      locale: "en-US",
      body_markdown: "## What shipped\n\nWe added a durable publishing workflow to our product.",
      author_profile_ids: [$author],
      category_ids: [$category],
      tag_ids: [$tag]
    }')")

POST_ID=$(printf '%s' "$POST_JSON" | jq -r '.id')
POST_VERSION=$(printf '%s' "$POST_JSON" | jq -r '.version')
printf 'Draft created: %s\n' "$POST_ID"

Publish after review.

curl -sS "https://api.cli-blog.com/v1/posts/$POST_ID" \
  -H "content-type: application/json" \
  -H "x-api-key: $CLI_BLOG_API_KEY" \
  -d "$(jq -n --argjson version "$POST_VERSION" '{ status: "published", expected_version: $version }')"

Use the Node SDK

Install the Node SDK in trusted server code.

npm install @cli-blog/node
import { CliBlog } from "@cli-blog/node";

const blog = new CliBlog({
  apiKey: process.env.CLI_BLOG_API_KEY!,
});

const draft = await blog.posts.create({
  title: "Shipping an API-first blog",
  body_markdown: "Start with the API, then add your publishing workflow.",
  author_profile_ids: ["author_123"],
});

await blog.posts.publish(draft.id, {
  expected_version: draft.version,
});

Show published posts in React

Use a public key in the frontend and keep private publishing keys on the server.

import { useEffect, useState } from "react";

export function BlogIndex() {
  const [posts, setPosts] = useState<Array<{ id: string; slug: string; title: string }>>([]);

  useEffect(() => {
    fetch("https://api.cli-blog.com/v1/posts?status=published&fields=summary", {
      headers: { "x-api-key": import.meta.env.PUBLIC_CLI_BLOG_KEY },
    })
      .then((response) => response.json())
      .then((result) => setPosts(result.data));
  }, []);

  return <ul>{posts.map((post) => <li key={post.id}>{post.title}</li>)}</ul>;
}

blog.posts.publish() is a convenience helper. This direct status update is equivalent:

await blog.posts.update(draft.id, {
  status: "published",
  expected_version: draft.version,
});

Work with an agent

Add the skill with one command and keep the key in the trusted agent runtime.

npx skills add https://github.com/cli-blog/cli-blog-skill --skill cli-blog

Review it on skills.sh, or inspect the source and other installation options in the GitHub repository.

Then ask for a draft-first flow:

Use the Cli Blog skill. Create a draft post, return the preview details, and wait for approval before publishing.

Next steps

On this page