What this skill does
EpidBot is an AI-powered assistant for Brazilian public health data (DATASUS). This skill is a REST API reference for all EpidBot operations. Make HTTP requests directly — no helper scripts needed.
Capabilities:
- Ask epidemiological questions and get AI-generated analysis with charts
- List, search, download plots from "My Plots" collection
- Download the Python code that generated each plot
- List and download reports (Markdown and PDF)
- Search code snippets saved from previous analyses
- List, upload, preview datasets in "My Data" area
When to use this skill
| User says... | Action |
|---|---|
| "Show my plots" / "Search plots for dengue" | GET /plots/?search=... |
| "Download plot 42" / "Give me the dengue chart" | GET /plots/{id}/file |
| "How was plot 42 made?" / "Show me the code for this plot" | GET /plots/{id}/snippet |
| "Download all my plots as ZIP" | POST /plots/download-zip |
| "List my reports" | GET /reports |
| "Download report 15 as PDF" | GET /reports/{id}/pdf |
| "Search for code snippets about ARIMA" | POST /search with source_type: snippet |
| "Show my datasets" / "List my data" | GET /uploads/ |
| "Upload this CSV to EpidBot" | POST /uploads/ (multipart) |
| Any epidemiological question / data analysis request | POST /chat → poll |
Authentication
All endpoints accept the X-API-Key header with an ek_-prefixed API key (obtained from EpidBot Settings → API Keys).
Exception: GET /plots/{id}/file does NOT read the X-API-Key header. For this endpoint, use Authorization: Bearer {EPIDBOT_API_KEY} instead. The server accepts ek_-prefixed keys as Bearer tokens.
Environment variables
| Variable | Description | Default |
|---|---|---|
| EPIDBOT_API_KEY | API key from EpidBot (starts with ek_). Required. | — |
| EPIDBOT_API_URL | Base URL of the EpidBot API. | https://epidbot.kwar-ai.com.br |
Chat
Submit a question and poll for the response. The API is asynchronous — you must poll until the job completes.
Submit question
POST {EPIDBOT_API_URL}/api/v1/chat
Headers:
X-API-Key: {EPIDBOT_API_KEY}
Content-Type: application/json
Body:
{"message": "Quantos casos de dengue em SP em 2024?", "locale": "en"}
Response (HTTP 200):
{"job_id": "abc123", "session_id": 42, "status": "processing"}
Poll for result
GET {EPIDBOT_API_URL}/api/v1/chat/{job_id}
Headers:
X-API-Key: {EPIDBOT_API_KEY}
Response (when completed):
{
"job_id": "abc123",
"status": "completed",
"content": "## Analysis\n\n... markdown ...",
"images": ["/file=/data/plots/sandbox/figure_001.png"]
}
Polling rules:
- Poll every 3 seconds until
statusis"completed","failed", or"cancelled" - Status values:
pending,processing,completed,failed,cancelled - Timeout: 5 minutes (300s)
- Markdown images in
contentusesyntax — these reference the EpidBot server and may require auth to display - Each query creates a new session prefixed with
[API]
Response modes
The content field may contain:
- Inline analysis — markdown tables, statistics, links
- Plot references —
— the chart was generated and saved - Combined — analysis text plus embedded plot references
Present the response clearly. If it contains plot references, note that the user can download them via the Plots endpoints.
Plots ("My Plots")
List / search plots
GET {EPIDBOT_API_URL}/api/v1/plots/
Headers: X-API-Key: {EPIDBOT_API_KEY}
Query params:
search (optional) — filters by filename/description (ILIKE match)
Response: [
{
"id": 42,
"filename": "figure_001.png",
"description": "Dengue cases São Paulo 2024",
"source": "chat",
"file_size_bytes": 48500,
"mime_type": "image/png",
"width": 1200,
"height": 800,
"created_at": "2025-01-15T10:30:00Z",
"has_snippet": true
}
]
Get plot metadata
GET {EPIDBOT_API_URL}/api/v1/plots/{plot_id}
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: { single PlotInfo object, same fields as list }
Download plot image
GET {EPIDBOT_API_URL}/api/v1/plots/{plot_id}/file
Headers: Authorization: Bearer {EPIDBOT_API_KEY} ← NOTE: Bearer, not X-API-Key!
Response: Binary image data (Content-Type: image/png or image/jpeg etc.)
Save the response body as a file. The filename from the plot metadata (filename field) is a good default.
Download plot's Python code
GET {EPIDBOT_API_URL}/api/v1/plots/{plot_id}/snippet
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: Python source code (Content-Type: text/x-python)
Returns HTTP 404 if no snippet was saved for this plot.
The has_snippet field in plot listings tells you whether code is available.
Download multiple plots as ZIP
POST {EPIDBOT_API_URL}/api/v1/plots/download-zip
Headers:
X-API-Key: {EPIDBOT_API_KEY}
Content-Type: application/json
Body: {"plot_ids": [42, 43, 44]}
Response: Binary ZIP data (Content-Type: application/zip)
Upload a new plot
POST {EPIDBOT_API_URL}/api/v1/plots/upload
Headers: X-API-Key: {EPIDBOT_API_KEY}
Body: multipart/form-data
file: (binary image, max 20 MB, allowed: png/jpg/jpeg/webp/gif/svg)
description: (string, optional)
Response: { PlotInfo object }
Update / delete plots
PATCH /api/v1/plots/{plot_id} Body: {"description": "new desc"}
DELETE /api/v1/plots/{plot_id}
POST /api/v1/plots/bulk-delete Body: {"plot_ids": [42, 43]}
Headers: X-API-Key: {EPIDBOT_API_KEY}
Reports
List reports
GET {EPIDBOT_API_URL}/api/v1/reports
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: [
{
"id": 15,
"title": "Dengue trends in Southeast Brazil",
"report_type": "manuscript",
"created_at": "2025-01-14T08:00:00Z",
"updated_at": "2025-01-14T08:05:00Z",
"image_count": 3,
"content_size_bytes": 45000,
"has_pdf": true,
"user_id": 1,
"username": "user",
"is_shared": false,
"permission": "owner",
"owner_name": "User Name",
"share_count": 0,
"zenodo_doi": null,
"zenodo_record_url": null,
"zenodo_status": null,
"reference_count": 12
}
]
Download report as PDF
GET {EPIDBOT_API_URL}/api/v1/reports/{report_id}/pdf
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: Binary PDF data (Content-Type: application/pdf)
The PDF is generated server-side via WeasyPrint with embedded charts and bibliography. To force regeneration, use POST /reports/{report_id}/regenerate-pdf.
Download report as Markdown
GET {EPIDBOT_API_URL}/api/v1/reports/{report_id}/download
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: Markdown text (Content-Type: text/markdown)
Get report details
GET {EPIDBOT_API_URL}/api/v1/reports/{report_id}
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: {
"id": 15,
"title": "...",
"report_type": "manuscript",
"prompt": "...",
"content": "# Abstract\n\n...",
"abstract": "...",
"image_count": 3,
"has_pdf": true,
"created_at": "...",
"updated_at": "...",
"user_id": 1,
"is_shared": false,
"permission": "owner"
}
Delete report
DELETE {EPIDBOT_API_URL}/api/v1/reports/{report_id}
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: {"message": "Report deleted"}
Additional report endpoints
GET /reports/{id}/versions — version history
GET /reports/{id}/references — bibliography listing
GET /reports/{id}/bibtex — download .bib file
POST /reports/{id}/regenerate-pdf — force PDF regeneration
Code Snippets
There is no dedicated snippets REST API. Use the unified search endpoint:
POST {EPIDBOT_API_URL}/api/v1/search
Headers:
X-API-Key: {EPIDBOT_API_KEY}
Content-Type: application/json
Body: {
"query": "ARIMA forecast",
"source_type": "snippet"
}
Response: {
"results": [
{
"source_type": "snippet",
"title": "Dengue ARIMA forecast",
"language": "python",
"source_code": "import pandas as pd\n...",
"description": "ARIMA model for dengue time series",
"tags": ["arima", "forecast", "dengue"],
"created_at": "2025-01-10T12:00:00Z"
}
],
"total": 1
}
The source_code field contains the full snippet. If you need all snippets without filtering, omit query and just pass source_type: "snippet".
My Data (User Datasets)
List datasets
GET {EPIDBOT_API_URL}/api/v1/uploads/
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: {
"datasets": [
{
"id": 7,
"name": "hospital_admissions",
"path": "/data/private/42/hospital_admissions/data.parquet",
"row_count": 15000,
"file_size_bytes": 2048000,
"file_count": 1,
"created_at": "2025-01-12T09:00:00Z",
"original_filename": "admissions.csv",
"description": "Monthly hospital admissions by municipality"
}
]
}
Upload a dataset
POST {EPIDBOT_API_URL}/api/v1/uploads/
Headers: X-API-Key: {EPIDBOT_API_KEY}
Body: multipart/form-data
file: (the dataset file)
description: (string, optional — description for the catalog)
Response: {
"id": 8,
"name": "my_dataset",
"path": "/data/private/42/my_dataset/data.parquet",
"row_count": 5000,
"file_size_bytes": 1024000,
"message": "Dataset uploaded successfully"
}
Supported formats: .csv, .ods, .xlsx, .xls (converted to Parquet) and .geojson, .json, .gpkg, .zip (converted to GIS Parquet). Max file size: 50 MB.
Uploaded datasets are automatically cataloged and can be queried by EpidBot in subsequent chat interactions.
Get dataset details
GET {EPIDBOT_API_URL}/api/v1/uploads/{dataset_id}
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: { single dataset object, same fields as list }
Preview dataset (first 10 rows)
GET {EPIDBOT_API_URL}/api/v1/uploads/{dataset_id}/preview
Headers: X-API-Key: {EPIDBOT_API_KEY}
Response: {
"columns": ["col1", "col2", "..."],
"rows": [["val1", "val2"], ...],
"total_rows": 5000,
"total_columns": 25,
"showing_columns": 15,
"truncated_columns": 10
}
Additional dataset endpoints
DELETE /uploads/{id} — delete dataset
POST /uploads/{id}/publish — publish to public catalog
PATCH /uploads/{id}/description — update description
GET /uploads/{id}/crate-metadata — read RO-Crate metadata
PATCH /uploads/{id}/metadata — update full metadata
Notes
- Chat is asynchronous. No synchronous request-response. Always poll.
- Plot file downloads require Bearer auth, not
X-API-Key. All other endpoints useX-API-Key. - Plot code snippets may not exist for every plot (
has_snippetfield tells you). - Code snippets are searched via the unified
/api/v1/searchendpoint withsource_type: "snippet". - Uploaded datasets are automatically converted to Parquet and cataloged. They become queryable via
read_parquet('/data/private/{user_id}/...')in subsequent chat queries. - Markdown images in chat responses (
) reference the EpidBot server. The files are in/data/plots/or/data/public/plots/sandbox/. They can be downloaded via the Plots endpoints. - All timestamps are in ISO 8601 format (UTC).
Scan to join WeChat group