Submit a task (curl)
# 1. Start a run
curl -X POST https://api.getspine.ai/v1/run \
-H "X-API-KEY: $SPINE_API_KEY" \
-F 'prompt=Build an investor-ready competitive analysis for the AI coding assistants space.' \
-F 'template=slides'
# → { "data": { "run_id": "uuid", "status": "running" } }
# 2. Poll until done
curl https://api.getspine.ai/v1/run/<run_id> \
-H "X-API-KEY: $SPINE_API_KEY"
# → { "data": { "status": "completed",
# "result": { "final_output": "...",
# "artifacts": [{ "name": "deck.pptx", "download_url": "..." }] } } }
JavaScript (fetch)
const form = new FormData();
form.append("prompt", "Build an investor-ready competitive analysis for the AI coding assistants space.");
form.append("template", "slides");
const res = await fetch("https://api.getspine.ai/v1/run", {
method: "POST",
headers: { "X-API-KEY": process.env.SPINE_API_KEY },
body: form,
});
const { data } = await res.json();
const runId = data.run_id;
// Poll until done
while (true) {
const r = await fetch(`https://api.getspine.ai/v1/run/${runId}`, {
headers: { "X-API-KEY": process.env.SPINE_API_KEY },
});
const { data: run } = await r.json();
if (["completed", "partial", "failed"].includes(run.status)) break;
await new Promise((res) => setTimeout(res, 5_000));
}
Python (httpx)
import os, time, httpx
API_KEY = os.environ["SPINE_API_KEY"]
BASE = "https://api.getspine.ai"
H = {"X-API-KEY": API_KEY}
r = httpx.post(f"{BASE}/v1/run", headers=H,
data={"prompt": "Build an investor-ready competitive analysis for the AI coding assistants space.",
"template": "slides"})
run_id = r.json()["data"]["run_id"]
while True:
run = httpx.get(f"{BASE}/v1/run/{run_id}", headers=H).json()["data"]
if run["status"] in ("completed", "partial", "failed"):
break
time.sleep(5)
for a in run["result"]["artifacts"]:
print(a["name"], "→", a["download_url"])
API Reference
Base URL: https://api.getspine.ai
Authentication
All endpoints require an `X-API-KEY` header. Get a key from the Spine dashboard → Settings → Developer Keys. Keys can be rotated or revoked at any time.
X-API-KEY: sk_spine_...
Start a run — request parameters
POST /v1/run accepts a multipart/form-data body with the following fields:
| Field | Required | Type | Description |
prompt | yes | string | Natural-language description of what to produce. |
template | no | string | One of: auto, deep_research, report, slides, memo, excel, app, landing_page. Defaults to 'auto'. |
blocks | no | JSON array | Advanced: pass an explicit array of block definitions to override the template. See valid block types above. |
Templates
Pass one of the following template values, or pass blocks (a JSON array) for finer control.
| id | what it does | output |
auto | Let Spine pick blocks based on the prompt | Varies |
deep_research | Multi-source research with citations | Memo (.docx) |
report | Structured report with sections | Report (.docx) |
slides | Presentation deck | Slides (.pptx) |
memo | Short executive memo | Memo (.docx) |
excel | Spreadsheet analysis | Workbook (.xlsx) |
app | Single-page web app | App (.html) |
landing_page | Marketing landing page | Page (.html) |
Block types (for blocks override)
prompt-block, list-block, memo-block, document-block, excel-block, deep-research-block, image-block, presentation-block, app-block, table-block, prototype-block, landing-page-block, text-block, web-block, yt-block, web-research-block, file-block.
Response shapes
Run just started:
{
"data": {
"run_id": "01HXZJ4P...K3Q9",
"status": "running"
}
}
Run completed:
{
"data": {
"status": "completed",
"result": {
"final_output": "<summary text>",
"artifacts": [
{ "name": "deck.pptx", "download_url": "https://..." }
]
}
}
}
Terminal statuses: completed, partial, failed. Non-terminal: queued, running.
Full polling loop (Python)
import os, time, httpx
API_KEY = os.environ["SPINE_API_KEY"]
BASE = "https://api.getspine.ai"
H = {"X-API-KEY": API_KEY}
def run(prompt, template="auto", **kwargs):
r = httpx.post(f"{BASE}/v1/run", headers=H,
data={"prompt": prompt, "template": template, **kwargs})
run_id = r.json()["data"]["run_id"]
while True:
p = httpx.get(f"{BASE}/v1/run/{run_id}", headers=H).json()["data"]
if p["status"] in ("completed", "partial", "failed"):
return p
time.sleep(5)
result = run("Build a landing page for an AI sales tool", template="landing_page")
print(result["result"]["final_output"])
for a in result["result"]["artifacts"]:
print(a["name"], "→", a["download_url"])
Use as a tool inside Claude / Anthropic SDK
// Use Spine as a tool inside the Anthropic SDK
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const tool = {
name: "spine_run",
description: "Spawn a multi-agent Spine run that produces research, memos, decks, excel, or apps.",
input_schema: {
type: "object",
properties: {
prompt: { type: "string" },
template: {
type: "string",
enum: ["auto", "deep_research", "report", "slides", "memo", "excel", "app", "landing_page"],
},
},
required: ["prompt"],
},
};
const resp = await client.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 2048,
tools: [tool],
messages: [{ role: "user", content: "Make a market report on AI agents" }],
});
// On stop_reason="tool_use" → POST /v1/run, poll GET /v1/run/{run_id}, feed result back.
Errors
Errors return {"success": false, "error": "..."} with one of these HTTP codes:
| Code | Reason |
400 | Bad template, malformed blocks, or invalid UUID. |
401 | Missing or invalid X-API-KEY. |
404 | Run or canvas not found (or not owned by the authenticated key). |
500 | Server error — retry with exponential backoff. |