Batch & Aggregate
When you need to look up many contacts at once, or roll events up by some dimension, paginating the list endpoints is wasteful. Use the batch and aggregate endpoints instead — both perform the work server-side and return a single response.
Batch Get Details
Section titled “Batch Get Details”POST /v1/batch/detailsRequired scope: contacts:read (works for both contacts and companies).
Fetch up to 25 contacts or companies by ID in one request.
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
entity_type | string | yes | contacts or companies. |
ids | string[] | yes | Array of 1–25 IDs. |
Example
Section titled “Example”curl -X POST https://api.pathbound.ai/v1/batch/details \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entity_type": "contacts", "ids": ["ct_abc", "ct_def", "ct_ghi"] }'Response — 200 OK
Section titled “Response — 200 OK”{ "status": "success", "contacts": [ /* up to 25 contact objects */ ]}IDs that don’t exist (or belong to a different tenant) are silently dropped from the response.
Batch Get Activity
Section titled “Batch Get Activity”POST /v1/batch/activityRequired scope: contacts:read.
Fetch recent events for up to 25 contacts in one request — without one busy contact starving the others. Each contact gets up to events_limit events independently.
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
contact_ids | string[] | yes | Array of 1–25 contact IDs. |
events_limit | number | no | Max events per contact (1–20, default 5). |
date_after | string | no | ISO 8601 lower bound on timestamp. |
date_before | string | no | ISO 8601 upper bound on timestamp. |
Response — 200 OK
Section titled “Response — 200 OK”{ "status": "success", "contact_count": 3, "activity": { "ct_abc": { "events": [ { "id": "evt_1", "event": "page_view", "url": "https://example.com/pricing", "timestamp": "...", "title": "Pricing" } ], "total_events": 18 }, "ct_def": { "events": [], "total_events": 0 }, "ct_ghi": { "events": [ /* … */ ], "total_events": 4 } }}Empty arrays are returned for contacts with no events in the window.
Aggregate
Section titled “Aggregate”POST /v1/aggregateRequired scope: depends on entity — contacts:read, companies:read, or events:read.
Group-by aggregation across contacts, companies, or events, with optional filters and metrics. This is the engine behind dashboard charts and aggregate_data in MCP.
Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
entity | string | yes | contacts, companies, or events. |
group_by | string | yes | Field to group on (e.g. lifecycle_stage, industry, country, event_type, domain, day). |
filters | object | no | Entity-specific filters applied before grouping. |
metric | string | no | count (default), avg, sum, min, max. |
metric_field | string | no | Required for non-count metrics — the field to aggregate. |
limit | number | no | Max buckets returned (1–50, default 25). |
Valid group_by dimensions
Section titled “Valid group_by dimensions”- Contacts:
lifecycle_stage,lead_status,industry,country,state,city,company,job_title. - Companies:
industry,country,state,size_bucket,revenue_bucket. - Events:
event_type,domain,url,url_path,title,text,element_type,element_id,class,contact_id,visitor_id,session_id,company_id,day,week,month,device_type,browser,os,referring_domain,is_bot.
size_bucket and revenue_bucket are derived buckets — 1-10 / 11-50 / 51-200 / etc. for numberofemployees, and <$1M / $1M-$10M / etc. for annualrevenue. day, week, and month are derived from each event’s timestamp. class groups on the full CSS class string, which is noisy (hashed tokens) — for targeting a specific element prefer the class_contains filter with a stable token.
Valid filters
Section titled “Valid filters”- Contacts:
company,industry,lifecycle_stage,lead_status,city,state,country,job_title,created_after,created_before,contact_ids(capped at 100). - Companies:
name,domain,industry,country,state,min_employees,max_employees. - Events:
event_type,event_types,domain,url,url_path,url_contains,text,text_contains,title,title_contains,element_type,element_id,class_contains,contact_id,contact_ids,visitor_id,session_id,referring_domain,device_type,browser,os,is_bot,identified_only,date_after,date_before.
Example — events per day for the last 30 days
Section titled “Example — events per day for the last 30 days”curl -X POST https://api.pathbound.ai/v1/aggregate \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "entity": "events", "group_by": "day", "filters": { "event_type": "page_view", "date_after": "2026-03-30T00:00:00Z" }, "metric": "count", "limit": 30 }'Response — 200 OK
Section titled “Response — 200 OK”{ "status": "success", "entity": "events", "group_by": "day", "metric": "count", "buckets": [ { "key": "2026-04-29", "value": 432 }, { "key": "2026-04-28", "value": 511 } ], "total": 11_900}Event aggregations additionally return distinct_groups — the total number of unique group_by values, not capped by limit. This answers “how many distinct X” in the same call: group_by=visitor_id with filters: { "event_type": "button_click", "text": "Go!" } returns total_matching (how many Go! clicks) alongside distinct_groups (how many distinct visitors clicked it at least once). Use group_by=contact_id to count distinct identified contacts instead of anonymous visitors.