Create a report card from JSON, saved exactly as sent (no model involved). chart/table: pass cardConfig {cardType, chartType (chart only), title, data, visualization?, presentation?, paletteId?}. data holds the query: metrics and/or dimensions with exact names from analytics_schema (a table may list dimensions only), timeDimension, filters, order, comparison. Optional ids on data fields (metric_<x> / dimension_<x>) are kept, so visualization can reference them. visualization = overrides deep-merged on Jepto defaults: chart options for charts; for tables pagination, sorting, rendering, columns [{id, width, header, cells}] and columnOrder [ids]. presentation.number = Number card format {prefix, suffix, precision, compact}, showSparkline, valueSize. Colors come from paletteId, not visualization. Rules: only keys you change; plain JSON, no functions; arrays replace on merge, so omit series rather than sending series: []; query fields stay in data. An invalid config returns error.details per field. Static cards: markdown/html (static copy, not KPI totals), image, analysis, filter (set controlType, e.g. date_range) via cardType + title/content/image. Examples: skills_get dataChatReport; help_article https://www.jepto.com/help/custom-visualizations. Cards are throwaway until placed: call report_page_get then report_page_update in the same flow (needsPlacement). To style a chart in plain language, create it first, then call report_card_update with visualizationPrompt.