## #1 on DeepSearchQA — by 8 points.

Spine Deep Research scores 87.6% on DeepSearchQA, ahead of Perplexity (79.5%), Claude (76.1%), ChatGPT (71.3%), and Gemini Deep Research (66.1%) on the same public eval.

[Read the benchmark write-up](https://blog.getspine.ai/spine-swarm-hits-1-on-gaia-level-3-and-google-deepmind-deepsearchqa)

## How it works

### 1. Start a run via REST

POST a prompt (and an optional template — slides, deep_research, report, excel, memo, app, landing_page) to /v1/run. You get a run_id back immediately — no long-lived connection required.

### 2. Async by design

One POST kicks off the agent swarm; webhook callbacks notify your app the moment results are ready.

### 3. Receive polished deliverables

Download .pptx decks, .docx briefs, Excel models with formulas, images, JSON research reports with citations, or interactive dashboards — whatever the task called for.

## Works inside every agentic surface

Spine is a REST API, not a framework. Call it from any coding agent, IDE, or chat.

- **Claude** — Turn any Claude turn into a 50-page investment memo or a 30-slide deck — not just a message.
- **Cursor** — Cursor agents ship research memos, decks, and spreadsheets from a rule file — not just code.
- **Replit** — Replit apps pull real research and client-ready artifacts inline — no more placeholder content.
- **Codex** — Give the Codex CLI long-running research agents and polished deliverables behind one REST call.
- **Lovable** — Lovable apps produce real investor decks, market memos, and research reports for end users.
- **OpenClaw** — OpenClaw agents ship real research briefs, decks, and spreadsheets — not just local-system actions.
- **Hermes** — Hermes agents send polished client deliverables as fast as they send messages.

Agent integration guide: [https://docs.getspine.ai/api-reference/for-agents](https://docs.getspine.ai/api-reference/for-agents)

## Every task is fully auditable

Spine returns a step-by-step trace of every agent action, sub-task dispatched, and intermediary output produced. Debug runs, cite sources, or show your work to clients — nothing is a black box.

- Every agent dispatch and tool call is logged with timing and tokens.
- Intermediary outputs (outlines, research notes, drafts) are retrievable via `GET /v1/canvas/{id}/tasks`.
- Ship deliverables alongside their sources — no black boxes.

### Example task tree

- Morning Brief: Axios + Mercor + Claude leak coverage [task]
  - Axios Attacks Researcher [persona]
    - Create Plan Note [agent]
    - Research: Supply-chain Attack Vectors [agent]
      - `axios-research-block`[block]
  - Morning Brief Synthesizer [persona]
    - Compose Exec Memo [agent]
      - `synthesis-memo-block`[block]
    - Render Dashboard [agent]
      - `deck.pptx`[block]

The same run is also visualised as a canvas DAG at `GET /v1/canvas/{id}/dag`: 7 nodes, 6 edges — each edge represents a dependency between blocks.

## REST endpoints

Small surface area. Full reference at [docs.getspine.ai](https://docs.getspine.ai/).

| Method | Path | Purpose |
| --- | --- | --- |
| `POST` | `/v1/run` | Start an async run (multipart form). Returns a run_id immediately. |
| `GET` | `/v1/run/{run_id}` | Poll status, retrieve final output and downloadable artifacts. |
| `GET` | `/v1/canvas/{id}/dag` | Block graph (nodes and edges) for the canvas this run produced. |
| `GET` | `/v1/canvas/{id}/tasks` | Task tree — every agent action, sub-task, and intermediary output. |

## Submit a task (curl)

```bash
# 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)

```javascript
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)

```python
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"])
```

## Pay as you go. No subscriptions.

- $1 = 1,000 credits
- $10 free to try

Sign up at platform.getspine.ai and get $10 in free credits on us — enough to run several real tasks. No subscriptions, no seats, no monthly minimums.

## Docs

Full request/response schemas, deliverable formats, and error codes: [docs.getspine.ai](https://docs.getspine.ai/).

* * *

## 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. |

### 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)

```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

```javascript
// 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.
