申请体验
▼

认证

Authentication2

所有受保护端点需要在 Header 中携带 Supabase JWT:

Header
Authorization: Bearer 

后端通过 get_current_user 校验 JWT 并解析用户所属组织,数据按 org_id 行级隔离。

POST/api/auth/ensure-profile创建/获取用户资料▶

Supabase Auth 注册/登录后调用,创建或返回用户资料。

json
{\n  "display_name": "Ada"\n}
Response 200
{\n  "profile": {\n    "id": "user_123",\n    "org_id": "00000000-0000-0000-0000-000000000001",\n    "display_name": "Ada",\n    "role": "analyst"\n  },\n  "created": true\n}
GET/api/auth/me当前用户▶

返回已认证用户、组织、角色、邮箱及头像 URL。

▼

基础路径与限制

Base Path & Limits

基础路径:/api(完整 URL 取决于部署环境,本地开发为 https://app.sparkxmmm.com/api/v1)

数据隔离:所有资源按 org_id 隔离,跨组织访问返回 403。

并发限制:每个项目同一时间只允许一个活跃模型运行,重复发起返回 409。

AI 速率限制:每个组织每 10 秒最多一次 LLM 生成;缓存命中不受限。

注意演示端点 POST /api/agent/upload {"demo":true} 无需认证,但仅返回示例数据。
▼

项目管理

Projects6
GET/api/projects/列出项目▶

返回当前组织的所有项目,包含 Champion run 摘要(如有)。

POST/api/projects/创建项目▶
json
{\n  "name": "Q1 Brand MMM",\n  "description": "Weekly revenue model",\n  "kpi_type": "revenue",\n  "time_granularity": "weekly",\n  "geo_level": false,\n  "model_type": "ridge"\n}
Response
{\n  "project": {\n    "id": "project_123",\n    "name": "Q1 Brand MMM",\n    "status": "draft",\n    "kpi_type": "revenue",\n    "time_granularity": "weekly",\n    "geo_level": false,\n    "model_type": "ridge"\n  }\n}
GET/api/projects/{project_id}获取项目▶

返回已认证用户、组织、角色、邮箱及头像 URL。

Response 200
{
  "user": {
    "id": "user_123",
    "org_id": "00000000-0000-0000-0000-000000000001",
    "email": "ada@brand.com",
    "role": "analyst",
    "display_name": "Ada",
    "avatar_url": null
  }
}
PATCH/api/projects/{project_id}更新项目▶

所有字段可选:

json
{\n  "name": "Q1 Brand MMM - Final",\n  "kpi_type": "revenue",\n  "time_granularity": "weekly",\n  "geo_level": true,\n  "model_type": "pymc",\n  "config": { "calendar": "us" }\n}
DELETE/api/projects/{project_id}删除项目▶

获取单个项目详情,包含状态、配置和 Champion run 摘要。

Response 200
{
  "project": {
    "id": "project_123",
    "name": "Q1 Brand MMM",
    "status": "active",
    "kpi_type": "revenue",
    "time_granularity": "weekly",
    "geo_level": false,
    "model_type": "ridge",
    "champion_run_id": "run_456"
  }
}
POST/api/projects/demo创建 Demo 项目▶

创建内置电商 demo 项目,自动上传演示数据、映射字段并启动 Ridge 运行。

▼

数据上传与映射

Data Upload8

支持 .csv / .xlsx / .xls,最大 50 MB。

POST/api/datasets/{project_id}/upload?strategy=replace上传数据集▶

Content-Type: multipart/form-data

字段类型必填说明
filefile是.csv / .xlsx / .xls
参数可选值默认说明
strategyreplace / append / new_rootreplace数据集版本策略
Response
{\n  "dataset": {\n    "id": "dataset_123",\n    "project_id": "project_123",\n    "file_name": "weekly_marketing.csv",\n    "row_count": 104,\n    "col_count": 9,\n    "version": 1,\n    "is_active": true,\n    "upload_status": "validated"\n  },\n  "analysis": {\n    "row_count": 104,\n    "col_count": 9,\n    "suggested_mappings": [\n      { "column": "week_start", "type": "date" },\n      { "column": "revenue_usd", "type": "kpi" }\n    ]\n  },\n  "quality": { "overall_status": "pass", "findings": [], "stats": {} }\n}
GET/api/datasets/{project_id}/datasets列出数据集版本▶

删除项目及其关联的数据集和运行记录。操作不可逆。

Response 200
{
  "deleted": true,
  "project_id": "project_123"
}
GET/api/datasets/{project_id}/active获取活跃数据集▶

返回项目的所有数据集版本,标记当前活跃版本。

Response 200
{
  "datasets": [
    {
      "id": "dataset_123",
      "file_name": "weekly_marketing.csv",
      "row_count": 104,
      "version": 1,
      "is_active": true,
      "upload_status": "validated"
    }
  ]
}
POST/api/datasets/{project_id}/activate/{dataset_id}激活数据集版本▶

返回当前活跃数据集及其分析摘要。

Response 200
{
  "dataset": {
    "id": "dataset_123",
    "file_name": "weekly_marketing.csv",
    "row_count": 104,
    "col_count": 9,
    "version": 1,
    "is_active": true
  }
}
GET/api/datasets/{dataset_id}/mappings获取字段映射▶

将指定数据集版本设为活跃。后续模型运行将使用此版本。

Response 200
{
  "dataset": { "id": "dataset_124", "is_active": true },
  "message": "Dataset version activated."
}
PUT/api/datasets/{dataset_id}/mappings更新字段映射▶
json
{\n  "mappings": [\n    { "source_column": "week_start", "target_type": "date" },\n    { "source_column": "revenue_usd", "target_type": "kpi" },\n    { "source_column": "google_spend", "target_type": "media_spend", "channel_name": "Google" },\n    { "source_column": "holiday_flag", "target_type": "control" }\n  ]\n}

target_type 可选值:date / kpi / media_spend / control / geo / ignore

GET/api/datasets/{dataset_id}/quality?granularity=weekly数据质量报告▶

返回当前字段映射配置。

Response 200
{
  "mappings": [
    { "source_column": "week_start", "target_type": "date" },
    { "source_column": "revenue_usd", "target_type": "kpi" },
    { "source_column": "google_spend", "target_type": "media_spend", "channel_name": "Google" },
    { "source_column": "holiday_flag", "target_type": "control" }
  ]
}
GET/api/datasets/{dataset_id}/edaEDA 探索性分析▶

返回列统计、时间序列、花费占比、相关矩阵和分布。

▼

建模分析

Modeling6
POST/api/modeling/{project_id}/run启动模型运行▶
json
{\n  "model_type": "ridge",\n  "n_chains": 4,\n  "n_iterations": 2000,\n  "config": {\n    "adstock_type": "geometric",\n    "priors": {},\n    "project_settings": {\n      "kpi_type": "revenue",\n      "time_granularity": "weekly",\n      "geo_level": false\n    }\n  }\n}
Response
{\n  "run_id": "run_123",\n  "status": "pending",\n  "dispatch_mode": "subprocess",\n  "message": "Model run started. Poll the status endpoint for progress."\n}
说明model_type 可选值:ridge(秒级基线)、pymc(贝叶斯后验)、stan(CmdStan,second-opinion)、nevergrad(进化算法超参搜索)、sparkx(时变参数,Instant Mode 默认)、sparkx-expert(TVP + 贝叶斯不确定性量化)、lgbm(LightGBM + SHAP,渠道交互检测)、meridian(Google Meridian,地理级 Bayesian)。Bayesian 类引擎需要 n_chains ≥ 2 且 n_iterations ≥ 100。关键数据质量问题返回 422。
GET/api/modeling/{project_id}/runs列出运行▶

返回数据质量报告,包含总体状态和具体 findings。

Response 200
{
  "overall_status": "pass",
  "findings": [
    {
      "severity": "warning",
      "code": "low_variation",
      "message": "Channel tv_spend has low variation (CV=0.08)",
      "column": "tv_spend"
    }
  ],
  "stats": {
    "row_count": 104,
    "col_count": 9,
    "missing_pct": 0.2,
    "duplicate_periods": 0
  }
}
说明granularity 参数可选 daily / weekly / monthly。
GET/api/modeling/run/{run_id}/status运行状态▶
Response
{\n  "id": "run_123",\n  "project_id": "project_123",\n  "status": "sampling",\n  "progress_pct": 45,\n  "current_step": "sampling",\n  "started_at": "2026-07-02T08:00:00Z",\n  "completed_at": null,\n  "duration_seconds": null,\n  "r_squared": null,\n  "mape": null,\n  "max_rhat": null,\n  "min_ess": null,\n  "error_message": null,\n  "model_type": "pymc",\n  "engine": null,\n  "run_config": {}\n}

状态流转:pending → preprocessing → sampling → completed / failed

POST/api/modeling/run/{run_id}/cancel取消运行▶

返回项目的所有模型运行记录,按时间倒序。

Response 200
{
  "runs": [
    {
      "id": "run_123",
      "status": "completed",
      "model_type": "ridge",
      "r_squared": 0.92,
      "mape": 4.8,
      "is_champion": true,
      "started_at": "2026-07-01T08:00:00Z",
      "duration_seconds": 25
    }
  ]
}
GET/api/modeling/latest最新运行▶

返回 Champion run(如有),否则返回最近一次完成的运行。

POST/api/champion/{project_id}/start-searchChampion 多引擎搜索▶
json
{\n  "engines": ["ridge", "pymc"],\n  "n_chains": 4,\n  "n_iterations": 2000,\n  "config": {}\n}

可选引擎:

  • ridge
  • pymc
  • stan
  • meridian
  • robyn
  • nevergrad
  • sparkx
  • sparkx-expert
  • lgbm
注意meridian 和 robyn 为环境依赖引擎,可能未在所有部署中启用。
▼

结果查询

Results6
GET/api/results/run/{run_id}/summary运行摘要▶

返回运行元数据和渠道摘要。

GET/api/results/run/{run_id}/channels渠道结果▶
Response
{\n  "channels": [\n    {\n      "channel_name": "Google",\n      "roi_mean": 3.2,\n      "roi_ci_low": 2.4,\n      "roi_ci_high": 4.1,\n      "contribution_pct": 28.5,\n      "adstock_halflife_weeks": 1.8,\n      "saturation_pct": 64.0,\n      "current_spend": 12000,\n      "marginal_roi": 1.7,\n      "health_score": 82\n    }\n  ]\n}
GET/api/results/run/{run_id}/diagnostics诊断▶

取消正在进行的模型运行。已完成的运行不受影响。

Response 200
{
  "run_id": "run_123",
  "status": "cancelled",
  "message": "Model run cancelled."
}
注意只有 pending / preprocessing / sampling 状态可取消。
GET/api/results/run/{run_id}/predictions预测▶

返回时间对齐的 actual / predicted / residual 序列(如可用)。

GET/api/results/run/{run_id}/decomposition贡献分解▶

返回 baseline 和各渠道贡献序列(如可用)。

GET/api/results/compare/{run_a}/{run_b}对比运行▶

返回模型诊断指标:R-squared、MAPE、预测 vs 实际序列、残差。

Response 200
{
  "r_squared": 0.92,
  "mape": 4.8,
  "n_observations": 104,
  "predictions": [
    { "date": "2026-01-01", "actual": 128500, "predicted": 126800, "residual": 1700 }
  ]
}
▼

预算优化

Optimization6

支持两种优化目标:给定预算最大化收入、给定收入目标最小化花费。

POST/api/optimizer/run/{run_id}/optimize优化预算▶

固定预算模式:

json
{\n  "objective": "maximize_revenue",\n  "total_budget": 250000,\n  "budget_constraints": {\n    "Google": { "min": 50000, "max": 120000 },\n    "Meta": { "min": 30000, "max": 100000 }\n  }\n}

目标收入模式:

json
{\n  "objective": "target_revenue",\n  "target_revenue": 1000000,\n  "budget_constraints": {\n    "Google": { "min": 50000, "max": 150000 }\n  }\n}
Response
{\n  "scenario": {\n    "id": "scenario_123",\n    "run_id": "run_123",\n    "total_budget": 250000,\n    "current_allocation": {},\n    "optimal_allocation": {},\n    "current_revenue": 850000,\n    "predicted_revenue": 930000,\n    "revenue_uplift_pct": 9.4,\n    "recommendations": []\n  }\n}
GET/api/optimizer/run/{run_id}/scenarios优化场景列表▶

对比两个运行的渠道 ROI、贡献度和诊断指标差异。

Response 200
{
  "run_a": { "id": "run_123", "model_type": "ridge", "r_squared": 0.92 },
  "run_b": { "id": "run_456", "model_type": "pymc", "r_squared": 0.94 },
  "channel_diff": [
    { "channel": "Google", "roi_a": 3.2, "roi_b": 3.5, "roi_diff": 0.3 }
  ]
}
POST/api/scenarios/run/{run_id}/simulate模拟场景▶
json
{\n  "allocations": {\n    "Google": 90000,\n    "Meta": 70000,\n    "TikTok": 30000\n  }\n}
POST/api/scenarios/run/{run_id}/save保存场景▶
json
{\n  "name": "Q3 constrained plan",\n  "allocations": { "Google": 90000, "Meta": 70000 },\n  "notes": "Finance-approved cap"\n}
GET/api/scenarios/run/{run_id}/saved列出保存的场景▶

返回该运行的所有优化场景。

Response 200
{
  "scenarios": [
    {
      "id": "scenario_123",
      "name": "Maximize Q3 Revenue",
      "total_budget": 250000,
      "predicted_revenue": 930000,
      "revenue_uplift_pct": 9.4
    }
  ]
}
DELETE/api/scenarios/run/{run_id}/saved/{scenario_id}删除场景▶

返回用户保存的 what-if 场景列表。

Response 200
{
  "scenarios": [
    {
      "id": "scenario_125",
      "name": "Q3 constrained plan",
      "allocations": { "Google": 90000, "Meta": 70000 },
      "notes": "Finance-approved cap"
    }
  ]
}
▼

AI 洞察

AI Insights3

Claude 驱动的自然语言解读,支持中英双语。每个 section 可独立生成或重新生成。

POST/api/interpretations/run/{run_id}/generate生成 AI 洞察▶
json
{\n  "section": "executive_summary",\n  "force_regenerate": false,\n  "locale": "zh",\n  "custom_prompt": null\n}

可选 section:

  • executive_summary — 执行摘要
  • channel_deep_dive — 渠道深度解读
  • risk_warnings — 风险提醒
  • action_plan — 行动计划
  • analyst_commentary — 分析师评论
  • budget_rationale — 预算依据
Response
{\n  "interpretation": {\n    "id": "interp_123",\n    "run_id": "run_123",\n    "section": "executive_summary",\n    "content_md": "## Executive Summary\\n...",\n    "content_structured": null,\n    "model_used": "claude-sonnet-4-20250514"\n  },\n  "cached": false\n}
速率限制每组织每 10 秒最多一次 LLM 生成。缓存命中不受限,force_regenerate=true 强制重新生成。
GET/api/interpretations/run/{run_id}获取全部洞察▶

删除指定的保存场景。删除后不可恢复。

Response 200
{
  "deleted": true,
  "scenario_id": "scenario_125"
}
POST/api/interpretations/run/{run_id}/chat对话追问▶
json
{\n  "locale": "zh",\n  "messages": [\n    { "role": "user", "content": "Which channel should I cut first?" }\n  ]\n}
▼

数据科学诊断

Diagnostics8

面向数据科学家的模型审计与方法论透明度视图。

GET/api/analyst/run/{run_id}/diagnostics完整诊断▶

拟合质量、运行元数据、R-squared、MAPE、R-hat、ESS 及参数摘要。

GET/api/analyst/run/{run_id}/convergence收敛诊断▶

返回该运行所有已生成的 AI 洞察 section。

Response 200
{
  "interpretations": [
    {
      "id": "interp_123",
      "section": "executive_summary",
      "content_md": "## Executive Summary\n...",
      "model_used": "claude-sonnet-4-20250514"
    },
    {
      "id": "interp_124",
      "section": "risk_warnings",
      "content_md": "## Risk Warnings\n..."
    }
  ]
}
GET/api/analyst/run/{run_id}/posterior后验诊断▶

返回 trace / forest / pair / posterior predictive 检查(仅 Bayesian 运行)。

GET/api/analyst/run/{run_id}/posterior-download后验下载▶

返回 posterior NetCDF 文件的签名 URL(如可用)。

GET/api/analyst/run/{run_id}/robustness稳健性▶

返回 Bayesian 运行的收敛指标:R-hat、ESS、divergences。非 Bayesian 运行返回 null。

Response 200
{
  "max_rhat": 1.01,
  "min_ess": 320,
  "n_divergences": 2,
  "n_chains": 4,
  "n_iterations": 2000,
  "converged": true
}
决策规则R-hat ≥ 1.1 的运行不可用于决策。
GET/api/analyst/run/{run_id}/backtest?n_folds=5&horizon=4回测▶

滚动起点验证,测试样本外稳定性。

GET/api/analyst/run/{run_id}/drift漂移检测▶

与项目 Champion 对比,检测模型或数据漂移。

GET/api/analyst/run/{run_id}/limitations局限性▶

基于模型类型、拟合、不确定性和饱和度的透明告警。

▼

报告下载

Reports2
GET/api/analyst/run/{run_id}/report.pptx下载 PowerPoint▶

返回二进制 .pptx 文件。

Content-Disposition: MMM_Report_{project_name}_{run_id}.pptx

GET/api/analyst/run/{run_id}/report.html下载 HTML 报告▶

返回自包含 HTML 报告,可直接在浏览器打开。

▼

Agent 与 Demo Pipeline

Agent & Demo4

AutoMMM 的对话式 pipeline 接口,支持 demo 模式和文件上传模式。

POST/api/agent/upload上传或启动 Demo▶

Demo 模式(无需认证):

json
{\n  "demo": true,\n  "mode": "instant",\n  "locale": "zh"\n}

文件模式(multipart):

字段类型说明
filefileCSV / XLSX / XLS
modestringinstant 或 expert
localestringzh 或 en
Response
{\n  "task_id": "task_123",\n  "status": "running",\n  "messages": []\n}
GET/api/agent/pipeline/{task_id}?offset=0轮询 Pipeline▶

返回模型稳健性评估:CI 宽度、预测精度、集中度风险。

Response 200
{
  "avg_ci_width": 0.8,
  "prediction_accuracy": 95.2,
  "concentration_risk": "low",
  "channel_stability": [
    { "channel": "Google", "ci_width": 0.6, "stable": true },
    { "channel": "TikTok", "ci_width": 1.8, "stable": false }
  ]
}
POST/api/agent/chatAgent 对话▶

轮询 AutoMMM pipeline 进度和消息流。offset 参数用于增量拉取新消息。

Response 200
{
  "task_id": "task_123",
  "status": "running",
  "progress_pct": 60,
  "current_step": "roi_analysis",
  "messages": [
    { "step": "data_quality", "status": "completed", "message": "Data quality check passed" },
    { "step": "eda", "status": "completed", "message": "EDA completed, 5 channels detected" },
    { "step": "roi_analysis", "status": "running", "message": "Computing channel ROI..." }
  ]
}
POST/api/agent/cancel/{task_id}取消 Pipeline▶

与 AutoMMM pipeline 进行对话式追问。基于当前 pipeline 结果上下文回答。

json
{
  "task_id": "task_123",
  "message": "TikTok 的 ROI 为什么这么高?"
}
Response 200
{
  "reply": "TikTok ROI 为 4.2,高于 Google(3.2)。主要原因是 TikTok 当前花费较低,处于响应曲线陡峭区间...",
  "context": { "run_id": "run_123" }
}
▼

错误码

Error Codes

SparkX 使用标准 HTTP 状态码,错误响应包含 JSON detail 字段。

状态码含义常见原因
400请求错误无效策略、不支持的引擎、参数格式错误
401未授权缺少或无效的 JWT
403禁止访问资源属于其他组织
404未找到项目、数据集、运行、诊断或报告不存在
409冲突该项目已有活跃模型运行
413文件过大上传文件超过 50 MB
422验证失败数据质量问题、模型配置无效
429速率限制AI 生成调用过于频繁
500服务器错误存储、解析或后端异常
502上游 AI 故障LLM 提供方失败
503服务不可用LLM 未配置
结构化错误
{
  "detail": {
    "code": "data_quality_failed",
    "message": "Data quality check failed (2 critical issues)",
    "findings": []
  }
}
简单错误
{
  "detail": "Project not found"
}
▼

代码示例

Code Examples

cURL — 上传 CSV

bash
curl -X POST "https://app.sparkxmmm.com/api/v1/datasets/project_123/upload?strategy=replace" \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@weekly_marketing.csv"

cURL — 启动运行并轮询

bash
curl -X POST "https://app.sparkxmmm.com/api/v1/modeling/project_123/run" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "model_type": "ridge", "n_chains": 4, "n_iterations": 2000 }'

curl "https://app.sparkxmmm.com/api/v1/modeling/run/run_123/status" \
  -H "Authorization: Bearer $TOKEN"

Python

python
import time, requests

BASE = "http://app.sparkxmmm.com"
TOKEN = "YOUR_SUPABASE_JWT"
H = {"Authorization": f"Bearer {TOKEN}"}

project = requests.post(f"{BASE}/api/projects/",
    headers={**H, "Content-Type": "application/json"},
    json={"name": "API MMM", "kpi_type": "revenue",
          "time_granularity": "weekly", "geo_level": False,
          "model_type": "ridge"}).json()["project"]

with open("weekly_marketing.csv", "rb") as f:
    upload = requests.post(f"{BASE}/api/datasets/{project['id']}/upload",
        headers=H, files={"file": f}).json()

run = requests.post(f"{BASE}/api/modeling/{project['id']}/run",
    headers={**H, "Content-Type": "application/json"},
    json={"model_type": "ridge", "n_chains": 4,
          "n_iterations": 2000, "config": {}}).json()

run_id = run["run_id"]
while True:
    st = requests.get(f"{BASE}/api/modeling/run/{run_id}/status",
        headers=H).json()
    print(st["status"], st.get("progress_pct"), st.get("current_step"))
    if st["status"] in ("completed", "failed"):
        break
    time.sleep(5)

summary = requests.get(f"{BASE}/api/results/run/{run_id}/summary",
    headers=H).json()
print(summary)

JavaScript

javascript
const BASE = "http://app.sparkxmmm.com";
const token = "YOUR_SUPABASE_JWT";

async function api(path, options = {}) {
  const headers = new Headers(options.headers || {});
  headers.set("Authorization", "Bearer " + token);
  if (!(options.body instanceof FormData))
    headers.set("Content-Type", "application/json");
  const res = await fetch(BASE + path, { ...options, headers });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

const { project } = await api("/api/projects/", {
  method: "POST",
  body: JSON.stringify({
    name: "JS MMM", kpi_type: "revenue",
    time_granularity: "weekly", geo_level: false, model_type: "ridge"
  })
});

const form = new FormData();
form.append("file", fileInput.files[0]);
await api("/api/datasets/" + project.id + "/upload?strategy=replace", {
  method: "POST", body: form
});

const { run_id } = await api("/api/modeling/" + project.id + "/run", {
  method: "POST",
  body: JSON.stringify({
    model_type: "ridge", n_chains: 4, n_iterations: 2000, config: {}
  })
});
const status = await api("/api/modeling/run/" + run_id + "/status");
console.log(status);

本站使用 Cookie 和类似技术以提升体验并分析流量。继续浏览即表示同意。详见隐私政策。