GET /v1/projects/:projectId/conversions
Rollup of purchase, subscribe, and custom conversion events.
/v1/projects/:projectId/conversions- Auth
- Bearer
- Scope
- events:read
Aggregates conversion events over a time window. Use it to render conversion widgets without walking the raw event stream and re-bucketing client-side.
Totals count every event matching the filter in the window. groups is present when groupBy is set - buckets are sparse, so zero-volume groups are omitted. value sums only events that carry a numeric value; precedence is revenue_amount → price_amount → properties.value (the first present wins, all in decimal dollars, rounded to 2dp). Currency mixing is not normalized - if events in the window carry more than one currency code, currency comes back null; pass a single-currency filter (or set a stable revenue_currency / price_currency SDK-side) if you need a clean sum.
The endpoint is backed by an in-process scan of sdk_events (no pre-aggregated rollup table yet), so reads are capped at 50,000 matching rows per request. When that cap is hit, the response carries truncated: true and totals/groups reflect only the first slice of events. Narrow the window or the eventNames filter to keep reads under the cap.
projectIdstringrequiredProject ID.
sincestring (ISO 8601, UTC Z)requiredInclusive lower bound on `occurred_at`.untilstring (ISO 8601, UTC Z)requiredExclusive upper bound on `occurred_at`.eventNamesstring[]optionalEvent names. Comma-separated (`eventNames=a,b`) or repeat the param (`eventNames=a&eventNames=b`). Defaults to the built-in conversion set: `purchase_success`, `subscribe_success`, `trial_start`.groupBystring[]optionalBucketing dimensions. Comma-separated (`groupBy=day,eventName`) or repeat the param (`groupBy=day&groupBy=eventName`).One of:platform,appId,eventName,day,hourappIdstringoptionalFilter to a single SDK app.
Example request
curl "https://api.layers.com/v1/projects/prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39/conversions?since=2026-04-11T00:00:00Z&until=2026-04-18T00:00:00Z&groupBy=day,eventName" \
-H "Authorization: Bearer lp_..."const { totals, groups } = await layers.conversions.list(
"prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
{
since: "2026-04-11T00:00:00Z",
until: "2026-04-18T00:00:00Z",
groupBy: ["day", "eventName"],
}
);result = layers.conversions.list(
project_id="prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
since="2026-04-11T00:00:00Z",
until="2026-04-18T00:00:00Z",
group_by=["day", "eventName"],
)Response
{
"window": {
"since": "2026-04-11T00:00:00Z",
"until": "2026-04-18T00:00:00Z"
},
"totals": {
"count": 1284,
"uniqueUsers": 912,
"value": 22647.4,
"currency": "USD"
},
"groups": [
{
"key": { "day": "2026-04-11", "eventName": "purchase_success" },
"count": 142,
"uniqueUsers": 131,
"value": 2501.85
},
{
"key": { "day": "2026-04-11", "eventName": "subscribe_success" },
"count": 38,
"uniqueUsers": 38,
"value": 380.00
},
{
"key": { "day": "2026-04-12", "eventName": "purchase_success" },
"count": 201,
"uniqueUsers": 185,
"value": 3487.20
}
],
"truncated": false
}Errors
| Status | Code | When |
|---|---|---|
| 422 | VALIDATION | Missing or malformed since/until, unknown groupBy dimension, window > 92 days. |
| 401 | UNAUTHENTICATED | Missing or invalid key. |
| 403 | FORBIDDEN_SCOPE | Key lacks events:read. |
| 404 | NOT_FOUND | Project does not exist. |
| 429 | RATE_LIMITED | Read budget exhausted. |
See also
GET /v1/projects/:projectId/events- raw event streamGET /v1/projects/:projectId/apple-ads-attribution- ASA-attributed installs