Multiples API

Aggregate Transactions

Introduction

This endpoint computes a per-bucket median multiple for a single cohort of deals.

You choose one metric (such as ev_revenue or valuation), slice the cohort by time_bucket (month, quarter, year, or a single overall bucket), and scope it with the same filters vocabulary as the transactions list.

The response returns {bucket, n, median, q1, q3} arrays plus the methodology constants used, so you can chart valuation trends or benchmark a comparable set without pulling and reducing the raw deals yourself.

Set up

Endpoint

POST https://multiples.vc/api/private/v1/transactions/aggregate

Request

Send a JSON body with the metric to aggregate, an optional time bucket, and a filters object that defines the cohort. metric and filters are required.

Median EV/Revenue per quarter across M&A deals:

{
  "metric": "ev_revenue",
  "time_bucket": "quarter",
  "filters": {
    "deal_type": ["M&A"],
    "date_from": "2021-01-01",
    "date_to": "2025-12-31"
  }
}

Median EV/Revenue per year for European Growth/Venture rounds:

{
  "metric": "ev_revenue",
  "time_bucket": "year",
  "filters": {
    "deal_type": [
      "Growth",
      "Venture"
    ],
    "target_region": [
      "Western Europe",
      "Northern Europe"
    ],
    "date_from": "2020-01-01",
    "date_to": "2024-12-31"
  }
}

Top-level parameters:

fieldtypedescription
metricstring (required)The value aggregated per bucket. One of ev_revenue, ev_ebitda, valuation, raised, revenue, ebitda.
time_bucketstringHow deals are grouped over time: month, quarter, year, or none. Defaults to none (one overall bucket).
filtersobject (required)Cohort definition. Accepts the full /transactions filter vocabulary (below).

filters fields (all optional):

fieldtypedescription
idarray of uuidMatch specific deals by ID.
target_idarray of uuidRestrict to deals whose target is one of these companies.
investor_idarray of uuidMatch deals where any of these companies participated as a lead investor or buyer.
deal_typearray of stringOne or more of Early, Growth, M&A, Public listing, Secondary, Venture.
deal_subtypearray of stringOne or more of Angel, ICO, PE buyout, Pre-seed, Secondary - private, Secondary - public, Seed, Series A-Series J, Strategic M&A, Strategic investment, Undisclosed stage.
date_fromdate (YYYY-MM-DD)Earliest deal date to include. Defaults to 5 years before today when omitted.
date_todate (YYYY-MM-DD)Latest deal date to include. Defaults to today when omitted.
valuation_min / valuation_maxnumberBound deal valuation (millions USD).
raised_min / raised_maxnumberBound amount raised.
revenue_min / revenue_maxnumberBound deal revenue.
ebitda_min / ebitda_maxnumberBound deal EBITDA.
ev_revenue_min / ev_revenue_maxnumberBound the EV/Revenue multiple.
ev_ebitda_min / ev_ebitda_maxnumberBound the EV/EBITDA multiple.
target_countryarray of stringTarget country (ISO 3166-1 alpha-3 codes).
target_regionarray of stringTarget region (e.g. North America, Western Europe).
target_verticalsarray of stringMatch deals whose target operates in any of these verticals.
target_themesarray of stringMatch deals whose target maps to any of these themes.
target_client_focusarray of stringMatch by target client focus (e.g. B2C).
target_revenue_modelarray of stringMatch by target revenue model.
target_company_typearray of stringMatch by target company type.
updated_atdate-timeChange-feed checkpoint: only deals updated at or after this timestamp.
include_deletedbooleanInclude soft-deleted deals. Defaults to false.

The accepted filter fields, metric enums, time buckets, and methodology constants are also discoverable at runtime via GET /lookup/transactions.

Response

Each data entry is one bucket. Buckets with no deals (n: 0) are returned so charts have explicit gaps, and buckets below the small-N threshold report n but suppress the statistics with warning: "insufficient_sample". Example for median EV/Revenue per year for European Growth/Venture rounds (the second request above):

{
  "data": [
    {
      "bucket": "2020",
      "n": 42,
      "median": 10.7718120805369,
      "q1": 5.55991124260355,
      "q3": 17.9166666666667,
      "warning": null
    },
    {
      "bucket": "2021",
      "n": 90,
      "median": 9.88470557582074,
      "q1": 5,
      "q3": 18.7724830128347,
      "warning": null
    },
    {
      "bucket": "2022",
      "n": 68,
      "median": 12.5009557522124,
      "q1": 6.70950704225352,
      "q3": 22.0485210171251,
      "warning": null
    },
    {
      "bucket": "2023",
      "n": 24,
      "median": 6.76799805385352,
      "q1": 4.93762963252847,
      "q3": 11.3538205980066,
      "warning": null
    },
    {
      "bucket": "2024",
      "n": 37,
      "median": 9.5,
      "q1": 4.46632478632479,
      "q3": 17,
      "warning": null
    }
  ],
  "meta": {
    "metric": "ev_revenue",
    "time_bucket": "year",
    "total_deals": 284,
    "outliers_trimmed": 23,
    "methodology": {
      "small_n_threshold": 3,
      "outlier_rule": "iqr_1.5",
      "default_date_range_years": 5,
      "empty_buckets_returned": true,
      "date_range": {
        "from": "2020-01-01",
        "to": "2024-12-31"
      }
    }
  }
}

When time_bucket is none, data holds a single entry whose bucket is null, covering the whole cohort:

{
  "data": [
    { "bucket": null, "n": 211, "median": 390, "q1": 100.05, "q3": 1000, "warning": null }
  ],
  "meta": {
    "metric": "valuation",
    "time_bucket": "none",
    "total_deals": 242,
    "outliers_trimmed": 31,
    "methodology": {
      "small_n_threshold": 3,
      "outlier_rule": "iqr_1.5",
      "default_date_range_years": 5,
      "empty_buckets_returned": true,
      "date_range": { "from": "2021-06-15", "to": "2026-06-15" }
    }
  }
}

Fields

data[] - one object per bucket:

fieldtypedescription
bucketstring | nullThe bucket label: YYYY-MM (month), YYYY-Qn (quarter), or YYYY (year). null when time_bucket is none.
nintegerNumber of deals in the bucket after outlier trimming.
mediannumber | nullMedian of the chosen metric for the bucket. null when n is below small_n_threshold or the bucket is empty.
q1number | nullFirst quartile (25th percentile) of the metric. null under the same conditions as median.
q3number | nullThird quartile (75th percentile) of the metric. null under the same conditions as median.
warningstring | nullinsufficient_sample when the bucket has too few deals to report statistics; otherwise null.

meta - context and methodology:

fieldtypedescription
metricstringThe metric that was aggregated (echoes the request).
time_bucketstringThe time bucket that was applied (echoes the request).
total_dealsintegerTotal matching deals across all buckets, before outlier trimming.
outliers_trimmedintegerNumber of deals removed by the outlier rule before computing statistics.
methodologyobjectConstants used for this aggregation (see below).

meta.methodology:

fieldtypedescription
small_n_thresholdintegerBuckets with fewer than this many deals report n but suppress median/q1/q3 and flag insufficient_sample.
outlier_rulestringThe outlier-trimming rule applied, e.g. iqr_1.5 (values outside 1.5×IQR of the quartiles are dropped).
default_date_range_yearsintegerLookback window (in years) used when date_from/date_to are omitted.
empty_buckets_returnedbooleanWhether zero-deal buckets are emitted in data (so time series have explicit gaps).
date_rangeobjectThe effective date window applied, with from and to (YYYY-MM-DD).
date_range.fromstring (date)Start of the effective window (inclusive).
date_range.tostring (date)End of the effective window (inclusive).

On this page