API REFERENCE

Patterns & Segmentation.

Common needs do not require a special endpoint: a forecast per customer segment, a revenue total split into its parts, or a churn rate projection. This page shows how to build each one with /v2/forecast and /v2/batch/forecast.

Forecast each segment separately

Use tenant_context to split one metric across a dimension. The pair identifier + tenant_context identifies a series. So mrr on plan-pro and mrr on plan-free are two independent series. Each one has its own history and its own accuracy tracking.

Despite the name, it is not only for multi-tenancy. Use it for any dimension you want to forecast: plan, region, store, channel, cohort, acquisition month, device type.

Batch accepts up to 100,000 series per call on a paid plan (10 on the free tier), so a whole segmentation fits in one request:

curl -X POST "https://forecastapi.com/v2/batch/forecast" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "series": [
      {
        "identifier": "mrr",
        "tenant_context": "plan-pro",
        "data": [{"date": "2024-01-01", "value": 41200}, {"date": "2024-02-01", "value": 43900}]
      },
      {
        "identifier": "mrr",
        "tenant_context": "plan-free",
        "data": [{"date": "2024-01-01", "value": 2100}, {"date": "2024-02-01", "value": 2450}]
      },
      {
        "identifier": "mrr",
        "tenant_context": "plan-enterprise",
        "data": [{"date": "2024-01-01", "value": 88000}, {"date": "2024-02-01", "value": 91500}]
      }
    ],
    "frequency": "M",
    "periods": 6,
    "data_type": "revenue"
  }'

Results return in results.data, keyed by entity ID rather than by your identifier. The same identifier can appear under several segments in one batch, so it would not be unique. Each result echoes its own identifier and tenant_context, so match on that pair.

Choose your segments before you send history
Each segment builds its own history and accuracy record. If you re-cut the same data under new tenant_context values later, the API creates new series that start empty. It does not relabel the series you already have.

Break a total into components

Send each part of a total as its own series and add the parts on your side. The parts might be new, expansion, contraction and churned revenue, or a split by category, channel or region. You then get a forecast per component instead of one aggregate number.

{
  "series": [
    {"identifier": "revenue-new",
     "data": [{"date": "2024-01-01", "value": 12000}, {"date": "2024-02-01", "value": 13100}]},
    {"identifier": "revenue-expansion",
     "data": [{"date": "2024-01-01", "value": 4300}, {"date": "2024-02-01", "value": 4650}]},
    {"identifier": "revenue-contraction",
     "data": [{"date": "2024-01-01", "value": -1800}, {"date": "2024-02-01", "value": -1720}]},
    {"identifier": "revenue-churned",
     "data": [{"date": "2024-01-01", "value": -3100}, {"date": "2024-02-01", "value": -2950}]}
  ],
  "frequency": "M",
  "periods": 6,
  "data_type": "revenue"
}

If you also forecast the total as its own series, the components will not sum to it. The API fits each series independently, and each series picks its own model and trend, so the two numbers will disagree. When the roll-up itself is the deliverable, use grouped forecasting instead. It reconciles the whole hierarchy, so the parts sum to the whole by construction. If you stay on batch, publish one figure: either the sum of the parts or the standalone total, not both.

Do not sum the confidence bounds
The sum of each component's lower value does not give you a lower bound for the sum. It assumes every component misses low at the same time, which is far more pessimistic than reality. Sum the point forecasts instead and treat the total's uncertainty as an open question. Or let grouped forecasting build the aggregate band under a stated correlation assumption. For the equivalent problem across periods rather than across series, accumulate handles it explicitly.

Forecast rates and percentages

Churn rate, conversion rate, utilization and margin are all ordinary time series, and they forecast normally. Send them in whatever unit you already use, 0–1 or 0–100, as long as you stay consistent.

Tell the API the range your series cannot leave with value_bounds. Either side is optional. A rate has both bounds, and a backlog has only a floor:

{
  "identifier": "churn-rate",
  "data": [{"date": "2024-01-01", "value": 2.4}, {"date": "2024-02-01", "value": 3.1}],
  "frequency": "M",
  "periods": 12,
  "value_bounds": {"min": 0, "max": 100}
}

The API then forecasts the series on a transformed scale and maps it back, so the forecast, the confidence bounds, and every quantile stay inside the range. The band is also no longer symmetric. On a rate near zero it has more room above than below, which is the honest shape for a number that cannot go below zero.

Why not just clamp the bounds yourself?
A clamp removes probability without redistributing it, so a clamped band no longer covers at its stated confidence level. You asked for 80% and got less. A clamp also cannot fix the shape of the band inside the range. It only removes the ends. value_bounds changes what the API forecasts rather than what it displays, so the stated coverage still holds.
Bounds have to match your data
If the history you send already falls outside the range you declared, the response reports the bounds as not applied and forecasts the series normally. It does not squeeze real observations into a range they contradict. Check model_info.bounds_transform in the response. It says whether the transform ran, and why not if it did not. The usual cause is a unit mismatch. Rates of 0–1 with a declared {"min": 0, "max": 100} work, but the reverse does not.

Build a fan chart

A fan chart needs several quantiles per period. Request them with the quantiles parameter. Each forecast row then returns a quantiles object alongside the usual bounds:

{
  "identifier": "SKU-12345",
  "data": [{"date": "2024-01-01", "value": 120}, {"date": "2024-02-01", "value": 135}],
  "frequency": "M",
  "periods": 6,
  "quantiles": [0.1, 0.3, 0.5, 0.7, 0.9]
}
Why not call the same series at several confidence levels?

This is the intuitive approach, but it costs more and gives you less. The API does not cache results, so five confidence levels bill as five forecasts.

More importantly, 0.80 is the widest band the foundation models produce natively. advanced-quantized, advanced-patched, multivariate and ensemble return the same 80% band whether you ask for 0.85 or 0.95, so those lines overlap. One quantiles request gives you genuinely distinct levels, read from each model's own quantile heads, for a single charge.

What is not directly supported

Per-customer churn scoring and per-customer LTV. The question "which of these customers will churn, and what is each one worth" means you classify customers by their attributes: plan, tenure, usage, support history. That is a different kind of model from time series forecasting. It needs data that this API does not accept.

The aggregate version does work well: forecast a churn rate or revenue series per cohort with tenant_context, then use accumulate to turn that forecast into a discounted lifetime total. That tells you what a segment is worth, rather than what one customer is worth.

Next Steps

LAST UPDATED — 14 AUG 2026 · FORECASTAPI DOCS
WAS THIS USEFUL? YES NO