Article Studio
API

Three on-ramps. One writer.

Ounie accounts hit REST with a bearer token. Assistants — including the Ounie AI Team — connect over MCP. Agents with no account at all pay per call in USDC on Base. All three run the same generator, the same guards, and the same refusals.

What gets refused, and when
Three checks, in this order. The first two are free; the third refunds.
1Relevance — before the model runs
400 topic_too_generic · 422 thin_material (reason: off_topic)

Semantic search always returns neighbours, so a subject with no coverage still yields pages. Every retrieved page must actually name your subject or it is dropped, and nothing surviving means there is no article — refunded in full, or on x402 refused before the payment settles. A subject with no content words at all (“how it works”) cannot be checked and is refused free, before any price is quoted.

2Resolution — while parsing the prose
silent

Any [[slug]] the model emits that was not in the retrieved set is deleted from the text. An invented source cannot reach a reader, even as a broken marker.

3Coverage — after the draft exists
422 thin_material (reason: low_coverage)

A draft can pass both checks above and still lean on two pages out of twenty: fluent, perfectly cited, and grounded in a sliver of your material. Measured on the real task, one common model cited four of sixty supplied sources. So the finished piece has to draw on a reasonable spread of what survived the anchor, or it is thin — and thin is never billed.

Authentication · two keys, one wallet
Send Authorization: Bearer <key> on any endpoint, or append ?api_key=<key> when your client cannot set headers. Cookie sessions work on the same routes.
art_live_… — this app's key

Minted at /dashboard/api-keys. Reads, lists, exports and shares. It cannot write, because writing reads your private Ounie brain and a per-app key carries no ounie.com credential to forward.

ounie_live_… — the fleet master key

Your ounie.com developer key, once you enable fleet access in ounie.com settings. This is the one that grounds writing: it is forwarded upstream as the Bearer for retrieval. Same wallet, same limits.

A short balance is a 402 carrying required_credits, balance_credits and buy_credits_url. An agent can never overdraw.

REST
POST/api/articlesWrite an article
{ "topic": "how our refund window works",
  "brain_ids": ["…"],
  "angle": "why we changed it in March",
  "audience": "support leads",
  "length": "standard",
  "include_faq": true }

Bills 15 credits. Needs a session or the ounie_live_ master key. Returns articleId, wordCount, citations, anchored/dropped counts and gaps.

GET/api/articlesList yours

Free.

POST/api/outlinePlan it first
{ "topic": "…", "brain_ids": ["…"], "length": "long" }

Bills 3 credits. Same gates, one model call.

GET/api/articles/{id}The full payload

Free. Sections, citations, gaps, internal links, JSON-LD, markdown, and both source lists.

POST/api/articles/{id}/sections/{sectionId}Rewrite one section
{ "instruction": "shorter, and lead with the exception" }

Bills 2 credits. Re-retrieves live rather than replaying a stored copy of your brain.

PATCH/api/articles/{id}/sections/{sectionId}Edit a section by hand
{ "heading": "…", "body": "…" }

Free.

POST/api/articles/{id}/sharePreview link

Free. DELETE the same path to revoke — the page is served no-store, so a revoke is immediate.

GET/api/articles/{id}/export?format=markdown|html|jsonDownload

Free.

DELETE/api/articles/{id}Delete

Free. Cascades sections.

x402 · keyless, pay per call
No Ounie account. Supply your own text, pay in USDC on Base, get the same article shape back.
POST /api/x402/article
{
  "topic": "how our refund window works",
  "source_text": "…your material, 200+ chars…",
  "mode": "article",          // or "outline"
  "length": "standard",
  "include_faq": false
}

→ 402  { x402Version, accepts: [{ scheme: "exact",
         network: "base", maxAmountRequired, payTo,
         asset, extra: { name: "USD Coin", version: "2" } }] }

Sign the EIP-3009 authorization, resend with
X-Payment: <base64>, and the article comes back.
  • A request that cannot succeed is refused for free. A malformed payload, source_text under the minimum, or a subject with no anchorable words returns 4xx with no quote in the body. You are never asked to sign for a guaranteed failure.
  • Verify, run, then settle. Thin material and low coverage are caught after your payment is verified and before it settles, so nothing moves on chain and your signed authorization simply goes unused.
  • All or nothing. A settlement must match the quote exactly, so a piece that comes back materially shorter than its own plan is retried once and then returned as 402 partial_delivery without settling. There is no partial charge on this rail because there is no refund on this rail.
  • No account means no hosted preview and no stored copy — the response is the whole deliverable.
  • Priced from the credit table at 1.2×: 15 credits → 180,000 atomic USDC. The price is computed from your payload and quoted in the 402, never hardcoded.
Shape of an article
// GET /api/articles/{id}
{
  "article": {
    "title", "slug", "meta_description", "dek", "pull_quote",
    "outline":  [{ "heading", "purpose", "sourceSlugs", "covered" }],
    "sections": [{ "position", "heading", "body", "citations" }],
    "faq":      [{ "question", "answer" }],
    "gaps":     ["what these sources do not cover"],
    "citations":     [{ "brainId", "slug", "title", "url" }],
    "internal_links":[{ "anchorText", "slug", "title", "url" }],
    "json_ld", "faq_json_ld", "word_count", "markdown",

    // the anchor's own verdict, so the relevance call is
    // inspectable rather than something you take on trust
    "sources_used":             [{ "slug", "title", "matched_terms" }],
    "sources_dropped_off_topic":[{ "slug", "title", "matched_terms" }]
  },
  "share_url": null
}

internal_links is anchor text plus the source page behind it. We do not know the URLs on your site and will not invent them — it is a suggestion you map in a minute, and saying so is more useful than a plausible-looking link that 404s.

MCP
Streamable HTTP at /api/mcp, legacy SSE at /api/sse.
https://articles.ounie.com/api/mcp
  ?api_key=art_live_…

The Ounie AI Team passes its key in the URL because its manual MCP entries cannot set static headers. Everything else should use the Authorization header.

list_articles
Your articles and outlines, newest first.
free
get_article
One article in full: sections, citations, gaps, internal links, JSON-LD, markdown.
free
write_article
Write the piece from your brain(s). Master key only.
15 credits
outline_article
Plan it first — sections, assigned sources, gaps. Master key only.
3 credits
regenerate_section
Rewrite one section from fresh retrieval. Master key only.
2 credits
export_article
Markdown with footnote citations.
free
share_article
Create or revoke the /p/<token> preview link.
free
get_credit_balance
Spendable Ounie credits + monthly included.
free
get_pricing
Per-action pricing and lengths. No auth required.
public
whoami
The authenticated key's owner + key id.
free
Lengths
short~700 words · 4 sections
standard~1200 words · 6 sections
long~2000 words · 8 sections
Availability
A scheduled probe checks the writing engine. While it is down, calls are refused up front with 503 upstream_unavailable — no quote on the x402 rail, no reserve on the credit rail, nothing charged. It recovers on its own within a few minutes of the engine coming back.
Errors
400 topic_too_generic
No subject words to anchor on. Free.
401 auth_required
Missing or unknown key.
402 insufficient_credits
Carries the numbers and a top-up link.
402 partial_delivery
x402 only. Nothing settled.
403 master_key_required
Writing needs your ounie_live_ key.
404 unknown_brain
That brain id is not on this account.
422 thin_material
off_topic or low_coverage. Refunded.
502 generation_failed
Model returned nothing usable. Refunded.
503 upstream_unavailable
Refused before anything was reserved.