# Trillboards Data API

Licensable audience, movement and inventory datasets.

Everything you can call with a **data-licensing key**: aggregate audience and
movement data, lookalike modelling, FEIN signals, semantic inventory search,
and the streaming/usage endpoints that go with them.

All paths are absolute against `https://api.trillboards.com`.

- Interactive reference: https://api.trillboards.com/docs#data
- OpenAPI document: https://api.trillboards.com/docs/openapi/bundled/data.json
- Every operation, machine-readable: https://api.trillboards.com/api/discover?surface=data

## Authentication

- `ApiKeyAuth`: API key in header `X-API-Key`. The same platform API key as `BearerAuth`, sent as a raw header value instead of a Bearer credential. `X-Trillboards-API-Key` is accepted as a legacy alias for this header. Scope semantics are identical.
- `BearerAuth`: HTTP bearer. Platform API key sent as `Authorization: Bearer <key>`. This is the canonical carrier. Scopes listed on an operation are enforced by `middleware/apiKeyAuth.js`; ALL listed scopes must be held. A key holding a namespace wildcard (e.g. `sdk:*`) satisfies any scope in that namespace. An operation listing no scope accepts any valid, unexpired key.

## Operations (11)

### Data API

Licensable third-party datasets: aggregate audience, lookalike modelling, FEIN signals, semantic inventory search, streaming and usage.

#### GET /v1/data/aggregate

Aggregate audience analytics for a time window.

Groups audience metrics by the requested dimension and returns summary statistics. Choose the dimension with `group_by` and the measure with `metric`; each lists its allowed values on the parameter.

- Auth: `BearerAuth` HTTP bearer (`read:historical`) or `ApiKeyAuth` header `X-API-Key` (`read:historical`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiAggregate`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `group_by` | query | `string`: one of `venue_type`, `daypart`, `day_of_week`, `income_estimated_level`, `primary_mood` |  | Dimension to group aggregations by. |
| `metric` | query | `string`: one of `avg_face_count`, `avg_attention`, `income_confidence`, `max_face_count` |  | Metric to aggregate on. |
| `since` | query | `string` |  | Relative time window (e.g. "24h", "7d"). |

Responses:

- `200` Grouped aggregations.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### GET /v1/data/lookalike

Find screens with similar audience profiles.

Returns screens ranked by audience similarity to the source screen. Use this for lookalike targeting expansion.

- Auth: `BearerAuth` HTTP bearer (`read:live`) or `ApiKeyAuth` header `X-API-Key` (`read:live`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiLookalikeScreens`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `screen_id` | query | `string` | yes | Internal screen identifier. |
| `limit` | query | `integer` |  |  |
| `min_similarity` | query | `number` |  |  |

Responses:

- `200` Ranked lookalike matches.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### POST /v1/data/query

Composable query DSL over approved datasets.

FEIN query DSL. Supply a `dataset`, optional `dimensions`, `measures`, `filters`, and `order_by`. Invalid dimensions or measures return `invalid_dimensions` / `invalid_measures` with the allowed set in `help`. `inference_outcomes` returns camera measurements (`inference_source = device`) unless the request filters on `inference_source`. Every `inference_outcomes` row carries `provenance`, and the response states which sources were read.

- Auth: `BearerAuth` HTTP bearer (`read:historical`) or `ApiKeyAuth` header `X-API-Key` (`read:historical`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiQueryDsl`

Request body (`application/json`, required): `DataApi.QueryDslBody`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `dataset` | `string` |  | Dataset name. Defaults to `inference_outcomes`. |
| `dimensions` | array of `string` |  |  |
| `filters` | array of `DataApi.QueryFilter` |  |  |
| `limit` | `integer` |  |  |
| `measures` | array of `string` |  |  |
| `order_by` | array of `DataApi.QueryOrderBy` |  |  |

Responses:

- `200` Rows matching the DSL query.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `410` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### GET /v1/data/screens

List screens visible to the caller.

Paginated list of screens under the caller's API key scope. Returns the current status and venue metadata for each screen.

- Auth: `BearerAuth` HTTP bearer (`read:live`) or `ApiKeyAuth` header `X-API-Key` (`read:live`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiListScreens`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `limit` | query | `integer` |  |  |
| `offset` | query | `integer` |  |  |
| `venue_type` | query | `string` |  | Filter by venue taxonomy type (e.g. bar, restaurant). |
| `country` | query | `string` |  | ISO-3166 alpha-2 country code. |

Responses:

- `200` Matching screens.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### GET /v1/data/screens/{screenId}/audience

Real-time audience snapshot for a screen.

Returns the latest live audience snapshot for the screen. When no snapshot is available the `audience` field is null.

- Auth: `BearerAuth` HTTP bearer (`read:live`) or `ApiKeyAuth` header `X-API-Key` (`read:live`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiScreenAudienceLive`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `screenId` | path | `string` | yes | Internal screen identifier. |

Responses:

- `200` Latest audience sample (possibly null).
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `404` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.
- `503` Canonical Trillboards error envelope.

#### GET /v1/data/screens/{screenId}/history

Historical audience_metrics rows for a screen.

Time-range query over the `audience_metrics` table. Defaults to the 100 most recent windows.

- Auth: `BearerAuth` HTTP bearer (`read:historical`) or `ApiKeyAuth` header `X-API-Key` (`read:historical`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiScreenAudienceHistory`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `screenId` | path | `string` | yes | Internal screen identifier. |
| `since` | query | `string` |  | ISO-8601 start timestamp. |
| `until` | query | `string` |  | ISO-8601 end timestamp. |
| `limit` | query | `integer` |  |  |

Responses:

- `200` Historical audience metrics.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `404` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### GET /v1/data/semantic-search

Similarity search over scene embeddings.

Vector similarity search against recently-ingested audience scene embeddings. Useful for finding screens or moments matching a natural-language prompt.

- Auth: `BearerAuth` HTTP bearer (`read:semantic`) or `ApiKeyAuth` header `X-API-Key` (`read:semantic`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiSemanticSearch`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `q` | query | `string` | yes |  |
| `limit` | query | `integer` |  |  |
| `since` | query | `string` |  | Relative time window (e.g. "24h", "7d"). |
| `min_similarity` | query | `number` |  |  |

Responses:

- `200` Ranked matches.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### GET /v1/data/stats

Platform-wide counters.

Returns active screens, embeddings stats, and recent metrics counts for the authenticated partner.

- Auth: `BearerAuth` HTTP bearer (`read:live`) or `ApiKeyAuth` header `X-API-Key` (`read:live`)
- Agent: agent_safe=true, idempotent=true, cost_tier=metered
- operationId: `dataApiStats`

Responses:

- `200` Platform counters.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### GET /v1/data/stream

Server-Sent Events stream of live audience/observation events.

Opens an SSE connection delivering live audience + observation events. Filter with `observation_family` or `venue_type` query params.

- Auth: `BearerAuth` HTTP bearer (`stream:live`) or `ApiKeyAuth` header `X-API-Key` (`stream:live`)
- Agent: agent_safe=true, idempotent=false, cost_tier=metered
- operationId: `dataApiStream`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `observation_family` | query | `string` |  |  |
| `venue_type` | query | `string` |  |  |

Responses:

- `200` Long-lived text/event-stream response.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `503` Canonical Trillboards error envelope.

#### GET /v1/data/usage

API usage for the authenticated key (billing dashboard).

Returns per-day request counts and billable records over the requested window. Used by the metering/billing dashboard.

- Auth: `BearerAuth` HTTP bearer (`read:live`) or `ApiKeyAuth` header `X-API-Key` (`read:live`)
- Agent: agent_safe=true, idempotent=true, cost_tier=free
- operationId: `dataApiUsage`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `days` | query | `integer` |  |  |

Responses:

- `200` Daily usage rows.
- `400` Canonical Trillboards error envelope.
- `401` Canonical Trillboards error envelope.
- `403` Canonical Trillboards error envelope.
- `429` Canonical Trillboards error envelope.
- `500` Canonical Trillboards error envelope.

#### GET /v1/example/healthcheck

Example healthcheck (Phase 3 pipeline proof)

Proof-of-concept operation wired through the Zod → OpenAPI 3.1 generator. Later migration phases replace this with real Data API operations.

- Auth: none (public)
- Agent: agent_safe=true, idempotent=true, cost_tier=free
- operationId: `exampleHealthcheck`

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `verbose` | query | `string`: one of `true`, `false` |  | When `true`, include diagnostic fields in the response. |

Responses:

- `200` Service is healthy.
- `500` Canonical Trillboards error envelope.
