Adapter
Context to brief
POST /v1/briefs turns conversation history, tool outputs, notes, and desired output into a ready-to-submit draft request.
Developer docs
The Non-AI Writer API compiles messy agent context into a writing brief, then creates an async draft run your workflow can poll until the final draft is ready.
Free while beta
Beta accounts can create hashed API keys, use free draft runs first, then call the production /v1/drafts endpoint from agents or automations.
Adapter
POST /v1/briefs turns conversation history, tool outputs, notes, and desired output into a ready-to-submit draft request.
Authentication
Send your key as Authorization: Bearer <api_key>. Raw keys are shown once, stored hashed, and can be revoked during the private beta.
Sources
Pass retrieved source text directly. URL ingestion is not supported yet, so agents should fetch or retrieve context before calling the API.
Runs
POST /v1/drafts creates a run. GET /v1/drafts/:id returns status, output, provenance, usage, and errors.
Compile context
Connectors use this when Claude or an agent already did the research and planning. It does not spend draft runs or write final prose; it returns draft_request for/v1/drafts.
curl -X POST https://non-ai-writerproduction.up.railway.app"/v1/briefs \
-H "Authorization: Bearer naiw_live_..." \
-H "Content-Type: application/json" \
-d '{
"desired_output": "blog article",
"messages": [
{
"role": "user",
"content": "Research the SERP and Reddit threads, then write the final article."
},
{
"role": "assistant",
"content": "The strongest buyer pain is that teams have keyword lists but no sharp point of view."
}
],
"tool_outputs": [
{
"name": "serp_and_reddit_research",
"type": "research",
"content": "Competitor pages repeat the same keyword clusters. Reddit threads complain about generic AI-written SEO posts..."
}
],
"options": {
"target_words": "auto",
"output_format": "markdown"
}
}'Create a draft
curl -X POST https://non-ai-writerproduction.up.railway.app"/v1/drafts \
-H "Authorization: Bearer naiw_live_..." \
-H "Content-Type: application/json" \
-d '{
"prompt": "Turn this source material into a launch post for technical founders.",
"sources": [
{
"type": "text",
"name": "product_notes",
"content": "We are launching a writing engine for agentic content workflows..."
}
],
"options": {
"target_words": "auto",
"output_format": "markdown"
},
"metadata": {
"external_id": "agent-run-123"
}
}'Poll a draft
curl https://non-ai-writerproduction.up.railway.app"/v1/drafts/<draft_id> \
-H "Authorization: Bearer naiw_live_..."JavaScript
const response = await fetch("https://non-ai-writerproduction.up.railway.app"/v1/drafts", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.OPENPEN_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
prompt: "Turn this research into a newsletter section.",
sources: [{ type: "text", name: "research", content: sourceText }],
options: { target_words: "auto", output_format: "markdown" }
})
});
const draftRun = await response.json();Adapter workflow
const brief = await fetch("https://non-ai-writerproduction.up.railway.app"/v1/briefs", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.OPENPEN_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
desired_output: "article",
messages: claudeMessages,
tool_outputs: [{ name: "research", type: "serp_scan", content: researchText }]
})
}).then((response) => response.json());
if (brief.ready && brief.draft_request) {
const draftRun = await fetch("https://non-ai-writerproduction.up.railway.app"/v1/drafts", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.OPENPEN_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(brief.draft_request)
}).then((response) => response.json());
}Agent skill
The public OpenPen agent skill at GitHub lets Claude or Codex package the visible conversation, research notes, and tool outputs, call /v1/briefs, submit the returned draft_request to /v1/drafts, then poll the final draft. The script cannot read a private conversation by itself; the agent passes relevant visible context when the skill runs.
Python
import os
import requests
response = requests.post(
"https://non-ai-writerproduction.up.railway.app"/v1/drafts",
headers={
"Authorization": f"Bearer {os.environ['OPENPEN_API_KEY']}",
"Content-Type": "application/json",
},
json={
"prompt": "Turn this source material into a landing page section.",
"sources": [{"type": "text", "name": "notes", "content": source_text}],
"options": {"target_words": "auto", "output_format": "markdown"},
},
)
draft_run = response.json()Errors
Every API failure returns an error object with a stable code, human-readable message, and retryability flag.
{
"error": {
"code": "preflight_failed",
"message": "This request could not be grounded safely.",
"retryable": false
}
}invalid_requestunauthorizedapi_key_revokedapi_beta_requiredrate_limitedinsufficient_creditsunsupported_source_typepreflight_failedbrief_failedengine_failednot_foundinternal_errorAutomation
In Claude or Codex, use the agent skill to package visible conversation context automatically. In n8n, use one HTTP Request node for /v1/briefs, a second for /v1/drafts, then poll the returned run id. In LangChain, CrewAI, or a custom agent, wrap the same sequence as a tool.
Known limits
Text sources only. Up to five sources per request. Up to 100k total source characters. Poll at a modest cadence so key-level rate limits are reserved for real runs. Streaming, URL ingestion, SDKs, and webhooks come after repeated beta workflows prove the shape.