general7 min read

DataStoryBot API Reference: Endpoints, Parameters, and Responses

Complete API reference for DataStoryBot. Endpoints, request/response schemas, parameters, error codes, and rate limits for CSV analysis.

By DataStoryBot Team

DataStoryBot API Reference: Endpoints, Parameters, and Responses

This is the complete reference for the DataStoryBot API. Four endpoints, no authentication during the open beta, and a linear pipeline: upload a CSV, analyze it, refine a story, download the outputs.

If you want a guided walkthrough instead, start with Getting Started with the DataStoryBot API and come back here when you need the specifics.

Base URL

https://datastory.bot

All endpoints are relative to this base. No versioning prefix — the API is in open beta and the contract is stable but not yet frozen.

Authentication

No API key is required during the current open beta. When auth is introduced, it will use a Bearer token:

Authorization: Bearer dsb_your_api_key

Check the DataStoryBot playground for the latest auth requirements.

Containers

Every session starts with a container — an ephemeral OpenAI Code Interpreter environment running GPT-4o. It holds your uploaded file, generated charts, filtered datasets, and the AI's execution state.

Container TTL: 20 minutes. After that, the container and all files are permanently deleted. No extension, no recovery. The containerId from the upload response is your session handle for all subsequent calls.


POST /api/upload

Uploads a CSV file and creates a new container.

Content-Type: multipart/form-data

ParameterTypeRequiredDescription
filefileYesCSV file, max 50 MB
curl -X POST https://datastory.bot/api/upload \
  -F "file=@sales_data.csv"
with open("sales_data.csv", "rb") as f:
    resp = requests.post(
        "https://datastory.bot/api/upload",
        files={"file": ("sales_data.csv", f, "text/csv")}
    )
result = resp.json()

Response — 200

{
  "containerId": "ctr_abc123def456",
  "fileId": "file-7x8y9z",
  "metadata": {
    "fileName": "sales_data.csv",
    "rowCount": 12840,
    "columnCount": 9,
    "columns": ["date", "region", "product", "revenue", "units",
                "cost", "channel", "customer_segment", "returns"]
  }
}
FieldTypeDescription
containerIdstringSession handle. Pass to all subsequent calls.
fileIdstringIdentifier for the uploaded file.
metadata.fileNamestringOriginal filename.
metadata.rowCountintegerData rows (excluding header).
metadata.columnCountintegerColumns detected.
metadata.columnsstring[]Column names from the header.

Errors

StatusCodeMeaning
400invalid_fileNo file provided, or not valid CSV.
413file_too_largeExceeds 50 MB limit.
429rate_limit_exceededToo many requests.
500execution_errorContainer creation failed.

POST /api/analyze

Discovers three story angles in the uploaded data. The AI reads your CSV, runs exploratory Python code inside the container, and returns structured results.

Content-Type: application/json

ParameterTypeRequiredDescription
containerIdstringYesFrom the upload response.
steeringPromptstringNoGuides the AI toward a specific topic. Does not force output — it weights certain patterns more heavily.
curl -X POST https://datastory.bot/api/analyze \
  -H "Content-Type: application/json" \
  -d '{
    "containerId": "ctr_abc123def456",
    "steeringPrompt": "Focus on regional differences in return rates"
  }'

Response — 200

{
  "stories": [
    {
      "title": "Q4 Revenue Surge Driven by Enterprise Segment",
      "summary": "Enterprise customers accounted for 68% of Q4 revenue growth, with a 42% QoQ increase concentrated in APAC.",
      "chartFileId": "file-chart001"
    },
    {
      "title": "Rising Return Rates Signal Product Quality Issues",
      "summary": "Returns increased 23% over 6 months. The Pro line shows 3x the return rate of other lines.",
      "chartFileId": "file-chart002"
    },
    {
      "title": "Direct Channel Overtakes Retail for First Time",
      "summary": "DTC sales surpassed retail revenue in March, driven by a 31% increase in repeat purchases.",
      "chartFileId": "file-chart003"
    }
  ]
}
FieldTypeDescription
storiesarrayAlways exactly 3 story objects.
stories[].titlestringHeadline for the story. Pass this exact string to /api/refine.
stories[].summarystring1-2 sentence summary with data points.
stories[].chartFileIdstringPreview chart. Download via /api/files.

Errors

StatusCodeMeaning
400invalid_requestMissing or invalid containerId.
404container_expiredContainer TTL elapsed.
429rate_limit_exceededToo many requests.
500execution_errorAnalysis failed inside container.

POST /api/refine

Generates a full narrative, charts, and filtered dataset for the selected story.

Content-Type: application/json

ParameterTypeRequiredDescription
containerIdstringYesFrom the upload response.
selectedStoryTitlestringYesExact title from an analyze response story.
refinementPromptstringNoAdjusts tone, length, format, or emphasis.
curl -X POST https://datastory.bot/api/refine \
  -H "Content-Type: application/json" \
  -d '{
    "containerId": "ctr_abc123def456",
    "selectedStoryTitle": "Q4 Revenue Surge Driven by Enterprise Segment",
    "refinementPrompt": "Executive summary. Under 300 words. Emphasize APAC."
  }'

Response — 200

{
  "narrative": "## Q4 Revenue Surge Driven by Enterprise Segment\n\nEnterprise customers drove 68% of Q4 growth...",
  "charts": [
    {
      "fileId": "file-chart101",
      "caption": "Quarterly revenue by customer segment (2025)"
    },
    {
      "fileId": "file-chart102",
      "caption": "Enterprise revenue growth by region"
    }
  ],
  "resultDataset": {
    "fileId": "file-ds001",
    "caption": "Filtered dataset: Enterprise segment transactions Q4 2025"
  }
}
FieldTypeDescription
narrativestringMarkdown-formatted narrative, typically 300-500 words.
chartsarray2-4 chart objects with fileId and caption.
resultDatasetobjectFiltered CSV with rows relevant to the story.
resultDataset.fileIdstringDownload via /api/files.

Errors

StatusCodeMeaning
400invalid_story_titleTitle does not match any story from the analyze step.
404container_expiredContainer TTL elapsed.
429rate_limit_exceededToo many requests.
500execution_errorRefinement failed inside container.

GET /api/files//

Downloads a file from the container — chart PNGs or filtered CSVs.

# Download a chart
curl -o chart.png \
  "https://datastory.bot/api/files/ctr_abc123def456/file-chart101"

# Download a filtered dataset
curl -o filtered.csv \
  "https://datastory.bot/api/files/ctr_abc123def456/file-ds001"

Response — 200

Raw file content. Content-Type varies:

File typeContent-Type
Chartimage/png
Datasettext/csv

Chart specifications

PropertyValue
FormatPNG, transparent background
Resolution150 DPI
Canvas10 x 6 inches (1500 x 900 px)
BackgroundDark theme (#141414)
Text#ffffff, #cccccc, #999999

Errors

StatusCodeMeaning
404container_expired or file_not_foundContainer expired or file ID invalid.
429rate_limit_exceededToo many requests.

Rate Limits

During open beta:

ResourceLimit
Uploads per minute10
Analyze calls per minute10
Refine calls per minute10
File downloads per minute60
Concurrent containers5

Rate limit responses include a Retry-After header:

{
  "error": "rate_limit_exceeded",
  "message": "Upload limit exceeded. Retry after 12 seconds.",
  "retryAfter": 12
}

Error Response Format

All errors follow this structure:

{
  "error": "container_expired",
  "message": "Container ctr_abc123def456 has expired. Upload again to create a new container."
}

The error field is a machine-readable code. The message field is human-readable. Rate limit errors also include retryAfter (integer, seconds until retry).

Error codes

CodeMeaning
invalid_fileNot valid CSV or empty.
file_too_largeExceeds 50 MB.
container_expired20-minute TTL elapsed.
container_not_foundContainer ID does not exist.
invalid_story_titleTitle does not match analyze output.
invalid_requestMissing required parameters.
rate_limit_exceededCheck retryAfter.
execution_errorCode execution failed. Retry once.

Next Steps

Ready to find your data story?

Upload a CSV and DataStoryBot will uncover the narrative in seconds.

Try DataStoryBot →