Documentation Index
Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
Use this file to discover all available pages before exploring further.
GET /api/v1/interaction-summaries reads rows from the InteractionSummary table — the materialized aggregate that powers contact-policy enforcement, behavioral-metric values, and frequency-cap evaluation. The endpoint is intended for verification, debugging, and integration tests; production read paths use the cached helpers in lib/interaction-summary directly.
What it does
Each row inInteractionSummary aggregates raw InteractionHistory rows for one (customerId, offerId | creativeId | channelId, periodType, periodKey) tuple. The route at src/app/api/v1/interaction-summaries/route.ts:22-77 accepts query filters and returns the matching rows with the count fields (impressions, positive, negative, neutral, converts, totalValue) and last-contact metadata. customerId is required — there is no all-customers list mode.
For the related materialized-aggregate writer and decay/retention rules, see Interaction Summary.
Quick start
Read all summaries for a customer across every period type:How it works
Authentication and roles
requireRole(request, "admin", "editor", "viewer") runs first (route.ts:26). All subsequent reads scope by tenantId from requireTenant. Cross-tenant reads are not possible.
Filter composition
The handler composes awhere clause from query parameters at route.ts:35-44. tenantId and customerId are always present. Optional periodType, offerId, and channelId filters are AND-ed onto the base clause when supplied. The query orders results by (periodType ASC, periodKey DESC) so the most recent period in each type appears first.
Pagination
A single integerlimit clamps results to 200 maximum (route.ts:46). Cursor pagination is not supported — for large result sets, narrow the query with periodType or offerId filters.
Reference
Query Parameters
Customer identifier. Missing this parameter returns
400 customerId is required (route.ts:31-33).One of
daily, weekly, monthly, alltime. When omitted, all period types are returned.Filter to summaries for one offer.
Filter to summaries for one channel.
Maximum rows returned. Clamped to
[1, 200] (route.ts:46).Response
Returned atroute.ts:54-73.
Matching summary rows, ordered by
(periodType ASC, periodKey DESC).Length of
data after the limit was applied. Not the total matching count — there is no separate count query.data[] per-item shape
Built at route.ts:55-71.
daily, weekly, monthly, or alltime.Period bucket identifier. For
daily, YYYY-MM-DD. For weekly, YYYY-Www. For monthly, YYYY-MM. For alltime, the literal "alltime".Present when the summary is per-offer. Null on aggregate-by-channel rows.
Count of impression-class outcomes in this period.
Count of outcomes whose
OutcomeType.classification is "positive".Count of outcomes whose classification is
"negative".Count of outcomes whose classification is
"neutral".Count of conversions specifically (typically a subset of
positive).Sum of
conversionValue across all positive outcomes in this period.ISO timestamp of the most recent interaction in this period.
OutcomeType.key of the most recent interaction."inbound" or "outbound" — the direction of the most recent interaction.Status codes
| Code | When | Source |
|---|---|---|
| 200 | Returns matching rows (possibly empty) | route.ts:54 |
| 400 | Missing customerId query parameter | route.ts:31-33 |
| 401 | Caller is not authenticated | requireRole |
| 403 | Caller is not viewer, editor, or admin | route.ts:26 |
| 500 | Unexpected error | route.ts:75 |
Required headers
| Header | Required | Read at | Purpose |
|---|---|---|---|
X-API-Key | Yes (one of the two) | tenant.ts:97 | API key (krn_…) |
X-Tenant-Id | Yes (one of the two) | tenant.ts:113 | Direct tenant id |
Honest limits
- The
totalfield counts rows in the current response, not total matching rows. Callers needing a true count must run a separateCOUNT(*)query against the underlying table. - No cursor pagination. With
limitcapped at 200, a customer with > 200 daily rows must narrow the query (e.g., addperiodType=monthlyorofferId=...) to read the rest. - The
400and500envelopes use the legacy{ title, detail }shape (route.ts:32) rather than the standardapiErrorenvelope fromlib/api-error.ts. Callers parsing errors should accept both shapes.
Related
- Interaction Summary — the materialized-aggregate writer + decay/retention helpers.
- Interaction History — the raw event-by-event read surface.
- Contact Policies — frequency-cap and suppression rules that consume these summaries.
- Behavioral Metrics — derived metrics that aggregate from this table.