DEVELOPER DOCS · BETA

The Harbor API & MCP

Generate SEO articles, landing pages and rewrites — and research topics and manage sites — from your own apps, n8n, or Claude Code. A curl-first REST API, an MCP server, and hand-written Python & TypeScript SDKs. Every call uses your existing Harbor article credits.

Overview

Harbor's API lets you run everything Harbor does programmatically. It's in beta — endpoints may change, and we'll give notice before any breaking change.

  • Base URLhttps://outgoing-oyster-428.convex.site/v1
  • MCP endpointhttps://outgoing-oyster-428.convex.site/mcp
  • Auth — every request needs the header Authorization: Bearer hrb_live_…
  • Billing — 1 article credit per generation (research is free). Failed jobs refund automatically.

Mint a key from the Devs page in your dashboard — it's shown once, so store it safely.

Quick start

List your sites, start an article, then poll it to done:

# 1. Find a site_id
curl "https://outgoing-oyster-428.convex.site/v1/sites" \
  -H "Authorization: Bearer hrb_live_..."

# 2. Start an article
curl -X POST "https://outgoing-oyster-428.convex.site/v1/articles" \
  -H "Authorization: Bearer hrb_live_..." \
  -H "Content-Type: application/json" \
  -d '{"site_id":"SITE_ID","keywords":"best running shoes"}'
# → { "id": "JOB_ID", "type": "article", "status": "queued" }

# 3. Poll until done (?wait=true blocks up to ~45s)
curl "https://outgoing-oyster-428.convex.site/v1/articles/JOB_ID?wait=true" \
  -H "Authorization: Bearer hrb_live_..."
# → { "status": "completed", "content": "<html>...", ... }

Endpoints

All endpoints are under /v1 and require the Bearer header.

Generate — POST, 1 credit each

  • POST /v1/articlessite_id, keywords, content_type?, tone?, instructions?, words_to_avoid?, webhook_url?
  • POST /v1/articles/bulksite_id, keywords[] (max 25), …same options
  • POST /v1/landing-pagessite_id, title, topic, page_type?, notes?, webhook_url?
  • POST /v1/reworksurl, mode? (rewrite|reforge), instructions?, webhook_url?

Articles inherit the site's saved settings — tone, brand voice, instructions, words-to-avoid — exactly like the dashboard. Body fields override them per request.

Research — POST, free

  • POST /v1/researchsite_id → poll for a topics array of ideas

Read — GET

  • GET /v1/articles/{id} — one job (also landing-pages, reworks, research)
  • GET /v1/articles?limit=&cursor= — paginated list
  • GET /v1/sites · GET /v1/sites/{id} — your sites with full settings
  • GET /v1/account — credits remaining + plan

Manage sites

  • POST /v1/sites — create a site (name, sitemap_url required)
  • PATCH /v1/sites/{id} — update any site setting

Jobs & polling

Generations are async. A POST returns a job id instantly; poll it until status is completed or failed. A full article takes ~3-6 minutes.

Add ?wait=true to a GET and it long-polls server-side for up to ~45s — returning the moment the job finishes — so you make a handful of requests instead of dozens.

{
  "id": "...",
  "type": "article | landing_page | rework | research",
  "status": "queued | generating | completed | failed",
  "progress": { "step": 2, "total": 3, "message": "Writing..." },
  "content": "<html>...</html>",   // when completed
  "title": "...", "word_count": 1840,
  "topics": [ ... ],               // research jobs
  "error": "...",                  // when failed
  "credit_refunded": true
}

Webhooks

Pass a webhook_url on any POST. When the job reaches a terminal state, Harbor sends POST <webhook_url> with the full job JSON and a header X-Harbor-Signature: sha256=<hmac> — HMAC-SHA256 of the raw body, secret = sha256_hex(your_api_key). Delivery retries ~3× on non-2xx.

MCP — Harbor inside Claude Code

Harbor ships a remote MCP server, so you can drop it into Claude Code, Claude Desktop, Cursor, or any MCP client. Install it with one command:

claude mcp add --transport http harbor \
  https://outgoing-oyster-428.convex.site/mcp \
  --header "Authorization: Bearer hrb_live_..."

Then just ask Claude — "research topics for my site and write the best 5" — and it runs the whole workflow. 11 tools: research, generate (single + bulk), landing pages, reworks, job status, full site management, and account.

Python SDK

Dependency-free (standard library only).

pip install harbor
from harbor import Harbor

h = Harbor(api_key="hrb_live_...")

# Generate an article and wait for it
job = h.articles.create(site_id="SITE_ID", keywords="best running shoes")
article = h.articles.wait(job.id)
print(article.content)

# Research, then bulk-generate the best ideas
research = h.research.wait(h.research.create(site_id="SITE_ID").id)
topics = [t["title"] for t in research.topics[:5]]
batch = h.articles.create_bulk(site_id="SITE_ID", keywords=topics)

Namespaces: articles, landing_pages, reworks, research, sites, account. .wait() polls until the job is done.

TypeScript SDK

Zero dependencies, fetch-based, fully typed.

npm install @harbor/sdk
import { Harbor } from "@harbor/sdk";

const h = new Harbor({ apiKey: "hrb_live_..." });

const job = await h.articles.create({
  siteId: "SITE_ID",
  keywords: "best running shoes",
});
const article = await h.articles.wait(job.id);
console.log(article.content);

n8n

There's no dedicated Harbor node — use n8n's built-in HTTP Request node. Method POST, URL https://outgoing-oyster-428.convex.site/v1/articles, a header Authorization: Bearer hrb_live_…, and a JSON body:

{
  "site_id": "SITE_ID",
  "keywords": "best running shoes"
}

The Devs page has copy-paste n8n recipes for every task, with your site pre-filled.

Errors

Errors use a consistent envelope: { "error": { "code": "...", "message": "..." } }

  • 400 — invalid request
  • 401 — missing / invalid / revoked key
  • 402 — out of article credits
  • 404 — not found
  • 500 — internal error

Ready to build? Mint a key and try every endpoint in the live playground.

Open the Devs page →