70 lines
2.8 KiB
Markdown
70 lines
2.8 KiB
Markdown
# Normalized report data
|
||
|
||
The renderer consumes normalized report data, not raw MCP responses. Build each semantic row by zipping `columns[].name` with the row values, then populate this schema. Ratios such as ROAS use multiplier units (`6.31` means `6.31×`); percentage fields use percentage points (`4.18` means `4.18%`). Money values use the account currency.
|
||
|
||
## Required shape
|
||
|
||
```json
|
||
{
|
||
"meta": {
|
||
"account_name": "Demo Commerce",
|
||
"account_id": "demo-account-001",
|
||
"currency": "MYR",
|
||
"reporting_timezone": "Asia/Kuala_Lumpur",
|
||
"period_label": "2026-08-19",
|
||
"comparison_label": "Previous 7 complete days",
|
||
"freshness_label": "2026-08-20 14:48 MYT",
|
||
"attribution_label": "TikTok GMV Max native attribution",
|
||
"status_label": "Cautiously positive"
|
||
},
|
||
"summary": {
|
||
"spend": 1837.84,
|
||
"revenue": 11593.35,
|
||
"orders": 663,
|
||
"ctr_percent": null,
|
||
"cpi": null,
|
||
"roas": 6.31,
|
||
"simple_roi_percent": 530.8,
|
||
"cost_per_order": 2.77
|
||
},
|
||
"monitoring_note": "Optional partial-day or data-quality note.",
|
||
"trend": [
|
||
{"label": "08/14", "roas": 6.45, "partial": false}
|
||
],
|
||
"campaigns": {
|
||
"winners": [
|
||
{"name": "Campaign name", "id": "external id", "status": "ENABLE", "spend": 10, "revenue": 80, "orders": 5, "roas": 8, "reason": "Balanced scale and efficiency"}
|
||
],
|
||
"anomalies": []
|
||
},
|
||
"creative": {
|
||
"row_count": 692,
|
||
"coverage_percent": 75.2,
|
||
"source_groups": [
|
||
{"label": "Affiliate / creator", "spend": 1232.55, "revenue": 7535.94, "orders": 463, "roas": 6.11},
|
||
{"label": "Account-owned", "spend": 150.2, "revenue": 121, "orders": 8, "roas": 0.81}
|
||
],
|
||
"winners": [
|
||
{"name": "Creative title", "id": "creative id", "creator": "creator", "spend": 20, "revenue": 350, "orders": 20, "roas": 17.5, "clicks": 89, "product_ctr_percent": 7.0}
|
||
],
|
||
"anomalies": [],
|
||
"insights": ["Short evidence-backed attribution clue"]
|
||
},
|
||
"recommendations": [
|
||
{"title": "Action title", "detail": "Observed evidence and bounded next step.", "confirmation": "required"}
|
||
],
|
||
"manual_confirmations": [
|
||
{"action": "Pause or change budget", "required": true, "reason": "Changes live delivery"}
|
||
],
|
||
"notes": ["Attribution and unavailable-data caveats"]
|
||
}
|
||
```
|
||
|
||
## Completion rules
|
||
|
||
- `recommendations` contains exactly three items. `confirmation` is `required`, `partial`, or `none`.
|
||
- Winner and anomaly tables should each contain three to five rows when sufficient data exists. Keep low-sample rows but identify the sample limitation in `reason`.
|
||
- Missing CTR/CPI/ROI inputs are JSON `null`. Never encode missing data as numeric zero.
|
||
- `creative.source_groups` may be empty when creator identity is unavailable. Keep `creative.insights` evidence-based and avoid causal language.
|
||
- `manual_confirmations` covers every recommended platform write. Read-only checks may use `required: false`.
|