Recast Knowledge Base
Breadcrumbs

The Insights API

The Insights API lets you programmatically run any report available in the Insights tab and Reporter tab of the Recast app, retrieve the results, and download the underlying data as CSVs. This is useful for automating recurring analyses, integrating Recast outputs into your own reporting pipelines, or running the same report across multiple date ranges at once.

See the Swagger documentation for full schema details: https://app.getrecast.com/api-docs

The simplest way to get started is to run the report you want in the Recast UI first. Once it completes successfully, use GET /reports/[id] to retrieve the form that was used. You can then resubmit that form, changing only the fields you need, rather than constructing the request from scratch.

The Endpoints

  1. GET /reports/[id] - Returns an existing report with its status, form, and available downloads

  2. POST /reports - Creates a new report

    • name - optional label for the report

    • show_in_ui - whether to show it in the Reporter tab of the app

  3. GET /reports - Returns a paginated list of all reports. Supports an optional report_type query parameter to filter results

  4. GET /reports/[id]/downloads/[key] - Returns a CSV download for a completed report

The Form

The form contains all the inputs for a report. It always requires deployment_id and report_type. Additional fields depend on the report type.

{  "name": "My Report",

  "show_in_ui": false,

  "form": {

    "deployment_id": 5716,

    "report_type": "compute_insights_overview",

    "start_date": "2024-01-01",

    "end_date": "2024-03-31"

  }

}

Report Types

The table below lists every available report type and the additional form fields each one requires. deployment_id and report_type are always required and are not repeated in the table.

Report type

What it shows

Additional required fields

compute_insights_overview

Channel-by-channel KPI contribution โ€” impact (shifted/unshifted), ROI, and MROI for the period

start_date, end_date

compute_spend_summary

Spend per channel over the period, in daily/weekly/monthly/total views

start_date, end_date

compute_period_summary

Breakdown of how much KPI was earned during the period vs. how much will be earned after from spend in the period

start_date, end_date

compute_marketing_vs_baseline

Split between marketing-driven KPI and organic/baseline KPI over time

start_date, end_date

compute_channel_uncertainty_drivers


start_date, end_date

compute_lower_funnel_waterfall

Which upper funnel channels drove spend into lower funnel channels, with rates and KPI effects

start_date, end_date

compute_in_sample_model_fit

Model fit quality โ€” predicted vs. actual KPI in-sample, with summary statistics

start_date, end_date

compute_context_variable_summary

Effect of contextual variables (e.g. price, brand awareness) on marketing effectiveness over time. Only available for models with contextual variables configured.

start_date, end_date

compute_baseline_summary

Non-marketing (organic/baseline) contribution to KPI over time, optionally including spike effects

start_date, end_date, include_spikes (boolean)

compute_share_of_spend_vs_effect

Each channel's share-of-effect minus share-of-spend over time. Positive = overperforming, negative = underperforming.

start_date, end_date, granularity ("daily", "weekly", or "monthly")

compute_roi_cpa_waterfall_plots

ROI/CPA decomposed into its drivers: baseline ROI, context variables, saturation, changing saturation, and seasonal effects

start_date, end_date, channels (array of channel name strings)

compute_upper_funnel_details

Direct ROI vs. Total ROI over time for selected channels, showing how much of total ROI is driven by lower funnel activity

start_date, end_date, channels

compute_prior_vs_posterior

Shows the difference between eh models' priors and posterior estimate

start_date, end_date, channels

compute_daily_spend_vs_KPI

Daily spend per channel vs. modeled KPI, plus correlation coefficients between channels

start_date, end_date, channels

compare_shift_curves

Time delay between when a channel spends and when the effect is realized

channels

compute_spend_response_curves

Impact, ROI/CPA, and MROI/MCPA at various spend levels for selected channels, anchored to actual spend in the lookback window

date (YYYY-MM-DD), num_days (integer 1โ€“90), channels

compute_fixed_spend_performance

Channel performance estimated at a fixed spend level

start_date, end_date, channels, spend (number), include_lower_funnel_effects ("true" or "false")

compute_grouped_channel_summaries

Channel performance with user-defined groupings: impact, ROI, and MROI per group across daily/weekly/monthly/total granularities

start_date, end_date, channel_groups (array of {name, channels}), include_lower_funnel_effects ("true" or "false")

compare_time_periods

ROI/CPA, mROI/mCPA, baseline, in-period effect, and total outcome compared across two time periods.

previous_start_date, previous_end_date, period_start_date, period_end_date

compute_spike_detail_summary

Day-by-day effect of promotions, holidays, and spikes on KPI, including pull-forward and pull-back. Provides both individual and grouped spike views.

(none)

compute_backtest_summaries

Out-of-sample backtest results showing how well the model predicts data it was not trained on

(none)

compute_model_configuration

Model configuration tables: priors, ROI settings, shift parameters, spike definitions, and channel linkings

(none)

compute_experiments_summaries

Experiment results summary

(none)

compute_clean_data

The clean input data used by the model, exported as a CSV

(none)

Polling

Reports run asynchronously. After creating a report, poll GET /reports/[id] until status is no longer "ready" or "processing". Typical run times are 1โ€“5 minutes. The results field which contains the list of available download keys is only present when status == "success".

Downloads

Each download key returns a CSV. The available keys are listed in results.downloads on the show response. For report types where the keys depend on inputs (e.g. compute_grouped_channel_summaries generates one CSV per group ร— metric ร— granularity combination), inspect results.downloads to see the full list of available downloads.

The downloads currently do not include the plots available on each insights report.

SKILL.md (Beta)

We have a skill file that can help AI coding assistants get up to speed on the Insights API. It is in beta and is best used for writing boilerplate code. Please review any generated code before running it.

reporter-api.md

Code Examples

R

R
# Recast Insights API โ€” R Usage Example
#
# Workflow: Fetch latest deployment โ†’ Create report โ†’ Poll โ†’ Download CSVs
#
# Prerequisites:
#   install.packages(c("httr2", "jsonlite"))
#   Add to .Renviron: API_PAT=gr_your_token_here
#     Generate your token: log into the Recast app โ†’ click your email (top right) โ†’ Generate API token
#     Store it in ~/.Renviron as: API_PAT=gr_your_token_here
#     Never hard-code or share this token.

library(httr2)
library(jsonlite)

# โ”€โ”€ Edit these โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
CLIENT_SLUG <- "myslug"                    # Your client slug (visible in the app URL)
REPORT_TYPE <- "compute_insights_overview"
START_DATE  <- "2024-01-01"
END_DATE    <- "2024-03-31"
SHOW_IN_UI  <- FALSE                           # TRUE to see this report in the app

# โ”€โ”€ Rarely needs changing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
BASE_URL <- "https://api.getrecast.com"
PAT      <- Sys.getenv("API_PAT")             # Set in ~/.Renviron, never hard-coded

# โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
parse <- \(resp) resp |> resp_body_string() |> fromJSON(simplifyVector = FALSE)

check <- function(resp, expected = 200) {
  if (resp_status(resp) != expected) {
    body <- tryCatch(resp_body_string(resp), error = \(e) "(no body)")
    stop(sprintf("HTTP %d: %s", resp_status(resp), body))
  }
  resp
}

api_request <- function(...) {
  request(BASE_URL) |>
    req_url_path_append("v1", "clients", CLIENT_SLUG, ...) |>
    req_auth_bearer_token(PAT) |>
    req_headers(Accept = "application/json") |>
    req_error(is_error = \(resp) FALSE)
}

# โ”€โ”€ Step 1: Fetch the latest deployment โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
deployment_id <- api_request("deployments") |>
  req_perform() |> check() |> parse() |>
  (\(r) r$data[[1]]$id)()
cat(sprintf("Using deployment ID: %d\n", deployment_id))

# โ”€โ”€ Step 2: Create a report โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
resp <- api_request("reports") |>
  req_method("POST") |>
  req_headers(`Content-Type` = "application/json") |>
  req_body_json(list(
    name       = paste("Channel Attribution -", Sys.Date()),
    show_in_ui = SHOW_IN_UI,
    form       = list(
      deployment_id = deployment_id,
      report_type   = REPORT_TYPE,
      start_date    = START_DATE,
      end_date      = END_DATE
    )
  ), auto_unbox = TRUE) |>
  req_perform() |>
  check(expected = 201)

report_id <- parse(resp)$id
cat(sprintf("Created report %d\n", report_id))

# โ”€โ”€ Step 3: Poll until complete (typically 1โ€“5 minutes) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
repeat {
  result <- api_request("reports", report_id) |> req_perform() |> check() |> parse()
  cat(sprintf("Status: %s\n", result$status))
  if (!result$status %in% c("ready", "processing")) break
  Sys.sleep(30)
}

if (result$status != "success") {
  stop(sprintf("Report ended with status: %s", result$status))
}

# โ”€โ”€ Step 4: Download all available CSVs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
downloads <- result$results$downloads
cat(sprintf("Downloading %d files...\n", length(downloads)))

for (dl in downloads) {
  csv_resp <- api_request("reports", report_id, "downloads", dl$key) |>
    req_perform() |>
    check()
  df <- read.csv(text = resp_body_string(csv_resp), check.names = FALSE)
  write.csv(df, file = paste0(dl$key, ".csv"), row.names = FALSE)
  cat(sprintf("  Saved %s.csv (%d rows)\n", dl$key, nrow(df)))
}

Python

Recast Insights API โ€” Python Usage Example

# Recast Insights API โ€” Python Usage Example
#
# Workflow: Fetch latest deployment โ†’ Create report โ†’ Poll โ†’ Download CSVs
#
# Prerequisites:
#   pip install requests pandas
#   Generate your token: log into the Recast app โ†’ click your email (top right) โ†’ Generate API token
#   Set as an environment variable: export API_PAT=gr_your_token_here
#   Never hard-code or share this token.

import os
import time
import io
import requests
import pandas as pd
from datetime import date

# โ”€โ”€ Edit these โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
CLIENT_SLUG = "myslug"                     # Your client slug (visible in the app URL)
REPORT_TYPE = "compute_insights_overview"
START_DATE  = "2024-01-01"
END_DATE    = "2024-03-31"
SHOW_IN_UI  = False                            # True to see this report in the app

# โ”€โ”€ Rarely needs changing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
BASE_URL = "https://api.getrecast.com"
PAT      = os.environ["API_PAT"]              # Set via: export API_PAT=gr_your_token_here

BASE_PATH = f"{BASE_URL}/v1/clients/{CLIENT_SLUG}"
HEADERS   = {"Authorization": f"Bearer {PAT}", "Accept": "application/json"}

# โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def check(resp, expected=200):
    if resp.status_code != expected:
        body = resp.text or "(no body)"
        raise Exception(f"HTTP {resp.status_code}: {body}")
    return resp

# โ”€โ”€ Step 1: Fetch the latest deployment โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
deployments = check(requests.get(f"{BASE_PATH}/deployments", headers=HEADERS)).json()
deployment_id = deployments["data"][0]["id"]
print(f"Using deployment ID: {deployment_id}")

# โ”€โ”€ Step 2: Create a report โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
resp = check(requests.post(
    f"{BASE_PATH}/reports",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={
        "name": f"Channel Attribution - {date.today()}",
        "show_in_ui": SHOW_IN_UI,
        "form": {
            "deployment_id": deployment_id,
            "report_type": REPORT_TYPE,
            "start_date": START_DATE,
            "end_date": END_DATE,
        },
    },
), expected=201)

report_id = resp.json()["id"]
print(f"Created report {report_id}")

# โ”€โ”€ Step 3: Poll until complete (typically 1โ€“5 minutes) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
while True:
    result = check(requests.get(f"{BASE_PATH}/reports/{report_id}", headers=HEADERS)).json()
    print(f"Status: {result['status']}")
    if result["status"] not in ("ready", "processing"):
        break
    time.sleep(30)

if result["status"] != "success":
    raise Exception(f"Report ended with status: {result['status']}")

# โ”€โ”€ Step 4: Download all available CSVs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
downloads = result["results"]["downloads"]
print(f"Downloading {len(downloads)} files...")

for dl in downloads:
    csv_resp = check(requests.get(
        f"{BASE_PATH}/reports/{report_id}/downloads/{dl['key']}",
        headers=HEADERS,
    ))
    df = pd.read_csv(io.StringIO(csv_resp.text))
    df.to_csv(f"{dl['key']}.csv", index=False)
    print(f"  Saved {dl['key']}.csv ({len(df)} rows)")