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/aggregateRequest
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:
| field | type | description |
|---|---|---|
metric | string (required) | The value aggregated per bucket. One of ev_revenue, ev_ebitda, valuation, raised, revenue, ebitda. |
time_bucket | string | How deals are grouped over time: month, quarter, year, or none. Defaults to none (one overall bucket). |
filters | object (required) | Cohort definition. Accepts the full /transactions filter vocabulary (below). |
filters fields (all optional):
| field | type | description |
|---|---|---|
id | array of uuid | Match specific deals by ID. |
target_id | array of uuid | Restrict to deals whose target is one of these companies. |
investor_id | array of uuid | Match deals where any of these companies participated as a lead investor or buyer. |
deal_type | array of string | One or more of Early, Growth, M&A, Public listing, Secondary, Venture. |
deal_subtype | array of string | One 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_from | date (YYYY-MM-DD) | Earliest deal date to include. Defaults to 5 years before today when omitted. |
date_to | date (YYYY-MM-DD) | Latest deal date to include. Defaults to today when omitted. |
valuation_min / valuation_max | number | Bound deal valuation (millions USD). |
raised_min / raised_max | number | Bound amount raised. |
revenue_min / revenue_max | number | Bound deal revenue. |
ebitda_min / ebitda_max | number | Bound deal EBITDA. |
ev_revenue_min / ev_revenue_max | number | Bound the EV/Revenue multiple. |
ev_ebitda_min / ev_ebitda_max | number | Bound the EV/EBITDA multiple. |
target_country | array of string | Target country (ISO 3166-1 alpha-3 codes). |
target_region | array of string | Target region (e.g. North America, Western Europe). |
target_verticals | array of string | Match deals whose target operates in any of these verticals. |
target_themes | array of string | Match deals whose target maps to any of these themes. |
target_client_focus | array of string | Match by target client focus (e.g. B2C). |
target_revenue_model | array of string | Match by target revenue model. |
target_company_type | array of string | Match by target company type. |
updated_at | date-time | Change-feed checkpoint: only deals updated at or after this timestamp. |
include_deleted | boolean | Include 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:
| field | type | description |
|---|---|---|
bucket | string | null | The bucket label: YYYY-MM (month), YYYY-Qn (quarter), or YYYY (year). null when time_bucket is none. |
n | integer | Number of deals in the bucket after outlier trimming. |
median | number | null | Median of the chosen metric for the bucket. null when n is below small_n_threshold or the bucket is empty. |
q1 | number | null | First quartile (25th percentile) of the metric. null under the same conditions as median. |
q3 | number | null | Third quartile (75th percentile) of the metric. null under the same conditions as median. |
warning | string | null | insufficient_sample when the bucket has too few deals to report statistics; otherwise null. |
meta - context and methodology:
| field | type | description |
|---|---|---|
metric | string | The metric that was aggregated (echoes the request). |
time_bucket | string | The time bucket that was applied (echoes the request). |
total_deals | integer | Total matching deals across all buckets, before outlier trimming. |
outliers_trimmed | integer | Number of deals removed by the outlier rule before computing statistics. |
methodology | object | Constants used for this aggregation (see below). |
meta.methodology:
| field | type | description |
|---|---|---|
small_n_threshold | integer | Buckets with fewer than this many deals report n but suppress median/q1/q3 and flag insufficient_sample. |
outlier_rule | string | The outlier-trimming rule applied, e.g. iqr_1.5 (values outside 1.5×IQR of the quartiles are dropped). |
default_date_range_years | integer | Lookback window (in years) used when date_from/date_to are omitted. |
empty_buckets_returned | boolean | Whether zero-deal buckets are emitted in data (so time series have explicit gaps). |
date_range | object | The effective date window applied, with from and to (YYYY-MM-DD). |
date_range.from | string (date) | Start of the effective window (inclusive). |
date_range.to | string (date) | End of the effective window (inclusive). |