Skip to main content
The API models two related but distinct things:
  • A run is a durable document. It persists across many calls and retains what the agent “knows” about what it built.
  • A task is one execution against a run — the act of submitting a prompt, running the agent, and producing output.
A run can have many tasks. The first task creates the run; subsequent tasks (when you pass run_id) resume it.

Why separate them

In the web app, agents work on a document over many chat turns. The API mirrors that: turn 1 creates the scaffold, turn 2 adds a section, turn 3 changes the branding — and each turn should cost a fraction of turn 1 because the agent remembers what it built. Without run-level durability, every turn would re-inspect the document from scratch. With it, bookmark IDs, sheet names, chart references — everything the agent learned in turn 1 — are still in context for turn 5.

Creating a run (implicit)

Every generation endpoint creates a run if you don’t pass run_id:
POST /excel/generate
{ "prompt": "Create a Q3 sales report" }

→ {
  "run_id": "run_01HXYZ...",
  "task_id": "task_01HXYZ...",
  "download_url": "...",
  "status": "completed",
  ...
}
The run_id is yours to keep. Store it with whatever record in your system represents this document.

Resuming a run

Pass the same run_id on the next call and add a new prompt:
POST /excel/generate
{
  "run_id": "run_01HXYZ...",
  "prompt": "Now add a forecast tab for FY26"
}
Semantics:
  • The agent’s conversation state is restored from our durable store, keyed on run_id.
  • The last saved document bytes are reloaded into the same run context the agent was using.
  • The new prompt is appended as a fresh user message.
  • The agent continues, using everything it already built.
  • download_url points to the new saved state after this turn.

Tasks

Each invocation produces a task. In sync mode the task shape is hidden — you get the finished result back directly. In async mode you get a task_id to poll:
POST /excel/generate
{ "prompt": "...", "async": true }

→ {
  "run_id": "run_01HXYZ",
  "task_id": "task_01HXYZ",
  "status": "queued"
}
Then:
GET /tasks/task_01HXYZ

→ {
  "task_id": "task_01HXYZ",
  "run_id": "run_01HXYZ",
  "status": "running",
  "phase": "agent_turn",
  "turn_index": 3,
  "progress": 45,
  "created_at": "...",
  "updated_at": "..."
}
See Async vs sync for the full state machine.

Listing runs

GET /runs?limit=20&format=excel&status=completed
Returns the most recent runs for your org, newest first. Cursor-based pagination via the next_cursor field.
{
  "items": [
    {
      "run_id": "run_01HXYZ",
      "format": "excel",
      "status": "completed",
      "prompt": "Create a Q3 sales report with...",
      "credits_used": 84,
      "duration_ms": 18432,
      "created_at": "2026-04-17T11:20:00Z",
      "file_name": "workbook.xlsx"
    }
  ],
  "next_cursor": "run_01HXY..."
}

Downloading

Two options per run:
# Option A: JSON response containing download_url (signed, 24h TTL)
GET /runs/{run_id}

# Option B: 302 redirect to the signed URL
GET /runs/{run_id}/download
Option B is what you want from a browser <a href> — no extra round-trip.

Exporting to other formats

Convert a run’s output to PDF, PNG, etc. via POST /runs//export:
POST /runs/{run_id}/export
{ "format": "pdf" }

→ {
  "format": "pdf",
  "download_url": "...",
  "expires_at": "..."
}
Supported conversions:
SourceTargets
xlsxpdf, csv, png, html
docxpdf, html, txt, odt
pptxpdf, png, odp
Exports are cached — calling /export?format=pdf twice for the same run only runs the conversion once.

Retention

Runs are retained for 30 days after their last task. After that:
  • The run_id still resolves via GET /runs/{run_id} for audit, but its state is marked expired.
  • Resuming an expired run returns 410 gone. Start a fresh run instead.
  • The saved document bytes are removed from storage 30 days after expiry.
Enterprise customers can extend retention — contact us.