Simba documentation

Report sales and media data

Simba can report the data you uploaded, not only a fitted model’s results. You can ask for any date window, at any grain, and by brand, channel or market. For example: “store sales and TV spend in the North region for August, by week.” Fitted model results can also be cut to a date window. Their channel summary is recalculated for that window, not filtered.

Both features are available through the API and through Simba MCP. The MCP tool reference is generated from the running server: see docs/tools.md in the simba-mcp repository for the exact parameters of get_data_report, upload_data and get_model_results.

Declare what each column is

A report needs to know what each column means: the KPI, a brand, a spend line, a price. Simba never guesses this from a column name. You declare column roles once, when you upload the data, or with each report request.

Only three names are recognised without a declaration, because the data schema itself defines them:

Every other column reports as unknown and is not aggregated until you declare it.

Role How it aggregates over a period Unit
kpi sum your KPI
spend, activity sum, per channel currency / count
outcome:online_sales, outcome:store_sales, outcome:margin sum currency
outcome:orders, outcome:new_customers sum count
media:impressions, media:clicks, media:grps sum, per channel count / GRPs
control:price mean currency
control:rate, control:index mean ratio / index
control:stock each brand’s last value in the period, summed across brands count
multiplier mean ratio
hierarchy, dimension:market, dimension:product, dimension:campaign keys for filtering and grouping —

A declaration is either a role name, or a role plus a channel for media columns:

{
  "revenue": "kpi",
  "brand": "hierarchy",
  "region": "dimension:market",
  "tv_grps": {"role": "media:grps", "channel": "tv"},
  "avg_price": "control:price",
  "orders": "outcome:orders"
}

Pass it as roles when you upload, for example upload_data(roles={...}) over MCP. You can also pass it as roles on a report request to override what was stored. An unknown role, or a column the file doesn’t have, is refused.

Ask for a report

GET /api/v1/datasets/{dataset_id}/report?start=2024-08-01&end=2024-08-31&granularity=week&group_by=channel&metrics=kpi,spend

Over MCP:

get_data_report(dataset_id=42, start="2024-08-01", end="2024-08-31",
                granularity="week", group_by="channel", metrics=["kpi", "spend"])
Parameter Values
start, end Dates as YYYY-MM-DD, inclusive
granularity native (the rows as stored), week, month or quarter
group_by hierarchy, channel, or a dimension role such as dimension:market
hierarchy Keep one brand or region
metrics Roles or role families: kpi, spend, outcome, outcome:orders, control, … By default, every metric role is included

Periods:

An example response, with a synthetic dataset and round numbers:

{
  "dataset": {"id": 42, "source": "upload", "sha256": "…", "data_through": "2024-12-30"},
  "granularity": "week",
  "rows": [
    {"period_start": "2024-08-05", "period_end": "2024-08-11", "group": "tv", "metric": "spend", "value": 12000, "unit": "currency"},
    {"period_start": "2024-08-05", "period_end": "2024-08-11", "group": "all", "metric": "kpi", "value": 85000, "unit": "kpi"}
  ],
  "meta": {"basis": "dataset", "aggregation": {"spend": "sum", "kpi": "sum", "calendar": "…"}, "roles": {"…": "…"}}
}

What the response tells you:

A report is capped at 10,000 rows. Past that you get an error: narrow the window or use a coarser grain.

Cut model results to a window

get_model_results, and the API’s model results, accept the same start, end and granularity. They window the per-period sections: contributions, the per-period media table (coefficients) and actual_vs_model.

The channel summary is recalculated for the window:

The response gains a meta block with the window, the basis (each period’s fitted contribution), data_through and the rules applied.

Things to keep in mind