@trillboards/api-client 3.2.30 → 3.2.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-255RYJQ4.mjs → chunk-DI7NS7B6.mjs} +2 -2
- package/dist/{chunk-255RYJQ4.mjs.map → chunk-DI7NS7B6.mjs.map} +1 -1
- package/dist/generated.d.mts +37 -10
- package/dist/generated.d.ts +37 -10
- package/dist/generated.js.map +1 -1
- package/dist/generated.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/generated/index.ts"],"names":[],"mappings":";;;;;;;;AA0+hBO,IAAM,cAAA,GAAiB;AAAA,EAC5B,WAAA,EAAa,GAAA;AAAA,EACb,cAAA,EAAgB,GAAA;AAAA,EAChB,SAAS,CAAC,IAAA,EAAK,YAAA,EAAa,qBAAA,EAAsB,iBAAgB,2BAAA,EAA4B,6BAAA,EAA8B,cAAA,EAAe,wBAAA,EAAyB,8BAA6B,yBAAA,EAA0B,iBAAA,EAAkB,yBAAA,EAA0B,aAAA,EAAc,eAAc,mBAAA,EAAoB,gBAAA,EAAiB,gBAAA,EAAiB,mBAAA,EAAoB,wBAAuB,oBAAA,EAAqB,yBAAA,EAA0B,4BAAA,EAA6B,eAAA,EAAgB,oCAAmC,wBAAA,EAAyB,2BAAA,EAA4B,mBAAA,EAAoB,0BAAA,EAA2B,sCAAqC,6BAAA,EAA8B,2BAAA,EAA4B,mCAAkC,yCAAA,EAA0C,uCAAA,EAAwC,wCAAuC,kDAAA,EAAmD,uCAAA,EAAwC,8CAAA,EAA+C,+CAAA,EAAgD,0CAAyC,uCAAA,EAAwC,0CAAA,EAA2C,0CAAA,EAA2C,4CAAA,EAA6C,yCAAwC,+CAAA,EAAgD,iDAAA,EAAkD,6CAAA,EAA8C,8CAAA,EAA+C,mCAAkC,qCAAA,EAAsC,8CAAA,EAA+C,0CAAyC,yCAAA,EAA0C,0CAAA,EAA2C,6CAA4C,+CAAA,EAAgD,qCAAA,EAAsC,0CAAA,EAA2C,4CAAA,EAA6C,sCAAqC,2CAAA,EAA4C,2CAAA,EAA4C,mDAAA,EAAoD,yDAAA,EAA0D,oCAAmC,6CAAA,EAA8C,2CAAA,EAA4C,wCAAA,EAAyC,oCAAA,EAAqC,oCAAmC,gCAAA,EAAiC,gCAAA,EAAiC,sCAAqC,4CAAA,EAA6C,oCAAA,EAAqC,8CAA6C,uCAAA,EAAwC,+CAAA,EAAgD,2CAAA,EAA4C,qCAAA,EAAsC,6CAA4C,iCAAA,EAAkC,yCAAA,EAA0C,kCAAA,EAAmC,kCAAA,EAAmC,4CAA2C,kCAAA,EAAmC,sCAAA,EAAuC,0CAAA,EAA2C,yCAAA,EAA0C,4CAA2C,kDAAA,EAAmD,kCAAA,EAAmC,wCAAuC,8CAAA,EAA+C,qCAAA,EAAsC,sCAAqC,mCAAA,EAAoC,qCAAA,EAAsC,6CAAA,EAA8C,qCAAA,EAAsC,+CAA8C,wCAAA,EAAyC,oCAAA,EAAqC,sCAAA,EAAuC,4CAAA,EAA6C,wCAAuC,4CAAA,EAA6C,+BAAA,EAAgC,qCAAA,EAAsC,uCAAA,EAAwC,+BAA8B,mCAAA,EAAoC,2CAAA,EAA4C,sEAAqE,sDAAA,EAAuD,wDAAA,EAAyD,oDAAmD,wDAAA,EAAyD,8DAAA,EAA+D,oCAAA,EAAqC,yCAAA,EAA0C,8CAA6C,yDAAA,EAA0D,yDAAA,EAA0D,sDAAA,EAAuD,2DAAA,EAA4D,0DAAyD,qDAAA,EAAsD,oCAAA,EAAqC,8DAAA,EAA+D,mDAAA,EAAoD,yDAAwD,8DAAA,EAA+D,kDAAA,EAAmD,uCAAsC,6CAAA,EAA8C,yCAAA,EAA0C,qCAAoC,yCAAA,EAA0C,gCAAA,EAAiC,sCAAA,EAAuC,wCAAA,EAAyC,mCAAkC,yCAAA,EAA0C,0CAAA,EAA2C,iCAAA,EAAkC,yCAAA,EAA0C,gCAA+B,sCAAA,EAAuC,8CAAA,EAA+C,iCAAA,EAAkC,qCAAA,EAAsC,uCAAsC,kCAAA,EAAmC,0CAAA,EAA2C,4CAA2C,mCAAA,EAAoC,8BAAA,EAA+B,2CAA0C,mCAAA,EAAoC,yCAAA,EAA0C,gCAAA,EAAiC,6BAAA,EAA8B,oCAAmC,0CAAA,EAA2C,eAAA,EAAgB,mBAAA,EAAoB,6BAAA,EAA8B,6BAA4B,sBAAA,EAAuB,0BAAA,EAA2B,qBAAA,EAAsB,sBAAA,EAAuB,kCAAiC,+BAAA,EAAgC,6BAAA,EAA8B,gCAAA,EAAiC,uBAAA,EAAwB,0BAAyB,uBAAA,EAAwB,2BAAA,EAA4B,gBAAA,EAAiB,sBAAA,EAAuB,UAAS,mBAAA,EAAoB,yBAAA,EAA0B,eAAA,EAAgB,sBAAA,EAAuB,2BAA0B,eAAA,EAAgB,2BAAA,EAA4B,cAAA,EAAe,kBAAA,EAAmB,mBAAkB,OAAA,EAAQ,WAAA,EAAY,qBAAoB,YAAA,EAAa,eAAA,EAAgB,iBAAgB,mBAAA,EAAoB,WAAA,EAAY,kBAAA,EAAmB,eAAA,EAAgB,wBAAuB,uBAAA,EAAwB,uBAAA,EAAwB,wBAAA,EAAyB,oBAAA,EAAqB,4BAA2B,kCAAA,EAAmC,4BAAA,EAA6B,yBAAA,EAA0B,0BAAA,EAA2B,6BAA4B,uBAAA,EAAwB,uBAAA,EAAwB,6BAA4B,iCAAA,EAAkC,uBAAA,EAAwB,0BAAyB,qBAAA,EAAsB,mBAAA,EAAoB,iBAAA,EAAkB,yBAAA,EAA0B,uBAAsB,iBAAA,EAAkB,cAAA,EAAe,mBAAA,EAAoB,uBAAA,EAAwB,mBAAkB,aAAA,EAAc,YAAA,EAAa,kBAAA,EAAmB,aAAA,EAAc,6BAA4B,6BAAA,EAA8B,iCAAA,EAAkC,2BAA0B,uBAAA,EAAwB,wBAAA,EAAyB,0BAAyB,yBAAA,EAA0B,2BAAA,EAA4B,mBAAA,EAAoB,wBAAA,EAAyB,8BAA6B,YAAA,EAAa,SAAA,EAAU,0BAAA,EAA2B,yBAAA,EAA0B,wBAAuB,4BAAA,EAA6B,4BAAA,EAA6B,qCAAA,EAAsC,4BAAA,EAA6B,qBAAoB,gCAAA,EAAiC,yBAAA,EAA0B,wBAAuB,qCAAA,EAAsC,2BAAA,EAA4B,iCAAgC,yBAAA,EAA0B,0BAAA,EAA2B,2BAAA,EAA4B,oBAAA,EAAqB,sBAAqB,+BAAA,EAAgC,qBAAA,EAAsB,2BAAA,EAA4B,qBAAA,EAAsB,mCAAkC,sBAAA,EAAuB,4BAAA,EAA6B,aAAA,EAAc,8BAAA,EAA+B,sCAAqC,oBAAA,EAAqB,+BAAA,EAAgC,sBAAqB,wBAAA,EAAyB,2BAAA,EAA4B,gBAAe,kBAAA,EAAmB,iBAAA,EAAkB,qBAAA,EAAsB,gBAAA,EAAiB,oBAAmB,2BAAA,EAA4B,2BAAA,EAA4B,8BAAA,EAA+B,yBAAA,EAA0B,yBAAwB,uBAAA,EAAwB,iBAAA,EAAkB,WAAA,EAAY,QAAA,EAAS,2BAA0B,aAAA,EAAc,0BAAA,EAA2B,iCAAgC,kBAAA,EAAmB,0BAAA,EAA2B,iCAAgC,wBAAA,EAAyB,cAAA,EAAe,oBAAA,EAAqB,uBAAA,EAAwB,gCAA+B,+BAAA,EAAgC,+BAAA,EAAgC,yBAAA,EAA0B,8BAAA,EAA+B,kBAAiB,oBAAA,EAAqB,YAAA,EAAa,aAAA,EAAc,kBAAA,EAAmB,oCAAmC,eAAA,EAAgB,qBAAA,EAAsB,WAAU,iBAAA,EAAkB,cAAA,EAAe,2BAA0B,gBAAgB,CAAA;AAAA,EACviU,UAAA,EAAY,CAAC,oBAAA,EAAqB,oBAAA,EAAqB,2BAA0B,+BAAA,EAAgC,oBAAA,EAAqB,0BAAA,EAA2B,0BAAA,EAA2B,6BAAA,EAA8B,2BAAA,EAA4B,4BAAA,EAA6B,uBAAA,EAAwB,4BAA2B,qBAAA,EAAsB,2BAAA,EAA4B,oCAAA,EAAqC,kBAAA,EAAmB,wBAAA,EAAyB,qBAAA,EAAsB,yBAAA,EAA0B,2BAAA,EAA4B,6BAA4B,qBAAA,EAAsB,0CAAA,EAA2C,4BAAA,EAA6B,8BAAA,EAA+B,0BAAyB,8BAAA,EAA+B,oCAAA,EAAqC,+BAAA,EAAgC,+BAAA,EAAgC,8BAA6B,iCAAA,EAAkC,8BAAA,EAA+B,2BAAA,EAA4B,oCAAA,EAAqC,yBAAA,EAA0B,6BAAA,EAA8B,oCAAA,EAAqC,wBAAA,EAAyB,qBAAoB,yBAAA,EAA0B,mBAAA,EAAoB,0BAAA,EAA2B,gBAAA,EAAiB,sBAAqB,2BAAA,EAA4B,kBAAA,EAAmB,yBAAA,EAA0B,iBAAA,EAAkB,sBAAqB,2BAAA,EAA4B,8BAAA,EAA+B,uBAAA,EAAwB,cAAA,EAAe,eAAA,EAAgB,cAAA,EAAe,gBAAA,EAAiB,cAAA,EAAe,yBAAwB,uBAAA,EAAwB,wBAAA,EAAyB,0BAAA,EAA2B,oBAAA,EAAqB,yBAAwB,gBAAA,EAAiB,cAAA,EAAe,wBAAA,EAAyB,qBAAA,EAAsB,iCAAgC,wBAAA,EAAyB,8BAAA,EAA+B,sBAAA,EAAuB,yBAAA,EAA0B,0BAAA,EAA2B,gCAAA,EAAiC,0BAAA,EAA2B,8BAAA,EAA+B,sBAAqB,eAAA,EAAgB,cAAA,EAAe,uBAAA,EAAwB,oBAAA,EAAqB,iBAAgB,uBAAA,EAAwB,uBAAA,EAAwB,yBAAA,EAA0B,mBAAA,EAAoB,sBAAqB,8BAAA,EAA+B,yBAAA,EAA0B,wBAAA,EAAyB,uBAAA,EAAwB,gBAAA,EAAiB,eAAA,EAAgB,iBAAA,EAAkB,mBAAA,EAAoB,mBAAkB,qBAAA,EAAsB,gCAAA,EAAiC,cAAA,EAAe,sBAAA,EAAuB,gBAAe,sBAAA,EAAuB,oBAAA,EAAqB,oBAAA,EAAqB,iBAAA,EAAkB,uBAAsB,uBAAA,EAAwB,2BAAA,EAA4B,sBAAA,EAAuB,uBAAA,EAAwB,uBAAA,EAAwB,oBAAA,EAAqB,uBAAA,EAAwB,sBAAA,EAAuB,wBAAuB,wBAAA,EAAyB,kBAAA,EAAmB,2BAAA,EAA4B,iBAAA,EAAkB,wBAAuB,kBAAA,EAAmB,cAAA,EAAe,2BAAA,EAA4B,wBAAA,EAAyB,mBAAkB,wBAAA,EAAyB,uBAAA,EAAwB,qBAAA,EAAsB,yBAAA,EAA0B,wBAAA,EAAyB,oBAAA,EAAqB,kBAAA,EAAmB,kCAAA,EAAmC,iCAAgC,gCAAA,EAAiC,kCAAA,EAAmC,gCAAA,EAAiC,gCAAA,EAAiC,gCAA+B,4BAAA,EAA6B,gCAAA,EAAiC,kCAAA,EAAmC,uBAAA,EAAwB,sBAAqB,cAAA,EAAe,2BAAA,EAA4B,sBAAA,EAAuB,eAAA,EAAgB,yBAAA,EAA0B,uBAAA,EAAwB,gBAAA,EAAiB,cAAA,EAAe,aAAY,cAAA,EAAe,iBAAA,EAAkB,kBAAA,EAAmB,oBAAA,EAAqB,aAAY,kCAAA,EAAmC,gCAAA,EAAiC,yBAAA,EAA0B,yBAAA,EAA0B,gCAA+B,kBAAA,EAAmB,aAAA,EAAc,kBAAA,EAAmB,sBAAA,EAAuB,8BAAA,EAA+B,kBAAA,EAAmB,oBAAA,EAAqB,aAAA,EAAc,wBAAuB,eAAA,EAAgB,iBAAA,EAAkB,yBAAA,EAA0B,mBAAA,EAAoB,mBAAkB,mBAAA,EAAoB,kBAAA,EAAmB,kBAAA,EAAmB,qBAAA,EAAsB,uBAAsB,sBAAA,EAAuB,wBAAA,EAAyB,gBAAA,EAAiB,sBAAA,EAAuB,mBAAA,EAAoB,kBAAA,EAAmB,2BAAA,EAA4B,+BAAA,EAAgC,oBAAmB,oBAAA,EAAqB,qBAAA,EAAsB,kBAAA,EAAmB,aAAA,EAAc,mBAAkB,mBAAA,EAAoB,yBAAA,EAA0B,YAAA,EAAa,oCAAA,EAAqC,cAAa,iBAAA,EAAkB,sBAAA,EAAuB,cAAA,EAAe,qBAAA,EAAsB,kBAAA,EAAmB,kBAAA,EAAmB,mBAAA,EAAoB,mBAAA,EAAoB,kBAAiB,mBAAA,EAAoB,yBAAA,EAA0B,0BAAA,EAA2B,6BAAA,EAA8B,kCAAiC,0BAAA,EAA2B,wBAAA,EAAyB,uBAAA,EAAwB,6BAAA,EAA8B,kCAAiC,2BAAA,EAA4B,+BAAA,EAAgC,4BAAA,EAA6B,iCAAA,EAAkC,sBAAA,EAAuB,oBAAA,EAAqB,4BAAA,EAA6B,8BAAA,EAA+B,gCAA+B,yBAAA,EAA0B,qBAAA,EAAsB,oBAAA,EAAqB,oBAAA,EAAqB,yBAAwB,yBAAA,EAA0B,0BAAA,EAA2B,2BAAA,EAA4B,4BAAA,EAA6B,oCAAmC,8BAAA,EAA+B,kCAAA,EAAmC,4BAAA,EAA6B,4BAAA,EAA6B,uBAAA,EAAwB,oBAAA,EAAqB,sBAAA,EAAuB,uBAAA,EAAwB,0BAAyB,2BAAA,EAA4B,8BAAA,EAA+B,yBAAA,EAA0B,2BAAA,EAA4B,8BAA6B,0BAAA,EAA2B,0BAAA,EAA2B,uBAAA,EAAwB,8BAAA,EAA+B,8BAA6B,0BAAA,EAA2B,6BAAA,EAA8B,0BAAA,EAA2B,2BAAA,EAA4B,2BAAA,EAA4B,wBAAA,EAAyB,2BAAA,EAA4B,4BAAA,EAA6B,sBAAqB,yBAAA,EAA0B,qBAAA,EAAsB,wBAAA,EAAyB,wBAAA,EAAyB,uBAAsB,iBAAA,EAAkB,kBAAA,EAAmB,kBAAA,EAAmB,sBAAA,EAAuB,oBAAmB,kBAAA,EAAmB,sBAAA,EAAuB,sBAAA,EAAuB,qBAAA,EAAsB,iBAAA,EAAkB,mBAAA,EAAoB,oBAAA,EAAqB,eAAA,EAAgB,mBAAkB,oBAAA,EAAqB,iBAAA,EAAkB,sBAAA,EAAuB,cAAA,EAAe,iBAAgB,eAAA,EAAgB,eAAA,EAAgB,sBAAA,EAAuB,aAAA,EAAc,oBAAmB,oBAAoB;AACr+N","file":"chunk-255RYJQ4.mjs","sourcesContent":["/* eslint-disable */\n/**\n * AUTO-GENERATED. DO NOT EDIT.\n *\n * Generated from: merged partner API, bundled Data API and mounted MCP Zod schemas\n * Generator: trillboards-api-client/scripts/generate.js\n *\n * Re-emit via `npm run generate`.\n */\n\n// OpenAPI version: 3.0.3\n// API title: Trillboards Partner API\n// API version: 1.2.0\n// Schema count: 329\n// Operation count: 298\n\n// ─── Component schemas ───────────────────────────────────────────────────\n\nexport type Ad = {\n /** Placement/allocation ID used for delivery accounting, make-goods, and pacing. */\n allocation_id?: string;\n /** Duration in seconds */\n duration?: number;\n /** Advertisement ID */\n id?: string;\n /** Server-generated impression ID that must be echoed when reporting proof-of-play. */\n impression_id?: string;\n /** **Deprecated alias of `tracking.impression_url`.** These two fields are the same string, byte for byte, produced from one value server-side — they are not two different hooks and firing both records the same call twice. Read `tracking.impression_url`; this flat field is retained only for clients that predate the `tracking` object and will be removed once they are off it. */\n impression_url?: string;\n /** The advertiser's own creative label from the booking record (its `title`, falling back to its `name`), carried through for your logs and QA. Omitted when the booking has neither. It is an internal label, not reviewed display copy, so do not surface it to viewers. */\n title?: string;\n /** Structured proof-of-play URLs for clients that prefer named tracking hooks over legacy flat fields. **Fire exactly one of `impression_url` / `complete_url` per play.** They resolve to the same endpoint and differ only by the `completed` query parameter, which that endpoint does not act on (see `GET /impression`) — calling both records the play twice. */\n tracking?: {\n /** Call when the ad completes playback/display dwell. This is `impression_url` plus `&completed=true`; the flag is inert server-side, so this is a delivery-accounting call, not proof of play. */\n complete_url?: string;\n /** Call when the ad is presented. Identical to the top-level `impression_url`. */\n impression_url?: string;\n /** **Server-signed proof of play. Present only on owner-billable direct bookings; absent on self-promo, house/QR, demo and fully-delivered placements.** When present, fire it VERBATIM — including the `sig`, `request_id` and `impid` parameters — once the ad has finished playing. Do not rewrite, re-sign, re-order, or drop any query parameter: the signature covers the values and any edit invalidates it. This is the only completion signal on the `data.ads` rail that settles; `complete_url` above is delivery accounting and is not billing-grade. Replays of the same play are collapsed on the SIGNED `request_id`, which carries this serve's `impression_id`. Because it is covered by `sig`, a replay that alters it to claim a fresh dedup key fails verification and records nothing — one served play can settle at most once. Firing it in addition to `complete_url` is correct and does not double-count — they land in different stores. */\n owned_direct_complete_url?: string;\n };\n /** `video` or `image`. On the partner/IMA rail an image instant-ad creative is substituted with its pre-rendered MP4 and reports `video`; seeing `image` here means that MP4 was not ready on this poll, so a video-only player should skip the entry and pick it up on a later poll rather than treat it as a still. */\n type?: \"video\" | \"image\";\n /** Media URL (CDN) */\n url?: string;\n};\n\nexport type AdSettings = {\n /** Partner-configured ad rotation cadence in seconds, served from the screen display setting `ad_interval_seconds` when present and legacy display preferences only as fallback. */\n ad_interval?: number;\n content_fit?: ContentFitSettings;\n /** Seconds to display image ads; independent from ad rotation cadence. */\n image_duration?: number;\n /** An ADVISORY delivery cap the client SDK is expected to honour — the server reports it and never enforces it anywhere. Sourced from the partner's `network_config.ad_delivery.max_ads_per_hour` (an integer 1-120), falling back to `sdk_config.max_ads_per_hour`; when neither is set the key is ABSENT from the response rather than null or defaulted. */\n max_ads_per_hour?: number;\n /** Label for the tap-to-continue overlay the partner Lite SDK draws over an ad. Read from `sdk_config.overlay_button_text` only — there is no runtime-config path for it — and the key is ABSENT when unset, in which case the SDK falls back to `TAP TO CONTINUE` client-side. */\n overlay_button_text?: string;\n /** Whether ad audio plays. It reads the typed `sound_enabled` column when that is non-null, otherwise `display_preferences.sound_enabled !== false` — so an unconfigured screen reports `true` and only an explicit `false` mutes. */\n sound_enabled?: boolean;\n};\n\n/**\n * Stateful resettable operating-system advertising identity. Send\n * `available` only with the current OS ID; send `limited`,\n * `consent_denied`, `unavailable`, `unsupported`, or `error` to clear a\n * previously observed identifier. UID2 and hashed email are audience\n * tokens, not OS advertising IDs, and do not belong in this envelope.\n *\n */\nexport type AdvertisingIdentity = {\n /** DISCARDED whenever `status` is `available` — the server stores `null` in that case, deliberately, because a resettable OS advertising ID stays valid until the OS rotates it and a collector's refresh or cache cadence is not identity expiry. It is only persisted for the non-`available` states. */\n expires_at?: string | null;\n /** Present only when status is `available`. */\n id?: string | null;\n /** Resettable OS identifier type. GAID maps to OpenRTB `aaid`. */\n id_type?: \"gaid\" | \"aaid\" | \"afai\" | \"rida\" | \"tifa\" | \"idfa\" | null;\n /** Must be false for `available` and true for `limited`. */\n limit_ad_tracking: boolean | null;\n /** When the device read the identifier from the OS. It is REQUIRED and strictly parsed — an unparseable or missing timestamp causes the entire identity envelope to be dropped without an error response, which is the most common silent rejection on this endpoint. */\n observed_at: string;\n /** Which platform API produced the identifier. `host_supplied` is the value the SERVER itself stamps when it synthesises an envelope from the legacy flat `advertisingId`/`limitAdTracking` fields or from a registration hardware tuple, so seeing it in a read does not mean the device claimed it. An unrecognised source rejects the whole envelope. */\n source: \"google_play_services\" | \"amazon_fire_os\" | \"roku_os\" | \"samsung_tizen\" | \"lg_webos\" | \"apple_platform\" | \"host_supplied\";\n /** Version of the platform component or SDK that read the identifier (e.g. the Play Services version), up to 128 characters, kept for provenance only. Trimmed, with a whitespace-only value stored as `null`. */\n source_version?: string | null;\n /** The state machine, not a label. `available` is accepted only with a valid `id`, an `id_type` and `limit_ad_tracking: false` — any other combination makes the server DISCARD the whole envelope behind a 200 and keep the previously stored identity. Every other value CLEARS a stored identifier, and `limited` additionally forces `limit_ad_tracking` to true. */\n status: \"available\" | \"limited\" | \"consent_denied\" | \"unavailable\" | \"unsupported\" | \"error\";\n};\n\n/**\n * Partner analytics summary (`@trillboards/api-client` `AnalyticsData`).\n *\n */\nexport type AnalyticsData = {\n /** **Never emitted** by the analytics endpoint, which returns impression counts and cached revenue only. */\n average_cpm: number;\n /** Optional per-screen breakdown. */\n by_screen?: Array<{\n earnings: number;\n impressions: number;\n name: string;\n screen_id: string;\n }>;\n /** Fraction of ad opportunities filled, 0..1. */\n fill_rate: number;\n /** The window this summary covers (e.g. day, week, month). */\n period: string;\n /** **Not emitted under this name.** The analytics endpoint returns `data.partner.active_devices`, derived from the screen's `online_status` via the partner device-status mapping, plus a `devices_by_status` breakdown. */\n screens_active: number;\n /** **Not emitted under this name.** The analytics endpoint returns `data.partner.total_devices`, a count of registered DEVICES rather than of screens — a device with no screen row still counts. */\n screens_total: number;\n /** **Not emitted.** `GET /v1/partner/analytics` returns `data.partner.total_revenue_cents` (integer US cents, read from the `partners.stats` cache) instead; that endpoint has no dollar-denominated earnings field. */\n total_earnings: number;\n /** Declared for the SDK type; `GET /v1/partner/analytics` does not return this shape. It returns `data.partner.total_impressions` — an ALL-TIME deduped `completed_impressions` count that ignores the `start_date`/`end_date` query parameters (those bound only `impressions_by_day`). */\n total_impressions: number;\n};\n\nexport type AudienceAnalyticsResponse = {\n /** `overview.total_impressions` counts `event_tracking` `start`/`impression` events — NOT the billable `completed_impressions` the dashboard and earnings endpoints use — and `active_screens` counts screens with ANY event in the window rather than screens that are online. **`trends.impressions_trend` and `trends.audience_trend` are hardcoded to the literal `stable`**, so the `increasing`/`decreasing` values are unreachable. `period` echoes `?period=` (`24h`/`7d`/`30d`; anything else silently means 7 days). */\n data?: {\n audience?: {\n avg_attention?: number;\n avg_face_count?: number;\n screens_with_data?: number;\n };\n overview?: {\n active_screens?: number;\n avg_impressions_per_screen?: number;\n total_impressions?: number;\n total_screens?: number;\n };\n period?: string;\n timestamp?: string;\n trends?: {\n audience_trend?: \"increasing\" | \"stable\" | \"decreasing\";\n impressions_trend?: \"increasing\" | \"stable\" | \"decreasing\";\n };\n };\n /** Per-request identifier (`req_` plus 32 hex), also returned on the `X-Request-Id` response header. */\n request_id?: string;\n /** Always `true` on a 2xx; failures return the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status. */\n success?: boolean;\n};\n\n/**\n * Backend-derived predictive attention signal + buyer-grade attentive-seconds. 1:1 with audience_metrics. Never null by contract; placeholder on row 1.\n */\nexport type AudienceAttentionPrediction = {\n /** attentive_face_count SMALLINT: distinct viewers meeting the >=1s threshold; the buyer-side CPMA denominator. NEVER NULL. */\n attentive_face_count: number;\n /** attentive_seconds_observed = SUM(per_face[].gaze_seconds >= 1.0), OpenOOH 2024 4.2. NEVER NULL by DDL, so 0.000 means 'no viewer met threshold' ONLY when per_face_observations[] was present. NUMERIC(6,3). */\n attentive_seconds_observed: number;\n /** attentive_seconds_predicted_15s: expected next-15s attentive seconds from per-screen history x attention-weight; bootstrap = linear extrapolation. No global tau. NUMERIC(6,3). */\n attentive_seconds_predicted_15s: number;\n next_state_abs_error?: number | null;\n next_state_attention_forecast?: number | null;\n next_state_attention_realized?: number | null;\n next_state_confidence?: number | null;\n next_state_forecast_at?: string | null;\n next_state_graded_at?: string | null;\n next_state_horizon_minutes?: number | null;\n next_state_method?: string | null;\n next_state_persist_abs_error?: number | null;\n next_state_sample_size?: number | null;\n next_state_xscreen_abs_error?: number | null;\n next_state_xscreen_method?: string | null;\n next_state_xscreen_sample_size?: number | null;\n next_state_xsv_abs_error?: number | null;\n next_state_xsv_sample_size?: number | null;\n /** predicted_attention_next_30s enum {high,medium,low,none}. 'none' is below 'low'; fires when rolling history converges to zero or on a trend down from 'low'. */\n predicted_attention_next_30s: \"high\" | \"medium\" | \"low\" | \"none\";\n /** predicted_disengagement_imminent needs elevated dwell AND a falling trend, so it is unreachable whenever the history vector is empty. A 0% fire rate is a HISTORY-PLUMBING alarm, not a quiet fleet. */\n predicted_disengagement_imminent: boolean;\n prediction_evidence: string;\n};\n\n/**\n * Live/aggregate audience data for a screen\n * (`@trillboards/api-client` `AudienceData`).\n *\n */\nexport type AudienceData = {\n /** Count of attentive viewers in the sample. */\n attention_count: number;\n /** Optional demographic breakdown. */\n demographics?: Record<string, unknown>;\n /** Average dwell time for the sample. */\n dwell_time_avg: number;\n /** Declared for the SDK type. `GET /v1/partner/audience/live/{screenId}` puts `screen_id` at the TOP level of an `object: audience_live` envelope alongside `status` and `audience`, not inside this shape. */\n screen_id: string;\n /** **Not emitted under this name.** The live audience endpoint returns `last_updated` — the time of the newest underlying observation, nullable — and returns `audience: null` with `status: offline` when the screen has no live data at all. */\n timestamp: string;\n};\n\nexport type AudienceExportResponse = {\n /** One entry per RESOLVED screen (max 50 ids per call), emitted even for screens with no audience data — those get a zeroed `audience` block rather than being omitted. `impressions` counts `event_tracking` `start`/`impression` events, which are NOT the billable `completed_impressions` the dashboard and earnings endpoints use, and every row repeats the same request-level `period`. */\n data?: Array<{\n audience?: {\n avg_attention?: number;\n avg_face_count?: number;\n demographics?: Record<string, unknown>;\n income_profile?: Record<string, unknown>;\n lifestyle_segments?: Array<string>;\n };\n country?: string;\n impressions?: number;\n location?: string;\n period?: {\n end?: string;\n start?: string;\n };\n screen_id?: string;\n screen_name?: string;\n }>;\n /** Per-request identifier (`req_` plus 32 hex), also on the `X-Request-Id` header. Absent from the `format=csv` variant, which returns a bare five-column body and no envelope. */\n request_id?: string;\n /** Always `true` — a failure returns the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status, so this field carries nothing the status code does not. */\n success?: boolean;\n /** `total_screens` counts the screens that RESOLVED, so it can be smaller than the id list you sent. `total_impressions` sums the same non-billable `start`/`impression` event counts. `aggregation` echoes the query parameter unvalidated (default `daily`) and does not change the shape of the response. */\n summary?: {\n aggregation?: string;\n period?: Record<string, unknown>;\n total_impressions?: number;\n total_screens?: number;\n };\n};\n\n/**\n * Per-device cross-day loyalty feature row emitted by the\n * `audience_loyalty_features` dataset. Keyed by a partner-scoped\n * pseudonymous ID — the same physical device yields a different ID\n * for each partner because the HMAC salt is partner-specific: one salt\n * per partner, whichever API key calls, so the ID is the same ref the\n * partner's device-level files carry.\n *\n */\nexport type AudienceLoyaltyFeaturesRow = {\n /** How the cross-day device key was formed. `primary_signal_source` is picked by a fixed precedence (`fixed_mac` > `mdns_vendor_model` > `wifi_bssid` > `ble_continuity` > `ble_mac_stable`) and `match_confidence` is a direct relabelling of it (first three `high`, `ble_continuity` `medium`, `ble_mac_stable` `low`) — not a computed probability. `wifi_bssid` marks a device observed over WiFi, whose key is its BSSID. */\n _match_disclosure?: {\n match_confidence?: \"high\" | \"medium\" | \"low\";\n primary_signal_source?: \"ble_continuity\" | \"ble_mac_stable\" | \"mdns_vendor_model\" | \"fixed_mac\" | \"wifi_bssid\";\n };\n /** NOT a per-device inference: it is the aggregate audience profile of the first screen in the device's visited screen set that has one, copied onto every device that touched that screen. All six sub-fields are `null` when no visited screen carries a profile. */\n demographic_inference?: {\n age_bracket?: string;\n attention_score_avg?: number;\n audience_attire_archetype?: string;\n audience_group_composition?: string;\n audience_intent_stage?: string;\n gender_distribution?: Record<string, unknown>;\n };\n /** Partner-scoped HMAC of cross-day device key (16 hex chars + tb_ prefix). Different partners get different IDs for the same physical device — preventing collusion. */\n device_id_pseudonymous: string;\n /** Distinct calendar days (ClickHouse server timezone) on which this device key was observed. This is the quantity behind the published `returning_visitor` qualification of two or more days. */\n distinct_days_in_window: number;\n /** Distinct SCREENS, not venues — a site with several screens contributes more than one, so this over-counts locations for any multi-screen venue. */\n distinct_venues_in_window?: number;\n /** Days since this device was first observed at any of the partner-scoped screens. */\n first_seen_relative_days: number;\n /** Whole days between now and the newest observation in the window, floored at 0 — `0` means seen today. An unparseable source timestamp also yields `0`, so it cannot be told apart from a same-day sighting. */\n last_seen_relative_days: number;\n /** Tier derived from the Bluetooth-SIG company identifier in the device's advertisement, not from any model string. Only five vendors carry an explicit tier (Apple / Samsung / Google `premium`, Microsoft `mainstream`, Sonos `audio_iot`); every other registered vendor, and every unresolvable id, falls to `other`. */\n manufacturer_class: \"premium\" | \"mainstream\" | \"audio_iot\" | \"other\";\n /** Vendor name resolved from the same Bluetooth-SIG company id. An id that resolves to no vendor returns the literal `Other tracked devices` rather than `null`, so an unknown device is not distinguishable by a null check. */\n manufacturer_label?: string;\n /** Raw cross-day-stable identifiers when available (NULL for randomized phone MACs without Continuity). */\n raw_identifiers?: {\n ble_mac?: string | null;\n /** First 3 bytes of BLE MAC (IEEE OUI vendor lookup). */\n ble_mac_oui?: string | null;\n ble_mac_oui_vendor?: string | null;\n manufacturer_company_id?: number | null;\n mdns_hostname?: string | null;\n wifi_bssid?: string | null;\n };\n /** Same arbitrary-row behaviour as `top_hour_of_day`, and the value comes from ClickHouse `toDayOfWeek` — **1 = Monday through 7 = Sunday**, which does not fit the declared 0..6 range. */\n top_day_of_week?: number;\n /** Produced by `argMax(toHour(observed_at), 1)`; because the ordering expression is the constant `1` every row ties, so this is the hour of an ARBITRARY observation in the window, not the modal hour. Do not read a peak out of it. */\n top_hour_of_day?: number;\n /** List of venue_category labels (Bar, Restaurant, etc.) the device was observed at. */\n venue_archetypes?: Array<string>;\n /** Count of raw radio OBSERVATIONS, not of visits — one dwelling device emits many rows per minute. */\n visit_count_in_window: number;\n};\n\nexport type AudienceMetricsResponse = {\n /** **Currently always the zero/`unknown` fallback.** The handler reads `metrics.live`, `metrics.aggregated` and `metrics.history`, but the underlying `getScreenMetrics` takes a time-range STRING and returns a FLAT object carrying none of those keys — so all three are undefined on every call and the hardcoded zeros are served. `period` echoes `?period=` (default `1h`) and is likewise not honoured downstream; `timestamp` is the response time, not a measurement time. */\n data?: {\n aggregated?: {\n avgAttention?: number;\n avgDwellMs?: number;\n avgFaceCount?: number;\n groupComposition?: Record<string, unknown>;\n incomeProfile?: {\n high?: number;\n low?: number;\n medium?: number;\n premium?: number;\n };\n };\n history?: Array<Record<string, unknown>>;\n live?: {\n /** Average attention score (0-1) */\n avgAttention?: number;\n /** Average faces detected */\n avgFaceCount?: number;\n incomeLevel?: \"unknown\" | \"low\" | \"medium\" | \"high\" | \"premium\";\n /** Maximum faces detected in period */\n maxFaces?: number;\n mood?: string;\n screenEngagement?: string;\n };\n period?: string;\n screen_id?: string;\n screen_name?: string;\n timestamp?: string;\n };\n /** Per-request identifier (`req_` plus 32 hex), also returned on the `X-Request-Id` response header. */\n request_id?: string;\n /** Always `true` on a 2xx; failures return the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status. */\n success?: boolean;\n};\n\nexport type AudienceSegment = {\n /** Creation time of the authoritative PG row; the 201 create response falls back to the server clock only if the insert returned no row. */\n created_at?: string;\n /** Free text, trimmed on write. Defaults to the empty string, never `null`, when omitted at create. */\n description?: string;\n /** 24-character hex ObjectId minted by the API at create time and stored as the PG row's `mongo_id` — not the table's integer primary key. This is the value the get / patch / delete / match routes take as `:segmentId`. */\n id?: string;\n /** Stored and echoed but **nothing reads it** — `POST /segments/{id}/match` runs a segment regardless, and the list endpoint does not filter on it. Treat it as a caller-owned label, not a gate. */\n is_active?: boolean;\n /** When `POST /segments/{id}/match` last ran. The update is fire-and-forget after the response is sent, so a failed write leaves this stale or `null` with no error surfaced to the caller. */\n last_matched_at?: string | null;\n /** Number of SCREENS returned by the most recent `POST /segments/{id}/match`, capped by that call's `limit` (default 50, max 100) — so it is the size of the last result page, not the segment's reach. `null` until the first match call. */\n last_matched_count?: number;\n /** Trimmed on write, max 100 characters, and unique per partner — a repeat name is rejected `409 duplicate_segment_name` rather than upserting the existing segment. */\n name?: string;\n /** Always the literal `audience_segment`. `GET /audience/segments` wraps these in an `object: list` envelope, so the discriminator appears on both the envelope and each element. */\n object?: string;\n /** Per-request identifier, `req_` plus 32 hex characters, minted server-side and also returned on the `X-Request-Id` response header. A client-supplied `X-Request-Id` is NOT adopted — it is echoed back on `X-Client-Request-Id` instead. */\n request_id?: string;\n /** Predicates combined with AND, at most 20 per segment. `field` is restricted to a 17-name allowlist (`income_level`, `lifestyle_segment`, `attention_score`, `face_count`, `dwell_time_ms`, `crowd_density`, `ad_receptivity`, `emotional_engagement`, `purchase_intent`, `occupancy`, `noise_level`, `venue_type`, `country`, `state`, `city`, `hour_of_day`, `day_of_week`) and `operator` to `eq`/`neq`/`gt`/`gte`/`lt`/`lte`/`in`/`nin`/`contains`; any other key on a rule object is stripped on write. */\n rules?: Array<{\n field?: string;\n operator?: string;\n value?: unknown;\n }>;\n /** Last write to the segment, INCLUDING the fire-and-forget match-stats update — so running a match bumps this even though name, rules and `is_active` did not change. Omitted entirely from the 201 create response. */\n updated_at?: string;\n};\n\n/**\n * Buyer-grade social amplification signal (5 typed columns). Cloud Vertex Gemini producer. 1 row per audience observation when cascade is observable.\n */\nexport type AudienceSocialAttention = {\n amplification_evidence: string;\n cascade_depth: number;\n data_projection_version: number;\n data_projection_xid: string;\n /** All 5 columns NOT NULL except primary_attention_anchor_face_index (only legit NULL: no anchor or solo scene). */\n primary_attention_anchor_face_index?: number | null;\n /** NUMERIC(4,3). */\n social_amplification_factor: number;\n /** viral_attention_score is the headline number Viant/T-Vision license. Composite of social_amplification_factor × cascade_depth × emotional engagement. NUMERIC(4,3). */\n viral_attention_score: number;\n};\n\nexport type BatchResult = {\n /** Number that failed */\n failed_count?: number;\n /** Not emitted. The live response names this array `errors`, and each entry carries `screen_id`, a human `error` string, and an additional machine `code`: `screen_not_found` for an id that is not 24-hex or that your partner account does not own, `write_failed` for a database failure. Read `errors`. */\n failed_screens?: Array<{\n error?: string;\n screen_id?: string;\n }>;\n /** Constant discriminator `batch_result`, shared verbatim by every partner batch endpoint (content preferences, display settings, programmatic settings) — it does not identify which one you called. */\n object?: string;\n /** Server-minted per HTTP request in the form `req_<32 hex>`, also returned in the `X-Request-Id` response header; omitted if no request id was assigned to the call. Quote it when reporting a partial batch failure — it is the only handle that ties your call to the per-screen error rows. */\n request_id?: string;\n /** Number of screens requested to update */\n total_requested?: number;\n /** Number successfully updated */\n updated_count?: number;\n /** IDs of successfully updated screens */\n updated_screens?: Array<string>;\n};\n\n/**\n * Partner billing snapshot — plan, credits, and month-to-date usage\n * (`@trillboards/api-client` `BillingInfo`).\n *\n */\nexport type BillingInfo = {\n /** **Never emitted**, so its unit is undefined. The credits that do exist are bought through `POST /billing/credits`, which reports `credits_added_cents` — integer US cents, not an abstract credit count. */\n credits_remaining: number;\n /** **Never emitted.** Consumption is reported by `GET /billing/usage` (`object: billing_usage`), which returns the billing service's usage summary rather than a credit counter. */\n credits_used: number;\n /** **No producer.** There is no `GET /v1/partner/billing` route; the live billing surface is `/billing/plans`, `/billing/subscribe`, `/billing/cancel`, `/billing/usage` and `/billing/subscription`, each returning a Stripe-style envelope tagged with an `object` marker plus `request_id`. */\n plan: string;\n /** Whether the partner has a connected Stripe account. */\n stripe_connected: boolean;\n /** Usage counters for the current billing month, keyed by metric. */\n usage_this_month: Record<string, number>;\n};\n\nexport type BleScanResultData = {\n /** Despite the name this is a GENERALISED advert-subtype code, and the server stores it as `manufacturer_subtype`. Values 0x00-0x1F are genuine Apple Continuity subtypes; 0x80 and above are SYNTHETIC markers this parser assigns to non-Apple formats — 0x80 iBeacon, 0x81 Eddystone-UID, 0x82 Fast Pair, 0x83 Tile, 0x85 Eddystone-URL, 0x86 AltBeacon. Note an Apple iBeacon reports 0x80, not its literal Apple subtype 0x02. */\n appleContinuitySubtype?: number | null;\n /** The Android `BluetoothDevice.getType()` constant: 0 UNKNOWN, 1 CLASSIC, 2 LE, 3 DUAL. Treat `0` as \"unknown OR the read threw\" — the producer catches any exception and substitutes 0 rather than omitting the field. */\n deviceType?: number | null;\n /** iBeacon major value, an unsigned 16-bit integer (0-65535) parsed BIG-endian from the advert. `null` unless a valid iBeacon frame was found, and meaningless without the accompanying `ibeaconUuid`. */\n ibeaconMajor?: number | null;\n /** iBeacon minor value, unsigned 16-bit big-endian (0-65535). `null` outside a valid iBeacon frame; major and minor are only comparable within one `ibeaconUuid` namespace. */\n ibeaconMinor?: number | null;\n /** The 16-byte iBeacon proximity UUID as canonical dashed lowercase, parsed BIG-endian. Present only for a well-formed Apple iBeacon frame — an Apple subtype 0x02 whose inner length is not 0x15 is explicitly rejected rather than partially parsed. */\n ibeaconUuid?: string | null;\n /** The Bluetooth SIG assigned company identifier from the advert's Manufacturer Specific Data structure (AD type 0xFF), read little-endian — e.g. 76 (0x004c) Apple, 6 Microsoft, 224 (0x00e0) Google. `null` when the record carries no such structure. One synthetic exception: a Google Fast Pair service-data advert is forced to the Google id even though it has no 0xFF structure. */\n manufacturerCompanyId?: number | null;\n /** The BLE advertiser address exactly as Android reports it, unhashed on the device. It is sent over TLS, and Trillboards stores it as received and as a keyed HMAC-SHA256 hash. On most modern phones this is a resolvable private address that ROTATES roughly every 15 minutes, so it is not a stable device identity; the sibling `addr_type` (`public`/`random`/`anonymous`) is what tells the two apart. */\n rawAddress: string;\n /** Received signal strength in dBm (negative, bounded -120..0). It is the MAXIMUM RSSI across every advertisement from this address inside the scan window — the closest observed reading, not a mean — because the scanner groups repeated adverts per address and keeps the strongest as the representative. */\n rssi: number;\n /** Advertised GATT service UUIDs, de-duplicated. 16-bit UUIDs are rendered as FOUR lowercase hex characters (e.g. `feaa`), not expanded to the full `0000feaa-0000-1000-8000-00805f9b34fb` base form; 128-bit UUIDs are canonical dashed lowercase. `null` rather than `[]` when the advert carries none. */\n serviceUuids?: Array<string> | null;\n /** Lowercase hex, no separators, of ONLY the advert sub-bytes that survive address rotation (an iBeacon UUID+major+minor, an Eddystone namespace+instance, a Fast Pair model id…), prefixed with the synthetic subtype byte. Calibration bytes such as TX power are deliberately excluded. It is `null` far more often than it is present: 13 rotating Apple subtypes are dropped outright and unknown Apple subtypes fail closed, so a populated `appleContinuitySubtype` with a null payload here is normal. */\n stableManufacturerPayloadHex?: string | null;\n /** Advertised transmit power in dBm (bounded -127..20) taken from the advert itself, NOT from `ScanResult.getTxPower()`. For iBeacon and Eddystone frames it is the format's calibrated 1-metre reference power, which overwrites the generic AD-type-0x0A value; `null` when the advert carries neither. */\n txPowerDbm?: number | null;\n [key: string]: unknown;\n};\n\nexport type CanonicalError = {\n error: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code: string;\n /** Per-field violations (populated from Zod errors). */\n details?: Array<{\n code?: string;\n message?: string;\n param?: string;\n }>;\n /** Link to the documentation for this error code (https://api.trillboards.com/docs/errors#<code>). */\n doc_url?: string;\n /** Agent-facing hints and suggestions. */\n help?: {\n portal_url?: string;\n suggestions?: Array<string>;\n summary?: string;\n try_next?: string;\n };\n /** Human-readable error message. Safe to surface to end-users. */\n message: string;\n /** Offending parameter name (when applicable). */\n param?: string;\n /** Echoed X-Request-Id for correlation. */\n request_id: string;\n /** Stripe-style error taxonomy (derived from utils/errorCatalog). */\n type: \"api_error\" | \"authentication_error\" | \"idempotency_error\" | \"invalid_request_error\" | \"permission_error\" | \"rate_limit_error\";\n };\n};\n\nexport type ChangelogEntry = {\n /** ISO date string or null for unreleased */\n date: string | null;\n /** Human-readable change description */\n description: string;\n /** API surface: data, sdk, device, sensing, openrtb, partner, all */\n surface: string;\n /** Keepachangelog type: added, changed, deprecated, removed, fixed, security */\n type: string;\n /** \"unreleased\" or a date like \"2026-04-16\" */\n version: string;\n};\n\nexport type ChangelogResponse = {\n /** Matching changelog entries */\n data: Array<ChangelogEntry>;\n /** Always \"list\" */\n object: \"list\";\n /** Number of entries returned */\n total: number;\n};\n\n/**\n * Completed-play observations from VAST complete and proof-of-play paths. Deduped by issued request/impression key for live revenue and daily earnings.\n */\nexport type CompletedImpressions = {\n /** NUMERIC(18,6). */\n actual_cpm?: number | null;\n /** NUMERIC(18,6). */\n actual_gross_revenue?: number | null;\n ad_id: string;\n advertiser_domain?: string | null;\n bid_request_id?: string | null;\n billable_key?: string | null;\n buyer_seat?: string | null;\n completed_at: string;\n /** Creative identity is NOT content_sha256 (35 of 430,165 ClickHouse rows since 2026-10-20): join creative_identity on the row's keys (identityKeys.identityJoinSql); its sidecar has the current and ti... */\n content_sha256?: string | null;\n /** chEventParityCron: exact-key repair; created_at/oldest authorized floor; original completed_at CH key; same writer/DLQ before ACK; no delivery debit. All leaf pending indexes must be valid; failed/... */\n created_at: string;\n creative_id?: string | null;\n currency: string;\n demand_partner_id?: number | null;\n device_id?: string | null;\n /** NUMERIC(5,4). */\n display_area_ratio?: number | null;\n display_mode?: string | null;\n /** NUMERIC(10,2). */\n duration_seconds?: number | null;\n earnings_deal_id?: string | null;\n earnings_deal_type?: string | null;\n earnings_source?: string | null;\n event_clock_skew_seconds?: number | null;\n event_timestamp_clamped?: boolean | null;\n givt_passed?: boolean | null;\n /** JustBaat dedupes issued request keys; Adipolo/VidVerto/others use rendered impression_id with request fallback. Readers/rollups dedupe overlapping vast_event, proof_of_play and approved partner_sdk. */\n id?: number | null;\n impression_id?: string | null;\n /** NUMERIC(12,6). */\n impression_multiplier: number;\n ingestion_path: string;\n /** SDK missing-price is server-pending until signed native pricing; directbillable_ is not authority. Client debit/mirror/pending claims are stripped. Legacy finalization: recorded/native nonnull zero... */\n metadata: Record<string, unknown>;\n normalized_event_timestamp?: string | null;\n play_id?: string | null;\n /** PG is the canonical completion write; completed_impressions_dist is its CH reporting mirror. pricing_source: 'placement_purchase'=ad_price/goal per play; '*_overdelivered'/'*_zero'=$0; 'config_defa... */\n pricing_source: string;\n quantity_measured_at?: string | null;\n quantity_source?: string | null;\n quantity_source_type?: number | null;\n quantity_vendor?: string | null;\n raw_client_timestamp?: string | null;\n /** owned_direct = signed src or verified SDK. VAST impid, request_id and SDK suffix share one nonce/PG row; completion, exact debit and eligible billing commit together. First authorized write owns CH... */\n request_id?: string | null;\n screen_id?: number | null;\n screen_mongo_id: string;\n serving_tenant_id?: number | null;\n signature?: string | null;\n /** ImpressionController drops rows with unknown source_provider (PR #2924); earnings use partner billing policy, not raw counts. Exclude pi_e2e_*, admin-allocation and is_demo_data from revenue. */\n source_provider: string;\n variant_id?: number | null;\n variant_name?: string | null;\n zone_id?: string | null;\n};\n\n/**\n * Per-content-type sizing returned and accepted by the Partner API.\n * `fit` preserves the entire creative and may letterbox; `fill` covers\n * the screen and may crop edges. Omitting this object from a write leaves\n * the screen's current behavior unchanged.\n *\n */\nexport type ContentFitSettings = {\n /** Sizing for direct and programmatic advertisements. */\n advertisements?: \"fit\" | \"fill\";\n /** Sizing for default/background streams. */\n default_streams?: \"fit\" | \"fill\";\n /** Sizing for self-promotion and QR-code house ads. */\n self_promo?: \"fit\" | \"fill\";\n};\n\nexport type ContentPreferencesInput = {\n /** Specific advertiser IDs to block */\n blocked_advertisers?: Array<string>;\n /** Ad categories to block (e.g., \"alcohol\", \"gambling\", \"adult\") */\n blocked_categories?: Array<string>;\n /** Max times same ad can show per hour */\n max_ad_frequency?: number;\n /** Minimum ad content rating */\n min_ad_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\";\n /** Preferred ad categories (prioritized in auctions) */\n preferred_categories?: Array<string>;\n};\n\nexport type ContentPreferencesResponse = {\n /** NOT EMITTED. No handler on this endpoint produces this key — neither `formatContentPreferences` nor the service feeding it has such a field. Advertiser blocking lives on the programmatic-settings resource instead, as `blocked_advertisers` on `GET/PUT /v1/partner/screens/{screenId}/programmatic-settings`. */\n blocked_advertisers?: Array<string>;\n /** The screen's own blocked list, `[]` when unset. Matched at approval time against the ad's typed `iab_categories` with `categoriesMatch`, so IAB codes and human-readable names both work. It is the only one of this schema's five list/rating fields the server actually emits. */\n blocked_categories?: Array<string>;\n /** NOT EMITTED, and the identifier does not occur anywhere in the API source. The only delivery cap this platform exposes to partners is the advisory `max_ads_per_hour` in the `/ads` response settings. */\n max_ad_frequency?: number;\n /** NOT EMITTED, and the identifier `min_ad_rating` does not occur anywhere in the API source. The response carries `max_age_rating` instead — an UPPER bound on the ad classification (`G`..`NC-17`), defaulting to `PG-13`, not a minimum. */\n min_ad_rating?: string;\n /** Always the literal `content_preferences`. This response is FLAT — there is no `success`/`data` envelope, unlike the L-bar and default-stream routes — and `POST .../content-preferences/apply-preset` returns this same object with an extra `preset_applied` field appended. */\n object?: string;\n /** NOT EMITTED, and the identifier does not occur anywhere in the API source. The nearest real control is `allowed_categories`, which the formatter does return and which acts as a scoring boost (+10 per match) rather than a hard preference. */\n preferred_categories?: Array<string>;\n /** Echo of the server-assigned `req.requestId`. The formatter attaches it only when one exists, so the key is ABSENT rather than null on a request that carried none. */\n request_id?: string;\n /** Echoed straight back from the `{screenId}` path parameter — the formatter is handed the path value, not a column — so it always equals what you asked for. */\n screen_id?: string;\n /** ISO-8601, but it is the SCREEN row's `updatedAt`, not a preferences-specific timestamp, so unrelated screen edits move it. When the screen has none the formatter substitutes the current time, so this field is never null and never proves a write landed. */\n updated_at?: string;\n};\n\nexport type ContentPreset = {\n /** Advertiser IDs blocked */\n blocked_advertisers?: Array<string>;\n /** Categories blocked by this preset */\n blocked_categories?: Array<string>;\n /** Preset description */\n description?: string;\n /** Unique preset identifier */\n id?: string;\n /** Minimum ad rating allowed */\n min_ad_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\";\n /** Human-readable preset name */\n name?: string;\n /** Full preference object applied by this preset */\n preferences?: Record<string, unknown>;\n};\n\nexport type CreatePartnerSensingRouteRequest = {\n /** The channel actions fired on a match; at least 1 and at most 10, each carrying exactly the destination its channel requires. A route with zero actions cannot exist, so use a `webhook` action for anything you do not want delivered to a person. */\n actions: Array<SensingRouteAction>;\n /** Seven-bit weekday mask evaluated in `activeTz`: bit 0 Monday through bit 6 Sunday, so the default 127 is every day and 0 means the route never fires. Requires `activeTz`. */\n activeDaysMask?: number;\n /** Inclusive end of the daily active window, minutes past local midnight in `activeTz` (0..1439). Set it BELOW `activeStartMinute` for an overnight window — 1200 to 360 is 20:00 through 06:00. */\n activeEndMinute?: number;\n /** Inclusive start of the daily active window, minutes past local midnight in `activeTz` (0..1439; 1200 = 20:00). Has no effect without `activeTz`, and omitting either end makes the window whole-day. */\n activeStartMinute?: number;\n /** IANA zone name (e.g. `America/New_York`) the active window is evaluated in, trimmed to 64 characters. Omitting it makes `activeStartMinute`, `activeEndMinute` and `activeDaysMask` inert — the route is then always active — and an unparseable zone fails open. */\n activeTz?: string;\n condition?: SensingRouteCondition;\n /** Minimum gap in seconds between alerts for the same (route, screen) episode; clamped to 0..86400, default 300. It also bounds the falling-edge clear window at 60 s, so a value below that re-arms the route faster too. */\n debounceSeconds?: number;\n /** Required when mode=digest. `field` is required for avg/max. */\n digest?: {\n field?: string;\n intervalMinutes?: number;\n metric?: \"count\" | \"avg\" | \"max\";\n windowMinutes?: number;\n };\n /** Only the JSON literal `false` creates the route disabled — any other value, including `0` and the string `\"false\"`, creates it enabled. Note the update endpoint inverts this test, so send a real boolean on both. */\n enabled?: boolean;\n /** `threshold` (the default) needs a `condition` and evaluates every incoming observation. `digest` needs a `digest` block instead, sends on a schedule, and rejects `screenFocusRegions` and explicit review timing. Only the exact string `digest` selects digest mode; anything else falls back to `threshold`. */\n mode?: \"threshold\" | \"digest\";\n /** Operator-supplied label, required, trimmed and capped at 200 characters. It is delivered as `route_name` on every fire and shown in operator surfaces; it is not the alert text. */\n name: string;\n /** Bind to a named Sense Anything profile (stable across redeploys). */\n profileName?: string;\n reviewTimingMode?: SensingRouteReviewTimingMode;\n reviewWaitSeconds?: SensingRouteReviewWaitSeconds;\n /** Optional per-camera rectangles or polygon lassos. Every entry must reference screenMongoIds. Supported only for visual threshold alerts using once_per_episode, on_escalation, or nag_until_resolved cadence; not digest, group-targeted, non-visual, or per_new_entity routes. */\n screenFocusRegions?: Array<SensingRouteScreenFocusRegion>;\n /** Screens to watch — all owned by this partner (foreign → 403). Provide EITHER screenMongoIds OR targetGroupId, not both. */\n screenMongoIds?: Array<string>;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainMinSamples?: number;\n /** How long the condition must hold before the FIRST alert, in seconds (600 = ten minutes). Omit to alert on the first true reading. Cadence-independent, because the evaluator compares timestamps - correct however often the screen reports, including when that rate changes while the condition holds. */\n sustainSeconds?: number;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainWindowSeconds?: number;\n /** A sg_ Screen Group id (owned by this partner) to target instead of an explicit screen set. The route fires on the group's live members. Requires SENSING_ROUTES_GROUP_TARGET_ENABLED. */\n targetGroupId?: string;\n};\n\n/**\n * Structured creative classification — the same shape the Trillboards venue portal renders for a served ad.\n */\nexport type CreativeClassification = {\n /** The name whoever FIRST submitted these bytes passed on `POST /creatives`, carried through the moderation queue. It is unverified free text, and because the review row is keyed on the content hash a later submitter of the same bytes reads the first submitter's value. `null` when none was supplied. */\n advertiser_name?: string | null;\n /** One of G, PG, PG-13, R, NC-17 (null until classified). */\n age_rating?: string | null;\n /** Descriptive output of the same classifier pass — visible subjects, keywords, scene setting, mood, a quality grade, and `text_content` recovered by OCR. Every field is `null`/empty until classification finishes. This is scene description, not the moderation verdict; that is `status` plus `moderation.flags`. */\n analysis?: {\n keywords?: Array<string>;\n mood?: string | null;\n quality?: string | null;\n setting?: string | null;\n subjects?: Array<string>;\n /** On-screen text (OCR). */\n text_content?: string | null;\n };\n /** Classifier output: `brand`, `category` and IAB category codes. All three are `null`/empty while `status` is `pending`, so an empty `iab_categories` means not yet classified rather than 'no categories apply'. */\n categorization?: {\n brand?: string | null;\n category?: string | null;\n iab_categories?: Array<string>;\n };\n /** Classification confidence, 0..1. */\n confidence?: number | null;\n /** SHA-256 of the bytes the SERVER fetched from your `media_url` — lowercase 64-hex, never a hash you declare — and `id` is this same value prefixed `sha256:`. Classification is content-addressed and global, so two partners submitting identical bytes share one record, and this is the byte-identity join key into `completed_impressions` and `vast_requests`. */\n content_sha256?: string;\n /** Canonical reference — `sha256:<hex>` of the creative bytes. Use as `creative_ref` when posting plays. */\n id?: string;\n /** `approved` is not an independent verdict — it is derived as `status === 'approved'`, so it is false for both `pending` and `blocked` and adds no information beyond `status`. `flags` is the classifier's reason list and is empty until classification finishes. */\n moderation?: {\n approved?: boolean;\n flags?: Array<string>;\n };\n /** Constant discriminator `creative_classification`. It is returned identically on the 202 (queued) and 200 (already classified) forms of this response, so it tells you nothing about whether classification has finished — read `status` for that. */\n object?: string;\n /** `pending` means queued and not yet classified. `approved`, `flagged` and `blocked` are terminal: re-submitting the same bytes then returns 200 immediately without re-running the classifier or consuming your daily classification quota, whereas a still-pending submit returns 202. The value is passed through from the shared review row unmapped, so a state outside this enum (e.g. `metadata_only`) can surface. */\n status?: \"pending\" | \"approved\" | \"flagged\" | \"blocked\";\n /** Always `null` in practice: the only writer of the underlying `creative_reviews.thumbnail_url` column has no remaining callers, so nothing populates it. When it did carry a value it was constrained to a Trillboards CDN host, so an off-host thumbnail was dropped rather than passed through. */\n thumbnail_url?: string | null;\n};\n\n/**\n * Native readiness hint delivered through existing partner SSE and the audited webhook queue. The hint is free; only the canonical reward page uses native paid admission.\n */\nexport type CreativeRewardsReadyEvent = {\n data: {\n advertisement_id: string;\n /** Lossless native build stamp. */\n build_stamp: string;\n builder_version: string;\n experiment_id: string;\n from: string;\n notification_id: string;\n object: \"creative_reward_ready\";\n recovery: \"rewind_and_dedupe\";\n request_idempotency_key_required: true;\n /** Canonical native reward path plus date scope; never contains credentials or a paid request key. */\n reward_reader_url: string;\n to: string;\n view: \"latest_state\";\n };\n event: \"creative.rewards_ready\";\n /** Audited webhook notification ID; SSE data carries the same ID inside data.notification_id. */\n id?: string;\n timestamp: string;\n};\n\nexport type DashboardResponse = {\n /** All amounts are integer US cents. `total_earned_cents` is lifetime earner revenue across every status (estimated + confirmed + paid); `available_payout_cents` is only the Net-60-matured payable balance minus anything already reserved, floored at 0; `next_payout_date` is simply the 1st of next month, computed in the handler with no reference to a scheduled transfer. `revenue_share_percent` is 0-100 and reads `60` when no `publisher_payout_rates` rule applies. */\n earnings?: {\n available_payout_cents?: number;\n next_payout_date?: string;\n pending_payout_cents?: number;\n revenue_share_percent?: number;\n total_earned_cents?: number;\n };\n /** Identity block copied off the partner row, where `created_at` is the registration timestamp. The row is read through a 10-minute Redis cache, so a just-changed name or status can lag by that much. */\n partner?: {\n created_at?: string;\n name?: string;\n slug?: string;\n status?: \"pending\" | \"active\" | \"suspended\" | \"terminated\";\n };\n /** The ten newest `impression_ledger` rows for the partner, newest first. `type` is always the literal `impression` — no other activity kind is ever emitted. */\n recent_activity?: Array<{\n ad_id?: string;\n screen_id?: string;\n timestamp?: string;\n type?: string;\n }>;\n /** `active_screens`/`offline_screens` count `online_status` `online`/`offline` from the live heartbeat mirror — a screen that has never heartbeated reads `unknown` and lands in NEITHER bucket, so the two need not sum to `total_screens`. `pending_screens` is the separate approval status and overlaps both. The three impression totals are deduped, GIVT-passed `completed_impressions` over midnight-today / the last 7 days / month-to-date, all cut in the API server's local timezone rather than the screen's. */\n stats?: {\n active_screens?: number;\n offline_screens?: number;\n pending_screens?: number;\n total_impressions_month?: number;\n total_impressions_today?: number;\n total_impressions_week?: number;\n total_screens?: number;\n };\n /** `connect_account_id` is **redacted**: it is the literal string `***` when an account is connected and `null` when it is not, so it can never be used as an identifier. `account_status` defaults to `pending` and must be `active` before a payout request is accepted. */\n stripe_status?: {\n account_status?: string;\n connect_account_id?: string;\n };\n /** The five screens with the most completed impressions since midnight today (server timezone). `name` falls back to the literal `Unknown Screen`, and `location` is a `City, State` string or `null` when either part is missing. */\n top_screens?: Array<{\n impressions_today?: number;\n location?: string;\n name?: string;\n screen_id?: string;\n }>;\n};\n\nexport type DataApi_AdSightingRecord = {\n /** The words read on the ad. */\n ad_text: string | null;\n advertiser_as_read: string | null;\n board_id: string | null;\n brand_as_read: string | null;\n brand_id: string | null;\n brand_name: string | null;\n cab_heading_deg: number | null;\n cab_lat: number | null;\n cab_lon: number | null;\n capture_mode: string | null;\n /** The resolved brand's IAB tier-1 category (brand_knowledge_graph.iab_category: its vote over the brand's reads), the code the history's category slice keys by (IAB8 is Food & Drink). Null where the brand has no vote or the record names no resolved brand. */\n category: string | null;\n confidence: number | null;\n face_lat: number | null;\n face_lon: number | null;\n flight_end: string | null;\n flight_label_kind: string | null;\n flight_open: boolean | null;\n flight_passes: number | null;\n flight_reads: number | null;\n flight_start: string | null;\n /** The ad box in the frame, fractions of the frame. */\n frame_box_x0: number | null;\n frame_box_x1: number | null;\n frame_box_y0: number | null;\n frame_box_y1: number | null;\n frame_expires_at: string | null;\n /** A short-lived capability link to the whole still the ad was read off, face-blurred: the still's blurred rendition, never the original. Null until the still is blurred, and for a still the face-blur engine excluded. */\n frame_url: string | null;\n /** ssr-v2 or ssr-v1 (the still reader), vlmtext-v1 or edge_ocr_v1. */\n instrument_version: string | null;\n /** The face carried no advertiser. */\n is_vacancy: boolean;\n legibility: string | null;\n /** Legible, Partial or Illegible. */\n legibility_label: string | null;\n market_code: string | null;\n market_country: string | null;\n market_key: string | null;\n market_name: string | null;\n match_basis: string | null;\n match_distance_m: number | null;\n /** matched | unmatched | no_candidate. */\n match_status: string | null;\n orientation_idx: number | null;\n parent_name: string | null;\n /** The ad (on a close-up, its words) inside the photo, fractions of the photo. */\n photo_box_x0: number | null;\n photo_box_x1: number | null;\n photo_box_y0: number | null;\n photo_box_y1: number | null;\n photo_expires_at: string | null;\n /** The ad itself, face-blurred: closeup = the capture-resolution close-up a tablet uploaded, its blurred rendition whole; crop = the ad cut at request time from the blurred frame (its box padded 50% per side), never stored. Null when no picture of the ad can be shared. */\n photo_kind: \"closeup\" | \"crop\" | null | null;\n /** A short-lived capability link to the photo on our endpoint. It serves the face-blurred rendition only (faces are always blurred in any in-vehicle picture), never the original; null until the still is blurred, and for a still the face-blur engine excluded. */\n photo_url: string | null;\n /** What kind of placement the reader judged the ad to be (still reader ssr-v2): paid_ad = a third party's ad on space a media owner sells; own_premises = the business's own sign at or by its own place, or its own vehicle livery; other = neither. Null where the reading classified none (ssr-v1, vlmtext-v1, edge_ocr_v1). */\n placement: \"paid_ad\" | \"own_premises\" | \"other\" | null | null;\n product_as_read: string | null;\n publisher_name: string | null;\n /** The still instant, UTC. */\n seen_at: string;\n sighted_creative_id: string | null;\n /** Stable id of the sighting (32 hex). */\n sighting_id: string;\n source: string | null;\n surface: string | null;\n /** The surface as a buyer reads it (Billboard, Digital board, Storefront, ...). */\n surface_label: string | null;\n ticker: string | null;\n vehicle_side: string | null;\n};\n\nexport type DataApi_AdSightingsHistoryResponse = {\n data: {\n next_cursor: string | null;\n /** One row per month (or week, or the window), market and brand (creative_brand_history), and per slice when the request names dimensions: flights active and started, creatives launched and confirmed, board faces and points, share of voice over every ad flight in the market or slice (by flights, by faces and by face-days, with its standard error), the market vacancy, face-days, the floor-priced media value and the attention on the brand's registered flights, each with the count it is taken over. A row carries the keys of the slices asked for. */\n rows: Array<DataApi_CreativeBrandHistoryRow>;\n };\n meta: {\n /** The markets, brand ids, dimensions and slice filters applied (null: not narrowed). */\n filters: Record<string, unknown> | null;\n /** market_month, fleet_month, market_week, fleet_week, market_window or fleet_window. */\n grain: string | null;\n metric: \"creative_brand_history\";\n product: \"ad_sightings\";\n records: number;\n request: Record<string, unknown>;\n view: \"history\";\n /** The window answered: from, to, days. */\n window: Record<string, unknown> | null;\n };\n success: true;\n};\n\nexport type DataApi_AdSightingsResponse = {\n data: {\n next_cursor: string | null;\n rows: Array<DataApi_AdSightingRecord>;\n };\n meta: {\n /** The markets (market_key, or rest for every market outside the top ones) whose pictures have no passing by-eye check at the current definition: their records are left out of this page until one passes. Absent when every market is sold. */\n held_markets?: Array<string>;\n product: \"ad_sightings\";\n records: number;\n request: Record<string, unknown>;\n };\n success: true;\n};\n\nexport type DataApi_AggregateResponse = {\n aggregations: Array<Record<string, unknown>>;\n group_by: string;\n metric: string;\n time_window: string;\n};\n\nexport type DataApi_CreativeBrandHistoryRow = {\n /** Each measure on the row with no value, and why (no_flight, no_ad_flight, no_sighting_held, ...). */\n absent?: Array<{\n measure: string;\n reason: string;\n }>;\n /** One of the brand's agencies of record as Winmo carries them, on an agency slice: a brand with several is on a row per agency. Null where none links (absent: no_agency_linked). */\n agency?: string | null;\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights: number;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Null when attention_flights is 0. */\n attention_passes: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces: number;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points: number;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Null when flights_active is 0. */\n brand_face_days: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Null when flights_active is 0. */\n brand_face_share: number | null;\n /** The brand's IAB tier-1 category. */\n brand_iab_tier1: string | null;\n /** Resolved brand id (brand graph). */\n brand_id: string | null;\n /** Brand name. */\n brand_label: string | null;\n /** The brand's IAB tier-1 category on a category slice (its vote, stamped on the ledger). Null without one (absent: no_category). */\n category?: string | null;\n /** The Census CBSA (Metropolitan or Micropolitan Statistical Area, OMB's July 2023 delineation) of the faces the row counts, on a cbsa slice. Null outside every CBSA and outside the US (absent: no_cbsa). */\n cbsa_code?: string | null;\n /** The CBSA's title (Las Vegas-Henderson-North Las Vegas, NV). */\n cbsa_name?: string | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched: number;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed: number;\n /** The face on a board slice: f:<board id>:<face index> (a registered face) or p:<point id> (an unregistered board point). */\n face_key?: string | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active: number;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started: number;\n /** static or digital on a format slice. Null where no read typed the face (absent: face_type_unknown). */\n format?: string | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Null when attention_flights is 0. */\n gaze_legible_s: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Null when attention_flights is 0. */\n gaze_looked_s: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Null when attention_flights is 0. */\n head_legible_s: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Null when attention_flights is 0. */\n head_looked_s: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Null when market_ad_flights is 0. */\n market_ad_face_days: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights: number;\n /** US DMA or CA CMA code. Null on a fleet row. */\n market_code: string | null;\n /** Country of the market: US or CA. Null on a fleet row. */\n market_country: string | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. Null when market_sightings is 0. */\n market_drawn_sightings: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Null when market_ad_flights is 0. */\n market_face_days: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Null when market_ad_flights is 0. */\n market_face_share: number | null;\n /** Market name. Null on a fleet row. */\n market_name: string | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights: number;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. Null when market_sightings is 0. */\n market_sightings: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. market_vacant_face_days / market_face_days; null when market_face_days is 0. */\n market_vacancy_face_day_share: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. market_vacancy_sightings / market_sightings; null when market_sightings is 0. */\n market_vacancy_share: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. market_vacancy_weighted_sightings / market_weighted_sightings; null when market_weighted_sightings is 0. */\n market_vacancy_share_drawn_weighted: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. Null when market_sightings is 0. */\n market_vacancy_sightings: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Null when market_drawn_sightings is 0. */\n market_vacancy_weighted_sightings: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. Null when market_sightings is 0. */\n market_vacant_board_faces: number | null;\n /** Their face-days in the period. Unit: face_days. Null when market_ad_flights is 0. */\n market_vacant_face_days: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights: number;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Null when market_drawn_sightings is 0. */\n market_weighted_sightings: number | null;\n /** The faces' registry owner on a media_owner slice: a programmatic face's publisher, a permit layer's owner of record. Null on an unregistered board point (absent: no_registered_owner). */\n media_owner?: string | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Null when media_value_priced_faces is 0. */\n media_value_floor_usd: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces: number;\n /** The month (its first day, YYYY-MM-DD). */\n month: string | null;\n /** The brand's parent company on a parent slice: the brand graph id of the parent's Wikidata family. Null where the graph names none (absent: no_parent_named). */\n parent_id?: string | null;\n /** The parent company's name. */\n parent_label?: string | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. named_flights_active / market_named_flights; null when market_named_flights is 0. */\n share_of_named_voice: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. flights_active / market_ad_flights; null when market_ad_flights is 0. */\n share_of_voice: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. brand_face_days / market_ad_face_days; null when market_ad_face_days is 0. */\n share_of_voice_face_days: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Null when market_ad_flights is 0. */\n share_of_voice_face_days_se: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. brand_face_share / market_face_share; null when market_face_share is 0. */\n share_of_voice_face_weighted: number | null;\n /** The reader surface the face's held reads named most, on a surface slice: billboard, digital_board, bus_shelter or kiosk. Null where none named one (absent: no_reader_surface). */\n surface?: string | null;\n /** The ISO week on a week grain: its Monday, YYYY-MM-DD. */\n week?: string | null;\n};\n\n/**\n * Ad delivery per screen-hour: completed plays as our billing policy counts them, distinct creatives and ads, played seconds (each play's longest reported duration) with the plays that carried one, GIVT-passed plays, average CPM, gross revenue and the most frequent source provider. Join place_activity_hourly for the audience of the same screen-hour, and play_audience for the audience of each play.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `screen_id`. Definition version 4. 11 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_ad_delivery_hourly = {\n /** Mean CPM of the plays, USD. Unit: usd_per_1000_plays. NULL: No play of the hour carried a price. */\n avg_cpm?: number | null;\n /** Completed plays as our billing policy identifies them: the play key on one screen, each play once, on its first day. Unit: plays. */\n completed_plays?: number;\n /** Distinct ad ids among the plays (the pod placeholder is not an ad). Unit: ads. */\n distinct_ads?: number;\n /** Distinct creative ids among the plays (the IMA house creative placeholder is not a creative). Unit: creatives. */\n distinct_creatives?: number;\n /** Plays that passed general invalid-traffic checks. Unit: plays. */\n givt_passed_plays?: number;\n /** Sum of the plays' gross revenue, USD. Unit: usd. NULL: No play of the hour carried a price. */\n gross_revenue?: number | null;\n /** Start of the UTC hour. A play counts in the hour its kept report completed. */\n hour_start: string;\n /** Most frequent demand source of the plays by exact count, ties to the alphabetically first. NULL: No play carried a real provider. */\n modal_source_provider?: string | null;\n /** Plays that carried a positive duration: the denominator of a mean play length (played_seconds / played_duration_plays). Unit: plays. */\n played_duration_plays?: number;\n /** Sum over the plays of each play's longest positive duration over every report of the play that day. Unit: seconds. NULL: No play of the hour carried a positive duration on any of its reports. */\n played_seconds?: number | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n};\n\n/**\n * Verified attention per sensing window per screen: one row per audienceSignals window a device sends with vas_weighted > 0 (vasEngine.recordVAS), stamped measured_at by the database clock at write.\n * \n * **Delivery:** Parquet day files, one row per `id`. Definition version 2. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_attention_ledger = {\n /** Ad id the attention was measured against. NULL: The entry named no ad (set on 71,140 of ~72M rows 2026-02..09). */\n ad_id?: string | null;\n /** Mean body engagement 0-1 of those faces. Unit: index. NULL: Not measured. */\n avg_body_engagement?: number | null;\n /** Mean emotional engagement 0-1 of those faces. Unit: index. NULL: Not measured. */\n avg_emotion_engagement?: number | null;\n /** Faces in the measurement. Unit: faces. NULL: Not measured. */\n face_count?: number | null;\n /** The ledger entry's id. */\n id: string;\n /** Impression id the attention was measured against. NULL: The entry named no impression. */\n impression_id?: string | null;\n /** When the attention was measured, UTC. */\n measured_at?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** Verified attention seconds before weighting. Unit: seconds. NULL: Not measured. */\n vas_raw?: number | null;\n /** Verified attention seconds, weighted: the canonical attention value. Unit: seconds. NULL: Not measured. */\n vas_weighted?: number | null;\n};\n\n/**\n * Auction outcomes and outbound OpenRTB proxy attempts keyed by bidder-facing request ID.\n * \n * **Delivery:** Parquet day files keyed by `timestamp`, one row per `auction_id`. Definition version 2. 15 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_auction_results = {\n /** The auction's id: one auction per bid request we ran. */\n auction_id: string;\n /** Auction mechanics: first_price, or outbound_openrtb_proxy for an auction we forwarded to a demand partner. */\n auction_type?: string;\n /** OpenRTB bid request id the auction answered. NULL: Not recorded on the auction. */\n bid_request_id?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** Floor price of the auction, USD CPM. Unit: usd_per_1000_plays. NULL: No floor was set. */\n floor_price_cpm?: number | null;\n /** Auction duration in milliseconds. Unit: ms. NULL: Not recorded. */\n latency_ms?: number | null;\n /** Outcome: bid_received, no_bid, timeout or error. */\n result?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** When the auction ran, UTC. */\n timestamp?: string;\n /** Bids the auction received. Unit: bids. */\n total_bids_received?: number;\n /** Id of the winning bid. NULL: No bid won. */\n winning_bid_id?: string | null;\n /** Price the winning bid offered, USD CPM. Unit: usd_per_1000_plays. NULL: No bid won. */\n winning_bid_price_cpm?: number | null;\n /** Price the winning bid cleared at, USD CPM. Unit: usd_per_1000_plays. NULL: No bid won, or no clearing price was recorded. */\n winning_clearing_price_cpm?: number | null;\n /** Creative id of the winning bid. NULL: No bid won, or the bid named no creative. */\n winning_creative_id?: string | null;\n /** Demand platform of the winning bid. NULL: No bid won. */\n winning_dsp_name?: string | null;\n};\n\n/**\n * Audience attribute mix at venue-type x DMA x week, from AI-vision readings. Starts 2026-07-16, which is when observation_demographics begins — it is not a retention cut. Every row carries observation_count and screens as its support; no cell is dropped for being small, so a buyer sets their own threshold. week_days_in_window counts the days of the week inside the delivery window, so the first and last weeks can be partial. In the key, dma_code '' means no DMA (outside the US), country '' an unresolved country, and openooh_venue_type_id 0 an unclassified venue. lifestyle values are numeric IAB Audience Taxonomy 1.1 segment ids (segtax=4); all other dimensions are our own vocabulary.\n * \n * **Delivery:** A snapshot, one row per `week_start` x `openooh_venue_type_id` x `dma_code` x `country` x `dimension` x `attribute_value`. Definition version 2. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_audience_composition_weekly = {\n /** observation_count over every reading of the dimension in the same week, venue type, DMA and country. Unit: share. */\n attribute_share?: number;\n /** The attribute's value. lifestyle values are numeric IAB Audience Taxonomy 1.1 segment ids (segtax=4); the other dimensions use our own vocabulary. */\n attribute_value: string;\n /** Country ('' = unresolved; a key column). */\n country: string;\n /** The audience attribute. head_turn and occupant_position are image-frame values: head_turn is turned_image_left, turned_image_right, not_turned or not_assessable (where the nose points relative to the edges of the picture), occupant_position is image_left_third, image_center_third, image_right_third or driving (the third of the picture the person occupies). Neither is a side of the vehicle or the street: a rearward cabin camera mirrors the vehicle's left and right. */\n dimension: string;\n /** Nielsen DMA code ('' = no DMA, outside the US; a key column). */\n dma_code: string;\n /** Readings of the value in the week and cell. Unit: readings. */\n observation_count?: number;\n /** OpenOOH venue type of the screens (0 = unclassified; a key column, so never NULL). */\n openooh_venue_type_id: number;\n /** Distinct screens carrying the value. Unit: screens. */\n screens?: number;\n /** Days of the week inside the delivery window (7 except at its two ends). Unit: days. */\n week_days_in_window?: number;\n /** Monday of the week. */\n week_start: string;\n};\n\n/**\n * FEIN 10-second window audience observations — face count, dwell, demographic signals per screen per interval.\n * \n * **Delivery:** Parquet day files, one row per `metric_id`. Definition version 3. 28 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_audience_metrics = {\n /** Ad receptivity score 0-1 of the window: how receptive the audience in view is to an ad. Unit: index. NULL: No receptivity reading. */\n ad_receptivity_score?: number | null;\n /** Attention level the camera read for the window: high, medium or low. NULL: No attention reading. */\n attention_level?: string | null;\n /** Head-pose index 0-1 of the window: the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. NULL: No head-pose reading. */\n avg_attention?: number | null;\n /** Mean dwell of the faces in view, in milliseconds, as the device reported it, not capped at the window's length (place_activity_hourly's avg_dwell_ms caps each window at its own length). Unit: ms. NULL: Not measured. */\n avg_dwell_time_ms?: number | null;\n /** Mean face count over the window's analysed frames, as the device wrote it (place_activity_hourly's avg_face_count prefers the newer per-window face_count and falls back to this). Unit: faces. NULL: Not measured. */\n avg_face_count?: number | null;\n /** Estimated ambient noise level of the window, in decibels, from the device's audio classification. Unit: decibels. NULL: No noise reading: the device sent none (stored as -1). */\n avg_noise_level?: number | null;\n /** Crowd density of the scene. NULL: No crowd reading. */\n crowd_density?: string | null;\n /** Daypart label in the screen's local time. NULL: Not recorded. */\n daypart?: string | null;\n /** Dominant ambience of the scene (quiet, ambient, crowded ...). NULL: No ambience reading. */\n dominant_ambience?: string | null;\n /** Emotional engagement score 0-1 of the faces in view. Unit: index. NULL: No emotional engagement reading. */\n emotional_engagement_score?: number | null;\n /** Device id (fingerprint) of the screen's sensing device that recorded the window; the Data API serves the same id as device_id. */\n fingerprint?: string;\n /** Venue type the vision model inferred from the scene. NULL: Not inferred. */\n inferred_venue_type?: string | null;\n /** True when the window fell on a weekend day. */\n is_weekend?: boolean;\n /** Largest face count of any one analysed frame in the window, as the device wrote it. Unit: faces. NULL: Not measured. */\n max_face_count?: number | null;\n /** The camera observation window's id (the key; joins play_audience_window.window_metric_id). */\n metric_id: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n mongo_screen_id?: string;\n /** Movement pace of the people in view. NULL: No pace reading. */\n movement_pace?: string | null;\n /** Dominant mood of the people in view. NULL: No mood reading. */\n primary_mood?: string | null;\n /** City of the screen's stored location. NULL: The screen has no stored city. */\n screen_city?: string | null;\n /** Country of the screen's stored location (for a vehicle, where it last synced). NULL: The screen has no stored country. */\n screen_country?: string | null;\n /** DMA of the screen's stored location. NULL: No DMA (outside the US, or not geocoded). */\n screen_dma_name?: string | null;\n /** Engagement with the screen: engaged, glancing or ignoring. NULL: No engagement reading. */\n screen_engagement?: string | null;\n /** Latitude of the screen's stored location (for a vehicle, where it last synced; geohash_activity_hourly places windows on the GPS trail). Unit: degrees. NULL: The screen has no stored coordinate. */\n screen_latitude?: number | null;\n /** Longitude of the same point. Unit: degrees. NULL: The screen has no stored coordinate. */\n screen_longitude?: number | null;\n /** The screen's registered venue category. NULL: The screen has no registered category. */\n screen_venue_category?: string | null;\n /** How the window was sensed (on-device model, cloud vision analysis ...). NULL: Not recorded. */\n sensing_mode?: string | null;\n /** End of the observation window, UTC. */\n window_end?: string;\n /** Start of the observation window (about 10 s long), UTC. NULL: Not recorded: a vision-analysis window carries no start (window_end is its time). */\n window_start?: string | null;\n};\n\n/**\n * One row per outdoor ad a still reading saw: the creative as read, the board face it was attributed to (or the cab position, heading and side when unmatched), brand, company, exact creative where known, and the reading inclusion probability.\n * \n * **Delivery:** Parquet day files keyed by `seen_at`, one row per `sighting_id`. Definition version 5. 56 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_creative_sighting = {\n /** Position of the ad among the ads the reading listed, from 0. */\n ad_ordinal?: number;\n /** The words read on the ad, verbatim, parts separated by \" | \". NULL: Nothing readable. */\n ad_text?: string | null;\n /** The glass the ad was seen through, judged against the edges of the picture: rear, left or right. NULL: The reading did not say. */\n ad_window?: string | null;\n /** The creative of that line item. NULL: No exact creative. */\n advertisement_id?: string | null;\n /** The advertiser as read off the ad. NULL: Not read. */\n advertiser?: string | null;\n /** The matched board: our board id, the key every board dataset and the measurement API use. NULL: Unmatched. */\n board_id?: string | null;\n /** Left edge of the ad in the still, a fraction of the picture width. NULL: A vlm_text sighting. */\n box_x0?: number | null;\n /** Right edge of the ad in the still. NULL: A vlm_text sighting. */\n box_x1?: number | null;\n /** Top edge of the ad in the still, a fraction of the picture height. NULL: A vlm_text sighting. */\n box_y0?: number | null;\n /** Bottom edge of the ad in the still. NULL: A vlm_text sighting. */\n box_y1?: number | null;\n /** The brand as read off the ad. NULL: Not read. */\n brand?: string | null;\n /** The resolved brand (our brand knowledge graph id). NULL: Not resolved. */\n brand_id?: string | null;\n /** How the advertiser was resolved to the brand: exact, domain, grounded_verified, minted or unresolved. NULL: Not resolved. */\n brand_match_method?: string | null;\n /** The resolved brand's name. NULL: Not resolved. */\n brand_name?: string | null;\n /** Cab heading at seen_at, degrees clockwise from north. Unit: degrees. NULL: No matched path covers the instant. */\n cab_heading_deg?: number | null;\n /** Cab latitude at seen_at on its matched path. Unit: degrees. NULL: No matched path covers the instant. */\n cab_lat?: number | null;\n /** Cab longitude at seen_at on its matched path. Unit: degrees. NULL: No matched path covers the instant. */\n cab_lon?: number | null;\n /** Board faces the cab was passing at seen_at. Unit: faces. */\n candidate_count?: number;\n /** Why the tablet took the still: board_burst, face_triggered, periodic_scene, signal_mismatch_probe, vehicle_triggered. */\n capture_mode?: string;\n /** The reader's own 0-1 confidence in the entry. NULL: A vlm_text sighting. */\n confidence?: number | null;\n /** line_item_flight = the face was one we bought for this advertiser and the sighting fell inside the flight. NULL: No exact creative. */\n creative_match_method?: string | null;\n /** IAB Content Taxonomy top-level codes of what the ad advertises (IAB1..IAB25). */\n iab_categories?: Array<unknown>;\n /** Probability the still was drawn for reading; weight a sighting by 1/inclusion_probability. Unit: probability. NULL: A vlm_text sighting: no draw chose the still. */\n inclusion_probability?: number | null;\n /** The reader generation that produced the reading (ssr-v1, ssr-v2, vlmtext-v1, edge_ocr_v1). From ssr-v2 the still reader also classifies the placement. */\n instrument_version?: string;\n /** 1 when the face carried no advertiser: blank, or the media owner's own available or advertise-here message. */\n is_vacancy?: number;\n /** legible = the advertiser named with certainty; partial = a best guess from partial words or a logo; illegible = an ad with nothing readable. NULL: A vlm_text sighting. */\n legibility?: string | null;\n /** Cabin light on the pass: bright, dim or dark. NULL: No light reading for the pass. */\n light_band?: string | null;\n /** Our purchased line item the sighting matched. NULL: No exact creative. */\n line_item_id?: string | null;\n /** The market: a DMA code in the US, a CMA code in Canada. A market is the pair (market_country, market_code). NULL: No board, reading or cab position placed the sighting. */\n market_code?: string | null;\n /** Country of the market: US or CA. NULL: No board, reading or cab position placed the sighting. */\n market_country?: string | null;\n /** Metro name of the market. NULL: Unplaced. */\n market_name?: string | null;\n /** How the face was chosen: burst_board (the face the cab's board burst was taken for), only_candidate, or nearest; '' (empty, not NULL, since v4) when unmatched. on_premise rows (the ad is the brand's own sign: a storefront read, a reading classified own_premises, or one of the brand's own places within 300 m of the cab or nearer than the face) are not ad data and are not delivered. */\n match_basis?: string;\n /** Bearing of the matched face relative to the cab's travel at seen_at; positive = the cab's right. Unit: degrees. NULL: Unmatched. */\n match_beta_deg?: number | null;\n /** Distance from the cab to the matched face at seen_at; on an on_premise row, to the face the ad was moved off. Unit: meters. NULL: Unmatched. */\n match_distance_m?: number | null;\n /** 1 when seen_at fell inside the pass's legible interval. NULL: Unmatched. */\n match_legible?: number | null;\n /** matched = attributed to a board face the cab was passing; unmatched = faces were near but none is the match (none on the sighting's side, none within 300 m, or the ad is the brand's own sign: match_basis on_premise); no_candidate = the cab was passing no known face. */\n match_status?: string;\n /** Where the cab's camera pointed that day (its dated cabin map): rearward, forward, side, upward or unclear. NULL: No dated cabin map covered the cab that day. */\n mount_class?: string | null;\n /** The matched face of the board, from 0. NULL: Unmatched. */\n orientation_idx?: number | null;\n /** Parent company of the brand. NULL: No parent known. */\n parent_name?: string | null;\n /** The cab's pass of the matched face (board_pass pass_id, a 64-bit id shipped as text). NULL: Unmatched. */\n pass_id?: string | null;\n /** paid_ad: the still reader (ssr-v2 and later) judged the ad a third-party placement on a billboard, digital board, transit shelter, kiosk or wrap; '' (empty): the reading did not classify it (ssr-v1, vlm_text and edge reads, delivered by the surface and on-premise rules). Of a classified reading only paid_ad is delivered: own_premises and other are not ads. */\n placement?: string;\n /** paid_ad: the second look (since v5) confirmed the reader's paid_ad on the ad itself, the still with the ad boxed and the ad enlarged (services/sensing/stillScan/adPlacementCheckMethod.js); '' (empty): a reading the reader did not classify (delivered by the surface and on-premise rules). A reader paid_ad ships only with placement_check paid_ad. */\n placement_check?: string;\n /** The product or offer as read. NULL: Not read. */\n product?: string | null;\n /** Media owner of the matched face. NULL: Unmatched. */\n publisher_name?: string | null;\n /** The cab that took the still. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** When the still was taken, UTC: the device shutter where plausible, else when the still reached us (seen_clock says which). */\n seen_at?: string;\n /** device_shutter or called_at: which clock seen_at is. */\n seen_clock?: string;\n /** Of those, the faces on the sighting's side. Unit: faces. */\n side_candidate_count?: number;\n /** The sighted creative the read belongs to (sighted_creatives.creative_id): one artwork recognised across faces and cabs; its flights are creative_flights. NULL: The read is not yet in a sighted creative. */\n sighted_creative_id?: string | null;\n /** The sighting: one outdoor ad in one reading of one cab still. Stable across rebuilds. */\n sighting_id: string;\n /** Sun on the pass: bright (10 degrees or more up), dim (0-10) or dark (below the horizon). NULL: No pass. */\n solar_band?: string | null;\n /** still_reader = the still reader read the ad off the stored still; vlm_text = the audience prompt's existing description of the same still named it (no box, no legibility); edge_ocr = the tablet read the ad's words on the device. */\n source?: string;\n /** The read: for still_reader and vlm_text the stored still it was read off (its call id, the key of camera_frame_corpus and of the proof archive copy); for edge_ocr the tablet's reading id. */\n still_call_id?: string;\n /** billboard, digital_board, bus_shelter or kiosk; wall_or_wrap or vehicle only when the reader classified the ad paid_ad; '' (empty, not NULL, since v4) when not stated, delivered only for a read matched to a registered board face (an edge read). A storefront read is a business's own sign, and an unclassified vehicle or wall read most often a business's own livery or wall sign: neither is delivered. */\n surface?: string;\n /** Listed ticker of the brand's company. NULL: No listed company. */\n ticker?: string | null;\n /** Side of the vehicle the ad was on: left, right or behind (the picture side converted through the cab's mount). NULL: The picture side does not convert for this mount. */\n vehicle_side?: string | null;\n};\n\n/**\n * Measured delivery per roadside face (board_id is the venue id of the board face), daypart and one-dimensional condition (all, light, weather, speed) over one 28-day window: measured impressions per spot (ips) with its interval and the passes and vehicles behind it, its terms (traffic flow, legible window and share, people per vehicle in position to see), our count under the owner's definition, the owner's modelled impressions per spot with the yield comparison, its annual value and the floor CPM it supports, expected unique ads per pass, and the light, glare and rain mix of the passes. The window is the newest one the builder verified that ends inside the delivery window (window_end, the same on every row). ips is NULL only where nothing was measured, with absent_reason saying what. The 2026-10-11 window: 962,168 cells over 141,704 faces, 775,993 of them with a measured ips, 192,810 with the yield comparison drawn.\n * \n * **Delivery:** A snapshot, one row per `window_end` x `board_id` x `daypart` x `cond_scope` x `cond_value`. Definition version 2. 68 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_currency_multiweek = {\n /** Annual average daily traffic facing the face, after the two-way split. Unit: vehicles_per_day. NULL: As flow_vph. */\n aadt_facing?: number | null;\n /** Weakest traffic-count basis among the face's ways: hpms (FHWA HPMS), mtq (Quebec), mtl (Montreal), nyc (New York City), modeled or imputed; empty when the face has no flow. */\n aadt_source?: string;\n /** Empty when ips is published. Otherwise what was not measured: no_viewshed, no_passes, no_window (passes with no legible window measured), no_persons or no_flow, where ips is NULL; owner_model_missing or incremental_basis withhold the yield only, and ips publishes. */\n absent_reason?: string;\n /** Mean expected complete ads per pass. Unit: ads_per_pass. NULL: As ads_seen_mean. */\n ads_complete_mean?: number | null;\n /** Mean expected unique ads seen per pass under the modelled rotation. Unit: ads_per_pass. NULL: No passes in the cell. */\n ads_seen_mean?: number | null;\n /** Mean expected unique ads touched per pass. Unit: ads_per_pass. NULL: As ads_seen_mean. */\n ads_touched_mean?: number | null;\n /** Annual value of the measured difference at the face's floor: spots_per_day_owner x (ips - ips_owner) x floor CPM / 1000 x 365. Unit: usd_per_year. NULL: As yield_ratio. */\n annual_opportunity_usd?: number | null;\n /** Average vehicle occupancy the window uses. Unit: persons_per_vehicle. */\n avo?: number;\n /** The roadside face: the venue id of the board face. */\n board_id: string;\n /** Version of the code that built the window. */\n builder_version?: number;\n /** When the window was built, UTC. */\n built_at?: string;\n /** The board_pass rows with camera evidence. Unit: passes. */\n camera_pass_rows?: number;\n /** Face passes with camera evidence. Unit: passes. NULL: As passes. */\n camera_passes?: number | null;\n /** The one-dimensional condition marginal the row is: all, light, weather or speed. Each scope partitions the passes on its own, so rows of two scopes are two cuts of the same passes. */\n cond_scope: string;\n /** The band within cond_scope (light: day, twilight, night; weather: clear, rain, snow_ice, low_visibility; speed: free_flow, slowed, congested; unknown where the band was not read), __all__ when cond_scope is all. */\n cond_value: string;\n /** Contacts per day: the sum over the day's hours of the flow times the people per vehicle in position to see. Unit: contacts_per_day. NULL: As ips. */\n daily_contacts?: number | null;\n /** Daypart of the cell (early_morning, morning, midday, afternoon, evening, night, late_night), or __all__ for the whole day. */\n daypart: string;\n /** Coefficient of variation of flow_vph. Unit: ratio. NULL: As flow_vph. */\n flow_cv?: number | null;\n /** Vehicles per hour past the face in the cell. Unit: vehicles_per_hour. NULL: The face has no traffic flow (absent_reason no_flow), or no passes. */\n flow_vph?: number | null;\n /** Share of the passes with glare. Unit: share. NULL: No passes in the cell. */\n glare_share?: number | null;\n /** Measured impressions per dollar of floor CPM: 1000 x yield_ratio / floor. Unit: impressions_per_usd. NULL: As yield_ratio. */\n imps_per_floor_usd?: number | null;\n /** How the ips interval is computed (lognormal_delta_vehicle_clustered). */\n interval_method?: string;\n /** Measured impressions per spot: (flow_vph / 3600) x (legible_share x slot_s + window_s_mean) x persons_per_vehicle over the face's road and direction streams. Unit: impressions_per_spot. NULL: Nothing measured for the cell: absent_reason says what (no_viewshed, no_passes, no_window, no_persons or no_flow). */\n ips?: number | null;\n /** High end of ips's interval. Unit: impressions_per_spot. NULL: As ips_low. */\n ips_high?: number | null;\n /** Low end of ips's interval (log-normal delta method, clustered on vehicles). Unit: impressions_per_spot. NULL: As ips, or one vehicle behind the cell. */\n ips_low?: number | null;\n /** The owner's modelled impressions per spot: the figure the measurement is compared with. Unit: impressions_per_spot. NULL: The face has no owner model. */\n ips_owner?: number | null;\n /** Our count per spot under the owner's definition: every vehicle occupant in view over the visible window, the slot charged to every vehicle ((flow_vph / 3600) x (slot_s + owner_def_window_s) x avo over every stream in the visibility zone). Beside ips, for the comparison with ips_owner. Unit: impressions_per_spot. NULL: As ips. */\n ips_owner_def?: number | null;\n /** High end of ips_owner_def's interval. Unit: impressions_per_spot. NULL: As ips_owner_def_low. */\n ips_owner_def_high?: number | null;\n /** Low end of ips_owner_def's interval. Unit: impressions_per_spot. NULL: As ips_owner_def, or one vehicle behind the cell. */\n ips_owner_def_low?: number | null;\n /** Flow-weighted share of the vehicles the face is legible to (a legible window above 0), each road direction's share shrunk toward the face's pooled share by its passes. Unit: share. NULL: No passes in the cell. */\n legible_share?: number | null;\n /** Length of the face's ad loop, seconds. Unit: seconds. NULL: The loop length is unknown. */\n loop_s?: number | null;\n /** Mean cabin light, lux. Unit: lux. NULL: No pass of the cell read cabin light. */\n lux_mean?: number | null;\n /** exposure_currency method version of the window. */\n method_version?: number;\n /** Moving speed past the face: the face-share-weighted median of path / (visible - stationary seconds) over the cell's passes that moved, metres per second. Unit: metres_per_second. NULL: No pass of the cell moved past the face, or the window was built before exposure_currency v6. */\n moving_speed_mps?: number | null;\n /** Ad slots in the loop. Unit: slots. NULL: The slot count is unknown. */\n n_slots?: number | null;\n /** Share of the passes in the night light band. Unit: share. NULL: No passes in the cell. */\n night_share?: number | null;\n /** Flow-weighted mean visible seconds per vehicle behind ips_owner_def, each stream shrunk toward the cell's pooled mean. Unit: seconds. NULL: As ips_owner_def. */\n owner_def_window_s?: number | null;\n /** Highest pass_audience method version among the pass audience partitions the window read. */\n pass_audience_mv_max?: number;\n /** Lowest pass_audience method version among the pass audience partitions the window read. */\n pass_audience_mv_min?: number;\n /** The board_pass rows behind the cell, one per candidate facing of a traversal: a reconciliation count, never a pass count. Unit: passes. */\n pass_rows?: number;\n /** Face passes of our map-matched vehicles past the face in the cell over the window, each traversal once (the sum of board_pass.face_share): the support. Unit: passes. NULL: The window was built before face passes (exposure_currency v6). */\n passes?: number | null;\n /** Passenger camera windows behind v_pax. Unit: windows. */\n pax_windows?: number;\n /** People per vehicle in position to see the face: v_driver + (avo - 1) x v_pax. Unit: persons_per_vehicle. NULL: No passes in the cell. */\n persons_per_vehicle?: number | null;\n /** Why yield_ratio is drawn at this face: vehicle_dominated (our count under the owner's definition reaches the vehicle share of ips_owner) or owner_vehicle_component; empty when it is not drawn. */\n population_basis?: string;\n /** Why yield_ratio is not drawn at this face: population_mismatch, audience_at_venue (a point-of-sale face), owner_derivation_unknown or owner_model_missing; empty when it is drawn. ips publishes either way. */\n population_reason?: string;\n /** Basis of the hourly traffic shape: fleet_blend (our fleet's observed traversal profile blended with the TMAS prior) or tmas_prior; empty when the face has no flow. */\n profile_basis?: string;\n /** Share of the passes in the rain band. Unit: share. NULL: No passes in the cell. */\n rain_share?: number | null;\n /** Floor CPM the measurement supports: the floor CPM x min(yield_low, the yield cap). Unit: usd_per_1000_impressions. NULL: As yield_ratio. */\n recommended_floor_cpm?: number | null;\n /** Length of one ad slot on the face, seconds. Unit: seconds. */\n slot_s?: number;\n /** Where slot_s comes from: declared, declared_range, publisher_type_median or format_default. */\n slot_source?: string;\n /** Harmonic mean speed of the passes, metres per second: one stopped pass dominates it, so the moving speed is beside it. Unit: metres_per_second. NULL: No passes in the cell. */\n speed_hmean_mps?: number | null;\n /** The owner's spots per day: its average daily impressions over its impressions per spot. Unit: spots. NULL: The face has no owner model. */\n spots_per_day_owner?: number | null;\n /** Share of the in-view seconds the passing vehicles stood still: stationary over visible seconds, face-share weighted. Unit: share. NULL: As moving_speed_mps (no visible seconds). */\n stopped_share?: number | null;\n /** Share of drivers in position to see the face. Unit: share. */\n v_driver?: number;\n /** In-cab camera instrument behind v_pax (head_yaw). */\n v_instrument?: string;\n /** Ladder level v_pax comes from: board, market or fleet; empty when v_pax is NULL. */\n v_level?: string;\n /** Passenger attention term: the share of passengers in position to see the face, from the in-cab camera (v_instrument) at the ladder level v_level. Unit: share. NULL: No ladder level (board, market, fleet) carries a passenger attention reading for the cell. */\n v_pax?: number | null;\n /** High end of v_pax's interval. Unit: share. NULL: As v_pax. */\n v_pax_high?: number | null;\n /** Low end of v_pax's interval. Unit: share. NULL: As v_pax. */\n v_pax_low?: number | null;\n /** Distinct vehicles behind those passes: the cluster the intervals are computed over. Unit: vehicles. */\n vehicles?: number;\n /** Window length in days (28). Unit: days. */\n window_days?: number;\n /** Last local date of the 28-day window. */\n window_end: string;\n /** Legible seconds per vehicle: the flow-weighted mean over the face's road and direction streams of each stream's mean legible window, each shrunk toward the cell's pooled mean by its passes. Unit: seconds. NULL: No passes in the cell. */\n window_s_mean?: number | null;\n /** Vehicle-clustered standard error of window_s_mean. Unit: seconds. NULL: No passes in the cell, or one vehicle behind it. */\n window_s_se?: number | null;\n /** ratio (the face's format carries owner impressions per spot to compare: yield_ratio is drawn) or incremental (drive-past contacts reported as incremental). */\n yield_basis?: string;\n /** High end of yield_ratio's interval. Unit: ratio. NULL: As yield_ratio. */\n yield_high?: number | null;\n /** Low end of yield_ratio's interval. Unit: ratio. NULL: As yield_ratio. */\n yield_low?: number | null;\n /** Measured over owner impressions per spot: ips / ips_owner. Unit: ratio. NULL: yield_basis is incremental, the face has no owner model, or population_reason names why the comparison is not drawn. */\n yield_ratio?: number | null;\n};\n\n/**\n * Modelled vehicles per hour past each roadside face (board_id is the venue id of the board face), by day type (weekday, saturday, sunday; holidays count as sunday) and board-local hour: directional AADT facing the face (aadt_facing, after the two-way split) x TMAS month and day factors x an hourly shape that blends our fleet's observed traversal profile with the TMAS prior (profile_basis, kappa). flow_cv is its coefficient of variation. aadt_source names the weakest basis among the ways (hpms: FHWA HPMS, whose US vintage is 2020; mtq: Quebec; imputed); aadt_year is the oldest AADT year and NULL where imputed. One snapshot, rebuilt whole; fit_window_end dates the fleet profile; the exposure_currency method version is on every row.\n * \n * **Delivery:** A snapshot, one row per `board_id` x `dow_type` x `local_hour`. Definition version 1. 13 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_flow_hourly = {\n /** Annual average daily traffic facing the face, after the two-way split. Unit: vehicles_per_day. */\n aadt_facing?: number;\n /** Weakest AADT basis among the ways: hpms (FHWA HPMS), mtq (Quebec) or imputed. */\n aadt_source?: string;\n /** Oldest AADT year among the ways. NULL: The AADT is imputed. */\n aadt_year?: number | null;\n /** The roadside face: the venue id of the board face. */\n board_id: string;\n /** Day type: weekday, saturday or sunday (holidays count as sunday). */\n dow_type: string;\n /** exposure_currency method version of the flow. */\n exposure_currency_method_version?: number;\n /** Last day of the fleet profile's fit window. */\n fit_window_end?: string;\n /** Coefficient of variation of flow_vph. Unit: ratio. */\n flow_cv?: number;\n /** Modelled vehicles per hour past the face. Unit: vehicles_per_hour. */\n flow_vph?: number;\n /** Strength of the prior against the fleet profile in the blend. NULL: The build used the TMAS prior alone. */\n kappa?: number | null;\n /** Board-local hour of the day, 0-23. */\n local_hour: number;\n /** Basis of the hourly shape: fleet_blend (our fleet's observed traversal profile blended with the TMAS prior) or tmas_prior (the prior alone). */\n profile_basis?: string;\n /** Road ways contributing to the face. Unit: ways. */\n ways?: number;\n};\n\n/**\n * One row per roadside face (board_id is the venue id of the board face) per board-local day: passes of our map-matched vehicles with the face in view, distinct vehicles, visible and legible seconds (legible = available to be read), cab occupancy, and the camera attention windows, summed over the dayparts of the measurement API's currency rollups, so a board-day here equals the API's. From local date 2026-05-12. occupied_share = occupied_passes / occupancy_known_passes, over the passes whose occupancy is known. pax_count_mean = pax_count_sum / pax_count_n: passengers per occupied pass over the occupied passes that carry a passenger count (pax_count_n), NULL on a board-day with none. Heads-up and eyes-out windows are per instrument: hy_* is head yaw, sh_* is shoulders. expected_passes is the face_share-weighted pass count for a face whose orientation is unresolved. The rollups rebuild recent local dates as later trip dates land, and a later delivery carries the rebuilt days.\n * \n * **Delivery:** Parquet day files keyed by `local_date`, one row per `local_date` x `board_id`. Definition version 2. 27 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_pass_daily = {\n /** The roadside face: the venue id of the board face. */\n board_id: string;\n /** Cabin camera windows during the passes. Unit: windows. */\n camera_windows?: number;\n /** Nielsen DMA of the face. NULL: The face is outside a DMA. */\n dma_code?: string | null;\n /** Face-share-weighted passes, for a face whose orientation is unresolved. Unit: passes. NULL: The currency rollup holds no row for the board-day. */\n expected_passes?: number | null;\n /** exposure_currency method version of the currency rollup. NULL: More than one method version, or no currency row. */\n exposure_currency_method_version?: number | null;\n /** Head-yaw instrument: windows with the eyes out of the vehicle. Unit: windows. */\n hy_eyes_out_windows?: number;\n /** Head-yaw instrument: windows with the head up. Unit: windows. */\n hy_heads_up_windows?: number;\n /** Head-yaw instrument: windows with a valid pose. Unit: windows. */\n hy_pose_valid_windows?: number;\n /** Seconds the face was legible (available to be read) over the passes. Unit: seconds. NULL: The currency rollup holds no row for the board-day. */\n legible_s?: number | null;\n /** The board's local calendar day. */\n local_date: string;\n /** Passes whose cab occupancy is known. Unit: passes. */\n occupancy_known_passes?: number;\n /** Of those, the passes with a passenger in the cab. Unit: passes. */\n occupied_passes?: number;\n /** occupied_passes / occupancy_known_passes. Unit: share. NULL: No pass with a known occupancy (occupancy_known_passes = 0). */\n occupied_share?: number | null;\n /** pass_audience method version of the audience rollup. NULL: The board-day was built under more than one method version. */\n pass_audience_method_version?: number | null;\n /** The board_pass rows behind the board-day, one per candidate facing of a traversal: a reconciliation count, never a pass count. Unit: passes. */\n pass_rows?: number;\n /** Face passes of our map-matched vehicles with the face in view: each traversal once (the sum of board_pass.face_share; a face whose facing is unresolved has one row per candidate facing at 1/k each). Unit: passes. NULL: The board-day was built before face passes (pass_audience v8). */\n passes?: number | null;\n /** Passengers per occupied pass: pax_count_sum / pax_count_n. Unit: passengers_per_pass. NULL: No occupied pass carries a passenger count (pax_count_n = 0). */\n pax_count_mean?: number | null;\n /** Occupied passes that carry a passenger count. Unit: passes. */\n pax_count_n?: number;\n /** Passengers summed over the occupied passes that carry a count. Unit: passengers. */\n pax_count_sum?: number;\n /** Media owner of the face (empty when none is recorded). */\n publisher_name?: string;\n /** Shoulder instrument: windows with the eyes out of the vehicle. Unit: windows. */\n sh_eyes_out_windows?: number;\n /** Shoulder instrument: windows with the head up. Unit: windows. */\n sh_heads_up_windows?: number;\n /** Shoulder (MoveNet) instrument: windows with a valid pose. Unit: windows. */\n sh_pose_valid_windows?: number;\n /** Passes on which this face was the site's primary face. Unit: passes. NULL: The currency rollup holds no row for the board-day. */\n site_primary_passes?: number | null;\n /** Distinct vehicles behind the passes. Unit: vehicles. */\n vehicles?: number;\n /** OpenOOH venue type id of the face (0 = unclassified). */\n venue_type_id?: number;\n /** Seconds the face was in view over the passes. Unit: seconds. NULL: The currency rollup holds no row for the board-day. */\n visible_s?: number | null;\n};\n\n/**\n * Camera frames: one JPEG per stored frame (19,622 bytes on average over the 1,000 frames of the v4 sample), from the fleet's cameras in the venues and vehicle cabins the screens are in, people in frame: the frame of every cloud vision call and, from definition 4, every frame the device uploaded while the call was capped, throttled or answered from memory (stored with no caption, response or model), and from definition 5 the rear-view board stills of the road behind the cab (capture modes board_rear*, stored the same way). Delivered as one JPEG object per call_id plus an index parquet keyed call_id (screen_id, called_at, captured_at, image_sha256, object path, the model's caption of the scene and its whole structured response, the model, the capture trigger, and the screen's registered region and venue). The v4 index holds 4,177,893 frames from 5,420 screens, 2026-05-05..10-11 (282,838 of them legacy frames before 06-21), 3,779,384 of them with a caption (measured 2026-10-13); 37,485 frames on 2026-10-10 alone. Video is the camera video corpus (camera_video_corpus).\n * \n * **Delivery:** An imagery corpus: the files plus `<corpus>-index.parquet`, one row per item, with these columns. Definition version 6. 19 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_camera_frame_corpus = {\n /** The frame's identity: the cloud vision call it was captured for. The delivered JPEG is named by it. */\n call_id: string;\n /** When the frame was sent for analysis, UTC. */\n called_at?: string;\n /** The model's description of the scene in the frame (its scene_description). NULL: The call carried no scene description: a failed or truncated cloud call, a frame an edge model analysed on the device (model local-vlm), a frame stored without a cloud call (worker frame_store), or a legacy frame. */\n caption?: string | null;\n /** The model's whole response for the frame, as JSON text: its scene description with the audience classes, extra observations, social attention, ad-fit verdict and every other key it returned (2,853 characters on average over the 1,833 whole responses of 2026-10-10 12:00-13:00 UTC; the scene description alone averages 80). NULL: The call's response is not whole JSON (a failed or truncated cloud call), the frame was stored without a cloud call (worker frame_store: no response exists), or a legacy frame. */\n caption_response?: string | null;\n /** What triggered the capture (e.g. periodic_scene, face_triggered). NULL: Not recorded (before 2026-09-24, or captured off-device). */\n capture_mode?: string | null;\n /** Why the device captured it (e.g. periodic_scene_baseline, face_detected). NULL: Not recorded (as capture_mode). */\n capture_reason?: string | null;\n /** When the camera captured the frame, UTC. NULL: Not recorded: the device shutter time is recorded from 2026-08-13; called_at is the nearest time. */\n captured_at?: string | null;\n /** Country of the screen's registered location. NULL: The screen has no registered country. */\n country?: string | null;\n /** Nielsen DMA code of the screen's registered location. NULL: Outside the US, or not geocoded. */\n dma_code?: string | null;\n /** DMA name. NULL: As dma_code. */\n dma_name?: string | null;\n /** SHA-256 (hex) of the stored JPEG, recorded when the frame was written. NULL: Not recorded: the stored hash is written from 2026-08-20; the delivered file's own hash is in the index the rail writes. */\n image_sha256?: string | null;\n /** Vision model that analysed the frame and wrote its caption. NULL: A legacy frame, or a frame stored without a cloud call (worker frame_store: the call was capped, throttled or answered from memory, or the capture mode is a rear-view board still stored by contract, so no model analysed this frame). */\n model?: string | null;\n /** That model's version. NULL: Not recorded, a legacy frame, or a frame stored without a cloud call (as model). */\n model_version?: string | null;\n /** Path of the stored JPEG in our private media store (vision-frames-private/YYYY/MM/DD/<call_id>.jpg; vision-evals/ for the legacy frames). */\n object_key?: string;\n /** Sensing profile the call ran under (e.g. transit_hub_v1). NULL: A legacy frame (the eval prefix records none). */\n profile_id?: string | null;\n /** Trillboards screen id of the camera that captured the frame. NULL: The call carried no screen id. */\n screen_id?: string | null;\n /** State or province of the screen's registered location. NULL: The screen has no registered state. */\n state?: string | null;\n /** The screen's registered venue category (transit = a vehicle cabin). NULL: Not classified. */\n venue_category?: string | null;\n /** The screen's registered venue type. NULL: Not classified. */\n venue_type?: string | null;\n};\n\n/**\n * Camera video: MP4 segments recorded by the fleet's cameras in the venues and vehicle cabins the screens are in, people in frame, delivered as one file per segment (segments/<YYYY-MM>/<segment_id>.mp4) plus an index parquet keyed segment_id, the SHA-256 of the file. Tablet cameras record H.264 segments (60 seconds, 1280x720 at 15 fps, 1,000,000 bps video with 96,000 bps AAC audio by default: 8,220,000 bytes a segment, 493,200,000 bytes a camera-hour) for as long as people are in front of the camera: back to back from the first window with a face until 20 seconds pass with none; CCTV cameras record continuously as a stream copy of the camera's own encoding. Duration, encoding, size and MD5 are measured per segment from the stored file. Labels join by time: the camera windows (faces, attention, head pose, gaze, emotion, demographics), face tracks, the cabin ride, board passes and stills that overlap each segment.\n * \n * **Delivery:** An imagery corpus: the files plus `<corpus>-index.parquet`, one row per item, with these columns. Definition version 1. 40 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_camera_video_corpus = {\n /** Build of the software that recorded the segment: the tablet agent's, or the edge connector's. */\n agent_version?: string;\n /** Audio bitrate, measured from the file. Unit: bits per second. NULL: The file carries no audio track (has_audio false), or the recorder could not measure its track. */\n audio_bitrate_bps?: number | null;\n /** Audio codec of the file (aac). NULL: The file carries no audio track (has_audio false), or its track is in a codec other than AAC (has_audio true). */\n audio_codec?: string | null;\n /** Size of the stored file. Unit: bytes. */\n bytes?: number;\n /** Hash (16 lowercase hex) of the camera calibration the device applied: segments with one hash share one camera geometry. NULL: The camera reported no calibration: every CCTV camera, and a tablet before a calibration reached it. */\n calibration_hash?: string | null;\n /** Which clock the capture times are on: device (the camera's wall clock, accepted by the server's plausibility check) or server (the time the server received the upload request, used when the device clock failed that check). */\n capture_clock?: string;\n /** When its last frame was captured, UTC, on the same clock. */\n capture_end?: string;\n /** When the segment's first frame was captured, UTC, on the clock capture_clock names. */\n capture_start?: string;\n /** Video codec of the file: h264 or hevc. */\n codec?: string;\n /** MD5 (lowercase hex) of the stored file, re-verified by the server from the stored bytes. */\n content_md5?: string;\n /** Country of the screen's registered location. NULL: The screen has no registered country (a CCTV feed is registered as a camera, not a screen). */\n country?: string | null;\n /** Nielsen DMA code of the screen's registered location. NULL: Outside the US, or not geocoded. */\n dma_code?: string | null;\n /** Nielsen DMA name of the screen's registered location. NULL: As dma_code. */\n dma_name?: string | null;\n /** Length of the segment, measured from the file. Unit: milliseconds. */\n duration_ms?: number;\n /** Frame rate, measured from the file. Unit: frames per second. */\n fps?: number;\n /** Horizontal accuracy the device reported for its fix. Unit: meters. NULL: Not a device fix: gps_source registered or none. */\n gps_accuracy_m?: number | null;\n /** When the device took that fix, UTC (at or before capture_start). NULL: Not a device fix: gps_source registered or none. */\n gps_fix_at?: string | null;\n /** Latitude (WGS84) of the position gps_source names. Unit: degrees. NULL: No position: gps_source none. */\n gps_lat?: number | null;\n /** Longitude (WGS84) of the same position. Unit: degrees. NULL: No position: gps_source none. */\n gps_lon?: number | null;\n /** Where gps_lat and gps_lon come from: device_fix (the device's last GNSS fix at or before capture_start), registered (the CCTV camera's registered location) or none. */\n gps_source?: string;\n /** Whether the file carries an audio track. */\n has_audio?: boolean;\n /** Frame height, measured from the file. Unit: pixels. */\n height?: number;\n /** Camera windows of the screen that overlap the segment: their per-window readings (faces, attention, head pose, gaze, emotion, demographics) join by time. Unit: camera windows. */\n n_audience_windows?: number;\n /** Distinct face tracks the screen's camera followed during the segment. Unit: face tracks. */\n n_face_tracks?: number;\n /** Billboard passes the vehicle made during the segment. Unit: board passes. */\n n_passes?: number;\n /** Path of the stored MP4 in our private media store (<folder>/vision-video-private/YYYY/MM/DD/<screen_id>/<segment_id>.mp4, screen_id the recording camera). */\n object_key?: string;\n /** The most faces any one camera window overlapping the segment counted: each window's instant face count (audience_metrics.face_count), the largest over the windows. Unit: faces. NULL: No camera window of the screen overlaps the segment, or none of the overlapping windows read a face count. */\n peak_face_count?: number | null;\n /** The cabin ride the segment overlaps most, for a vehicle-cabin screen. NULL: No cabin ride overlaps the segment: every CCTV segment, and a tablet segment recorded between rides. */\n ride_id?: string | null;\n /** Trillboards screen id of the camera that recorded the segment: the tablet's screen, or the CCTV feed the edge connector records. */\n screen_id?: string;\n /** The segment's identity: the SHA-256 (lowercase hex) of the MP4 file exactly as the camera uploaded it, re-verified by the server from the stored bytes. The delivered MP4 is named by it. */\n segment_id: string;\n /** Which camera recorded it: tablet (the camera of a screen in a venue or a vehicle cabin) or cctv (a venue's CCTV camera, recorded by the edge connector as a stream copy of the camera's own encoding). */\n source?: string;\n /** State or province of the screen's registered location. NULL: The screen has no registered state. */\n state?: string | null;\n /** call_id of every stored still the same camera captured during the segment (rows of the camera frame corpus); empty when none. */\n still_call_ids?: Array<unknown>;\n /** The event that started the recording: faces (people in front of the camera), or the sensing profile's own trigger id. NULL: No trigger id: a duty_cycle or continuous segment. */\n trigger_id?: string | null;\n /** Why the camera recorded: event (people in front of the camera, or another event the device detected, named in trigger_id), duty_cycle (a periodic recording, off by default) or continuous (every minute the camera is on: the CCTV recordings). */\n trigger_kind?: string;\n /** The network the file was uploaded over: wifi, cellular, ethernet or unknown. */\n upload_network?: string;\n /** When the server verified the uploaded file (SHA-256, MD5 and size read back from the stored bytes) and indexed it, UTC. */\n uploaded_at?: string;\n /** The screen's registered venue category (transit = a vehicle cabin). NULL: Not classified. */\n venue_category?: string | null;\n /** Video bitrate, measured from the file. Unit: bits per second. */\n video_bitrate_bps?: number;\n /** Frame width, measured from the file. Unit: pixels. */\n width?: number;\n};\n\n/**\n * Completed-play observations from VAST complete and proof-of-play paths.\n * \n * **Delivery:** Parquet day files keyed by `completed_at`, one row per `play_key` x `screen_mongo_id`. Definition version 4. 24 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_completed_impressions = {\n /** CPM the play was priced at, USD; pricing_source says how the price was set. Unit: usd_per_1000_plays. NULL: No price was recorded. */\n actual_cpm?: number | null;\n /** Gross revenue of the play in USD; pricing_source says how it was set. Unit: usd. NULL: No price was recorded. */\n actual_gross_revenue?: number | null;\n /** Ad id of the play. NULL: No ad id, or the pod-build placeholder ('ima_pending') of an ad whose id arrives later. */\n ad_id?: string | null;\n /** OpenRTB bid request id (joins auction_results.bid_request_id). NULL: The report carried no bid request id. */\n bid_request_id?: string | null;\n /** When the kept report says the play completed, UTC. */\n completed_at?: string;\n /** SHA-256 of the bytes of the media file that played: the creative's content identity. NULL: The report carried no content hash. */\n content_sha256?: string | null;\n /** When we stored the report, UTC. */\n created_at?: string;\n /** Creative id the demand source supplied for the ad. NULL: No creative id, or the IMA house/fallback creative ('-1' or ''). */\n creative_id?: string | null;\n /** Currency of the price. */\n currency?: string;\n /** Share of the screen the ad occupied, 0-1. Unit: share. */\n display_area_ratio?: number;\n /** How the ad was displayed (fullscreen on every row of 2026-08..10). */\n display_mode?: string;\n /** Play length the kept report carried. ad_delivery_hourly.played_seconds uses the longest positive duration over every report of the play. Unit: seconds. NULL: The kept report carried no duration (a vast_event report never does). */\n duration_seconds?: number | null;\n /** True when the play passed general invalid-traffic checks. */\n givt_passed?: boolean;\n /** Impression id the report carried. NULL: The report carried no impression id. */\n impression_id?: string | null;\n /** OpenRTB 2.6 impression multiplier applied to the play's revenue (1 on every row to date). */\n impression_multiplier?: number;\n /** Which report of the play this is: vast_event, proof_of_play, partner_sdk or owned_direct. The kept report is the one billing keeps. */\n ingestion_path?: string;\n /** The player's own id for the play. NULL: The report carried no play id. */\n play_id?: string | null;\n /** The play's identity as our billing policy keys it: the impression id, else the bid request, else the request; the request for a request-level provider and for an SDK callback without a real impression id. With screen_mongo_id it is the key. */\n play_key: string;\n /** How the price was set: openrtb_clearing_cpm, vast_pricing, a *_reporting_api value (the price a partner's reporting API reported), placement_purchase and its variants (a direct booking), cpm_estimate or config_default (a configured estimate, not a settled price), or a *_zero value for a play that earns nothing. */\n pricing_source?: string;\n /** Our ad request id (joins vast_requests.request_id). NULL: The report carried no request id. */\n request_id?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** Proof-of-play signature over the play's impression, ad, screen, device, time and event (Ed25519, or HMAC on the older version), verifiable against our published key. NULL: The report carried no signature. */\n signature?: string | null;\n /** Demand source that served the ad. */\n source_provider?: string;\n /** Serving variant (the ad-serving configuration arm) of the request or play. NULL: Not recorded. */\n variant_name?: string | null;\n};\n\n/**\n * One row per flight: one sighted creative on one face (a registered board face, or a board our cabs pass that no registry holds) from its first read to its last before a 14-day gap. Every live flight that overlaps the delivery window ships. The ledger has no retention: a flight stays after the reads and stills behind it expire. A static face runs one creative per flight, a digital face a set (set_size, the loop). From 2026-10-13, the first still read.\n * \n * **Delivery:** A snapshot, one row per `face_key` x `creative_id` x `flight_start`. Definition version 1. 29 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_creative_flights = {\n /** The registered board (the key every board dataset and the measurement API use). NULL: A point face. */\n board_id?: string | null;\n /** The creative's brand (our brand knowledge graph id), at build time. NULL: Unlabelled. */\n brand_id?: string | null;\n /** The brand's name, at build time. NULL: Unlabelled. */\n brand_name?: string | null;\n /** The identity build that wrote the row. */\n builder_version?: string;\n /** When the row was written, UTC. */\n built_at?: string;\n /** The sighted creative (sighted_creatives.creative_id): one artwork, recognised across faces and cabs. */\n creative_id: string;\n /** The face the flight ran on: f:<board_id>:<orientation_idx> for a registered board face, p:<point_id> for a board the cabs pass that no registry holds. */\n face_key: string;\n /** registered or point. */\n face_kind?: string;\n /** static or digital. */\n face_type?: string;\n /** How face_type was decided: board_dim (a registered face) or reader_surface (the surface the point's reads named most). */\n face_type_basis?: string;\n /** The last read of the creative on the face in the flight, UTC; it moves while the flight is open. */\n flight_end?: string;\n /** The first read of the creative on the face in the flight, UTC. */\n flight_start: string;\n /** A point's circular mean cab heading at its reads, degrees clockwise from north. Unit: degrees. NULL: A registered face. */\n heading_deg?: number | null;\n /** How the creative's brand was decided, at build time. NULL: Unlabelled. */\n label_kind?: string | null;\n /** A registered face's position; for a point, the mean cab position of its reads. Unit: degrees. */\n lat?: number;\n /** Longitude, as lat. Unit: degrees. */\n lon?: number;\n /** The market: a DMA code in the US, a CMA code in Canada. NULL: Unplaced. */\n market_code?: string | null;\n /** Country of the market: US or CA. NULL: Unplaced. */\n market_country?: string | null;\n /** Metro name of the market. NULL: Unplaced. */\n market_name?: string | null;\n /** 1 = no evidence the flight has ended yet. */\n open?: number;\n /** The face of the registered board, from 0. NULL: A point face. */\n orientation_idx?: number | null;\n /** Distinct cab passes among them: (cab, board pass) on a registered face, (cab, 10-minute bucket) at a point. Unit: passes. */\n passes?: number;\n /** The unregistered board point: pt- + 16 hex, stable across builds. NULL: A registered face. */\n point_id?: string | null;\n /** Reads of the creative on the face in the flight. Unit: reads. */\n reads?: number;\n /** The cabs whose reads support the flight, sorted. */\n screen_mongo_ids?: Array<unknown>;\n /** Distinct cabs among them. Unit: screens. */\n screens?: number;\n /** Creatives with 2+ passes live on the face during the flight, this one included: the loop size on a digital face, 1 on a static one. Unit: creatives. */\n set_size?: number;\n /** The creative's reads over every read of the face in the flight: about 1 on a static face, about 1/loop on a digital one. Unit: ratio. */\n share?: number;\n /** The side of the cab the point was read on: left, right or behind. NULL: Undecided. */\n vehicle_side?: string | null;\n};\n\n/**\n * L2 cross-screen transitions (cross-screen flow): ASOF JOIN over the RSSI-INDEPENDENT stable_device_id_hash emits a row when a device appears at a different screen within 1-60 minutes.\n * \n * **Delivery:** Parquet day files keyed by `dt`, one row per `dt` x `source_screen_id` x `destination_screen_id`. Definition version 3. 7 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_cross_screen_edges_daily = {\n /** Screen the device was seen at next, 1-60 minutes later. */\n destination_screen_id: string;\n /** UTC day of the transitions. */\n dt: string;\n /** Distinct transitions (device key, screens, time, lag) from the source to the destination that day. Unit: transitions. */\n edge_count?: number;\n /** Exact median minutes between the two sightings. Unit: minutes. */\n lag_p50_minutes?: number;\n /** Screen the device was seen at first. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n source_screen_id: string;\n /** Exact median great-circle distance between the two screens' stored coordinates. The transition writer stores 0 where either screen has no coordinate, so 0 means co-located or not located. Unit: meters. */\n transition_distance_p50_m?: number;\n /** Distinct device keys behind the transitions (the RSSI-independent stable key). Unit: identifiers. */\n unique_devices?: number;\n};\n\n/**\n * The sellable curated-package catalogue: one row per behavioural segment x geography, with its inventory selector, its footprint across owned screens and partner venues, its buyer copy, the panel fit that priced it WITH its Wilson interval, and which legs evidence the areas sold.\n * \n * **Delivery:** Parquet day files, one row per `package_key`. Definition version 1. 35 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_curated_inventory_packages = {\n /** Buyer-facing audience description. NULL: No audience line written. */\n audience_line?: string | null;\n /** When the package was computed, UTC (rebuilt whole each run). */\n computed_at?: string;\n /** Countries the package selects. NULL: Not restricted by country. */\n countries?: Array<unknown> | null;\n /** Buyer-facing delivery description. NULL: No delivery line written. */\n delivery_line?: string | null;\n /** Buyer-facing package name. */\n display_name?: string;\n /** Nielsen DMA code of a DMA package. NULL: A national package. */\n dma_code?: string | null;\n /** DMAs the package selects. NULL: Not restricted by DMA. */\n dma_codes?: Array<unknown> | null;\n /** DMA name. NULL: A national package. */\n dma_name?: string | null;\n /** Device keys behind the residence evidence. Unit: identifiers. NULL: Not measured. */\n evidence_device_equivalents?: number | null;\n /** Census block groups with a home-location leg behind the areas sold. Unit: block_groups. NULL: Not measured. */\n evidence_home_block_groups?: number | null;\n /** Block groups with all three legs (camera, device, MAID). Unit: block_groups. NULL: Not measured. */\n evidence_three_leg_block_groups?: number | null;\n /** Share of the block groups with all three legs. Unit: share. NULL: Not measured. */\n evidence_three_leg_share?: number | null;\n /** Strength of the residence evidence for the areas sold. NULL: Not measured. */\n evidence_tier?: string | null;\n /** Last day of the evidence window. NULL: Not measured. */\n evidence_window_end?: string | null;\n /** First day of the evidence window. NULL: Not measured. */\n evidence_window_start?: string | null;\n /** Derived floor price of the package, USD CPM. Unit: usd_per_1000_plays. NULL: No floor derived. */\n floor_cpm?: number | null;\n /** Geography of the package: national or a DMA. */\n geo_scope?: string;\n /** Buyer-facing headline. NULL: No headline written. */\n headline?: string | null;\n /** The share over the national share (1.0 = national). Unit: index. NULL: No share. */\n index_vs_national?: number | null;\n /** Our screens in the package's footprint. Unit: screens. */\n owned_screens?: number;\n /** The package's id: one behavioural segment in one geography. */\n package_key: string;\n /** Of those, the observations in the segment. Unit: observations. NULL: No share. */\n panel_match_n?: number | null;\n /** Panel screens behind the share. Unit: screens. NULL: No share. */\n panel_screens?: number | null;\n /** Panel observations the share is computed over. Unit: observations. NULL: No share. */\n panel_support_n?: number | null;\n /** Partner venues in the footprint (supply we buy). Unit: venues. */\n partner_venues?: number;\n /** Daypart where the segment concentrates most. NULL: The package does not lead on a daypart. */\n peak_daypart?: string | null;\n /** The peak daypart's share over the package's share. Unit: index. NULL: No peak daypart. */\n peak_daypart_index?: number | null;\n /** Which panel rung the share was projected from. NULL: No share. */\n projection_tier?: string | null;\n /** The merchandised segment the package sells. */\n segment_key?: string;\n /** Fitted share of the audience in the segment, 0-1. Unit: share. NULL: The segment was not observed in the package's cells (a venue-led package). */\n share?: number | null;\n /** Upper bound of the share's Wilson interval. Unit: share. NULL: No share. */\n share_ci_high?: number | null;\n /** Lower bound of the share's Wilson interval. Unit: share. NULL: No share. */\n share_ci_low?: number | null;\n /** Venue types the package selects. NULL: Not restricted by venue type. */\n venue_types?: Array<unknown> | null;\n /** Last day of that window. */\n window_end?: string;\n /** First day of the panel window the share was fitted on. */\n window_start?: string;\n};\n\n/**\n * Hourly aggregate of device_exposure_events per (screen, hour, source: ble, wifi, mdns, ssdp, http_probe): unique devices, returning and cross-screen devices, dwell + attention sums, dwell quantiles.\n * \n * **Delivery:** Parquet day files keyed by `hour`, one row per `hour` x `screen_mongo_id` x `source`. Definition version 3. 13 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_device_exposure_hourly = {\n /** Windows whose slot carried a camera attention value. Through 2026-09-23 a slot no camera window covered carried none; from 2026-09-24 the windower writes 0 for such a slot, so every window counts. Unit: exposure_windows. */\n attention_windows?: number;\n /** Of those, the keys that also appear at another screen (cross_screen_transitions). Unit: identifiers. */\n cross_screen_devices?: number;\n /** UTC hour the 6-minute exposure slots of the row started. */\n hour: string;\n /** Exposure windows: one per device key, screen, source and 6-minute slot. Unit: exposure_windows. */\n n_windows?: number;\n /** Exact median dwell of the windows. Unit: seconds. */\n p50_dwell_seconds?: number;\n /** Exact 90th-percentile dwell of the windows. Unit: seconds. */\n p90_dwell_seconds?: number;\n /** Of those, the keys seen at this screen on an earlier day (30-day look-back). Unit: identifiers. */\n returning_devices?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** Radio signal source: ble, wifi, mdns, ssdp or http_probe. */\n source: string;\n /** Sum over those windows of the slot's camera attention seconds (the slot's high or medium attention camera windows times their length); every window of a slot carries the slot's value. From 2026-09-24 a slot no camera covered counts 0. Unit: seconds. NULL: No window of the row carried a camera attention value (through 2026-09-23: no camera window covered its slots). */\n total_attention_seconds?: number | null;\n /** Sum over the windows of each window's dwell (first to last sighting in the slot). Unit: seconds. */\n total_dwell_seconds?: number;\n /** Distinct device keys (the canonical visitor id) seen at the screen in the hour on the source. Unit: identifiers. */\n unique_devices?: number;\n /** 1 when the source is one the canonical visitor count uses (ble, mdns, ssdp, http_probe), 0 for wifi. Visitor headline counts sum the rows with 1. */\n visitor_source?: number;\n};\n\n/**\n * Every device seen at every screen: one row per (screen, 6-minute slot, device, radio source) on every radio source (BLE, WiFi, mDNS, SSDP, HTTP probe; visitor_source is 1 on the sources a visitor count uses, 0 on WiFi), with the device's pings, dwell and strongest signal in the slot, the slot's camera attention, and whether the device returns to the screen or appears at another. The device is this partner's tb_<16 hex> pseudonym, the same ref every device-level file to this partner carries. From 2026-05-24 (2026-08-08 is absent from the source); the radio camera-less screens are here too.\n * \n * **Delivery:** Parquet day files keyed by `window_start`, one row per `window_start` x `screen_id` x `source` x `device_ref`. Definition version 1. 12 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_device_exposure_windows = {\n /** Camera attention seconds of the slot: its high or medium attention camera windows times their length. From 2026-09-24 a slot no camera window covered carries 0. Unit: seconds. NULL: No camera window covered the slot (stored so through 2026-09-23). */\n attention_seconds?: number | null;\n /** The device as this partner's pseudonym: tb_ + the first 16 hex of HMAC-SHA256(partner salt, the canonical visitor id). Stable across days and across every file this partner receives (and the Data API's refs under the same salt); unrelated to another partner's refs. Unit: identifiers. */\n device_ref: string;\n /** Seconds from the first to the last ping in the slot. Unit: seconds. */\n dwell_seconds?: number;\n /** 1 when the device also appears at another screen. */\n is_cross_screen?: number;\n /** 1 when the device was seen at this screen on an earlier day (30-day look-back). */\n is_returning?: number;\n /** Strongest signal of the device in the slot (closer is higher). Unit: dBm. NULL: The source reports no signal strength. */\n max_rssi?: number | null;\n /** Radio pings of the device in the slot. Unit: pings. */\n n_observations?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Radio signal source: ble, wifi, mdns, ssdp or http_probe. */\n source: string;\n /** 1 when the source is one the canonical visitor count uses (ble, mdns, ssdp, http_probe), 0 for wifi. Visitor counts take the rows with 1. */\n visitor_source?: number;\n /** Last sighting of the device in the slot, UTC. */\n window_end?: string;\n /** Start of the 6-minute exposure slot, UTC. */\n window_start: string;\n};\n\n/**\n * One row per screen id that the delivery's ClickHouse-held datasets carry in the window (audience windows, plays and per-play audience, camera inference, demographics, IP observations, radio exposure and movement, and ad serving), with its activity in the window: the first and last day and the number of days any of them holds a row of the screen, and whether its camera, its radio and its plays were among them. Screens that appear only in the lake-archived months of the raw datasets (2026-02..06) and never in those tables inside the window have no row. Deduplicated with argMax(_version), not FINAL. in_screen_registry = 0 means the screen id is one of ours but our screen registry no longer holds it, so every attribute is NULL. The ad-serving datasets also carry ids that are not screens (partner-exchange placements such as web and mobile players); those have no row here. dma_code is NULL outside the US; city is not shipped because it is 1.88% populated fleet-wide and 0% on partner screens -- use geohash6 or postal_code to place a fixed screen. publisher_name is not shipped: measured 0% on this population. The coordinate is ONE stored point: for a fixed screen its site, for a mobile screen (is_mobile, location_basis = mobile_last_known) wherever the device last synced or was enrolled. geohash_activity_hourly places a mobile screen's activity on its GPS trail, window by window. The venue_brand_* columns say which business the screen's venue is: a partner venue is tied by place agreement (a branded place in the Overture Maps catalogue within 50 m whose brand name is a whole-word part of the venue's name) or by the brand its name carries, an owned fixed screen by place agreement; a vehicle screen has no venue brand. With the brand ship its parent, the ticker and exchange of the listed company it belongs to, the link's method and confidence, and venue_brand_as_of, when the link was decided; venue_brand_id NULL with venue_brand_as_of set means the venue was examined and is no brand the graph holds. venue_brand_id is the key ride_places' pickup and drop-off brands carry.\n * \n * **Delivery:** A snapshot, one row per `screen_id`. Definition version 4. 34 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_dim_screen = {\n /** Distinct UTC days in the window with such a row. Unit: days. */\n active_days?: number;\n /** Country of the screen's registered location. NULL: Unresolved, or not in the registry. */\n country?: string | null;\n /** Nielsen DMA code. NULL: Outside the US, unresolved, or not in the registry. */\n dma_code?: string | null;\n /** DMA name. NULL: As dma_code. */\n dma_name?: string | null;\n /** Registered environment type of the screen (e.g. indoor, outdoor). NULL: Not classified, or not in the registry. */\n environment_type?: string | null;\n /** First UTC day in the delivery window on which any of the delivery's ClickHouse-held datasets holds a row of the screen. */\n first_seen?: string;\n /** Geohash-6 cell of the stored point. NULL: No stored coordinate, or not in the registry. */\n geohash6?: string | null;\n /** 1 when the window holds a camera row of the screen: a face- or person-backed audience window, a device inference row or a demographic reading. */\n has_camera?: number;\n /** 1 when the window holds a play of the screen (a report carrying the billing key, or a per-play audience row). */\n has_plays_in_window?: number;\n /** 1 when the window holds a radio row of the screen: a radio exposure window (any source), a cross-screen transition or a movement edge. */\n has_radio?: number;\n /** 1 when our screen registry holds the screen; 0 = one of our screen ids the registry no longer holds, so every registry attribute is NULL. */\n in_screen_registry?: number;\n /** 1 for a vehicle-mounted screen (venue_category transit). NULL: Not in the registry. */\n is_mobile?: number | null;\n /** The device's last heartbeat our registry holds, UTC, as of the delivery. NULL: Not in the registry. */\n last_heartbeat_at?: string | null;\n /** Last such UTC day. */\n last_seen?: string;\n /** Latitude of the screen's one stored point: its site for a fixed screen, where it last synced for a vehicle (location_basis). Unit: degrees. NULL: No stored coordinate (a (0, 0) placeholder is NULL too), or not in the registry. */\n latitude?: number | null;\n /** What the coordinate is: fixed_site, or mobile_last_known for a vehicle. NULL: No coordinate. */\n location_basis?: string | null;\n /** Longitude of the same point. Unit: degrees. NULL: As latitude. */\n longitude?: number | null;\n /** OpenOOH venue taxonomy id. NULL: Unclassified (the 0 placeholder), or not in the registry. */\n openooh_venue_type_id?: number | null;\n /** Name of the place the screen is in. NULL: No place name, or not in the registry. */\n place_name?: string | null;\n /** How the screen is placed in the venue. NULL: Not classified, or not in the registry. */\n placement_type?: string | null;\n /** Postal code of the registered location. NULL: Unresolved, or not in the registry. */\n postal_code?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** State or province of the registered location. NULL: Unresolved, or not in the registry. */\n state?: string | null;\n /** IANA timezone of the screen. NULL: No registered timezone, or not in the registry. */\n timezone?: string | null;\n /** Mapping as-of, UTC: when the venue was tied to this brand, or examined and found to be none (venue_brand_id NULL with this set). The brand's name, parent, ticker and exchange are the brand graph's at the screen's last registry sync. NULL: The screen's venue has not been examined: a vehicle screen (only fixed screens are tied to a venue brand), a screen no daily pass has reached yet, or not in the registry. */\n venue_brand_as_of?: string | null;\n /** The confidence the link's source states, 0-1: the agreeing Overture place's confidence for place_agreement, the brand extraction's for venue_brand_key. Unit: share. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. Or the link's source states no confidence. */\n venue_brand_confidence?: number | null;\n /** ISO 10383 market identifier code (MIC) of the exchange the ticker trades on, e.g. XNYS, XNAS. NULL: As venue_brand_ticker, or the listing records no exchange. */\n venue_brand_exchange?: string | null;\n /** The brand the screen's venue is, as the brand graph's id (the key ride_places' brand columns carry): a partner venue tied by place agreement or its brand key, an owned fixed screen by place agreement (venue_brand_method). NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. */\n venue_brand_id?: string | null;\n /** How the venue was tied to the brand: place_agreement (a branded place in the Overture Maps catalogue within 50 m whose brand name is a whole-word part of the venue's own name) or venue_brand_key (the brand stem read from the partner venue's name, decided once in the brand resolution store). NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. */\n venue_brand_method?: string | null;\n /** The brand's name. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. */\n venue_brand_name?: string | null;\n /** The brand's immediate parent company, as the brand graph's id. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. Or the brand graph records no parent of the brand. */\n venue_brand_parent_id?: string | null;\n /** The parent company's name. NULL: As venue_brand_parent_id. */\n venue_brand_parent_name?: string | null;\n /** Ticker of the listed company the brand belongs to: the listing of the brand's Wikidata family (the brand and the brand rows sharing its Wikidata id: one business), else of its nearest listed parent up the parent chain (a brand of a listed parent reads the parent's); a listing only our curated seed states yields to a parent's that SEC or Wikidata states. A listing is SEC EDGAR's by CIK first, then Wikidata's stock-exchange statements, then the seed's. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. Or no listing is recorded for the brand, its family or its parents. */\n venue_brand_ticker?: string | null;\n /** Registered venue category (transit = a vehicle). NULL: Not classified, or not in the registry. */\n venue_category?: string | null;\n};\n\n/**\n * VAST playback event funnel from IMA SDK (start, firstQuartile, midpoint, thirdQuartile, complete) plus heartbeat mirrors.\n * \n * **Delivery:** Parquet day files keyed by `occurred_at`, one row per `event_id`. Definition version 1. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_event_tracking = {\n /** Ad id the event belongs to. NULL: The event named no ad. */\n ad_mongo_id?: string | null;\n /** When we stored the event, UTC. */\n created_at?: string;\n /** Creative id the demand source supplied for the ad. '-1' is the IMA house/fallback creative. NULL: The event named no creative. */\n creative_id?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** The event's id. */\n event_id: string;\n /** Player event: impression, start, firstQuartile, midpoint, thirdQuartile, complete, heartbeat or error. */\n event_type?: string;\n /** Impression id the event belongs to. NULL: The event named no impression. */\n impression_id?: string | null;\n /** When the event happened, UTC. */\n occurred_at?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. NULL: The event named no screen. */\n screen_mongo_id?: string | null;\n /** Serving variant (the ad-serving configuration arm) of the request or play. */\n variant_name?: string;\n};\n\n/**\n * Camera and radio activity per geohash-6 cell, UTC hour and registered venue category, each unit placed where its screen WAS: on the map-matched vehicle path at the instant where one covers it, else at the screen's last GPS trail fix at or before it (looking back to UTC midnight 7 days before the day; fix_age_p50_s and fix_age_p90_s give the fixes' age), else, for a fixed screen, at its registered site. A vehicle's registered coordinate is never used. Camera: the face- and person-backed windows at their close, with faces, people in view, dwell and the head-pose index per window. Radio: the 6-minute slots of each screen at their midpoint, with the visitor-source identifiers (BLE, mDNS, SSDP, HTTP probe) concurrent in each, near and far field, and the distinct identifiers of the cell-hour; a row no radio slot fell in carries its radio readings NULL. The approved metric radio_identifiers_per_person (the in-cab panel's passenger near-field Bluetooth identifiers per person the camera read) converts identifiers of that population to people. Radio from 2026-05-24, camera from 2026-06-24 02:39 UTC.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `geohash6` x `venue_category`. Definition version 2. 33 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_geohash_activity_hourly = {\n /** Head-pose index, 0-1: the mean over every window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. NULL: No camera window in the row. */\n avg_attention?: number | null;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). Unit: ms. NULL: No window of the row carries a start time (dwell_capped_windows = 0). */\n avg_dwell_ms?: number | null;\n /** Mean faces per window: the device's face_count where it wrote one, else the window's mean face count. Unit: faces_per_window. NULL: No camera window in the row (observation_windows = 0). */\n avg_face_count?: number | null;\n /** The windows avg_dwell_ms averages: camera windows that carry a start time. Unit: windows. */\n dwell_capped_windows?: number;\n /** Of those, the face-backed windows. Unit: windows. */\n face_backed_windows?: number;\n /** Of those, the identifiers whose strongest signal was below it: the devices around the screen. Sources that report no signal strength (mDNS, SSDP, HTTP probe) are in neither split. Unit: identifier_slots. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_key_slots?: number | null;\n /** far_key_slots / radio_slots. Unit: identifiers_per_slot. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_keys_per_slot?: number | null;\n /** Median age of those fixes at the window's instant. Unit: seconds. NULL: No camera window of the row was placed by a trail fix. */\n fix_age_p50_s?: number | null;\n /** 90th-percentile age of those fixes. Unit: seconds. NULL: No camera window of the row was placed by a trail fix. */\n fix_age_p90_s?: number | null;\n /** Camera windows of a fixed screen with no trail fix in the lookback, placed at its registered site. Unit: windows. */\n fixed_site_positioned_windows?: number;\n /** Geohash-6 cell (about 1.2 x 0.6 km) where the screen was at the unit's instant: on its map-matched path, else at its last GPS trail fix, else (a fixed screen) at its registered site. */\n geohash6: string;\n /** Start of the UTC hour. A camera window counts in the hour it closed, a radio slot in the hour of its midpoint. */\n hour_start: string;\n /** Camera windows placed at the screen's last GPS fix at or before their instant. Unit: windows. */\n last_fix_positioned_windows?: number;\n /** The near-field boundary of the row's day: the active pass_audience method register's rf_near_rssi_dbm, the boundary the in-cab radio uses. Unit: dbm. */\n near_field_rssi_dbm?: number;\n /** Of those, the identifiers whose strongest signal in the slot was at or above near_field_rssi_dbm: in the vehicle or against the screen. Unit: identifier_slots. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_key_slots?: number | null;\n /** near_key_slots / radio_slots: near-field identifiers concurrent in one slot. The approved metric radio_identifiers_per_person converts near-field passenger Bluetooth identifiers to people: it is measured in the cab, where the driver's phone and the vehicle's own devices are removed by role. Unit: identifiers_per_slot. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_keys_per_slot?: number | null;\n /** Camera-graded windows (face- or person-backed, ~10 s each) placed in the cell. Unit: windows. */\n observation_windows?: number;\n /** Exact 95th percentile of the per-window face reading over the row's windows. Unit: faces_per_window. NULL: No camera window in the row. */\n p95_face_count?: number | null;\n /** Camera windows placed on the map-matched vehicle path at their instant. Unit: windows. */\n path_positioned_windows?: number;\n /** Of those, the person-backed windows. Unit: windows. */\n person_backed_windows?: number;\n /** The windows persons_per_window averages. Unit: windows. */\n person_reading_windows?: number;\n /** Mean people in view per camera window, faced or not: per window the larger of its mean person count and its mean face count (the in-cab panel's persons reading), over the windows that carry one. Unit: persons_per_window. NULL: No camera window of the row carries a persons reading (person_reading_windows = 0). */\n persons_per_window?: number | null;\n /** Radio slots of a fixed screen with no trail fix in the lookback, placed at its registered site. Unit: slots. */\n radio_fixed_site_positioned_slots?: number;\n /** Radio slots placed at the screen's last GPS fix at or before their midpoint. Unit: slots. */\n radio_last_fix_positioned_slots?: number;\n /** Radio slots placed on the map-matched path at their midpoint. Unit: slots. */\n radio_path_positioned_slots?: number;\n /** Radio observations of the visitor identifiers in the row's slots. Unit: pings. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_pings?: number | null;\n /** Distinct screens whose radio slots the row holds. Unit: screens. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_screens?: number | null;\n /** 6-minute radio slots of screens placed in the cell: a slot in which the screen's visitor radio read an identifier (a slot in which the scanner reported only the screen's own Wi-Fi access point does not show the visitor radio ran, and is no slot here). 0 when only camera windows fell in the row. Unit: slots. */\n radio_slots?: number;\n /** Distinct screens whose camera windows the row holds. Unit: screens. */\n screens?: number;\n /** Distinct visitor-source identifiers over the row's slots, exact. A distinct count: rows do not add. Unit: identifiers. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n unique_devices?: number | null;\n /** The screen's registered venue category (transit for a vehicle screen); empty when the registry holds none. */\n venue_category: string;\n /** Visitor-source radio identifiers (BLE, mDNS, SSDP, HTTP probe) distinct within each slot, summed over the slots. Unit: identifier_slots. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_key_slots?: number | null;\n /** visitor_key_slots / radio_slots: identifiers concurrent in one 6-minute slot, every visitor source and both fields. Unit: identifiers_per_slot. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_keys_per_slot?: number | null;\n};\n\n/**\n * OpenRTB bid-chain diagnostic records with contract validation.\n * \n * **Delivery:** Parquet day files keyed by `timestamp`, one row per `impression_event_id`. Definition version 2. 11 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_impression_events = {\n /** Ad id of the impression. NULL: No ad id, or the pod-build placeholder ('ima_pending') of an ad whose id arrives later. */\n ad_id?: string | null;\n /** OpenRTB bid request id of the impression. NULL: Not recorded. */\n bid_request_id?: string | null;\n /** Creative id the demand source supplied for the ad. NULL: No creative id, or the IMA house/fallback creative ('-1' or ''). */\n creative_id?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** Id of the player event that opened the impression. */\n event_id?: string;\n /** The impression event's id. */\n impression_event_id: string;\n /** Impression id. */\n impression_id?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** When the ad started, UTC. */\n start_time?: string;\n /** Impression status (started on every row of 2026-09-01..07). NULL: Not recorded. */\n status?: string | null;\n /** When the impression was recorded, UTC. */\n timestamp?: string;\n};\n\n/**\n * ML model inference results per video frame.\n * \n * **Delivery:** Parquet day files, one row per `inference_snapshot_id`. Definition version 3. 14 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_inference_outcomes = {\n /** Device attention composite 0-1 of the frame. Unit: index. NULL: Not measured. */\n attention_score?: number | null;\n /** Device body-engagement score 0-1 of the frame. Unit: index. NULL: Not measured. */\n body_engagement?: number | null;\n /** Daypart label in the screen's local time. NULL: Not recorded. */\n daypart?: string | null;\n /** Device emotion score 0-1 of the frame. Unit: index. NULL: Not measured. */\n emotion_score?: number | null;\n /** Faces the device model detected in the frame. Unit: faces. NULL: Not measured. */\n face_count?: number | null;\n /** Device id (fingerprint) of the screen's sensing device that ran the inference; the Data API serves the same id as device_id. */\n fingerprint?: string;\n /** Region of the image frame where attention concentrated (a position in the camera's frame, not on the street). NULL: Not measured. */\n focus_region?: string | null;\n /** When the inference ran, UTC. Every row is a camera (device) row. */\n inference_at?: string;\n /** The inference's id: one on-device model inference over one captured frame. */\n inference_snapshot_id: string;\n /** Ambient noise tier from the device microphone. NULL: No audio reading (the device writes -1). */\n noise_tier?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** Verified attention seconds the inference contributed, weighted. Unit: seconds. NULL: Not measured. */\n vas_weighted?: number | null;\n /** Venue type the device reported. NULL: Not recorded. */\n venue_type?: string | null;\n /** Weather code at the screen when the frame was taken. NULL: Not recorded. */\n weather_code?: string | null;\n};\n\n/**\n * Hashed public IP a screen egressed from, per UTC day, with ISP/ASN/geo enrichment: one row per (ip_hash, screen, observed_date).\n * \n * **Delivery:** Parquet day files keyed by `observed_at`, one row per `ip_hash` x `screen_mongo_id` x `observed_date`. Definition version 2. 12 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_ip_geo_observations = {\n /** City of the address's IP geolocation. NULL: The IP lookup returned no city. */\n city?: string | null;\n /** Line type from the IP lookup: residential, commercial, mobile or unknown. NULL: The IP lookup did not classify the line. */\n connection_type?: string | null;\n /** Country of the address's IP geolocation. NULL: The IP lookup returned no country. */\n country?: string | null;\n /** Geohash-6 cell (about 1.2 x 0.6 km) of the address's IP geolocation. NULL: The IP lookup returned no location. */\n geohash_6?: string | null;\n /** Hash of the public IP address the screen egressed from (the screen's network, never a visitor's); the address itself is not shipped. */\n ip_hash: string;\n /** 1 when the IP lookup classifies the address as residential, else 0. */\n is_residential?: number;\n /** Internet service provider of the address. NULL: The IP lookup named no provider. */\n isp?: string | null;\n /** Latest time that day the screen was seen on the address, UTC. */\n observed_at?: string;\n /** UTC day the screen's traffic left from the address. */\n observed_date: string;\n /** Organization the address is registered to. NULL: The IP lookup named no organization. */\n org?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** State or region of the address's IP geolocation. NULL: The IP lookup returned no state. */\n state?: string | null;\n};\n\n/**\n * Screen-to-screen movement per day and signal source, anchored on ad plays: identifiers seen at the source screen during a play and at the destination screen within 24 hours. Each row carries the day's distinct identifiers as a range, from unique_identifiers_floor (the largest hour-by-ad-window cell) to identifier_cell_sum (the sum of the cells); repeated_signal_count, ad_window_cells and median_lag_minutes describe the same cells.\n * \n * **Delivery:** Parquet day files keyed by `flow_date`, one row per `flow_date` x `source_screen_id` x `destination_screen_id` x `source`. Definition version 2. 9 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_mobility_flows_daily = {\n /** The hour-by-ad-window cells the row aggregates. Unit: cells. */\n ad_window_cells?: number;\n /** Screen where the same identifiers were seen within the next 24 hours. */\n destination_screen_id: string;\n /** UTC day of the source sightings. */\n flow_date: string;\n /** Sum of the cells' distinct identifiers: the most the day's distinct count can be. Unit: identifiers. */\n identifier_cell_sum?: number;\n /** Mean over the cells of each cell's median minutes from the source to the destination sighting. Unit: minutes. */\n median_lag_minutes?: number;\n /** Pairs of (source sighting, destination sighting) behind the row. Unit: signal_pairs. */\n repeated_signal_count?: number;\n /** Radio signal source of the identifiers: ble, mdns, ssdp or http_probe. */\n source: string;\n /** Screen where identifiers were seen during an ad play. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n source_screen_id: string;\n /** Distinct identifiers in the day's largest single hour-by-ad-window cell: the least the day's distinct count can be. Unit: identifiers. */\n unique_identifiers_floor?: number;\n};\n\n/**\n * Per-(observation, dimension, value) demographics at OBSERVATION grain in CH: age, gender, mood, activity state, device engagement (phone use), attire, carried items, intent, lifestyle.\n * \n * **Delivery:** Parquet day files keyed by `observed_date`, one row per `observation_id` x `dimension` x `value`. Definition version 2. 7 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_observation_demographics = {\n /** Readings of the value in the observation: 1 on every row (one row is one reading). Unit: readings. */\n count?: number;\n /** The audience attribute read (config/observationDemographicsDimensions.js): age, gender, mood, device_engagement, activity_state, intent, attire, lifestyle, carried_items and the others declared. head_turn and occupant_position are image-frame values: head_turn is turned_image_left, turned_image_right, not_turned or not_assessable (where the nose points relative to the edges of the picture), occupant_position is image_left_third, image_center_third, image_right_third or driving (the third of the picture the person occupies). Neither is a side of the vehicle or the street: a rearward cabin camera mirrors the vehicle's left and right. */\n dimension: string;\n /** The camera observation (one analysed frame window) the reading belongs to. */\n observation_id: string;\n /** When the camera observation the reading comes from was made, UTC. */\n observed_at?: string;\n /** UTC day of the reading. */\n observed_date?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** The value read for the dimension. lifestyle values are numeric IAB Audience Taxonomy 1.1 segment ids (segtax=4); the other dimensions use our own vocabulary. */\n value: string;\n};\n\n/**\n * Open Measurement SDK viewability sessions tracking MRC-compliant viewable percentage and duration per ad play.\n * \n * **Delivery:** Parquet day files keyed by `created_at`, one row per `session_id` x `created_at`. Definition version 1. 11 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_omsdk_sessions = {\n /** Ad id the session opened for. */\n ad_id?: string;\n /** OM ad session type: video on every row to date. */\n ad_session_type?: string;\n /** When the session opened, UTC. With session_id it is the key. */\n created_at: string;\n /** OM SDK events the session recorded: 1 on every row to date, the open. Unit: events. */\n event_count?: number;\n /** Impression id the session opened for. NULL: The session named no impression (1 row). */\n impression_id?: string | null;\n /** OMID API version of the session (1.4). */\n omid_api_version?: string;\n /** OM integration partner that opened the session: Trillboards, our own integration. */\n partner_name?: string;\n /** Version of that integration (1.0.0). */\n partner_version?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. NULL: The session named no screen (16 of 291.7M rows). */\n screen_id?: string | null;\n /** The Open Measurement SDK session's id. */\n session_id: string;\n /** Session status: active on every row to date (no session has recorded a close). */\n status?: string;\n};\n\n/**\n * Fitted share of a merchandised segment within (venue context x daypart x market), with a Wilson interval, from TWO panels: the Ember sensing fleet (behavioural) and the Intuizi store-visit panel (brand affinity).\n * \n * **Delivery:** Parquet day files, one row per `segment_key` x `venue_type` x `daypart` x `market`. Definition version 1. 13 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_panel_segment_cells = {\n /** Upper bound of the share's Wilson interval. Unit: share. */\n ci_high?: number;\n /** Lower bound of the share's Wilson interval. Unit: share. */\n ci_low?: number;\n /** When the cell was computed, UTC. */\n computed_at?: string;\n /** Daypart of the cell (__all__ = every daypart). */\n daypart: string;\n /** Market of the cell (__all__ = every market). */\n market: string;\n /** Evaluable observations in the segment. Unit: observations. */\n match_n?: number;\n /** Panel screens behind the cell. Unit: screens. */\n panel_screens?: number;\n /** The merchandised segment (visits-* segments come from the store-visit panel, the rest from the camera panel). */\n segment_key: string;\n /** Fitted share of the cell in the segment, 0-1. Segments overlap, so shares do not sum to 1. A segment never observed in a cell has no row. Unit: share. */\n share?: number;\n /** Evaluable observations of the cell: camera observations carrying a dimension the segment reads, or store-visit exposure edges by resolvable devices on the visits leg. Unit: observations. */\n support_n?: number;\n /** Venue context of the cell (__all__ = every venue). */\n venue_type: string;\n /** Last day of the panel window. */\n window_end?: string;\n /** First day of the panel window. */\n window_start?: string;\n};\n\n/**\n * Camera-graded activity per screen-hour, one row per (hour, screen, evidence grade): the face- and person-backed camera windows of each screen, in the UTC hour each window closed, from the governed camera screen-hour (method camera_screen_hour v3). Covers 2026-06-01 onward; MANIFEST.json classifies every day of a delivery window, with a day whose governed source holds fewer camera windows than ClickHouse's raw copy for any screen-hour marked partial. evidence_grade: face_backed or person_backed: the grade of the camera windows the row counts. observation_windows: Camera windows (about 10 s each) of the row's grade that closed in the hour. avg_face_count: Mean faces per window: the device's face_count where it wrote one, else the window's mean face count. p95_face_count: Exact 95th percentile of that per-window face reading over the hour. avg_dwell_ms: Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). dwell_capped_windows: The windows avg_dwell_ms averages: camera windows that carry a start time. dwell_over_window_windows: camera windows whose reported dwell exceeded their own length. avg_attention: Head-pose index, 0-1: the mean over every window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. head_pose_index_windows: Camera windows whose head-pose index is above 0 (a pose was read); avg_attention averages over every camera window (observation_windows). avg_gaze_pct_on_screen: the gaze instrument's on-screen share, over the windows it read. gaze_pct_windows: The windows avg_gaze_pct_on_screen averages: camera windows that carry a gaze reading. modal_crowd_density and modal_attention_level: the most frequent real reading by exact count, ties to the alphabetically first, NULL when there was none. daypart_local: Daypart label in the screen's local time. Since v3 each row also carries receptivity, the passer-by ratio and the crowded share, the modal pace, screen engagement and mood, and the 10-minute buckets of the hour with a window and with a face; since v4 the screen-hour's online and camera-on minutes. DICTIONARY.json describes every column. On 2026-09-25 the camera began closing windows more often: on the same 3,555 screens, the weeks either side, camera windows per screen-hour rose from a median of 45 to 77 (mean 57 to 108) while faces per window held (1.0585, 1.0603), so compare periods on per-window and per-minute rates, never on window counts.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `screen_id` x `evidence_grade`. Definition version 4. 35 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_place_activity_hourly = {\n /** Head-pose index, 0-1: the mean over every window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. */\n avg_attention?: number;\n /** Mean body-engagement score 0-1 over every camera window of the row (a window without the score counts 0). Unit: index. */\n avg_body_engagement?: number;\n /** Mean over every camera window of the window's crowded share 0-1: the share of its audio snapshots the device's microphone classified as crowded (a window without audio counts 0). Unit: share. */\n avg_crowded_share?: number;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). Unit: ms. NULL: No window of the row carries a start time (dwell_capped_windows = 0). */\n avg_dwell_ms?: number | null;\n /** Mean emotional engagement score 0-1 over the windows that carry one (emotional_engagement_windows). Unit: index. NULL: No window carries an emotional engagement score (emotional_engagement_windows = 0). */\n avg_emotional_engagement?: number | null;\n /** Mean faces per window: the device's face_count where it wrote one, else the window's mean face count. Unit: faces_per_window. */\n avg_face_count?: number;\n /** Mean on-screen gaze share 0-1 of the gaze instrument (FaceLandmarker) over the windows it read. Unit: share. NULL: No window of the row carries a gaze reading (gaze_pct_windows = 0). */\n avg_gaze_pct_on_screen?: number | null;\n /** Mean of the device's passer-by ratio (its estimated foot traffic over the peak face count of the window; above 1 when people pass without facing the screen) over the windows that carry one. Unit: ratio. NULL: No window carries a passer-by ratio (passerby_ratio_windows = 0). */\n avg_passerby_ratio?: number | null;\n /** Mean of the device's queue estimate per window (people waiting near the screen, from the trend of its face counts and dwell), over the windows that carry one. Unit: people_per_window. NULL: No camera window of the row carried the reading. */\n avg_pedestrian_count?: number | null;\n /** Mean ad-receptivity score 0-1 (the window's reading of how receptive the audience in view is to an ad), over the windows that carry one. Unit: index. NULL: No window carries a receptivity score (receptivity_windows = 0). */\n avg_receptivity?: number | null;\n /** Mean vehicles in view per window (the device's vehicle detector), over the windows that carry a count. Unit: vehicles_per_window. NULL: No camera window of the row carried the reading. */\n avg_vehicle_count?: number | null;\n /** Mean of the device's viewability score 0-1 (dwell, full at 1 s, times attention times the ambient-light factor, on a window with a face) over the windows that carry one. Unit: index. NULL: No window of the row saw a face (the device writes no score without one). */\n avg_viewability_score?: number | null;\n /** Minutes of the hour the sensing SDK reported it was sensing: the uptime a per-minute rate divides by. Per screen-hour, like online_minutes. Unit: minutes. NULL: The heartbeat measured none of the hour, or reported no sensing status. */\n camera_on_minutes?: number | null;\n /** Daypart label in the screen's local time. NULL: The device kept no daypart label for the hour. */\n daypart_local?: string | null;\n /** The windows avg_dwell_ms averages: camera windows that carry a start time. Unit: windows. */\n dwell_capped_windows?: number;\n /** Camera windows whose reported dwell exceeded their own length, and were capped at it in avg_dwell_ms. Unit: windows. */\n dwell_over_window_windows?: number;\n /** The windows avg_emotional_engagement averages: camera windows carrying an emotional engagement score. Unit: windows. */\n emotional_engagement_windows?: number;\n /** face_backed or person_backed: the grade of the camera windows the row counts. */\n evidence_grade: string;\n /** The windows avg_gaze_pct_on_screen averages: camera windows that carry a gaze reading. Unit: windows. */\n gaze_pct_windows?: number;\n /** Camera windows whose head-pose index is above 0 (a pose was read); avg_attention averages over every camera window (observation_windows). Unit: windows. */\n head_pose_index_windows?: number;\n /** Start of the UTC hour. A camera window counts in the hour it closed. */\n hour_start: string;\n /** True when the hour fell on a weekend day in the screen's local time (the device's label). */\n is_weekend?: boolean;\n /** The 10-minute buckets of the hour (0-6) in which a camera window of the row's grade closed: how much of the hour the camera covered. Unit: 10_minute_buckets. */\n look_buckets?: number;\n /** Most frequent attention-level reading (high, medium, low) of the hour by exact count, ties to the alphabetically first. NULL: The hour carried no real attention-level reading. */\n modal_attention_level?: string | null;\n /** Most frequent crowd-density reading of the hour by exact count, ties to the alphabetically first. NULL: The hour carried no real crowd reading (only 'unknown' or none). */\n modal_crowd_density?: string | null;\n /** Most frequent screen-engagement reading (engaged, glancing, ignoring) by exact count, ties to the alphabetically first. NULL: The hour carried no real engagement reading. */\n modal_engagement?: string | null;\n /** Most frequent mood reading of the people in view (e.g. happy, neutral, focused, bored) by exact count, ties to the alphabetically first. NULL: The hour carried no real mood reading. */\n modal_mood?: string | null;\n /** Most frequent movement-pace reading of the people in view (e.g. idle, standing, slow, strolling, moderate, hurrying) by exact count, ties to the alphabetically first. NULL: The hour carried no real pace reading. */\n modal_pace?: string | null;\n /** Camera windows (about 10 s each) of the row's grade that closed in the hour. Unit: windows. */\n observation_windows?: number;\n /** Minutes of the hour the screen was online (5 x the 5-minute buckets with a heartbeat). A property of the screen-hour: both grade rows of a screen-hour carry the same value, so take it once per (hour_start, screen_id). Unit: minutes. NULL: The heartbeat measured none of the hour. */\n online_minutes?: number | null;\n /** Exact 95th percentile of that per-window face reading over the hour. Unit: faces_per_window. */\n p95_face_count?: number;\n /** The windows avg_passerby_ratio averages. Unit: windows. */\n passerby_ratio_windows?: number;\n /** The 10-minute buckets of the hour (0-6) in which such a window saw at least one face (its peak face count above 0). Unit: 10_minute_buckets. */\n present_buckets?: number;\n /** The windows avg_receptivity averages. Unit: windows. */\n receptivity_windows?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. Only ids of that shape ship. */\n screen_id: string;\n};\n\n/**\n * The audience of each ad play: one row per logged play (our billing policy's play key on one screen per UTC day, or a partner's play), including the plays no audience window overlapped (windows_n = 0). Each camera measure is the overlap-weighted mean over the camera windows inside the play (window [window_end - 10 s, window_end), attributed when it overlaps the play widened 5 s each side), with the window count and overlap behind it, so plays re-aggregate exactly: a mean times its overlap_ms, summed, over the summed overlap_ms. Faces, head pose, gaze, facing angle per instrument (head yaw and shoulders, never pooled), dwell, receptivity, emotional engagement and emotion, audio level, ambient light and face tracks. NULL means nothing measured it, never 0. From 2026-06-24; play_audience_window lists each play's windows (audience_metrics.metric_id).\n * \n * **Delivery:** Parquet day files keyed by `play_date`, one row per `play_date` x `screen_id` x `play_source` x `play_key`. Definition version 2. 58 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_play_audience = {\n /** Ad id of the kept report. NULL: No ad id, or the pod placeholder. */\n ad_id?: string | null;\n /** Overlap-weighted mean ambient light. Unit: lux. NULL: No light reading. */\n ambient_lux_mean?: number | null;\n /** Loudest audio level over those windows. Unit: dB. NULL: No audio reading. */\n audio_db_max?: number | null;\n /** Overlapping windows carrying an audio level. Unit: windows. */\n audio_windows_n?: number;\n /** Digest of the builder SQL that built the row (pa-<12 hex>). */\n builder_version?: string;\n /** Overlap of those windows: the weight of face_count_mean and head_pose_index_mean. Unit: ms. */\n camera_overlap_ms?: number;\n /** Overlapping windows that are camera-graded: the base of every camera measure. Unit: windows. */\n camera_windows_n?: number;\n /** SHA-256 of the media file's bytes that played. NULL: The report carried none. */\n content_sha256?: string | null;\n /** Lossless issued creative-feedback v1 JSON snapshot of the kept play report; empty where none was issued. Never reconstructed from current campaign or variant state. */\n creative_feedback?: string;\n /** Creative id of the kept report. NULL: No creative id, or the IMA house/fallback creative. */\n creative_id?: string | null;\n /** The emotion with the most overlap, ties to the alphabetically first. NULL: No emotion reading. */\n dominant_emotion?: string | null;\n /** Overlap milliseconds per dominant-emotion value: the play's emotion distribution. Unit: ms. */\n dominant_emotion_overlap_ms?: Record<string, unknown>;\n /** 1 when no report carried a positive duration, so the play's interval is the 30 s default. */\n duration_imputed?: number;\n /** Overlap-weighted mean dwell, each window capped at its own length. Unit: ms. NULL: No such window. */\n dwell_capped_ms_mean?: number | null;\n /** Overlap of those windows. Unit: ms. */\n dwell_overlap_ms?: number;\n /** Camera windows with a capped dwell (a start time to cap at). Unit: windows. */\n dwell_windows_n?: number;\n /** Camera windows with a real dominant-emotion reading. Unit: windows. */\n emotion_windows_n?: number;\n /** Overlap-weighted mean emotional engagement score 0-1. Unit: index. NULL: None carried one. */\n emotional_engagement_mean?: number | null;\n /** Overlap of those windows. Unit: ms. */\n emotional_engagement_overlap_ms?: number;\n /** Camera windows carrying an emotional engagement score. Unit: windows. */\n emotional_engagement_windows_n?: number;\n /** Attributed windows by evidence grade ('' = none recorded); sums to windows_n. Unit: windows. */\n evidence_grade_windows?: Record<string, unknown>;\n /** Largest per-window face reading over the camera windows. Unit: faces. NULL: No camera window. */\n face_count_max?: number | null;\n /** Overlap-weighted mean face reading over the camera windows. Unit: faces_per_window. NULL: No camera window. */\n face_count_mean?: number | null;\n /** Per-face observation rows whose span overlaps the logged play. Unit: face_rows. */\n face_rows_n?: number;\n /** Distinct face tracks over those rows (the edge's pre-merge track id where it sent one); distinct counts do not add across plays. Unit: face_tracks. NULL: No face row. */\n face_tracks_n?: number | null;\n /** Camera windows whose face reading is above 0. Unit: windows. */\n face_windows_n?: number;\n /** Face rows carrying gaze seconds. Unit: face_rows. */\n gaze_face_rows_n?: number;\n /** Overlap of those windows: gaze_pct_on_screen's weight. Unit: ms. */\n gaze_overlap_ms?: number;\n /** Overlap-weighted mean on-screen gaze share 0-1. Unit: share. NULL: No gaze window. */\n gaze_pct_on_screen?: number | null;\n /** Gaze seconds of those rows inside the logged play. Unit: seconds. NULL: No such row. */\n gaze_seconds?: number | null;\n /** Camera windows carrying a gaze reading. Unit: windows. */\n gaze_windows_n?: number;\n /** Overlap-weighted mean head-pose index (0.4 yaw + 0.3 pitch + 0.3 eye-open) over every camera window; gaze is gaze_pct_on_screen. Unit: index. NULL: No camera window. */\n head_pose_index_mean?: number | null;\n /** Camera windows whose head-pose index is above 0 (its coverage, not its denominator). Unit: windows. */\n head_pose_windows_n?: number;\n /** Overlap-weighted share of those windows facing the screen within 30 degrees. Never pooled with the shoulder instrument. Unit: share. NULL: No such window. */\n head_yaw_heads_up_share?: number | null;\n /** Overlap of those windows. Unit: ms. */\n head_yaw_overlap_ms?: number;\n /** Camera windows whose facing angle came from the head-yaw instrument and is above 0. Unit: windows. */\n head_yaw_windows_n?: number;\n /** Impression id of the kept report. NULL: The report carried none. */\n impression_id?: string | null;\n /** The kept report's path (vast_event, proof_of_play, partner_sdk, owned_direct; partner_measurement for a partner play). */\n ingestion_path?: string;\n /** Overlap of those windows. Unit: ms. */\n lux_overlap_ms?: number;\n /** Overlapping windows with an ambient light reading. Unit: windows. */\n lux_windows_n?: number;\n /** Milliseconds of window inside the logged play, summed. Unit: ms. */\n overlap_ms_sum?: number;\n /** Of those, the windows inside the logged play itself. Unit: windows. */\n overlap_windows_n?: number;\n /** When the kept report says the play completed, UTC. */\n play_completed_at?: string;\n /** UTC day of the play (of its kept report's completion). */\n play_date: string;\n /** With play_date, screen_id and play_source it is the play: billing's partner-aware key (completed_impressions.play_key) per UTC day, or partner_id:play_id for a partner play. */\n play_key: string;\n /** Where the play is logged: completed_impressions, or partner_measurement_plays for a play a partner served. */\n play_source: string;\n /** play_completed_at minus the play's length (its longest positive reported duration, else 30 s), UTC. */\n play_started_at?: string;\n /** Overlap-weighted mean ad-receptivity score 0-1. Unit: index. NULL: None carried one. */\n receptivity_mean?: number | null;\n /** Overlap of those windows. Unit: ms. */\n receptivity_overlap_ms?: number;\n /** Camera windows carrying an ad-receptivity score. Unit: windows. */\n receptivity_windows_n?: number;\n /** Our ad request id (joins vast_requests). NULL: The report carried none. */\n request_id?: string | null;\n /** Attributed windows carrying a vision-model scene description. Unit: windows. */\n scene_frames_n?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Overlap-weighted share of those windows within 30 degrees. Unit: share. NULL: No such window. */\n shoulder_heads_up_share?: number | null;\n /** Overlap of those windows. Unit: ms. */\n shoulder_overlap_ms?: number;\n /** Camera windows whose facing angle came from the shoulder (MoveNet) instrument and is above 0. Unit: windows. */\n shoulder_windows_n?: number;\n /** Demand source of the play. */\n source_provider?: string;\n /** Audience windows attributed to the play: every window overlapping it widened by 5 s each side, any sensing mode and grade. Unit: windows. */\n windows_n?: number;\n};\n\n/**\n * Which audience windows each logged play overlapped: one row per (play, window), keys and overlap only. Join play_audience on the play key for the play and audience_metrics on window_metric_id = metric_id for the window's readings. A play with three windows is three rows: count plays in play_audience. From 2026-06-24.\n * \n * **Delivery:** Parquet day files keyed by `play_date`, one row per `play_date` x `screen_id` x `play_source` x `play_key` x `window_metric_id`. Definition version 2. 8 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_play_audience_window = {\n /** Lossless issued creative-feedback v1 JSON snapshot of this play; empty where none was issued. Same kept report as its canonical play. */\n creative_feedback?: string;\n /** Milliseconds of the window inside the logged play; 0 = attributed by the 5 s clock tolerance alone. Unit: ms. */\n overlap_ms?: number;\n /** UTC day of the play. */\n play_date: string;\n /** With play_date, screen_id and play_source it is the play: billing's partner-aware key (completed_impressions.play_key) per UTC day, or partner_id:play_id for a partner play. */\n play_key: string;\n /** completed_impressions or partner_measurement_plays. */\n play_source: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** End of the window, UTC; the window is the 10 s before it. */\n window_end?: string;\n /** The attributed audience window (joins audience_metrics.metric_id). */\n window_metric_id: string;\n};\n\n/**\n * Which devices were in range of each ad play: one row per (screen, creative, device, 6-minute exposure slot) in which a play of the creative completed on the screen while the device was in radio range, with the device's dwell, the slot's camera attention, and whether the device returned to the screen on a later day or appears at another screen. The device is this partner's tb_<16 hex> pseudonym, the same ref every device-level file to this partner carries; person_ref is the identity crosswalk's person, where one resolved. Every radio source the spine reads (BLE, WiFi, mDNS, SSDP, HTTP probe). From 2026-06-20; the spine keeps 180 days.\n * \n * **Delivery:** Parquet day files keyed by `window_start`, one row per `window_start` x `screen_id` x `creative_id` x `device_ref`. Definition version 1. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_play_device_exposure = {\n /** Ad id of the play. NULL: No ad id, or the pod placeholder. */\n ad_id?: string | null;\n /** Camera attention seconds of the slot: its high or medium attention camera windows times their length. From 2026-09-24 a slot no camera window covered carries 0. Unit: seconds. NULL: No camera window covered the slot (stored so through 2026-09-23). */\n attention_seconds?: number | null;\n /** Creative id of the play that completed inside the slot ('' = the play carried none; '-1' = the IMA house creative). */\n creative_id: string;\n /** The device as this partner's pseudonym: tb_ + the first 16 hex of HMAC-SHA256(partner salt, the canonical visitor id). Stable across days and across every file this partner receives (and the Data API's refs under the same salt); unrelated to another partner's refs. Unit: identifiers. */\n device_ref: string;\n /** Seconds from the device's first to last sighting in the slot. Unit: seconds. */\n dwell_seconds?: number;\n /** 1 when the device also appears at another screen. */\n is_cross_screen?: number;\n /** 1 when the device was seen at this screen on an earlier day (30-day look-back). */\n is_returning?: number;\n /** The person the identity crosswalk resolved the device to, as this partner's tb_ pseudonym of the crosswalk person id (the same HMAC as device_ref). NULL: No person resolved for the device. */\n person_ref?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Start of the device's 6-minute exposure slot at the screen, UTC. */\n window_start: string;\n};\n\n/**\n * Hourly screen-to-screen proximity edges: identifiable radio device keys seen at a source screen during an ad play and at another screen within 24 h.\n * \n * **Delivery:** Parquet day files keyed by `hour_bucket`, one row per `hour_bucket` x `source_screen_id` x `destination_screen_id` x `source`. Definition version 2. 9 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_proximity_graph_edges_hourly = {\n /** The (creative, ad) cells the row aggregates. Unit: cells. */\n ad_window_cells?: number;\n /** Screen where the same identifiers were seen within the next 24 hours. */\n destination_screen_id: string;\n /** UTC hour the identifiers were seen at the source screen during an ad play. */\n hour_bucket: string;\n /** Sum of the cells' distinct identifiers: the most the hour's distinct count can be (an identifier seen in two cells counts twice here). Unit: identifiers. */\n identifier_cell_sum?: number;\n /** Mean over the cells of each cell's median minutes from the source sighting to the destination sighting. Unit: minutes. */\n median_lag_minutes?: number;\n /** Pairs of (source-screen signal, destination-screen signal) behind the row, summed over its ad-window cells. Unit: signal_pairs. */\n repeated_signal_count?: number;\n /** Radio signal source of the identifiers: ble, mdns, ssdp or http_probe. */\n source: string;\n /** Screen where the identifiers were seen during the play. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n source_screen_id: string;\n /** Distinct identifiers in the largest single (creative, ad) cell of the hour: the least the hour's distinct count can be. Unit: identifiers. */\n unique_identifiers_floor?: number;\n};\n\n/**\n * Camera-measured attention, dwell and gaze in front of Trillboards screens, one row per UTC hour, country, state, city and venue category, each with the screens and camera windows behind it. A camera window is about 10 seconds of the screen's own camera, graded face_backed or person_backed (method camera_screen_hour v3); it counts in the hour it closed. The measures carry the governed camera screen-hour's names: head_pose_index_mean (attention) over every window, dwell_capped_ms_mean over the windows with a start time, gaze_pct_mean over the windows the gaze instrument read, face_count_mean, and each mean carries its window count, so rows re-merge exactly: sum(mean x windows) / sum(windows). The place is where each screen is registered (for a vehicle screen, its market). Every row ships, whatever its count. Covers 2026-06-01 onward.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `country` x `state` x `city` x `venue_category`. Definition version 1. 14 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_public_attention_city_venue_hourly = {\n /** Camera windows (about 10 s each, face_backed or person_backed) of the row's screens that closed in the hour: face_count_mean and head_pose_index_mean average over them. Unit: windows. */\n camera_windows?: number;\n /** City, from the screen registry (the screens' newest registry version): the place each screen is registered in, which for a vehicle screen (venue_category transit) is the market it is registered to. Spellings that differ only in accents and case within one country and state are one city, named by its most frequent registry spelling. NULL: The registry holds no value for the row's screens. */\n city: string | null;\n /** ISO 3166-1 alpha-2 country, from the screen registry (the screens' newest registry version): the place each screen is registered in, which for a vehicle screen (venue_category transit) is the market it is registered to. NULL: The registry holds no value for the row's screens. */\n country: string | null;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over dwell_capped_windows. Unit: ms. NULL: No window of the row carries a start time (dwell_capped_windows = 0). */\n dwell_capped_ms_mean?: number | null;\n /** The windows dwell_capped_ms_mean averages: camera windows that carry a start time. Unit: windows. */\n dwell_capped_windows?: number;\n /** Mean faces per camera window over camera_windows: the device's face_count where it wrote one, else the window's mean face count. Unit: faces_per_window. NULL: No camera window of the row carried the reading. */\n face_count_mean?: number | null;\n /** Mean on-screen gaze share 0-1 of the gaze instrument (FaceLandmarker) over gaze_pct_windows. Unit: share. NULL: No window of the row carries a gaze reading (gaze_pct_windows = 0). */\n gaze_pct_mean?: number | null;\n /** The windows gaze_pct_mean averages: camera windows that carry a gaze reading. Unit: windows. */\n gaze_pct_windows?: number;\n /** Attention as the head-pose index, 0-1: the mean over every camera window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. */\n head_pose_index_mean?: number;\n /** Camera windows whose head-pose index is above 0 (a pose was read); head_pose_index_mean averages over every camera window (camera_windows). Unit: windows. */\n head_pose_index_windows?: number;\n /** Start of the UTC hour. A camera window counts in the hour it closed. */\n hour_start: string;\n /** Distinct screens with at least one camera window in the row. Unit: screens. */\n screens?: number;\n /** State, province or region code, from the screen registry (the screens' newest registry version): the place each screen is registered in, which for a vehicle screen (venue_category transit) is the market it is registered to. NULL: The registry holds no value for the row's screens. */\n state: string | null;\n /** The screens' registered venue type (transit, retail, office, ...), the category dim_screen.venue_category carries. NULL: The registry holds no value for the row's screens. */\n venue_category: string | null;\n};\n\n/**\n * Every ride of our camera-equipped cabs (the cab's occupied camera windows, or the passenger-onboard instants its vision model read): its span, its kind (a trip, or stationary_presence: occupied windows while the cab stood still), and for the pickup and the drop-off the named place it sits in or at (Overture Maps polygons: the largest one containing the endpoint, else the nearest within 30 m, the roadside a cab stops at; an airfield is never the place, its terminals and garages are) and the brand that place is. A place is tied to its brand by a hand-checked rule naming the polygon (named_place: the Las Vegas resorts and venues, each to its operator), by its name decided once in the brand resolution store (place_name), or by a branded place in the Overture catalogue within 50 m whose brand name is part of the place's name (place_agreement). With the brand ship its parent and the ticker and exchange of the listed company it belongs to (the brand's own Wikidata family's listing, else its nearest listed parent's; SEC EDGAR by CIK first, then Wikidata, then our curated seed), as the brand graph stated them when the row was labelled (brand_mapping_as_of): a day is labelled again whenever a decision or a linked brand's company fact moves. The brand id is the key dim_screen.venue_brand_id carries. place_status says why an endpoint has no place (none, outside_coverage, no_position). From 2026-07-28; a day ships once its rides are labelled.\n * \n * **Delivery:** Parquet day files keyed by `observed_date`, one row per `observed_date` x `screen_id` x `ride_start`. Definition version 1. 43 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_ride_places = {\n /** Mapping as-of, UTC: when the row's places and brands were labelled, with the brand decisions and the brand graph's company facts (name, parent, ticker, exchange) as they stood then. A day is labelled again whenever a decision, its confidence or a linked brand's company fact moves. */\n brand_mapping_as_of?: string;\n /** camera (a run of occupied camera windows) or vlm (passenger-onboard instants the vision model read with no camera ride around them; ride_end equals ride_start). NULL: As ride_end. */\n detector?: string | null;\n /** As pickup_brand_confidence, for the drop-off. Unit: share. NULL: As pickup_brand_confidence, for the drop-off. */\n dropoff_brand_confidence?: number | null;\n /** As pickup_brand_exchange, for the drop-off. NULL: As pickup_brand_exchange, for the drop-off. */\n dropoff_brand_exchange?: string | null;\n /** As pickup_brand_id, for the drop-off. NULL: As pickup_brand_id, for the drop-off. */\n dropoff_brand_id?: string | null;\n /** As pickup_brand_m, for the drop-off. Unit: meters. NULL: As pickup_brand_m, for the drop-off. */\n dropoff_brand_m?: number | null;\n /** As pickup_brand_method, for the drop-off. NULL: As pickup_brand_method, for the drop-off. */\n dropoff_brand_method?: string | null;\n /** As pickup_brand_name, for the drop-off. NULL: As pickup_brand_name, for the drop-off. */\n dropoff_brand_name?: string | null;\n /** As pickup_brand_parent_id, for the drop-off. NULL: As pickup_brand_parent_id, for the drop-off. */\n dropoff_brand_parent_id?: string | null;\n /** As pickup_brand_parent_name, for the drop-off. NULL: As pickup_brand_parent_name, for the drop-off. */\n dropoff_brand_parent_name?: string | null;\n /** As pickup_brand_ticker, for the drop-off. NULL: As pickup_brand_ticker, for the drop-off. */\n dropoff_brand_ticker?: string | null;\n /** As pickup_place_class, for the drop-off. NULL: As pickup_place_class, for the drop-off. */\n dropoff_place_class?: string | null;\n /** As pickup_place_id, for the drop-off. NULL: As pickup_place_id, for the drop-off. */\n dropoff_place_id?: string | null;\n /** As pickup_place_m, for the drop-off. Unit: meters. NULL: As pickup_place_m, for the drop-off. */\n dropoff_place_m?: number | null;\n /** As pickup_place_name, for the drop-off. NULL: As pickup_place_name, for the drop-off. */\n dropoff_place_name?: string | null;\n /** As pickup_place_status, for the drop-off. */\n dropoff_place_status?: string;\n /** As pickup_place_subtype, for the drop-off. NULL: As pickup_place_subtype, for the drop-off. */\n dropoff_place_subtype?: string | null;\n /** As pickup_place_type, for the drop-off. NULL: As pickup_place_type, for the drop-off. */\n dropoff_place_type?: string | null;\n /** As pickup_position_source, for the drop-off. NULL: As pickup_position_source, for the drop-off. */\n dropoff_position_source?: string | null;\n /** UTC day the ride started (ride_start). */\n observed_date: string;\n /** Overture Maps release the places were read from (e.g. 2026-08-19.0). */\n overture_release?: string;\n /** The confidence the link's source states, 0-1: the brand decision's for named_place and place_name, the agreeing Overture place's for place_agreement. Unit: share. NULL: As pickup_brand_id, or the link's source states no confidence. */\n pickup_brand_confidence?: number | null;\n /** ISO 10383 market identifier code (MIC) of the exchange the ticker trades on, e.g. XNYS, XNAS. NULL: As pickup_brand_ticker, or the listing records no exchange. */\n pickup_brand_exchange?: string | null;\n /** The brand the pickup place is, as the brand graph's id (the key dim_screen.venue_brand_id carries). NULL: No brand: the pickup is at no named place, or the place is no brand the graph holds. */\n pickup_brand_id?: string | null;\n /** Metres from the pickup to the place (0 inside) for named_place and place_name; to the agreeing branded place for place_agreement. Unit: meters. NULL: As pickup_brand_id. */\n pickup_brand_m?: number | null;\n /** How the place was tied to its brand: named_place (a hand-checked rule naming that polygon), place_name (the place's name, decided once in the brand resolution store), or place_agreement (a branded place in the Overture Maps catalogue within 50 m of the pickup whose brand name is a whole-word part of the place's name). NULL: As pickup_brand_id. */\n pickup_brand_method?: string | null;\n /** The brand's name. NULL: As pickup_brand_id. */\n pickup_brand_name?: string | null;\n /** The brand's immediate parent company, as the brand graph's id. NULL: As pickup_brand_id, or the brand graph records no parent of the brand. */\n pickup_brand_parent_id?: string | null;\n /** The parent company's name. NULL: As pickup_brand_parent_id. */\n pickup_brand_parent_name?: string | null;\n /** Ticker of the listed company the brand belongs to: the listing of the brand's Wikidata family (the brand and the brand rows sharing its Wikidata id: one business), else of its nearest listed parent up the parent chain (a brand of a listed parent reads the parent's); a listing only our curated seed states yields to a parent's that SEC or Wikidata states. A listing is SEC EDGAR's by CIK first, then Wikidata's stock-exchange statements, then the seed's. NULL: As pickup_brand_id, or no listing is recorded for the brand, its family or its parents. */\n pickup_brand_ticker?: string | null;\n /** Overture class of the place (e.g. international_airport, hotel, retail). NULL: As pickup_place_id, or Overture states no class. */\n pickup_place_class?: string | null;\n /** Overture Maps GERS id of the place: the largest named polygon containing the pickup, else the nearest within 30 m (an airfield polygon is never the place; its terminals and garages are). NULL: pickup_place_status is not named. */\n pickup_place_id?: string | null;\n /** 0 when the place contains the pickup, else the metres from the pickup to it (at most 30 m: the roadside a cab stops at). Unit: meters. NULL: As pickup_place_id. */\n pickup_place_m?: number | null;\n /** Name of the place, e.g. an airport terminal, a resort, a store, a stadium. NULL: As pickup_place_id. */\n pickup_place_name?: string | null;\n /** named (the pickup sits in or at a named place), none (inside the loaded map coverage, no named place within 30 m), outside_coverage (beyond the loaded map extent) or no_position (the ride has no pickup position). */\n pickup_place_status?: string;\n /** Overture subtype of the place (e.g. airport, commercial, entertainment). NULL: As pickup_place_id, or Overture states no subtype. */\n pickup_place_subtype?: string | null;\n /** Overture theme type of the place polygon: building, land_use or infrastructure. NULL: As pickup_place_id. */\n pickup_place_type?: string | null;\n /** Where the pickup position comes from: matched_path (the map-matched vehicle path at the instant), asof_last_fix (the cab's last GPS fix before it) or none. NULL: The ride was rebuilt after its places were labelled; the next labelling of the day carries it. */\n pickup_position_source?: string | null;\n /** End of the ride, UTC: the last occupied window end, or the last onboard instant. NULL: The ride was rebuilt after its places were labelled; the next labelling of the day carries it. */\n ride_end?: string | null;\n /** Stable id of the ride (a 64-bit hash of the screen and ride_start, as text). */\n ride_id?: string;\n /** ride, or stationary_presence: occupied camera windows while the cab stood still (its path moved less than the stationary threshold), not a trip. NULL: As ride_end. */\n ride_kind?: string | null;\n /** Start of the ride, UTC: the cab's first occupied camera window, or the first passenger-onboard instant its vision model read (detector). */\n ride_start: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. The cab's screen. */\n screen_id: string;\n};\n\n/**\n * Camera x radio co-presence per screen-hour: radio devices from the visitor sources the resolved radio buckets carry (BLE and mDNS) in each 5-minute bucket, joined to the face- or person-backed camera windows that closed within 15 seconds of it. unique_devices counts the distinct canonical visitor keys of the screen-hour. evidence_grade is the grade of the latest such camera window. face_present_windows counts buckets whose camera window read at least 0.5 of a face (the face_count primitive, else the per-window mean). attention_high_windows counts buckets whose window qualifies under the published attention rule. total_radio_pings sums every visitor source. Covers 2026-06-24 02:39 UTC onward, where both sources exist.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `screen_mongo_id` x `evidence_grade`. Definition version 2. 8 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_screen_hourly_presence = {\n /** Of those, the pairs whose camera window qualifies under the published attention rule. Unit: device_buckets. */\n attention_high_windows?: number;\n /** Grade (face_backed or person_backed) of the latest camera window that closed within 15 s of a bucket of the row. */\n evidence_grade: string;\n /** Of those, the pairs whose camera window read at least half a face. Unit: device_buckets. */\n face_present_windows?: number;\n /** Start of the UTC hour. The hour of the 5-minute radio bucket. */\n hour_start: string;\n /** Distinct (visitor key, 5-minute bucket) pairs. Unit: device_buckets. */\n observation_windows?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** Radio pings of the visitor keys in those buckets (each key and bucket's largest cluster size, capped at 255). Unit: pings. */\n total_radio_pings?: number;\n /** Distinct canonical visitor keys (BLE, mDNS, SSDP, HTTP probe) in the screen-hour's buckets that had a camera window within 15 s. Unit: identifiers. */\n unique_devices?: number;\n};\n\n/**\n * The screen panel: one row per (month, panel, screen) of every screen whose camera (panel camera) or visitor radio (panel radio) was up on at least one UTC day of the month. Membership is by uptime, not by audience: a camera that ran and saw nobody is a member. The evidence is the activity dim_screen is built from, plus the heartbeat: camera windows, the camera pipeline's inference rows (the census predicate), vision demographic readings and heartbeat camera-on minutes; visitor-source radio windows, cross-screen transitions and movement edges. evidence_days counts the days of each. audience_rate is visitor identifiers per 6-minute slot on the radio panel (audience per unit time) and faces per occupied camera window on the camera panel (the group in view while someone is in view); the 2026-09-25 camera cadence step (median windows per screen-hour 45 to 77, faces per window flat) moves neither. in_previous_month marks the screens of the same panel the month before, NULL unless that month is built whole; the approved metric same_panel_index compares the rate month over month on those screens, on the evidence kinds both months hold. Every month that begins in the delivery window, its days inside the window (days_built, month_complete). The panel holds days from 2026-05-24, the first visitor radio windows; camera windows from 2026-06-01, vision demographic readings from 2026-07-16, heartbeat camera-on minutes from 2026-08-26. A day's camera_inference evidence is the inference rows ClickHouse held when the day was built (it keeps them 90 days), so a day first built later than that carries none.\n * \n * **Delivery:** A snapshot, one row per `month` x `panel` x `screen_id`. Definition version 1. 16 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_screen_panel_monthly = {\n /** UTC days of the month the instrument was up (any evidence in evidence_days): the membership. Unit: days. */\n active_days?: number;\n /** audience_sum / audience_units. radio: identifiers concurrent in a 6-minute slot, audience per unit time. camera: faces per occupied window, the group in view while someone is in view, not audience per unit time. A change in how often an instrument reports moves neither. NULL: No audience unit in the month (audience_units = 0). */\n audience_rate?: number | null;\n /** camera: faces summed over those windows; radio: visitor-source identifiers distinct within each slot, summed over the slots. */\n audience_sum?: number;\n /** camera: the face- and person-backed camera windows of the month (~10 s each, made only while someone is in view); radio: the 6-minute slots in which the screen's visitor radio read an identifier. */\n audience_units?: number;\n /** Heartbeat minutes the sensing SDK reported it was sensing, over the active days. Unit: minutes. NULL: The heartbeat measured none of the active days. */\n camera_on_minutes?: number | null;\n /** Days of the month inside the delivery window that the panel holds. Unit: days. */\n days_built?: number;\n /** Active days per kind of evidence. camera: camera_window, camera_inference (the camera pipeline ran, empty scenes included), camera_demographics, camera_heartbeat (the sensing SDK reported sensing); radio: radio_visitor_window, radio_transition, radio_movement_edge. Unit: days. */\n evidence_days?: Record<string, unknown>;\n /** First active day of the month. */\n first_active_day?: string;\n /** 1 when the screen was in the same panel the month before, else 0. NULL: The previous month is not built whole (the panel starts in it, or a day of it is missing): no answer is drawn from part of a month. */\n in_previous_month?: number | null;\n /** Last active day of the month. */\n last_active_day?: string;\n /** First day of the UTC calendar month. */\n month: string;\n /** 1 when every day of the month is built. */\n month_complete?: number;\n /** Heartbeat minutes the screen was online over its active days. Unit: minutes. NULL: The heartbeat measured none of the active days. */\n online_minutes?: number | null;\n /** camera or radio: the instrument whose uptime made the screen a member. */\n panel: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Of those, the days with the panel's own audience evidence: a face- or person-backed camera window (camera); a visitor-source radio window (radio). Unit: days. */\n window_days?: number;\n};\n\n/**\n * One row per live sighted creative read in the delivery window: an artwork recognised across faces and cabs from its reads (crop embeddings, the words read and the brand evidence), with its brand, its reads, cabs, faces, points and markets, and its sharpest read, whose still is kept in the proof archive. The registry has no retention. From 2026-10-13, the first still read.\n * \n * **Delivery:** A snapshot, one row per `creative_id`. Definition version 1. 20 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_sighted_creatives = {\n /** Its brand (our brand knowledge graph id). NULL: Unlabelled. */\n brand_id?: string | null;\n /** The brand's name. NULL: Unlabelled. */\n brand_name?: string | null;\n /** The identity build that wrote the row. */\n builder_version?: string;\n /** When the row was written, UTC. */\n built_at?: string;\n /** The sighted creative: sc- + 16 hex, stable across builds. One artwork our cab cameras read, recognised across faces and cabs. */\n creative_id: string;\n /** Of reads, the ones a tablet read on the edge (edge_ocr_v1). Unit: reads. */\n edge_reads?: number;\n /** Distinct registered faces it was read on. Unit: faces. */\n faces?: number;\n /** Its first read, UTC. */\n first_seen?: string;\n /** Reads whose own evidence names another brand. Unit: reads. */\n label_conflicts?: number;\n /** How its brand was decided. NULL: Unlabelled. */\n label_kind?: string | null;\n /** Reads whose own evidence names the label. Unit: reads. */\n label_support?: number;\n /** Its last read, UTC. */\n last_seen?: string;\n /** The markets it was read in, as COUNTRY:CODE. */\n markets?: Array<unknown>;\n /** Distinct unregistered board points it was read on. Unit: points. */\n points?: number;\n /** Reads of it. Unit: reads. */\n reads?: number;\n /** The ad of that read, as in board_creative_sighting. NULL: No representative read. */\n rep_ad_ordinal?: number | null;\n /** The instrument of that read: ssr-v1, vlmtext-v1 or edge_ocr_v1. NULL: No representative read. */\n rep_instrument_version?: string | null;\n /** Its sharpest read: the still's call id for a cloud read (the camera_frame_corpus key), the reading id for an edge read. NULL: No read with a stored still and a box. */\n rep_still_call_id?: string | null;\n /** Distinct cabs that read it. Unit: screens. */\n screens?: number;\n /** Its most supported words, most supported first, at most 12. */\n words?: Array<unknown>;\n};\n\n/**\n * Raw VAST request telemetry.\n * \n * **Delivery:** Parquet day files keyed by `requested_at`, one row per `request_id` x `requested_at`. Definition version 3. 37 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_vast_requests = {\n /** VAST AdSystem of the response (empty when none). */\n ad_system?: string;\n /** Advertiser the ad response named. NULL: The response named no advertiser. */\n advertiser_name?: string | null;\n /** Id of the auction request the ad request triggered. NULL: The request ran no auction. */\n auction_request_id?: string | null;\n /** Buyer seat of the winning bid (empty when none). */\n buyer_seat?: string;\n /** Clearing price the response carried, USD CPM. Unit: usd_per_1000_plays. NULL: No price was returned. */\n clearing_cpm?: number | null;\n /** True once the ad completed (a latch: it never reverts). */\n completed?: boolean;\n /** MIME type of the media file returned (empty when none). */\n content_type?: string;\n /** Creative id the demand source supplied for the ad. NULL: No creative id, or the IMA house/fallback creative ('-1' or ''). */\n creative_id?: string | null;\n /** Landing page (click-through) of the creative served. NULL: The response named no landing page. */\n creative_landing_url?: string | null;\n /** Currency of the price (empty when none). */\n currency?: string;\n /** Device family of the player (e.g. Amazon Fire TV, Android box, Samsung tablet). NULL: Not classified. */\n device_category?: string | null;\n /** Player environment the request declared (e.g. ctv). NULL: Not classified. */\n device_environment?: string | null;\n /** OpenRTB device type the player declared. NULL: Not sent. */\n device_type_hint?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** Serving experiment arms the request was assigned (JSON). NULL: The request was in no serving experiment. */\n experiment_assignments?: string | null;\n /** Google IMA SDK error code. NULL: No IMA error. */\n ima_error_code?: number | null;\n /** Time to answer the request, milliseconds. Unit: ms. NULL: Not recorded. */\n latency_ms?: number | null;\n /** URL of the creative's media file. NULL: The response named no media file. */\n media_url?: string | null;\n /** Bids the OpenRTB auction returned. Unit: bids. NULL: The request was not an OpenRTB auction. */\n openrtb_bid_count?: number | null;\n /** Seats that bid in the OpenRTB auction. Unit: seats. NULL: The request was not an OpenRTB auction. */\n openrtb_seat_count?: number | null;\n /** Latest outcome of the request: requested, bid_received, no_bid, no_fill, filled, redirect, player_served, completed, skipped, timeout or error. NULL: Not recorded. */\n outcome?: string | null;\n /** Operating system the player declared. NULL: Not sent. */\n platform_hint?: string | null;\n /** Our ad request id. With requested_at it is the key; to count requests keep the latest requested_at per request_id. */\n request_id: string;\n /** SHA-256 of the request's host, path and query parameters (correlator and request id excluded): one value per request shape. NULL: Not computed (an older server-built request). */\n request_signature_hash?: string | null;\n /** How the request was built: vast_wrap, server_constructed, proxy_auction, client_lifecycle or partner_sdk. NULL: Not recorded. */\n request_source?: string | null;\n /** When the request was made, UTC (a partner-supplied request id is re-stamped at each later update). */\n requested_at: string;\n /** OpenRTB supply chain object (JSON) of the request. NULL: The request carried no supply chain. */\n schain?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. Partner-exchange placements carry a non-screen id here. */\n screen_mongo_id?: string;\n /** Ad SDK of the player (e.g. google-ima). NULL: Not sent. */\n sdk_type?: string | null;\n /** Version of that SDK. NULL: Not sent. */\n sdk_version?: string | null;\n /** Demand source the request was sent to. NULL: Not recorded. */\n source_name?: string | null;\n /** VAST extensions the upstream response carried (JSON). NULL: The upstream response carried no extensions. */\n upstream_extensions?: string | null;\n /** Serving variant (the ad-serving configuration arm) of the request or play. */\n variant_name?: string;\n /** VAST error code. NULL: No VAST error. */\n vast_error_code?: number | null;\n /** Shape of the VAST response: inline, inline_resolved, wrapper_passthrough or empty. NULL: Not classified. */\n vast_type?: string | null;\n /** Venue category of the screen at request time. NULL: Not recorded. */\n venue_type?: string | null;\n /** Position of the demand source in the screen's waterfall. NULL: Not in a waterfall. */\n waterfall_position?: number | null;\n};\n\nexport type DataApi_DataProducts_AudienceRow = {\n /** Interval upper bound. */\n ci_high: number | null;\n /** Interval lower bound. */\n ci_low: number | null;\n /** Daypart, or `__all__`. */\n daypart: string;\n /** Audience dimension (occupancy, age, gender, activity, mood, ...). */\n dimension: string;\n /** dense_measure (measured on every pass), face_blend (age, gender, cohort, intent from pass_audience v8: the face's own camera share blended with its area or market share in proportion to how many riders the face measured) or mrp_label (the area model's share, earlier versions). */\n estimand_kind: string;\n fit_window: {\n /** Last day. */\n end: string;\n /** First day. */\n start: string;\n } | null;\n /** This board's share against its DMA (1.0 = same). */\n index_vs_dma: number | null;\n /** Matched observations (owner mount), weighted. */\n match_n?: number | null;\n /** Its upper bound. */\n measured_ci_high: number | null;\n /** Its lower bound. */\n measured_ci_low: number | null;\n /** The share measured at this board alone. */\n measured_share: number | null;\n /** Observations at this board. */\n measured_support_n: number | null;\n /** Level the share resolved at (board_daypart, board, dma, geohash5, ...). */\n resolved_level: string | null;\n /** Share of the passing audience with this value. */\n share: number | null;\n /** Observations the share rests on. */\n support_n: number | null;\n /** share, or a mean per pass (approved-metric answers). */\n unit?: string;\n /** Measurement units (owner mount). */\n units?: number | null;\n /** The dimension value. */\n value: string;\n /** Distinct vehicles behind those observations. */\n vehicles: number | null;\n};\n\nexport type DataApi_DataProducts_AuthError = {\n /** NO_TOKEN, TOKEN_EXPIRED, TOKEN_REVOKED, INVALID_API_KEY, INSUFFICIENT_SCOPE, ... */\n code: string;\n /** Why the credential was refused. */\n message: string;\n /** The scopes the key must hold (INSUFFICIENT_SCOPE). */\n required_scopes?: Array<string>;\n success?: false;\n};\n\nexport type DataApi_DataProducts_Benchmark = {\n market: {\n /** Market code. */\n code: string;\n /** dma or cma. */\n kind: string;\n };\n measured_ips?: {\n deciles: Array<{\n /** Quantile. */\n q: number;\n /** Value. */\n value: number;\n }>;\n /** Highest. */\n max: number;\n /** Median. */\n median: number;\n /** Lowest. */\n min: number;\n /** First quartile. */\n q25: number;\n /** Third quartile. */\n q75: number;\n };\n /** Comparable faces in the market. */\n peers: number;\n /** Its percentile. */\n percentile?: number;\n /** This face's rank among them by measured impressions per spot. */\n rank?: number;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n};\n\nexport type DataApi_DataProducts_BoardAudience = {\n /** Board face id. */\n board_id: string;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours: Record<string, Array<number>>;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_AudienceRow>;\n window: DataApi_DataProducts_Window;\n};\n\nexport type DataApi_DataProducts_BoardAudienceResponse = {\n data: DataApi_DataProducts_BoardAudience;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BoardCurrency = {\n absent: Array<DataApi_DataProducts_CurrencyAbsent>;\n board: DataApi_DataProducts_CurrencyBoard;\n /** The condition scope the cells are split by. */\n by: string;\n cells: Array<DataApi_DataProducts_CurrencyCell>;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours: Record<string, Array<number>>;\n loop: {\n /** Loop length, seconds (owner mount). */\n loop_s?: number | null;\n /** Spots in the loop (owner mount). */\n n_slots?: number | null;\n /** Spot length, seconds. */\n slot_s: number | null;\n /** declared, owner_spec or format default. */\n slot_source: string | null;\n } | null;\n method: DataApi_DataProducts_Method;\n owner?: {\n /** The owner's average daily impressions. */\n avg_daily_impressions: number | null;\n /** The face's floor CPM, USD. */\n floor_cpm_usd: number | null;\n /** The owner's impressions per spot. */\n impressions_per_spot: number | null;\n /** The owner's spots per day. */\n spots_per_day: number | null;\n };\n /** Owner mount: the catalogue the owner figures come from. */\n source?: string;\n window: DataApi_DataProducts_Window & {\n built_at?: string;\n };\n};\n\nexport type DataApi_DataProducts_BoardCurrencyResponse = {\n data: DataApi_DataProducts_BoardCurrency;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BoardLookedShare = {\n /** Board face id. */\n board_id: string;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_LookedShareRow>;\n /** What the share is, in words. */\n what_this_measures: string;\n window: {\n /** First local date. */\n from: string;\n /** Last local date. */\n to: string;\n };\n};\n\nexport type DataApi_DataProducts_BoardLookedShareResponse = {\n data: DataApi_DataProducts_BoardLookedShare;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BoardPointCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_BoardPointProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_BoardPointMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_BoardPointMeta = {\n audience?: {\n /** The dimension asked for (audience=). */\n dimension: string;\n /** face_blend: the face rows of pass_audience v8. */\n estimand_kind: string;\n /** Its value. */\n value: string;\n };\n /** The bbox drawn. */\n bbox: Array<number>;\n /** The brand searched (brand=). */\n brand?: string | null;\n /** Points returned. */\n count: number;\n filters?: {\n /** The face types asked for (type=). */\n faceTypes: Array<string>;\n /** The formats asked for (format=). */\n formats: Array<string>;\n /** The owners asked for (owner=). */\n owners: Array<string>;\n /** The venue type ids asked for (venue=). */\n venueTypeIds: Array<number>;\n } | null;\n /** Extra layers drawn (sightings). */\n layers?: Array<string>;\n /** The curated set drawn, or null. */\n set_key: string | null;\n sighting_window?: {\n /** Days in the window. */\n days: number;\n /** First day of the sighting window. */\n since: string;\n /** Day after its last. */\n until_exclusive: string;\n };\n /** The points were capped at the overlay limit. */\n truncated: boolean;\n /** Unmatched sightings drawn (layers=sightings). */\n unmatched_sighting_count?: number;\n /** The sighting layer was capped. */\n unmatched_sightings_truncated?: boolean;\n /** Viewshed build version. */\n viewshed_version: string | null;\n watermark?: DataApi_DataProducts_Watermark;\n /** Currency window end. */\n window_end: string | null;\n};\n\nexport type DataApi_DataProducts_BoardPointProperties = {\n /** Advertiser as read (unmatched sighting). */\n advertiser?: string | null;\n /** With `audience=`: the level the blend's prior came from (geohash5, dma_daypart, national, ...). */\n audience_level?: string | null;\n /** With `audience=`: the distinct riders the face measured for that dimension (the row's n). */\n audience_n?: number | null;\n /** With `audience=`: the share of the passing riders with that value, measured at this face (pass_audience v8: its own camera share blended with its area or market share by the riders it measured). Null where the window carries no face row for the value. */\n audience_share?: number | null;\n /** Board structure id. */\n board_id?: string;\n /** Brand as read (unmatched sighting). */\n brand?: string | null;\n /** Cab heading, degrees (unmatched sighting). */\n cab_heading_deg?: number | null;\n /** With `brand=`: sightings of that brand on this board. */\n camera_brand_sightings?: number | null;\n /** Newest sighting on the board, UTC. */\n camera_last_sighted_at?: string | null;\n /** Distinct brands among those sightings. */\n camera_sighting_brands?: number | null;\n /** Ads our cab cameras read on this board in the sighting window (paid placements only). Null where no reading matched to it. */\n camera_sightings?: number | null;\n /** The most-read brands on the board, with their sightings. */\n camera_top_brands?: Array<{\n /** Brand as read. */\n brand: string;\n /** Sightings of it on this board. */\n sightings: number;\n }> | null;\n /** Sightings that saw the face carrying no advertiser. */\n camera_vacancy_sightings?: number | null;\n /** City. */\n city?: string | null;\n /** ISO-3166 alpha-2. */\n country?: string | null;\n /** Name shown on the card. */\n display_name?: string | null;\n /** What the face is: digital (a screen) or static (a printed board). The value the `type` filter reads. */\n face_type?: string | null;\n faces?: Array<{\n /** Direction the face points, degrees. */\n azimuth_deg: number | null;\n /** Face index. */\n orientation_idx: number;\n /** Share of the structure's passes the face serves. */\n orientation_share: number;\n }>;\n /** The face's format (a digital face's pixel-size class, a static face's type): the value the `format` filter reads. */\n format_label?: string | null;\n /** Billboard, Digital board, Street furniture, ... */\n inventory_type_label?: string | null;\n /** Measured impressions per spot (numbered points). */\n ips?: number | null;\n /** Why a measured face carries no impressions per spot (`no_slot`: a static face has no slot). Null where it carries one. */\n ips_absent_reason?: string | null;\n /** Interval upper bound. */\n ips_high?: number | null;\n /** Interval lower bound. */\n ips_low?: number | null;\n /** Who ips counts: `vehicle_occupants`. */\n ips_population?: string;\n /** The face carried no advertiser (unmatched sighting). */\n is_vacancy?: boolean;\n /** board, or unmatched_sighting (layers=sightings). */\n kind: string;\n /** Latitude. */\n latitude?: number | null;\n /** Longitude. */\n longitude?: number | null;\n /** Market name (unmatched sighting). */\n market_name?: string | null;\n /** unmatched or no_candidate (unmatched sighting). */\n match_status?: string | null;\n /** The face has passes in the current currency window (whatever its impressions per spot). */\n measured?: boolean;\n /** Board name. */\n name?: string | null;\n /** Face passes behind the figure (the sum of each pass's share of this face, a fraction where a facing is unresolved). Null on a window built before exposure_currency v6. */\n passes?: number | null;\n /** Place name. */\n place_name?: string | null;\n /** Media owner. */\n publisher_name?: string | null;\n /** The Find Screens card id for the board. */\n screen_id?: string | null;\n /** Still instant, UTC (unmatched sighting). */\n seen_at?: string;\n /** The face is sold: false for a static registry board, which is measured and never sold. */\n sellable?: boolean;\n /** Sighting id (unmatched sighting). */\n sighting_id?: string;\n /** still_reader or vlm_text (unmatched sighting). */\n source?: string;\n /** State or province. */\n state?: string | null;\n /** Surface as read (unmatched sighting). */\n surface?: string | null;\n /** Side of the cab the ad was on (unmatched sighting). */\n vehicle_side?: string | null;\n /** Distinct vehicles behind the figure. */\n vehicles?: number | null;\n /** OpenOOH venue type id. */\n venue_type_id?: number | null;\n /** Currency window end. */\n window_end?: string | null;\n};\n\nexport type DataApi_DataProducts_BoardTiles = {\n /** Board face id. */\n board_id: string;\n by_week: Array<DataApi_DataProducts_TileSum>;\n cells: Array<{\n /** Daypart. */\n daypart: string;\n /** Instrumented legible seconds. */\n facing_base_s: number | null;\n /** Facing seconds. */\n facing_s: number | null;\n /** Legible seconds. */\n legible_s: number;\n /** Passes (face-share weighted). */\n passes: number;\n /** Distinct vehicles behind the leaf. */\n vehicles: number;\n /** Monday the week starts on. */\n week_start: string;\n }>;\n meta: {\n bbox?: Array<number>;\n /** Boards summed. */\n boards?: number;\n /** Tiles returned. */\n count?: number;\n facing: DataApi_DataProducts_FacingVerdict;\n /** Days measured under two method versions. */\n method_mixed_days: Array<string>;\n /** Geohash precision. */\n precision?: number;\n weeks?: Array<string>;\n };\n total: DataApi_DataProducts_TileSum;\n weeks: Array<string>;\n};\n\nexport type DataApi_DataProducts_BoardTilesResponse = {\n data: DataApi_DataProducts_BoardTiles;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BrandMarket = {\n /** The box the market's reads were taken in, [minLon, minLat, maxLon, maxLat]. */\n bbox: Array<number> | null;\n /** Of those, reads on a registered board face. */\n face_sightings: number;\n /** Distinct registered faces it was read on. */\n faces: number;\n /** Every read held for the market, any window. */\n held_sightings: number;\n /** Market as COUNTRY:CODE (US DMA, CA CMA). */\n market_key: string;\n /** Market name. */\n market_name: string | null;\n /** Reads of the brand in the market in the window. */\n sightings: number;\n /** Reads on no registered face (street, storefront, vehicle). */\n street_sightings: number;\n};\n\nexport type DataApi_DataProducts_BrandSearch = {\n brands: Array<DataApi_DataProducts_SightedBrand>;\n /** Its brand key: letters and digits, lower-cased (McDonald's and mcdonalds are one key). */\n key: string;\n /** The query as sent. */\n query: string;\n /** When the brand index was last rebuilt, UTC. */\n refreshed_at: string | null;\n window: {\n /** Days in the window. */\n days: number;\n /** First day of the window. */\n since: string;\n /** Day after its last. */\n until_exclusive: string;\n };\n};\n\nexport type DataApi_DataProducts_BrandSearchResponse = {\n data: DataApi_DataProducts_BrandSearch;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_Calibration = {\n calibration: DataApi_DataProducts_CalibrationVersion;\n columns: Array<{\n /** What the column measures. */\n definition: string;\n /** CSV header. */\n header: string;\n /** Column key. */\n key: string;\n /** MRC OOH requirements the column serves. */\n mrc: Array<string>;\n /** Unit. */\n unit: string;\n }>;\n /** Hash of this file. */\n content_sha256: string;\n filter: {\n /** readable or facing. */\n calibration: string | null;\n /** Instrument. */\n instrument: string | null;\n /** second, pass, ... */\n unit: string | null;\n };\n rows: Array<DataApi_DataProducts_CalibrationCell>;\n /** Where the column-to-MRC specification lives. */\n spec: string;\n /** Rows were capped. */\n truncated: boolean;\n};\n\nexport type DataApi_DataProducts_CalibrationCell = {\n /** Format class. */\n aspect_class: string;\n /** Bearing band. */\n bearing_band: string;\n /** Band upper edge, degrees. */\n bearing_max_deg: number | null;\n /** Band lower edge, degrees. */\n bearing_min_deg: number | null;\n /** readable = P(readable | geometry, speed, time); facing = P(facing | readable, bearing, format). */\n calibration: string;\n /** Version id. */\n calibration_id: string;\n /** Currency method version. */\n currency_method_version: number;\n /** Daypart. */\n daypart: string;\n /** Local hours of the daypart. */\n daypart_local_hours: string;\n /** Denominator. */\n den: number;\n /** Instrument. */\n instrument: string | null;\n /** Interval method. */\n interval_method: string;\n /** Mean speed, m/s. */\n mean_speed_mps: number | null;\n /** Boards. */\n n_boards: number;\n /** Passes. */\n n_passes: number;\n /** Distinct vehicles. */\n n_vehicles: number;\n /** Observation windows. */\n n_windows: number | null;\n /** Numerator. */\n num: number;\n /** The probability. */\n p: number;\n /** Interval upper bound. */\n p_high: number | null;\n /** Interval lower bound. */\n p_low: number | null;\n /** Pass-audience method version. */\n pass_audience_version: number;\n /** Road class. */\n road_class: string;\n /** Standard error. */\n se: number | null;\n /** free_flow, slowed, congested. */\n speed_band: string;\n /** second or pass. */\n unit: string;\n /** Venue type. */\n venue_type: string;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n /** Last day. */\n window_end: string;\n /** First day. */\n window_start: string;\n};\n\nexport type DataApi_DataProducts_CalibrationResponse = {\n data: DataApi_DataProducts_Calibration;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_CalibrationVersion = {\n /** Attention observations. */\n attention_rows: number;\n /** Boards. */\n boards: number;\n /** When it was cut, UTC. */\n built_at: string;\n /** Version id, mcal-<window_end>-cv<N>-pa<N>-b<N>. */\n calibration_id: string;\n /** Calibration cells. */\n cells: number;\n /** Hash of the version content. */\n content_sha256: string;\n /** Currency method version. */\n currency_method_version: number;\n /** Fingerprint of the currency parameters. */\n currency_params_fingerprint: string;\n engine_versions: Array<string>;\n /** Facing tolerance, degrees. */\n facing_tol_deg: number | null;\n graph_versions: Array<string>;\n matcher_versions: Array<string>;\n /** Fingerprint of the pass-audience parameters. */\n pass_audience_params_fingerprint: string;\n /** Pass-audience method version. */\n pass_audience_version: number;\n /** Passes the version rests on. */\n passes: number;\n /** Congested speed ratio threshold. */\n speed_congested_ratio: number | null;\n /** Free-flow speed ratio threshold. */\n speed_free_flow_ratio: number | null;\n /** Speed profile version. */\n speed_profile_version: string | null;\n time_model_versions: Array<string>;\n timing_curve_versions: Array<string>;\n /** Distinct vehicles. */\n vehicles: number;\n viewshed_versions: Array<string>;\n /** Days. */\n window_days: number;\n /** Last day. */\n window_end: string;\n /** First day. */\n window_start: string;\n};\n\nexport type DataApi_DataProducts_CalibrationVersions = {\n /** The newest version. */\n latest: string | null;\n /** Where the specification lives. */\n spec: string;\n versions: Array<DataApi_DataProducts_CalibrationVersion>;\n};\n\nexport type DataApi_DataProducts_CalibrationVersionsResponse = {\n data: DataApi_DataProducts_CalibrationVersions;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_CurationSet = {\n countries: Array<string>;\n coverage: DataApi_DataProducts_SetCoverage;\n /** Set name. */\n display_name: string;\n /** DMA code. */\n dma_code: string | null;\n /** DMA name. */\n dma_name: string | null;\n /** The caller holds the set. */\n entitled?: boolean;\n /** dma, national, ... */\n geo_scope: string | null;\n /** Audience segment the set is curated for. */\n segment_key: string | null;\n /** Curated set key. */\n set_key: string;\n};\n\nexport type DataApi_DataProducts_CurationSetList = {\n /** The coverage window. */\n coverage_window_end: string | null;\n /** More sets follow. */\n has_more: boolean;\n /** Page size. */\n limit: number;\n limits: {\n /** Largest bbox span the map routes accept, degrees. */\n max_bbox_deg: number;\n /** Most boards one overlay draws. */\n max_overlay_boards: number;\n };\n /** Page offset. */\n offset: number;\n /** Sets on this page. */\n returned: number;\n sets: Array<DataApi_DataProducts_CurationSet>;\n /** Sets matching. */\n total: number;\n};\n\nexport type DataApi_DataProducts_CurationSetListResponse = {\n data: DataApi_DataProducts_CurationSetList;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_CurrencyAbsent = {\n /** Condition scope. */\n cond_scope: string;\n /** Condition value. */\n cond_value: string;\n /** Daypart. */\n daypart: string;\n /** The board-pass rows seen (owner mount): a reconciliation count, never a pass count. */\n pass_rows?: number | null;\n /** Face passes seen (owner mount): the sum of face_share, a fraction where a facing is unresolved. Null on a window built before exposure_currency v6. */\n passes?: number | null;\n /** Why the currency holds no figure for the cell (no_window, no_persons, ...). */\n reason: string;\n /** Vehicles seen (owner mount). */\n vehicles?: number | null;\n};\n\nexport type DataApi_DataProducts_CurrencyBoard = {\n /** Board face id. */\n board_id: string;\n /** ISO-3166 alpha-2. */\n country: string;\n /** Nielsen DMA code. */\n dma_code: string | null;\n /** The face is active in the catalogue (owner mount). */\n is_active?: boolean;\n /** Face latitude. */\n latitude: number;\n /** Face longitude. */\n longitude: number;\n /** The media owner selling the face. */\n publisher_name: string;\n /** State or province. */\n state: string | null;\n /** IANA zone the dayparts are local to. */\n timezone: string;\n /** The face as the inventory catalogue names it. */\n venue_name: string;\n /** OpenOOH venue type id (301 = billboards). */\n venue_type_id: number;\n};\n\nexport type DataApi_DataProducts_CurrencyCell = {\n /** Why a measured cell carries no impressions per spot: `no_slot` (a face with no slot, a static board: its passes, flow, daily contacts and speed are measured). Null where it carries one; absent from a body served before serving version 16. */\n absent_reason?: string | null;\n ads_per_pass: {\n /** Ads played whole during the pass (mean). */\n complete: number | null;\n /** Passes timed to the owner's play log. */\n exact_passes: number | null;\n /** Ads seen per pass (mean). */\n seen: number | null;\n /** Ads seen per pass on passes timed to the owner's play log. */\n seen_exact: number | null;\n /** Ads on screen at any point of the pass (mean). */\n touched: number | null;\n } | null;\n /** Condition the cell is split by (all, light, weather, speed). */\n cond_scope: string;\n /** The condition value, or `__all__`. */\n cond_value: string;\n conditions: {\n /** Share of passes in sun glare. */\n glare_share: number | null;\n /** Mean ambient light, lux. */\n lux_mean: number | null;\n /** Share of passes at night. */\n night_share: number | null;\n /** Share of passes in rain. */\n rain_share: number | null;\n } | null;\n /** People passing in position to see the face per day. */\n daily_contacts: number | null;\n /** Daypart of the cell, or `__all__`. */\n daypart: string;\n flow_vph: {\n /** Annual average daily traffic facing the board (owner mount). */\n aadt_facing?: number | null;\n /** Coefficient of variation of the hourly flow. */\n cv: number | null;\n /** Vehicles per hour past the face. */\n mean: number | null;\n /** What the hourly profile is built from (fleet_blend, ...). */\n profile_basis: string | null;\n /** Traffic count source (owner mount). */\n source?: string | null;\n } | null;\n impressions_per_spot: {\n /** Interval upper bound. */\n high: number | null;\n /** How the interval is computed (lognormal_delta_vehicle_clustered). */\n interval_method: string | null;\n /** Interval lower bound. */\n low: number | null;\n /** Measured impressions per spot. */\n measured: number | null;\n /** The owner's own figure for the spot (owner mount). */\n owner?: number | null;\n } | null;\n /** Who the measured impressions per spot count: `vehicle_occupants`. */\n ips_population: string;\n legible_window_s: {\n /** Mean seconds the face is legible from a passing vehicle. */\n mean: number | null;\n /** Standard error of the mean, seconds. */\n se: number | null;\n } | null;\n /** Owner mount: what the measurement is worth at the floor. */\n money?: {\n /** Annual revenue difference at the floor, USD. */\n annual_opportunity_usd: number | null;\n /** Measured impressions per floor dollar. */\n imps_per_floor_usd: number | null;\n /** Recommended floor CPM, USD. */\n recommended_floor_cpm: number | null;\n };\n persons_in_position_to_see: {\n /** Average vehicle occupancy. */\n avo: number | null;\n /** Instrument that measured it (head_yaw, ...). */\n instrument: string | null;\n /** Level the visibility was resolved at (board, format, market). */\n level: string | null;\n /** Driver visibility factor. */\n v_driver: number | null;\n /** Share of passengers in position to see it. */\n v_pax: number | null;\n /** Upper bound of v_pax. */\n v_pax_high: number | null;\n /** Lower bound of v_pax. */\n v_pax_low: number | null;\n /** People per vehicle in position to see the face. */\n value: number | null;\n } | null;\n /** The harmonic-mean speed of earlier versions, km/h: dominated by stopped passes, kept beside the moving speed. Absent from a body served before serving version 16. */\n speed_harmonic_kph?: number | null;\n /** Moving speed past the face, km/h: the face-share-weighted median of path / (visible - stationary) seconds over the passes that moved (exposure_currency v6). Null on a window built before v6. */\n speed_kph: number | null;\n /** Share of the in-view seconds the passing vehicles stood still (stationary over visible seconds, face-share weighted; exposure_currency v6). Absent from a body served before serving version 16. */\n stopped_share?: number | null;\n support: {\n /** The board-pass rows with an in-cab camera reading. */\n camera_pass_rows?: number | null;\n /** Face passes with an in-cab camera reading (a fraction where a facing is unresolved). Null on a window built before exposure_currency v6. */\n camera_passes: number | null;\n /** The board-pass rows behind the cell (one per candidate facing of a traversal): a reconciliation count, never a pass count. */\n pass_rows?: number | null;\n /** Face passes the cell is measured over: the sum of each pass's share of this face. A traversal that crosses m of the k candidate facings of a face whose facing is unresolved adds m/k, so the count can be a fraction. Null on a window built before exposure_currency v6. */\n passes: number | null;\n /** Passenger observation windows. */\n pax_windows: number | null;\n /** Distinct vehicles behind those passes. */\n vehicles: number | null;\n };\n /** Owner mount: the measured figure against the owner's. */\n yield?: {\n /** Why no ratio is served. */\n absent_reason: string | null;\n /** ratio or incremental. */\n basis: string | null;\n /** Interval upper bound. */\n high: number | null;\n /** Interval lower bound. */\n low: number | null;\n /** Measured over the owner's figure. */\n ratio: number | null;\n };\n};\n\nexport type DataApi_DataProducts_DeliveryReport = {\n /** Per creative: creative_key, advertiser, campaign_key, precision, days, plays, measured_impressions (with low/high), owner_modelled_impressions, fleet_exposure. */\n by_creative: Array<Record<string, unknown>>;\n /** Per local day: play_date, plays, measured_impressions (with low/high), owner_modelled_impressions, fleet_passes, priced_at_window_end, state. */\n by_day: Array<Record<string, unknown>>;\n columns: Array<{\n /** CSV header. */\n header?: string;\n /** Column key. */\n key: string;\n }>;\n /** board_id, name, owner, venue_type_id, timezone, country, state, dma_code, latitude, longitude, owner_ips. */\n face: Record<string, unknown>;\n flight: {\n /** Days. */\n days: number;\n /** First day. */\n from: string;\n /** Last day. */\n to: string;\n };\n /** Who the measured impressions count. */\n ips_population: string;\n /** kinds, precisions, owner_log, modelled_rotation_only. */\n plays_basis: Record<string, unknown>;\n /** windows (each currency window that priced a day: measured_ips with its interval, slot, passes, vehicles, owner_ips, versions) and spans_windows. */\n pricing: Record<string, unknown>;\n /** One row per (day, creative), the CSV rows: board_id, face, owner, play_date, creative_key, advertiser, campaign_key, plays_basis, precision, plays, measured_impressions (with low/high), owner_modelled_impressions, fleet_passes, priced_at_window_end, priced_ips (with low/high), ips_population, measured_state. */\n rows: Array<Record<string, unknown>>;\n /** plays, measured_impressions (with low/high), owner_modelled_impressions, measured_over_owner, fleet_passes, days_with_plays, days_measured, days_unmeasured, days_without_delivery_row, unmeasured_plays. */\n totals: Record<string, unknown>;\n};\n\nexport type DataApi_DataProducts_DeliveryReportResponse = {\n data: DataApi_DataProducts_DeliveryReport;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_DmaFormatIndex = {\n /** The base the indices are against (US). */\n base: string;\n meta: {\n facing: DataApi_DataProducts_FacingVerdict;\n /** What each index means. */\n indices: Record<string, string>;\n };\n rows: Array<DataApi_DataProducts_DmaFormatIndexRow>;\n weeks: Array<string>;\n};\n\nexport type DataApi_DataProducts_DmaFormatIndexResponse = {\n data: DataApi_DataProducts_DmaFormatIndex;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_DmaFormatIndexRow = {\n /** Board-weeks measured. */\n board_weeks: number;\n /** Boards measured. */\n boards: number;\n /** DMA code. */\n dma_code: string;\n /** Why no facing index is served. */\n facing_absent_reason: string | null;\n /** Instrumented legible seconds. */\n facing_base_s: number | null;\n /** Facing seconds per instrumented legible second against the US base, x100. */\n facing_share_index: number | null;\n /** Format. */\n format: string;\n /** Legible seconds per pass against the US base, x100. */\n legible_s_per_pass_index: number | null;\n /** Passes. */\n passes: number;\n /** Passes per board-week against the US base, x100. */\n passes_per_board_week_index: number | null;\n /** Distinct vehicles. */\n vehicles: number;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n};\n\nexport type DataApi_DataProducts_FacingVerdict = {\n /** Instrument the facing seconds are measured with (head_yaw). */\n instrument: string;\n /** The facing gate is open: facing seconds are served. */\n open: boolean;\n /** Why the gate is closed. */\n reason: string | null;\n};\n\nexport type DataApi_DataProducts_FeedPublication = {\n /** Boards in the feed. */\n boards: number;\n /** Cells in the feed. */\n cells: number;\n /** Hash of the feed content. */\n content_sha256: string;\n /** When the feed was due, UTC. */\n due_at: string | null;\n /** Cells due for reissue. */\n due_cells: number;\n /** Feed date. */\n feed_date: string;\n /** When it was published, UTC. */\n published_at: string | null;\n /** Release the feed carries. */\n release_id: string;\n};\n\nexport type DataApi_DataProducts_GeohashTileCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_GeohashTileProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_GeohashTileMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_GeohashTileMeta = {\n bbox?: Array<number>;\n /** Boards summed. */\n boards?: number;\n /** Tiles returned. */\n count?: number;\n facing?: DataApi_DataProducts_FacingVerdict;\n method_mixed_days?: Array<string>;\n /** Geohash precision (5, 6 or 7). */\n precision?: number;\n watermark?: DataApi_DataProducts_Watermark;\n weeks?: Array<string>;\n};\n\nexport type DataApi_DataProducts_GeohashTileProperties = {\n /** Entitled boards in the cell. */\n boards: number;\n /** Instrumented legible seconds. */\n facing_base_s: number | null;\n /** Facing seconds. */\n facing_s: number | null;\n /** Geohash cell. */\n geohash: string;\n /** Legible seconds. */\n legible_s: number;\n /** Passes (face-share weighted). */\n passes: number;\n weeks: Array<DataApi_DataProducts_TileSum>;\n};\n\nexport type DataApi_DataProducts_Geometry = {\n /** RFC 7946 coordinates, [longitude, latitude] order. */\n coordinates: Array<unknown>;\n /** GeoJSON geometry type. */\n type: \"Point\" | \"LineString\" | \"Polygon\" | \"MultiPolygon\" | \"MultiLineString\";\n} | null;\n\nexport type DataApi_DataProducts_LookedShareRow = {\n /** single (one person in the frame) or multi (several, whose direction is a mean). Never pooled. */\n face_stratum: string;\n /** The instrument the row measured with: head_mlkit (head direction on every analysed frame), gaze_fl (eye gaze), head_yaw, shoulder. Never pooled. */\n instrument: string;\n /** Judged seconds the share divides by: the seconds the instrument read a direction. */\n judged_s: number | null;\n /** Expected looked seconds behind the share. */\n looked_s: number | null;\n /** Share of the judged seconds in which an occupant was turned toward this face. Null where nothing was judged. */\n share_of_judged: number | null;\n /** Distinct vehicles behind the row. */\n vehicles: number | null;\n};\n\nexport type DataApi_DataProducts_MeasurementError = {\n /** Machine-readable reason, e.g. invalid_bbox, board_not_found, not_entitled, quota, measurement_unavailable. */\n code: string;\n /** Owner upload refusals (sheet_refused, sheet_empty, log_refused, ssp_venue_conflict, write_failed): the plan or load report the refusal is about, with rows read, refused lines and their reasons, unmatched and ambiguous faces, and for ssp_venue_conflict the `conflicts`. */\n data?: Record<string, unknown>;\n /** What was refused and how to ask again. */\n message: string;\n /** The scopes the key must hold (INSUFFICIENT_SCOPE on the owner upload routes, which need `measurement:write`). */\n required_scopes?: Array<string>;\n status: false;\n};\n\nexport type DataApi_DataProducts_Method = {\n /** Method name (exposure_currency, pass_audience, camera_screen_hour, ...). */\n name: string;\n /** Method version the figures were computed under. */\n version: number | null;\n};\n\nexport type DataApi_DataProducts_MetricAnswer = {\n absent?: Array<Record<string, unknown>>;\n /** Board metrics: the board route's own body (board_measured_impressions_per_spot = /boards/{boardId}/currency; board_pass_audience = /boards/{boardId}/audience with each row's unit and the support behind it). */\n answer?: DataApi_DataProducts_BoardCurrency | {\n /** Board face id. */\n board_id: string;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours?: Record<string, Array<number>>;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_AudienceRow>;\n /** The passes and vehicles the rows rest on, with the window. */\n support: Record<string, unknown> | null;\n window: DataApi_DataProducts_Window;\n } | null | null;\n day_summary?: Record<string, unknown>;\n /** How hours are assigned to dayparts. */\n daypart_basis?: string | null;\n days?: Array<{\n /** Day. */\n day: string;\n /** The source measured the day. */\n measured: boolean;\n /** complete, partial or not_measured. */\n status: string;\n }>;\n /** Demographics metrics: each dimension read, with its readings in the window. */\n dimensions_measured?: Array<{\n /** A demographic dimension the answer reads. */\n dimension: string;\n /** Readings of that dimension in the window. */\n readings_in_window: number;\n }>;\n /** Metric family. */\n family: string;\n /** The filters applied (screens, markets, brands, board_id, by, ...). */\n filters: Record<string, unknown>;\n /** Camera evidence grade. */\n grade?: string | null;\n /** Grain of the rows. */\n grain: string;\n headline: {\n /** Denominator. */\n denominator: string | null;\n /** Headline measure. */\n key: string;\n /** Unit. */\n unit: string;\n };\n /** Label. */\n label: string;\n limits?: Record<string, unknown>;\n measures: Array<DataApi_DataProducts_MetricMeasure>;\n method?: Record<string, unknown> | null;\n /** Approved metric name. */\n metric: \"camera_people_per_screen_hour\" | \"camera_dwell_capped_ms\" | \"camera_head_pose_index\" | \"camera_gaze_pct\" | \"demographic_share\" | \"sensing_census\" | \"board_measured_impressions_per_spot\" | \"board_pass_audience\" | \"same_panel_index\" | \"radio_identifiers_per_person\" | \"creative_sightings\" | \"creative_share_of_voice\" | \"creative_street_presence\" | \"creative_vacancy_rate\" | \"creative_brand_history\" | \"seatbelt_compliance\" | \"seatbelt_unbuckled_ride_rate\";\n /** The population the shares are over. */\n population?: string | null;\n /** The question it answers. */\n question: string;\n /** Rows in the answer. */\n row_count?: number;\n /** One row per grain cell: the grain keys, then every measure of the metric (see the table on this operation), each with the count it is taken over; `absent` lists the measures with no value and why. */\n rows?: Array<Record<string, unknown>>;\n /** The totals over the window, shaped like `rows`: one row when the answer has one key, one row per key when it has several (per brand for creative_share_of_voice, per panel for a panel metric, per dimension value for demographics); null when no day was measured. */\n totals?: Record<string, unknown> | Array<Record<string, unknown>> | null | null;\n /** The window answered: from, to, days, timezone, defaulted (or window_end, window_days for a board metric). */\n window: Record<string, unknown>;\n};\n\nexport type DataApi_DataProducts_MetricAnswerResponse = {\n data: DataApi_DataProducts_MetricAnswer;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricBoardMeasuredImpressionsPerSpotResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n answer?: DataApi_DataProducts_BoardCurrency & Record<string, unknown> | null;\n /** This metric. */\n metric?: \"board_measured_impressions_per_spot\";\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricBoardPassAudienceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** The board route's own body for the board and window asked. */\n answer?: {\n /** Board face id. */\n board_id: string;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours?: Record<string, Array<number>>;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_AudienceRow>;\n /** The passes and vehicles the rows rest on, with the window. */\n support: Record<string, unknown> | null;\n window: DataApi_DataProducts_Window;\n } | null;\n /** This metric. */\n metric?: \"board_pass_audience\";\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraDwellCappedMsResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_dwell_capped_ms\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean dwell per window in ms, each window's dwell capped at its own length. Unit: ms. Taken over `dwell_capped_windows`. */\n dwell_capped_ms_mean?: number | null;\n /** Camera windows that carry a start time, the dwell mean's denominator. Unit: windows. */\n dwell_capped_windows?: number | null;\n /** Windows whose reported dwell exceeded their own length and were capped. Unit: windows. */\n dwell_over_window_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean dwell per window in ms, each window's dwell capped at its own length. Unit: ms. Taken over `dwell_capped_windows`. */\n dwell_capped_ms_mean?: number | null;\n /** Camera windows that carry a start time, the dwell mean's denominator. Unit: windows. */\n dwell_capped_windows?: number | null;\n /** Windows whose reported dwell exceeded their own length and were capped. Unit: windows. */\n dwell_over_window_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean dwell per window in ms, each window's dwell capped at its own length. Unit: ms. Taken over `dwell_capped_windows`. */\n dwell_capped_ms_mean?: number | null;\n /** Camera windows that carry a start time, the dwell mean's denominator. Unit: windows. */\n dwell_capped_windows?: number | null;\n /** Windows whose reported dwell exceeded their own length and were capped. Unit: windows. */\n dwell_over_window_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraGazePctResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_gaze_pct\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean on-screen gaze share 0-1 over the windows carrying a gaze reading. Unit: share. Taken over `gaze_pct_windows`. */\n gaze_pct_mean?: number | null;\n /** Windows carrying a gaze reading, the gaze mean's denominator. Unit: windows. */\n gaze_pct_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean on-screen gaze share 0-1 over the windows carrying a gaze reading. Unit: share. Taken over `gaze_pct_windows`. */\n gaze_pct_mean?: number | null;\n /** Windows carrying a gaze reading, the gaze mean's denominator. Unit: windows. */\n gaze_pct_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean on-screen gaze share 0-1 over the windows carrying a gaze reading. Unit: share. Taken over `gaze_pct_windows`. */\n gaze_pct_mean?: number | null;\n /** Windows carrying a gaze reading, the gaze mean's denominator. Unit: windows. */\n gaze_pct_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraHeadPoseIndexResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_head_pose_index\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows, the index mean's denominator. Unit: windows. */\n camera_windows?: number | null;\n /** Mean over every camera window of the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (a window without a face reads 0). Unit: index. Taken over `camera_windows`. */\n head_pose_index_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_min?: number | null;\n /** Windows whose head-pose index is above 0 (a pose was read). Unit: windows. */\n head_pose_index_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows, the index mean's denominator. Unit: windows. */\n camera_windows?: number | null;\n /** Mean over every camera window of the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (a window without a face reads 0). Unit: index. Taken over `camera_windows`. */\n head_pose_index_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_min?: number | null;\n /** Windows whose head-pose index is above 0 (a pose was read). Unit: windows. */\n head_pose_index_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows, the index mean's denominator. Unit: windows. */\n camera_windows?: number | null;\n /** Mean over every camera window of the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (a window without a face reads 0). Unit: index. Taken over `camera_windows`. */\n head_pose_index_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_min?: number | null;\n /** Windows whose head-pose index is above 0 (a pose was read). Unit: windows. */\n head_pose_index_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraPeoplePerScreenHourResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_people_per_screen_hour\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows (face_backed or person_backed, ~10 s each). Unit: windows. */\n camera_windows?: number | null;\n /** Mean per-window face reading: the device face_count where it wrote one, else the window mean face count. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_min?: number | null;\n /** Exact 95th percentile of the per-window face reading of one screen-hour; at a coarser grain the answer carries face_count_p95_busiest_screen_hour, the largest screen-hour p95 in the row. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_p95?: number | null;\n /** stats=spread, coarser grains: the mean over the row's screen-hours of each screen-hour's exact p95. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_mean?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour p95 in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_min?: number | null;\n /** Windows whose reading is the device face_count primitive. Unit: windows. */\n face_count_primitive_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows (face_backed or person_backed, ~10 s each). Unit: windows. */\n camera_windows?: number | null;\n /** Mean per-window face reading: the device face_count where it wrote one, else the window mean face count. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_min?: number | null;\n /** Exact 95th percentile of the per-window face reading of one screen-hour; at a coarser grain the answer carries face_count_p95_busiest_screen_hour, the largest screen-hour p95 in the row. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_p95?: number | null;\n /** stats=spread, coarser grains: the mean over the row's screen-hours of each screen-hour's exact p95. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_mean?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour p95 in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_min?: number | null;\n /** Windows whose reading is the device face_count primitive. Unit: windows. */\n face_count_primitive_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows (face_backed or person_backed, ~10 s each). Unit: windows. */\n camera_windows?: number | null;\n /** Mean per-window face reading: the device face_count where it wrote one, else the window mean face count. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_min?: number | null;\n /** Exact 95th percentile of the per-window face reading of one screen-hour; at a coarser grain the answer carries face_count_p95_busiest_screen_hour, the largest screen-hour p95 in the row. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_p95?: number | null;\n /** stats=spread, coarser grains: the mean over the row's screen-hours of each screen-hour's exact p95. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_mean?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour p95 in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_min?: number | null;\n /** Windows whose reading is the device face_count primitive. Unit: windows. */\n face_count_primitive_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCatalog = {\n metrics: Array<DataApi_DataProducts_MetricCatalogEntry>;\n};\n\nexport type DataApi_DataProducts_MetricCatalogEntry = {\n /** How hours are assigned to dayparts. */\n daypart_basis?: string | null;\n /** Default grain. */\n default_grain: string;\n /** Default fleet grain. */\n default_grain_fleet: string | null;\n dimensions?: Array<string>;\n /** camera, demographics, census, board, panel, calibration, creative or seatbelt. */\n family: string;\n grades?: Array<string> | null;\n grains: Array<string>;\n headline: {\n /** Denominator. */\n denominator: string | null;\n /** Headline measure. */\n key: string;\n /** Unit. */\n unit: string;\n };\n /** Label. */\n label: string;\n limits: {\n /** Most rows per answer. */\n max_rows: number;\n /** Most screens per request. */\n max_screens: number;\n /** Longest window per request, days. */\n max_window_days: number | null;\n };\n measures: Array<DataApi_DataProducts_MetricMeasure>;\n method?: {\n /** Method. */\n name: string;\n /** Version. */\n version: number | null;\n } | null;\n /** Approved metric name. */\n metric: \"camera_people_per_screen_hour\" | \"camera_dwell_capped_ms\" | \"camera_head_pose_index\" | \"camera_gaze_pct\" | \"demographic_share\" | \"sensing_census\" | \"board_measured_impressions_per_spot\" | \"board_pass_audience\" | \"same_panel_index\" | \"radio_identifiers_per_person\" | \"creative_sightings\" | \"creative_share_of_voice\" | \"creative_street_presence\" | \"creative_vacancy_rate\" | \"creative_brand_history\" | \"seatbelt_compliance\" | \"seatbelt_unbuckled_ride_rate\";\n params: Array<string>;\n populations?: Array<string>;\n /** The question the metric answers. */\n question: string;\n stats?: {\n allowed: Array<string>;\n default: Array<string>;\n } | null;\n};\n\nexport type DataApi_DataProducts_MetricCatalogResponse = {\n data: DataApi_DataProducts_MetricCatalog;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeBrandHistoryResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_brand_history\";\n /** One row per grain cell. */\n rows?: Array<{\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights?: number | null;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Taken over `attention_flights`. */\n attention_passes?: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points?: number | null;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Taken over `flights_active`. */\n brand_face_days?: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Taken over `flights_active`. */\n brand_face_share?: number | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched?: number | null;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed?: number | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active?: number | null;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started?: number | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_legible_s?: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_looked_s?: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Taken over `attention_flights`. */\n head_legible_s?: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Taken over `attention_flights`. */\n head_looked_s?: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_ad_face_days?: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights?: number | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_face_days?: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Taken over `market_ad_flights`. */\n market_face_share?: number | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights?: number | null;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. */\n market_sightings?: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. Taken over `market_face_days`. */\n market_vacancy_face_day_share?: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. Taken over `market_sightings`. */\n market_vacancy_share?: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. Taken over `market_weighted_sightings`. */\n market_vacancy_share_drawn_weighted?: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. */\n market_vacancy_sightings?: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. */\n market_vacant_board_faces?: number | null;\n /** Their face-days in the period. Unit: face_days. Taken over `market_vacant_flights`. */\n market_vacant_face_days?: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights?: number | null;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Taken over `media_value_priced_faces`. */\n media_value_floor_usd?: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces?: number | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. Taken over `market_named_flights`. */\n share_of_named_voice?: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. Taken over `market_ad_flights`. */\n share_of_voice?: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days?: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days_se?: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. Taken over `market_face_share`. */\n share_of_voice_face_weighted?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights?: number | null;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Taken over `attention_flights`. */\n attention_passes?: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points?: number | null;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Taken over `flights_active`. */\n brand_face_days?: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Taken over `flights_active`. */\n brand_face_share?: number | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched?: number | null;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed?: number | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active?: number | null;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started?: number | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_legible_s?: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_looked_s?: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Taken over `attention_flights`. */\n head_legible_s?: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Taken over `attention_flights`. */\n head_looked_s?: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_ad_face_days?: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights?: number | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_face_days?: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Taken over `market_ad_flights`. */\n market_face_share?: number | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights?: number | null;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. */\n market_sightings?: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. Taken over `market_face_days`. */\n market_vacancy_face_day_share?: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. Taken over `market_sightings`. */\n market_vacancy_share?: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. Taken over `market_weighted_sightings`. */\n market_vacancy_share_drawn_weighted?: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. */\n market_vacancy_sightings?: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. */\n market_vacant_board_faces?: number | null;\n /** Their face-days in the period. Unit: face_days. Taken over `market_vacant_flights`. */\n market_vacant_face_days?: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights?: number | null;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Taken over `media_value_priced_faces`. */\n media_value_floor_usd?: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces?: number | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. Taken over `market_named_flights`. */\n share_of_named_voice?: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. Taken over `market_ad_flights`. */\n share_of_voice?: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days?: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days_se?: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. Taken over `market_face_share`. */\n share_of_voice_face_weighted?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights?: number | null;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Taken over `attention_flights`. */\n attention_passes?: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points?: number | null;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Taken over `flights_active`. */\n brand_face_days?: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Taken over `flights_active`. */\n brand_face_share?: number | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched?: number | null;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed?: number | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active?: number | null;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started?: number | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_legible_s?: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_looked_s?: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Taken over `attention_flights`. */\n head_legible_s?: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Taken over `attention_flights`. */\n head_looked_s?: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_ad_face_days?: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights?: number | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_face_days?: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Taken over `market_ad_flights`. */\n market_face_share?: number | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights?: number | null;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. */\n market_sightings?: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. Taken over `market_face_days`. */\n market_vacancy_face_day_share?: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. Taken over `market_sightings`. */\n market_vacancy_share?: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. Taken over `market_weighted_sightings`. */\n market_vacancy_share_drawn_weighted?: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. */\n market_vacancy_sightings?: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. */\n market_vacant_board_faces?: number | null;\n /** Their face-days in the period. Unit: face_days. Taken over `market_vacant_flights`. */\n market_vacant_face_days?: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights?: number | null;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Taken over `media_value_priced_faces`. */\n media_value_floor_usd?: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces?: number | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. Taken over `market_named_flights`. */\n share_of_named_voice?: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. Taken over `market_ad_flights`. */\n share_of_voice?: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days?: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days_se?: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. Taken over `market_face_share`. */\n share_of_voice_face_weighted?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeShareOfVoiceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_share_of_voice\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct board faces the brand was sighted on. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings on registered board faces. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings on registered board faces in the key: the headline denominator. Unit: sightings. */\n market_sightings?: number | null;\n /** Every named brand's drawn sightings weighted by 1 / inclusion_probability: the weighted share's denominator. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** brand_sightings / market_sightings: the brand's share of every named brand's sightings on registered board faces, each counted once. Unit: share. Taken over `market_sightings`. */\n share?: number | null;\n /** The design-weighted share: the brand's drawn sightings weighted by 1 / inclusion_probability over every named brand's. Never mixed into share. Unit: share. Taken over `market_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct board faces the brand was sighted on. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings on registered board faces. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings on registered board faces in the key: the headline denominator. Unit: sightings. */\n market_sightings?: number | null;\n /** Every named brand's drawn sightings weighted by 1 / inclusion_probability: the weighted share's denominator. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** brand_sightings / market_sightings: the brand's share of every named brand's sightings on registered board faces, each counted once. Unit: share. Taken over `market_sightings`. */\n share?: number | null;\n /** The design-weighted share: the brand's drawn sightings weighted by 1 / inclusion_probability over every named brand's. Never mixed into share. Unit: share. Taken over `market_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct board faces the brand was sighted on. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings on registered board faces. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings on registered board faces in the key: the headline denominator. Unit: sightings. */\n market_sightings?: number | null;\n /** Every named brand's drawn sightings weighted by 1 / inclusion_probability: the weighted share's denominator. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** brand_sightings / market_sightings: the brand's share of every named brand's sightings on registered board faces, each counted once. Unit: share. Taken over `market_sightings`. */\n share?: number | null;\n /** The design-weighted share: the brand's drawn sightings weighted by 1 / inclusion_probability over every named brand's. Never mixed into share. Unit: share. Taken over `market_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeSightingsResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_sightings\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct board faces with a matched sighting. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct brands sighted (the resolved brand, else the name as read). Unit: brands. */\n brands?: number | null;\n /** Distinct cabs whose stills carried a sighting. Unit: vehicles. */\n cabs?: number | null;\n /** Sightings carrying an inclusion probability (the still reader's). Unit: sightings. */\n drawn_sightings?: number | null;\n /** Sightings attributed to the board face the cab was passing. Unit: sightings. */\n matched_sightings?: number | null;\n /** Ads read off the stills in the key and source: one per ad per reading. Unit: sightings. */\n sightings?: number | null;\n /** Sightings on no face we hold, kept with the cab position, heading and side. Unit: sightings. */\n unmatched_sightings?: number | null;\n /** Sightings of a face carrying no advertiser. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** The still reader's sightings weighted by 1 / inclusion_probability: the sightings of the whole frame the draw represents. NULL on the vlm_text source. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct board faces with a matched sighting. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct brands sighted (the resolved brand, else the name as read). Unit: brands. */\n brands?: number | null;\n /** Distinct cabs whose stills carried a sighting. Unit: vehicles. */\n cabs?: number | null;\n /** Sightings carrying an inclusion probability (the still reader's). Unit: sightings. */\n drawn_sightings?: number | null;\n /** Sightings attributed to the board face the cab was passing. Unit: sightings. */\n matched_sightings?: number | null;\n /** Ads read off the stills in the key and source: one per ad per reading. Unit: sightings. */\n sightings?: number | null;\n /** Sightings on no face we hold, kept with the cab position, heading and side. Unit: sightings. */\n unmatched_sightings?: number | null;\n /** Sightings of a face carrying no advertiser. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** The still reader's sightings weighted by 1 / inclusion_probability: the sightings of the whole frame the draw represents. NULL on the vlm_text source. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct board faces with a matched sighting. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct brands sighted (the resolved brand, else the name as read). Unit: brands. */\n brands?: number | null;\n /** Distinct cabs whose stills carried a sighting. Unit: vehicles. */\n cabs?: number | null;\n /** Sightings carrying an inclusion probability (the still reader's). Unit: sightings. */\n drawn_sightings?: number | null;\n /** Sightings attributed to the board face the cab was passing. Unit: sightings. */\n matched_sightings?: number | null;\n /** Ads read off the stills in the key and source: one per ad per reading. Unit: sightings. */\n sightings?: number | null;\n /** Sightings on no face we hold, kept with the cab position, heading and side. Unit: sightings. */\n unmatched_sightings?: number | null;\n /** Sightings of a face carrying no advertiser. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** The still reader's sightings weighted by 1 / inclusion_probability: the sightings of the whole frame the draw represents. NULL on the vlm_text source. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeStreetPresenceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_street_presence\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct registered board faces the brand was sighted on in the class. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings in the surface class. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings in the class weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n class_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings in the key and surface class: the headline denominator. Unit: sightings. */\n class_sightings?: number | null;\n /** Every named brand's drawn sightings in the class, weighted: the weighted share's denominator. Unit: sightings. Taken over `class_drawn_sightings`. */\n class_weighted_sightings?: number | null;\n /** brand_sightings / class_sightings: the brand's share of every named brand's sightings in the key and surface class (street = every surface), each counted once. Unit: share. Taken over `class_sightings`. */\n share?: number | null;\n /** The design-weighted share: drawn sightings weighted by 1 / inclusion_probability. Never mixed into share. Unit: share. Taken over `class_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct registered board faces the brand was sighted on in the class. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings in the surface class. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings in the class weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n class_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings in the key and surface class: the headline denominator. Unit: sightings. */\n class_sightings?: number | null;\n /** Every named brand's drawn sightings in the class, weighted: the weighted share's denominator. Unit: sightings. Taken over `class_drawn_sightings`. */\n class_weighted_sightings?: number | null;\n /** brand_sightings / class_sightings: the brand's share of every named brand's sightings in the key and surface class (street = every surface), each counted once. Unit: share. Taken over `class_sightings`. */\n share?: number | null;\n /** The design-weighted share: drawn sightings weighted by 1 / inclusion_probability. Never mixed into share. Unit: share. Taken over `class_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct registered board faces the brand was sighted on in the class. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings in the surface class. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings in the class weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n class_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings in the key and surface class: the headline denominator. Unit: sightings. */\n class_sightings?: number | null;\n /** Every named brand's drawn sightings in the class, weighted: the weighted share's denominator. Unit: sightings. Taken over `class_drawn_sightings`. */\n class_weighted_sightings?: number | null;\n /** brand_sightings / class_sightings: the brand's share of every named brand's sightings in the key and surface class (street = every surface), each counted once. Unit: share. Taken over `class_sightings`. */\n share?: number | null;\n /** The design-weighted share: drawn sightings weighted by 1 / inclusion_probability. Never mixed into share. Unit: share. Taken over `class_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeVacancyRateResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_vacancy_rate\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Of those, the sightings with an inclusion probability. Unit: sightings. */\n drawn_sightings?: number | null;\n /** Every still-reader sighting in the key: the headline denominator. Unit: sightings. */\n sightings?: number | null;\n /** vacancy_sightings / sightings: the share of the still reader's sightings that were vacant faces, each counted once. Unit: share. Taken over `sightings`. */\n vacancy_share?: number | null;\n /** The design-weighted share: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into vacancy_share. Unit: share. Taken over `weighted_sightings`. */\n vacancy_share_drawn_weighted?: number | null;\n /** Still-reader sightings of a vacant face. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** Vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant. Unit: board_faces. */\n vacant_board_faces?: number | null;\n /** Every drawn still-reader sighting weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Of those, the sightings with an inclusion probability. Unit: sightings. */\n drawn_sightings?: number | null;\n /** Every still-reader sighting in the key: the headline denominator. Unit: sightings. */\n sightings?: number | null;\n /** vacancy_sightings / sightings: the share of the still reader's sightings that were vacant faces, each counted once. Unit: share. Taken over `sightings`. */\n vacancy_share?: number | null;\n /** The design-weighted share: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into vacancy_share. Unit: share. Taken over `weighted_sightings`. */\n vacancy_share_drawn_weighted?: number | null;\n /** Still-reader sightings of a vacant face. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** Vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant. Unit: board_faces. */\n vacant_board_faces?: number | null;\n /** Every drawn still-reader sighting weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Of those, the sightings with an inclusion probability. Unit: sightings. */\n drawn_sightings?: number | null;\n /** Every still-reader sighting in the key: the headline denominator. Unit: sightings. */\n sightings?: number | null;\n /** vacancy_sightings / sightings: the share of the still reader's sightings that were vacant faces, each counted once. Unit: share. Taken over `sightings`. */\n vacancy_share?: number | null;\n /** The design-weighted share: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into vacancy_share. Unit: share. Taken over `weighted_sightings`. */\n vacancy_share_drawn_weighted?: number | null;\n /** Still-reader sightings of a vacant face. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** Vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant. Unit: board_faces. */\n vacant_board_faces?: number | null;\n /** Every drawn still-reader sighting weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricDemographicShareResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"demographic_share\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Every reading of the dimension in the key, the share's denominator. Unit: readings. */\n dimension_readings?: number | null;\n /** Classifier readings of the value: sum(count) over the key. Unit: readings. */\n readings?: number | null;\n /** Distinct screens carrying the value in the key. Unit: screens. */\n screens?: number | null;\n /** The value's readings over every reading of the dimension in the same key. Unit: share. Taken over `dimension_readings`. */\n share?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Every reading of the dimension in the key, the share's denominator. Unit: readings. */\n dimension_readings?: number | null;\n /** Classifier readings of the value: sum(count) over the key. Unit: readings. */\n readings?: number | null;\n /** Distinct screens carrying the value in the key. Unit: screens. */\n screens?: number | null;\n /** The value's readings over every reading of the dimension in the same key. Unit: share. Taken over `dimension_readings`. */\n share?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Every reading of the dimension in the key, the share's denominator. Unit: readings. */\n dimension_readings?: number | null;\n /** Classifier readings of the value: sum(count) over the key. Unit: readings. */\n readings?: number | null;\n /** Distinct screens carrying the value in the key. Unit: screens. */\n screens?: number | null;\n /** The value's readings over every reading of the dimension in the same key. Unit: share. Taken over `dimension_readings`. */\n share?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricMeasure = {\n /** The count the measure is taken over. */\n denominator: string | null;\n /** What the measure counts. */\n description: string;\n /** Measure key, a column of the rows. */\n key: string;\n /** Unit (share, seconds, faces_per_window, flights, sightings, readings, vehicles, usd, ...). */\n unit: string;\n};\n\nexport type DataApi_DataProducts_MetricRadioIdentifiersPerPersonResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"radio_identifiers_per_person\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Passenger-candidate Bluetooth keys near the tablet in one radio delivery, each ride's most, summed over the panel rides (the driver's phone and the vehicle's own devices removed by their role). Unit: identifiers. */\n keys?: number | null;\n /** Trips both instruments read: the ratio's rides. Unit: rides. */\n panel_rides?: number | null;\n /** People the cabin camera read per ride (the 90th percentile over its windows of the persons reading), summed over the panel rides. Unit: persons. */\n persons?: number | null;\n /** keys / persons over the panel rides: trips (not parked presence) that both the cabin radio and the cabin camera read. Unit: identifiers_per_person. Taken over `persons`. */\n radio_identifiers_per_person?: number | null;\n /** Upper end of the 95% interval. Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_high?: number | null;\n /** Lower end of the 95% interval: ratio estimator, vehicle-clustered linearisation, normal approximation, intersected with [0, inf). Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_low?: number | null;\n /** Every ride of the key, the panel's and the rest. Unit: rides. */\n rides?: number | null;\n /** Vehicles with a panel ride: the clusters of the interval. Unit: vehicles. */\n vehicles?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Passenger-candidate Bluetooth keys near the tablet in one radio delivery, each ride's most, summed over the panel rides (the driver's phone and the vehicle's own devices removed by their role). Unit: identifiers. */\n keys?: number | null;\n /** Trips both instruments read: the ratio's rides. Unit: rides. */\n panel_rides?: number | null;\n /** People the cabin camera read per ride (the 90th percentile over its windows of the persons reading), summed over the panel rides. Unit: persons. */\n persons?: number | null;\n /** keys / persons over the panel rides: trips (not parked presence) that both the cabin radio and the cabin camera read. Unit: identifiers_per_person. Taken over `persons`. */\n radio_identifiers_per_person?: number | null;\n /** Upper end of the 95% interval. Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_high?: number | null;\n /** Lower end of the 95% interval: ratio estimator, vehicle-clustered linearisation, normal approximation, intersected with [0, inf). Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_low?: number | null;\n /** Every ride of the key, the panel's and the rest. Unit: rides. */\n rides?: number | null;\n /** Vehicles with a panel ride: the clusters of the interval. Unit: vehicles. */\n vehicles?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Passenger-candidate Bluetooth keys near the tablet in one radio delivery, each ride's most, summed over the panel rides (the driver's phone and the vehicle's own devices removed by their role). Unit: identifiers. */\n keys?: number | null;\n /** Trips both instruments read: the ratio's rides. Unit: rides. */\n panel_rides?: number | null;\n /** People the cabin camera read per ride (the 90th percentile over its windows of the persons reading), summed over the panel rides. Unit: persons. */\n persons?: number | null;\n /** keys / persons over the panel rides: trips (not parked presence) that both the cabin radio and the cabin camera read. Unit: identifiers_per_person. Taken over `persons`. */\n radio_identifiers_per_person?: number | null;\n /** Upper end of the 95% interval. Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_high?: number | null;\n /** Lower end of the 95% interval: ratio estimator, vehicle-clustered linearisation, normal approximation, intersected with [0, inf). Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_low?: number | null;\n /** Every ride of the key, the panel's and the rest. Unit: rides. */\n rides?: number | null;\n /** Vehicles with a panel ride: the clusters of the interval. Unit: vehicles. */\n vehicles?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSamePanelIndexResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"same_panel_index\";\n /** One row per grain cell. */\n rows?: Array<{\n /** The same-panel series: the product of the monthly indexes from the answer's first month, which reads 1. Unit: ratio. Taken over `same_panel_screens`. */\n chain_index?: number | null;\n /** Days of the month the panel holds (a month in progress holds fewer). Unit: days. */\n days_built?: number | null;\n /** Camera panel: faces per occupied camera window (a face- or person-backed window: the group in view while someone is in view, not audience per unit time) this month over the same-panel screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window?: number | null;\n /** Camera panel: faces per occupied camera window this month over every member. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_panel?: number | null;\n /** Camera panel: faces per occupied camera window the month before over the same screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_previous?: number | null;\n /** Radio panel: visitor identifiers concurrent in a 6-minute slot this month over the same-panel screens: audience per unit time. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot?: number | null;\n /** Radio panel: the same this month over every member. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_panel?: number | null;\n /** Radio panel: the same the month before over the same screens. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_previous?: number | null;\n /** Members of the panel the month before on the evidence kinds both months hold (evidence_compared): the retention's denominator. Unit: screens. */\n previous_comparable_screens?: number | null;\n /** Members of the panel the month before. Unit: screens. */\n previous_screens?: number | null;\n /** same_panel_screens / previous_comparable_screens, with a Wilson interval: the previous month's members still in the panel, on the evidence both months hold (heartbeat camera-on minutes start 2026-08-26, device inference rows are held 90 days). Unit: share. Taken over `previous_comparable_screens`. */\n retained_share?: number | null;\n /** The month's rate over the previous month's, both over the screens in the panel both months. 1 is no change. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index?: number | null;\n /** Upper end of the 95% interval. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_high?: number | null;\n /** Lower end of the 95% interval: two ratio estimators over the same screens, screen-clustered linearisation on the log scale. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_low?: number | null;\n /** Members both months, each month counted on the evidence kinds both months hold (evidence_compared): the screens the index compares. Unit: screens. */\n same_panel_screens?: number | null;\n /** Members of the panel this month. Unit: screens. */\n screens?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** The same-panel series: the product of the monthly indexes from the answer's first month, which reads 1. Unit: ratio. Taken over `same_panel_screens`. */\n chain_index?: number | null;\n /** Days of the month the panel holds (a month in progress holds fewer). Unit: days. */\n days_built?: number | null;\n /** Camera panel: faces per occupied camera window (a face- or person-backed window: the group in view while someone is in view, not audience per unit time) this month over the same-panel screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window?: number | null;\n /** Camera panel: faces per occupied camera window this month over every member. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_panel?: number | null;\n /** Camera panel: faces per occupied camera window the month before over the same screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_previous?: number | null;\n /** Radio panel: visitor identifiers concurrent in a 6-minute slot this month over the same-panel screens: audience per unit time. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot?: number | null;\n /** Radio panel: the same this month over every member. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_panel?: number | null;\n /** Radio panel: the same the month before over the same screens. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_previous?: number | null;\n /** Members of the panel the month before on the evidence kinds both months hold (evidence_compared): the retention's denominator. Unit: screens. */\n previous_comparable_screens?: number | null;\n /** Members of the panel the month before. Unit: screens. */\n previous_screens?: number | null;\n /** same_panel_screens / previous_comparable_screens, with a Wilson interval: the previous month's members still in the panel, on the evidence both months hold (heartbeat camera-on minutes start 2026-08-26, device inference rows are held 90 days). Unit: share. Taken over `previous_comparable_screens`. */\n retained_share?: number | null;\n /** The month's rate over the previous month's, both over the screens in the panel both months. 1 is no change. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index?: number | null;\n /** Upper end of the 95% interval. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_high?: number | null;\n /** Lower end of the 95% interval: two ratio estimators over the same screens, screen-clustered linearisation on the log scale. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_low?: number | null;\n /** Members both months, each month counted on the evidence kinds both months hold (evidence_compared): the screens the index compares. Unit: screens. */\n same_panel_screens?: number | null;\n /** Members of the panel this month. Unit: screens. */\n screens?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** The same-panel series: the product of the monthly indexes from the answer's first month, which reads 1. Unit: ratio. Taken over `same_panel_screens`. */\n chain_index?: number | null;\n /** Days of the month the panel holds (a month in progress holds fewer). Unit: days. */\n days_built?: number | null;\n /** Camera panel: faces per occupied camera window (a face- or person-backed window: the group in view while someone is in view, not audience per unit time) this month over the same-panel screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window?: number | null;\n /** Camera panel: faces per occupied camera window this month over every member. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_panel?: number | null;\n /** Camera panel: faces per occupied camera window the month before over the same screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_previous?: number | null;\n /** Radio panel: visitor identifiers concurrent in a 6-minute slot this month over the same-panel screens: audience per unit time. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot?: number | null;\n /** Radio panel: the same this month over every member. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_panel?: number | null;\n /** Radio panel: the same the month before over the same screens. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_previous?: number | null;\n /** Members of the panel the month before on the evidence kinds both months hold (evidence_compared): the retention's denominator. Unit: screens. */\n previous_comparable_screens?: number | null;\n /** Members of the panel the month before. Unit: screens. */\n previous_screens?: number | null;\n /** same_panel_screens / previous_comparable_screens, with a Wilson interval: the previous month's members still in the panel, on the evidence both months hold (heartbeat camera-on minutes start 2026-08-26, device inference rows are held 90 days). Unit: share. Taken over `previous_comparable_screens`. */\n retained_share?: number | null;\n /** The month's rate over the previous month's, both over the screens in the panel both months. 1 is no change. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index?: number | null;\n /** Upper end of the 95% interval. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_high?: number | null;\n /** Lower end of the 95% interval: two ratio estimators over the same screens, screen-clustered linearisation on the log scale. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_low?: number | null;\n /** Members both months, each month counted on the evidence kinds both months hold (evidence_compared): the screens the index compares. Unit: screens. */\n same_panel_screens?: number | null;\n /** Members of the panel this month. Unit: screens. */\n screens?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSeatbeltComplianceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"seatbelt_compliance\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Every visible rear rider buckled. Unit: readings. */\n all_buckled_readings?: number | null;\n /** The drawn all_buckled readings weighted by 1 / inclusion_probability. Unit: readings. Taken over `drawn_determined_readings`. */\n all_buckled_weighted_readings?: number | null;\n /** Distinct cabs with a seatbelt reading. Unit: vehicles. */\n cabs?: number | null;\n /** Riders present, no strap could be judged: in no denominator. Unit: readings. */\n cannot_determine_readings?: number | null;\n /** all_buckled_readings / determined_readings: every reading that judged a strap (all_buckled, some_unbuckled, none_buckled) counted once, drawn or not. Unit: share. Taken over `determined_readings`. */\n compliance?: number | null;\n /** The design-weighted check: all_buckled over the readings the vision governor drew, each weighted by 1 / inclusion_probability. Never mixed into compliance. Unit: share. Taken over `determined_weighted_readings`. */\n compliance_drawn_weighted?: number | null;\n /** The stratum with no draw (board-burst and UTC-governor admissions): all_buckled over its readings that judged a strap. Unit: share. Taken over `not_drawn_determined_readings`. */\n compliance_not_drawn?: number | null;\n /** The readings that judged a strap: the headline denominator. Unit: readings. */\n determined_readings?: number | null;\n /** The drawn determined readings weighted by 1 / inclusion_probability: the check's denominator. Unit: readings. Taken over `drawn_determined_readings`. */\n determined_weighted_readings?: number | null;\n /** Of those, the readings the vision governor drew (an inclusion probability). Unit: readings. */\n drawn_determined_readings?: number | null;\n /** The back seat was empty: in no denominator. Unit: readings. */\n no_rider_readings?: number | null;\n /** Rear riders present, no strap on any of them. Unit: readings. */\n none_buckled_readings?: number | null;\n /** The all_buckled readings with no draw. Unit: readings. */\n not_drawn_all_buckled_readings?: number | null;\n /** Of those, the readings with no draw (NULL inclusion probability). Unit: readings. */\n not_drawn_determined_readings?: number | null;\n /** not_drawn_determined_readings / determined_readings: the share of judged readings with no draw. A capture-rate change moves it. Unit: share. Taken over `determined_readings`. */\n not_drawn_share?: number | null;\n /** At least one rear rider buckled and one not. Unit: readings. */\n some_unbuckled_readings?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Every visible rear rider buckled. Unit: readings. */\n all_buckled_readings?: number | null;\n /** The drawn all_buckled readings weighted by 1 / inclusion_probability. Unit: readings. Taken over `drawn_determined_readings`. */\n all_buckled_weighted_readings?: number | null;\n /** Distinct cabs with a seatbelt reading. Unit: vehicles. */\n cabs?: number | null;\n /** Riders present, no strap could be judged: in no denominator. Unit: readings. */\n cannot_determine_readings?: number | null;\n /** all_buckled_readings / determined_readings: every reading that judged a strap (all_buckled, some_unbuckled, none_buckled) counted once, drawn or not. Unit: share. Taken over `determined_readings`. */\n compliance?: number | null;\n /** The design-weighted check: all_buckled over the readings the vision governor drew, each weighted by 1 / inclusion_probability. Never mixed into compliance. Unit: share. Taken over `determined_weighted_readings`. */\n compliance_drawn_weighted?: number | null;\n /** The stratum with no draw (board-burst and UTC-governor admissions): all_buckled over its readings that judged a strap. Unit: share. Taken over `not_drawn_determined_readings`. */\n compliance_not_drawn?: number | null;\n /** The readings that judged a strap: the headline denominator. Unit: readings. */\n determined_readings?: number | null;\n /** The drawn determined readings weighted by 1 / inclusion_probability: the check's denominator. Unit: readings. Taken over `drawn_determined_readings`. */\n determined_weighted_readings?: number | null;\n /** Of those, the readings the vision governor drew (an inclusion probability). Unit: readings. */\n drawn_determined_readings?: number | null;\n /** The back seat was empty: in no denominator. Unit: readings. */\n no_rider_readings?: number | null;\n /** Rear riders present, no strap on any of them. Unit: readings. */\n none_buckled_readings?: number | null;\n /** The all_buckled readings with no draw. Unit: readings. */\n not_drawn_all_buckled_readings?: number | null;\n /** Of those, the readings with no draw (NULL inclusion probability). Unit: readings. */\n not_drawn_determined_readings?: number | null;\n /** not_drawn_determined_readings / determined_readings: the share of judged readings with no draw. A capture-rate change moves it. Unit: share. Taken over `determined_readings`. */\n not_drawn_share?: number | null;\n /** At least one rear rider buckled and one not. Unit: readings. */\n some_unbuckled_readings?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Every visible rear rider buckled. Unit: readings. */\n all_buckled_readings?: number | null;\n /** The drawn all_buckled readings weighted by 1 / inclusion_probability. Unit: readings. Taken over `drawn_determined_readings`. */\n all_buckled_weighted_readings?: number | null;\n /** Distinct cabs with a seatbelt reading. Unit: vehicles. */\n cabs?: number | null;\n /** Riders present, no strap could be judged: in no denominator. Unit: readings. */\n cannot_determine_readings?: number | null;\n /** all_buckled_readings / determined_readings: every reading that judged a strap (all_buckled, some_unbuckled, none_buckled) counted once, drawn or not. Unit: share. Taken over `determined_readings`. */\n compliance?: number | null;\n /** The design-weighted check: all_buckled over the readings the vision governor drew, each weighted by 1 / inclusion_probability. Never mixed into compliance. Unit: share. Taken over `determined_weighted_readings`. */\n compliance_drawn_weighted?: number | null;\n /** The stratum with no draw (board-burst and UTC-governor admissions): all_buckled over its readings that judged a strap. Unit: share. Taken over `not_drawn_determined_readings`. */\n compliance_not_drawn?: number | null;\n /** The readings that judged a strap: the headline denominator. Unit: readings. */\n determined_readings?: number | null;\n /** The drawn determined readings weighted by 1 / inclusion_probability: the check's denominator. Unit: readings. Taken over `drawn_determined_readings`. */\n determined_weighted_readings?: number | null;\n /** Of those, the readings the vision governor drew (an inclusion probability). Unit: readings. */\n drawn_determined_readings?: number | null;\n /** The back seat was empty: in no denominator. Unit: readings. */\n no_rider_readings?: number | null;\n /** Rear riders present, no strap on any of them. Unit: readings. */\n none_buckled_readings?: number | null;\n /** The all_buckled readings with no draw. Unit: readings. */\n not_drawn_all_buckled_readings?: number | null;\n /** Of those, the readings with no draw (NULL inclusion probability). Unit: readings. */\n not_drawn_determined_readings?: number | null;\n /** not_drawn_determined_readings / determined_readings: the share of judged readings with no draw. A capture-rate change moves it. Unit: share. Taken over `determined_readings`. */\n not_drawn_share?: number | null;\n /** At least one rear rider buckled and one not. Unit: readings. */\n some_unbuckled_readings?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSeatbeltUnbuckledRideRateResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"seatbelt_unbuckled_ride_rate\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct cabs with such a ride. Unit: vehicles. */\n cabs?: number | null;\n /** Rides with at least one drawn judged reading: the check's rides. Unit: rides. */\n drawn_rides?: number | null;\n /** Rides whose judged readings were all outside the draw. Unit: rides. */\n not_drawn_rides?: number | null;\n /** Of those, the unbuckled rides. Unit: rides. */\n not_drawn_unbuckled_rides?: number | null;\n /** Camera rides with at least one seatbelt reading that judged a strap. Unit: rides. */\n rides?: number | null;\n /** The drawn rides weighted by 1 / their inclusion probability. Unit: rides. Taken over `drawn_rides`. */\n rides_weighted?: number | null;\n /** unbuckled_rides / rides: every camera ride with a reading that judged a strap counted once, drawn or not. Unit: share. Taken over `rides`. */\n unbuckled_ride_rate?: number | null;\n /** The design-weighted check: unbuckled_rides_weighted / rides_weighted over the rides with a drawn reading, each weighted by 1 / the largest inclusion probability among them. Never mixed into the rate. Unit: share. Taken over `rides_weighted`. */\n unbuckled_ride_rate_drawn_weighted?: number | null;\n /** The stratum with no draw: unbuckled over the rides whose judged readings were all outside the draw. Unit: share. Taken over `not_drawn_rides`. */\n unbuckled_ride_rate_not_drawn?: number | null;\n /** Of those, the rides where any such reading saw an unbuckled rider. Unit: rides. */\n unbuckled_rides?: number | null;\n /** The drawn unbuckled rides, weighted the same way. Unit: rides. Taken over `drawn_rides`. */\n unbuckled_rides_weighted?: number | null;\n /** Camera rides whose seatbelt readings were all cannot_determine: riders there, no strap judged. Counted beside the rate, in neither of its terms. Unit: rides. */\n undetermined_rides?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct cabs with such a ride. Unit: vehicles. */\n cabs?: number | null;\n /** Rides with at least one drawn judged reading: the check's rides. Unit: rides. */\n drawn_rides?: number | null;\n /** Rides whose judged readings were all outside the draw. Unit: rides. */\n not_drawn_rides?: number | null;\n /** Of those, the unbuckled rides. Unit: rides. */\n not_drawn_unbuckled_rides?: number | null;\n /** Camera rides with at least one seatbelt reading that judged a strap. Unit: rides. */\n rides?: number | null;\n /** The drawn rides weighted by 1 / their inclusion probability. Unit: rides. Taken over `drawn_rides`. */\n rides_weighted?: number | null;\n /** unbuckled_rides / rides: every camera ride with a reading that judged a strap counted once, drawn or not. Unit: share. Taken over `rides`. */\n unbuckled_ride_rate?: number | null;\n /** The design-weighted check: unbuckled_rides_weighted / rides_weighted over the rides with a drawn reading, each weighted by 1 / the largest inclusion probability among them. Never mixed into the rate. Unit: share. Taken over `rides_weighted`. */\n unbuckled_ride_rate_drawn_weighted?: number | null;\n /** The stratum with no draw: unbuckled over the rides whose judged readings were all outside the draw. Unit: share. Taken over `not_drawn_rides`. */\n unbuckled_ride_rate_not_drawn?: number | null;\n /** Of those, the rides where any such reading saw an unbuckled rider. Unit: rides. */\n unbuckled_rides?: number | null;\n /** The drawn unbuckled rides, weighted the same way. Unit: rides. Taken over `drawn_rides`. */\n unbuckled_rides_weighted?: number | null;\n /** Camera rides whose seatbelt readings were all cannot_determine: riders there, no strap judged. Counted beside the rate, in neither of its terms. Unit: rides. */\n undetermined_rides?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct cabs with such a ride. Unit: vehicles. */\n cabs?: number | null;\n /** Rides with at least one drawn judged reading: the check's rides. Unit: rides. */\n drawn_rides?: number | null;\n /** Rides whose judged readings were all outside the draw. Unit: rides. */\n not_drawn_rides?: number | null;\n /** Of those, the unbuckled rides. Unit: rides. */\n not_drawn_unbuckled_rides?: number | null;\n /** Camera rides with at least one seatbelt reading that judged a strap. Unit: rides. */\n rides?: number | null;\n /** The drawn rides weighted by 1 / their inclusion probability. Unit: rides. Taken over `drawn_rides`. */\n rides_weighted?: number | null;\n /** unbuckled_rides / rides: every camera ride with a reading that judged a strap counted once, drawn or not. Unit: share. Taken over `rides`. */\n unbuckled_ride_rate?: number | null;\n /** The design-weighted check: unbuckled_rides_weighted / rides_weighted over the rides with a drawn reading, each weighted by 1 / the largest inclusion probability among them. Never mixed into the rate. Unit: share. Taken over `rides_weighted`. */\n unbuckled_ride_rate_drawn_weighted?: number | null;\n /** The stratum with no draw: unbuckled over the rides whose judged readings were all outside the draw. Unit: share. Taken over `not_drawn_rides`. */\n unbuckled_ride_rate_not_drawn?: number | null;\n /** Of those, the rides where any such reading saw an unbuckled rider. Unit: rides. */\n unbuckled_rides?: number | null;\n /** The drawn unbuckled rides, weighted the same way. Unit: rides. Taken over `drawn_rides`. */\n unbuckled_rides_weighted?: number | null;\n /** Camera rides whose seatbelt readings were all cannot_determine: riders there, no strap judged. Counted beside the rate, in neither of its terms. Unit: rides. */\n undetermined_rides?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSensingCensusResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"sensing_census\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Screens with a device-sourced inference row in the day: the camera pipeline ran. Unit: screens. */\n camera_screens?: number | null;\n /** Screens with a visitor-source radio row (BLE, mDNS, SSDP, HTTP probe) in the day. Unit: screens. */\n radio_screens?: number | null;\n /** Screens with either: the union, never the intersection. Unit: screens. */\n sensing_screens?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Screens with a device-sourced inference row in the day: the camera pipeline ran. Unit: screens. */\n camera_screens?: number | null;\n /** Screens with a visitor-source radio row (BLE, mDNS, SSDP, HTTP probe) in the day. Unit: screens. */\n radio_screens?: number | null;\n /** Screens with either: the union, never the intersection. Unit: screens. */\n sensing_screens?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Screens with a device-sourced inference row in the day: the camera pipeline ran. Unit: screens. */\n camera_screens?: number | null;\n /** Screens with a visitor-source radio row (BLE, mDNS, SSDP, HTTP probe) in the day. Unit: screens. */\n radio_screens?: number | null;\n /** Screens with either: the union, never the intersection. Unit: screens. */\n sensing_screens?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MultiplierFeed = {\n absent_faces?: Array<{\n /** Faces with that reason. */\n faces: number;\n /** Why the faces carry no multiplier. */\n reason: string;\n }>;\n columns: Array<{\n /** CSV header. */\n header: string;\n /** Column key. */\n key: string;\n }>;\n /** Hash of this file. */\n content_sha256: string;\n /** multipliers (per-face impression multipliers), faces or demographics. */\n dataset: string;\n feed: {\n /** Feed hash. */\n content_sha256: string;\n /** Due, UTC. */\n due_at: string | null;\n /** Feed date. */\n feed_date: string;\n /** Published, UTC. */\n published_at: string | null;\n } | null;\n /** Who the multipliers count: `vehicle_occupants`. */\n ips_population?: string;\n qty?: {\n /** OpenRTB qty.sourcetype. */\n sourcetype: number;\n /** qty.vendor. */\n vendor: string;\n };\n release: {\n /** Release hash. */\n content_sha256: string;\n /** When it came into force. */\n published_at: string;\n /** Release id. */\n release_id: string;\n /** Currency window. */\n window_end: string;\n } | null;\n /** One row per face x daypart (multipliers: release_id, feed_date, ssp, ssp_venue_id, vistar_venue_id, venue_name, publisher_name, venue_type_id, dma_code, state, country, latitude, longitude, timezone, daypart, daypart_local_hours, qty_multiplier, qty_multiplier_low, qty_multiplier_high, multiplier_absent_reason, ips_population, qty_sourcetype, qty_vendor, interval_method, release_window_end, release_passes, release_vehicles, carried_from, reissue_reason, measured_ips, measured_ips_low, measured_ips_high, measured_passes, measured_vehicles, reissue_due) or per face x dimension value (demographics: window_end, window_days, dimension, value, estimand_kind, share, ci_low, ci_high, support_n, vehicles, resolved_level, measured_share). `columns` lists them in order. */\n rows: Array<Record<string, string | number | boolean | null | null>>;\n /** The SSP whose venue ids key the file (vistar default). */\n ssp: string;\n /** Rows were capped. */\n truncated: boolean;\n};\n\nexport type DataApi_DataProducts_MultiplierFeedResponse = {\n data: DataApi_DataProducts_MultiplierFeed;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OccluderCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_OccluderProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_OccluderMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_OccluderMeta = {\n /** Why no buildings are served. */\n absent_reason: string | null;\n /** Board face id. */\n board_id: string;\n /** Buildings returned. */\n count: number;\n /** Height assumed for a building with none recorded, metres. */\n floor_height_m: number;\n orientations: Array<{\n /** Face index. */\n orientation_idx: number;\n /** Visibility range, metres. */\n visibility_range_m: number | null;\n }>;\n /** Overture Maps buildings release. */\n overture_release: string;\n /** Radius searched, metres. */\n radius_m: number;\n /** The building list was capped. */\n truncated: boolean;\n /** Viewshed build version. */\n viewshed_version: string | null;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OccluderProperties = {\n /** The height is measured, not the floor default. */\n height_known: boolean;\n /** Building height, metres. */\n height_m: number | null;\n /** Height of the building's base, metres. */\n min_height_m: number | null;\n};\n\nexport type DataApi_DataProducts_OwnerFace = {\n /** Why the face carries no measured figure. */\n absent_reason: string | null;\n /** Ads seen per pass. */\n ads_seen_per_pass: number | null;\n benchmark: DataApi_DataProducts_Benchmark & Record<string, unknown> | null;\n /** Board face id. */\n board_id: string;\n /** ISO-3166 alpha-2. */\n country: string;\n /** People passing in position to see, per day. */\n daily_contacts: number | null;\n /** DMA code. */\n dma_code: string | null;\n facing: {\n /** Why facing seconds are absent. */\n absent_reason?: string;\n /** Instrumented legible seconds. */\n facing_base_s?: number | null;\n /** Facing seconds. */\n facing_s?: number | null;\n /** First day. */\n from?: string;\n /** Instrument. */\n instrument: string;\n pass_audience_versions?: Array<number>;\n /** Facing share. */\n share?: number | null;\n /** Last day. */\n to?: string;\n };\n impressions_per_spot: {\n /** Upper bound. */\n high: number | null;\n /** Interval method. */\n interval_method: string | null;\n /** Lower bound. */\n low: number | null;\n /** Measured impressions per spot. */\n measured: number | null;\n /** The owner's figure. */\n owner: number | null;\n };\n /** The face is one the headline figures are computed over (measured by 2+ vehicles). */\n in_headline: boolean;\n /** Who the measured figure counts. */\n ips_population: string;\n /** Active in the catalogue. */\n is_active: boolean;\n /** Latitude. */\n latitude: number;\n /** Longitude. */\n longitude: number;\n /** The face carries a measured cell in the window. */\n measured: boolean;\n money: {\n /** Annual revenue difference at the floor, USD. */\n annual_opportunity_usd: number | null;\n /** Current floor CPM, USD. */\n floor_cpm_usd: number | null;\n /** Recommended floor CPM, USD. */\n recommended_floor_cpm: number | null;\n /** Why none is drawn (population_mismatch, audience_at_venue). */\n revenue_available_absent_reason: string | null;\n /** Cells it is drawn from. */\n revenue_available_cells: number | null;\n /** Annual revenue the measurement makes available, USD. */\n revenue_available_usd: number | null;\n };\n /** Publisher. */\n publisher_name: string;\n release: {\n /** Upper bound. */\n high: number;\n /** Lower bound. */\n low: number;\n /** Multiplier in force. */\n multiplier: number;\n /** Release. */\n release_id: string;\n /** Window. */\n window_end: string;\n } | null;\n /** The owner's spots per day. */\n spots_per_day_owner: number | null;\n /** State or province. */\n state: string | null;\n support: {\n /** Passes. */\n passes: number | null;\n /** Distinct vehicles. */\n vehicles: number | null;\n };\n /** IANA zone. */\n timezone: string;\n /** Catalogue name. */\n venue_name: string;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n yield: {\n /** Why no ratio is served. */\n absent_reason: string | null;\n /** ratio or incremental. */\n basis: string | null;\n /** Upper bound. */\n compared_high: number | null;\n /** That count per spot. */\n compared_impressions_per_spot: number | null;\n /** Lower bound. */\n compared_low: number | null;\n /** The count the owner's figure is compared with. */\n compared_population: string | null;\n /** Upper bound. */\n high: number | null;\n /** Lower bound. */\n low: number | null;\n /** Measured over the owner's figure. */\n ratio: number | null;\n };\n};\n\nexport type DataApi_DataProducts_OwnerFaceDetail = {\n audience: DataApi_DataProducts_BoardAudience & Record<string, unknown> | null;\n benchmark: DataApi_DataProducts_Benchmark & Record<string, unknown> | null;\n currency: DataApi_DataProducts_BoardCurrency & Record<string, unknown> | null;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours: Record<string, Array<number>>;\n face: DataApi_DataProducts_OwnerFace;\n release: {\n cells: Array<Record<string, unknown>>;\n /** In force since. */\n published_at: string;\n /** Release. */\n release_id: string;\n } | null;\n spec: Record<string, unknown> | null;\n ssp_venues: Array<{\n /** Where we hold it from. */\n source: string;\n /** Reference. */\n source_ref?: string | null;\n /** SSP. */\n ssp: string;\n /** Its venue id. */\n ssp_venue_id: string;\n }>;\n window: DataApi_DataProducts_Window;\n};\n\nexport type DataApi_DataProducts_OwnerFaceResponse = {\n data: DataApi_DataProducts_OwnerFaceDetail;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OwnerFaces = {\n faces: Array<DataApi_DataProducts_OwnerFace>;\n markets: Array<DataApi_DataProducts_Benchmark>;\n method: DataApi_DataProducts_Method;\n owner: {\n /** Organisation. */\n org: string;\n publishers: Array<string>;\n };\n release: {\n /** Hash. */\n content_sha256: string;\n /** In force since. */\n published_at: string;\n /** Release. */\n release_id: string;\n /** Window. */\n window_end: string;\n } | null;\n /** faces, faces_active, measured, absent, passes, headline {min_vehicles, faces, passes}, revenue_available {usd_year, faces, cells, counted_faces, absent_faces, days_per_year, ranking_bar}, measured_impressions_day, owner_impressions_day, weighted_yield, annual_difference_at_floor_usd, facing_s, facing_base_s, facing_share. */\n summary: Record<string, unknown>;\n /** Faces were capped. */\n truncated: boolean;\n window: DataApi_DataProducts_Window;\n};\n\nexport type DataApi_DataProducts_OwnerFacesResponse = {\n data: DataApi_DataProducts_OwnerFaces;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OwnerUploadResponse = {\n /** The plan: rows read, refused lines with their reasons, unmatched and ambiguous faces, and what was written (dry_run writes nothing). */\n data: Record<string, unknown>;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_PassReplay = {\n /** Board face id. */\n board_id: string;\n /** Local day replayed. */\n date: string;\n meta: {\n /** Board face id. */\n board_id: string;\n /** Clip distance around the viewshed, metres. */\n clip_m: number;\n /** The face has a play log for the day. */\n creative_log: boolean;\n /** Days the replay trails real time. */\n delay_days: number;\n /** Face passes on the day: the traversals those rows make (the sum of face_share). */\n face_passes_total?: number | null;\n facing: DataApi_DataProducts_FacingVerdict;\n /** Offset of the next page. */\n next_offset: number | null;\n /** Page offset. */\n offset: number;\n /** Page order. */\n order: string;\n /** Pass rows on this page. */\n passes_returned: number;\n /** Pass rows on the day: the items the pages hold (one per candidate facing of a traversal). */\n passes_total: number;\n /** Seconds of path kept around each pass. */\n path_window_s: number;\n /** Passes were capped. */\n truncated: boolean;\n viewshed_versions: Array<string>;\n };\n passes: Array<DataApi_DataProducts_ReplayPass>;\n};\n\nexport type DataApi_DataProducts_PassReplayResponse = {\n data: DataApi_DataProducts_PassReplay;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_Release = {\n /** Cells new in this release. */\n added_cells: number;\n /** Boards in the release. */\n boards: number;\n /** Board x daypart cells in the release. */\n cells: number;\n /** Hash of the release content. */\n content_sha256: string;\n /** Currency method version. */\n currency_method_version: number;\n /** Smallest relative change that triggers a reissue. */\n min_rel_change: number | null;\n /** Cells that moved from the previous release. */\n moved_cells: number;\n /** Pass-audience method version. */\n pass_audience_version: number;\n /** When it came into force, UTC. */\n published_at: string;\n /** 0 for the first issue. */\n reissue_number: number;\n /** The release this one reissues. */\n reissue_of: string | null;\n /** Release id (mooh-YYYY-MM[-rN]). */\n release_id: string;\n /** Month the release is for. */\n release_month: string;\n /** When it was superseded, UTC. */\n superseded_at: string | null;\n /** Currency window the release was cut from. */\n window_end: string;\n};\n\nexport type DataApi_DataProducts_ReleaseRegistry = {\n feeds: Array<DataApi_DataProducts_FeedPublication>;\n /** The release in force. */\n in_force: string | null;\n qty: {\n /** OpenRTB qty.sourcetype (1 = measurement vendor). */\n sourcetype: number;\n /** qty.vendor (trillboards.com). */\n vendor: string;\n };\n releases: Array<DataApi_DataProducts_Release>;\n /** What a release's multipliers count: measured_impressions_per_spot. */\n unit: string;\n};\n\nexport type DataApi_DataProducts_ReleaseRegistryResponse = {\n data: DataApi_DataProducts_ReleaseRegistry;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_ReplayPass = {\n /** Angle from the face normal per second, degrees. */\n beta_1hz: Array<number | null>;\n creatives?: Array<{\n /** Advertiser. */\n advertiser: string | null;\n /** owner_play_log or modelled_rotation. */\n basis: string;\n /** Campaign. */\n campaign_key: string | null;\n /** Creative on air during the pass. */\n creative_key: string;\n /** Seconds the creative was on air while the face was legible. */\n overlap_s: number;\n /** Probability the creative was seen. */\n p_seen: number | null;\n /** exact or modelled. */\n precision: string;\n }> | null;\n /** Distance to the face per second, metres. */\n dist_1hz: Array<number | null>;\n /** Why facing seconds are absent. */\n facing_absent_reason: string | null;\n /** Seconds a rider faced the board. */\n facing_s: number | null;\n /** 1 when the face was legible that second. */\n legible_1hz: Array<number>;\n /** Legible seconds in the pass. */\n legible_s: number | null;\n /** Face passed. */\n orientation_idx: number;\n /** Pass id (vehicle pseudonym keyed to the caller and session, and pass number). */\n pass_key: string;\n /** The vehicle path, [lon, lat] at 1 Hz, clipped to the viewshed +-200 m. */\n path: Array<Array<number>>;\n /** driver or passenger side. */\n read_side: string | null;\n /** Side of the road the face is on, relative to travel. */\n side: string | null;\n /** Speed at the closest point, m/s. */\n speed_at_closest_mps: number | null;\n /** Seconds from entry to the closest point. */\n t_closest_off_s: number | null;\n /** When the vehicle entered the viewshed, UTC. */\n t_enter: string;\n /** Offset of each path point from t_enter, ms. */\n t_off_ms: Array<number>;\n /** Visible seconds in the pass. */\n visible_s: number | null;\n};\n\nexport type DataApi_DataProducts_RoadCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_RoadProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_ViewshedMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_RoadProperties = {\n /** 0 = with the way's drawing direction, 1 = against it. */\n direction?: number;\n /** Free-flow speed, km/h. */\n free_flow_kph?: number | null;\n /** OSM highway class. */\n highway: string;\n /** road. */\n kind: string;\n /** The road serves a measured board in the bbox or set. */\n measured?: boolean;\n /** The metric the feature carries. */\n metric?: string;\n /** Road name. */\n name?: string | null;\n /** The road serves a member of the set. */\n serves_set?: boolean;\n /** Measured speed, km/h. */\n speed_kph?: number | null;\n /** Measured over free-flow speed. */\n speed_ratio?: number | null;\n /** Fleet traversals scaled to the response's busiest road (1.0). */\n traversal_index?: number | null;\n /** OpenStreetMap way id. */\n way_id: string;\n};\n\nexport type DataApi_DataProducts_SetCoverage = {\n /** When the coverage was built. */\n built_at: string | null;\n /** People passing in position to see, per day, summed. */\n daily_contacts: number | null;\n /** Members with a measured currency cell. */\n measured: number | null;\n /** Measured impressions per day, summed. */\n measured_impressions_day: number | null;\n /** Boards in the set. */\n members: number | null;\n /** Currency method version. */\n method_version: number | null;\n /** The board-pass rows across the members: a reconciliation count, never a pass count. */\n pass_rows?: number | null;\n /** Face passes across the members (the sum of each pass's share of its face). Null on a window built before they existed. */\n passes: number | null;\n /** Distinct vehicles behind them. */\n vehicles: number | null;\n /** Days in the window. */\n window_days: number | null;\n /** Currency window end. */\n window_end: string | null;\n /** Members our fleet passed. */\n with_passes: number | null;\n /** Members with a built viewshed. */\n with_viewshed: number | null;\n} | null;\n\nexport type DataApi_DataProducts_SetCoverageEnvelope = {\n data: DataApi_DataProducts_SetCoverageResponse;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_SetCoverageResponse = {\n coverage: DataApi_DataProducts_SetCoverage;\n set: DataApi_DataProducts_CurationSet;\n};\n\nexport type DataApi_DataProducts_SightedBrand = {\n /** Brand name. */\n brand: string;\n /** Resolved brand id (brand graph), when resolved. */\n brand_id: string | null;\n /** Brand key. */\n brand_key: string;\n /** Of those, reads on a registered board face. */\n face_sightings: number;\n /** Distinct registered faces it was read on. */\n faces: number;\n /** First read, UTC. */\n first_seen_at: string | null;\n /** Every read held for the brand, any window. */\n held_sightings: number;\n /** Newest read, UTC. */\n last_seen_at: string | null;\n markets: Array<DataApi_DataProducts_BrandMarket>;\n /** exact or prefix. */\n match: string | null;\n /** The spelling the query matched. */\n matched: string | null;\n /** Reads of the brand in the window. */\n sightings: number;\n /** Reads on no registered face. */\n street_sightings: number;\n};\n\nexport type DataApi_DataProducts_TileSum = {\n /** Legible seconds on instrumented passes (the facing denominator). */\n facing_base_s: number | null;\n /** Facing seconds (head turned to the face), when the facing gate is open. */\n facing_s: number | null;\n /** Week x daypart leaves summed. */\n leaves?: number;\n /** Legible seconds. */\n legible_s: number;\n /** Passes (face-share weighted). */\n passes: number;\n /** Monday the week starts on. */\n week_start?: string;\n};\n\nexport type DataApi_DataProducts_ViewshedCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_ViewshedProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_ViewshedMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_ViewshedMeta = {\n /** Why no viewshed is served. */\n absent_reason?: string | null;\n /** The bbox drawn, if one was asked. */\n bbox?: Array<number> | null;\n /** Board face id (single-board viewshed). */\n board_id?: string;\n /** Features returned. */\n count?: number;\n /** Day-of-week type. */\n dow_type?: string;\n /** Local hour, or null for every hour. */\n hour?: number | null;\n /** Set members drawn. */\n members?: number;\n /** Road metric drawn. */\n metric?: string;\n /** Faces on the structure. */\n orientations?: number;\n /** included, or omitted past the overlay cap. */\n polygons?: string;\n /** Road speed profile version. */\n profile_version?: string | null;\n /** Curated set key (set viewsheds and roads), or null when no set was drawn. */\n set_key?: string | null;\n /** The set was capped at the overlay limit. */\n truncated?: boolean;\n /** Viewshed build version. */\n viewshed_version?: string | null;\n watermark?: DataApi_DataProducts_Watermark;\n /** Currency window end. */\n window_end?: string | null;\n};\n\nexport type DataApi_DataProducts_ViewshedProperties = {\n /** Why no figure is served (no_passes, ...). */\n absent_reason: string | null;\n /** Ads seen per pass. */\n ads_seen_mean: number | null;\n /** legible or visible. */\n area?: string;\n /** Face format class (bulletin, poster, junior, ...). */\n aspect_class?: string | null;\n /** Direction the face points, degrees from north. */\n azimuth_deg?: number | null;\n /** Where the azimuth came from (owner_spec, name_token, road_snap, ...). */\n azimuth_source?: string | null;\n /** Board face id. */\n board_id: string;\n /** Face height, metres. */\n face_height_m?: number | null;\n /** The face's own name (the owner's reference, else the catalogue venue name). */\n face_name?: string | null;\n /** owner_spec or catalogue. */\n face_name_source?: string | null;\n /** Face width, metres. */\n face_width_m?: number | null;\n /** Measured impressions per spot. */\n ips: number | null;\n /** Interval upper bound. */\n ips_high: number | null;\n /** Interval lower bound. */\n ips_low: number | null;\n /** Who ips counts: `vehicle_occupants`. */\n ips_population: string;\n /** viewshed (legible or visible area polygon) or face (the face point). */\n kind: string;\n /** Distance the face is legible from, metres. */\n legibility_range_m?: number | null;\n /** The face carries a measured currency cell. */\n measured: boolean;\n /** Height of the face centre above the road, metres. */\n mount_height_m?: number | null;\n /** Source of the mount height (format, rooftop, a spec source). */\n mount_source?: string | null;\n /** Share of the viewshed blocked by buildings. */\n occluded_share?: number | null;\n /** Face index on the structure. */\n orientation_idx?: number;\n /** Share of the structure's passes this face serves. */\n orientation_share?: number;\n /** Passes behind the figure. */\n passes: number | null;\n /** Media owner. */\n publisher_name: string;\n /** Source of the served size (owner_spec, ...); null for the format default. */\n size_source?: string | null;\n /** Distinct vehicles behind the figure. */\n vehicles: number | null;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n /** ok, or why the viewshed is degenerate. */\n viewshed_status?: string | null;\n /** Viewshed build version. */\n viewshed_version?: string | null;\n /** Distance the face is visible from, metres. */\n visibility_range_m?: number | null;\n};\n\n/**\n * Present on every body read on a ledger (an organisation's or an account's): it names the licensee and the UTC day.\n */\nexport type DataApi_DataProducts_Watermark = {\n /** Watermark id, also embedded in the body's validator. */\n id: string;\n /** UTC day the body was issued. */\n issued_on: string;\n /** The visible licence line: who the body was read for and the UTC day. */\n text: string;\n};\n\nexport type DataApi_DataProducts_Window = {\n /** Days in the window (28 for the currency window). */\n window_days: number;\n /** Last local day of the measurement window. */\n window_end: string;\n};\n\nexport type DataApi_DataProducts_YieldReport = {\n columns: Array<{\n /** CSV header. */\n header: string;\n /** Column key. */\n key: string;\n }>;\n /** Daypart reported. */\n daypart: string;\n filters: {\n /** DMA filter. */\n dma: string | null;\n /** Venue type filter. */\n venue_type_id: number | null;\n };\n method: DataApi_DataProducts_Method;\n /** Publisher. */\n publisher: string;\n /** Active faces. */\n publisher_boards_active: number;\n /** Faces the publisher holds. */\n publisher_boards_total: number;\n /** One row per face: the columns listed in `columns`. */\n rows: Array<Record<string, unknown>>;\n /** boards, boards_active, measured, absent, ratio_boards, share_yield_low_above_one, weighted_yield, annual_difference_at_floor_usd. */\n summary: Record<string, unknown>;\n /** Rows were capped. */\n truncated: boolean;\n /** Days. */\n window_days: number | null;\n /** Currency window. */\n window_end: string | null;\n /** published, none or unverified. */\n window_state: string;\n};\n\nexport type DataApi_DataProducts_YieldReportResponse = {\n data: DataApi_DataProducts_YieldReport;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_Error = {\n error: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code: string;\n /** Per-field violations (populated from Zod errors). */\n details?: Array<{\n code?: string;\n message?: string;\n param?: string;\n }>;\n /** Link to the documentation for this error code (https://api.trillboards.com/docs/errors#<code>). */\n doc_url?: string;\n /** Agent-facing hints and suggestions. */\n help?: {\n portal_url?: string;\n suggestions?: Array<string>;\n summary?: string;\n try_next?: string;\n };\n /** Human-readable error message. Safe to surface to end-users. */\n message: string;\n /** Offending parameter name (when applicable). */\n param?: string;\n /** Echoed X-Request-Id for correlation. */\n request_id: string;\n /** Stripe-style error taxonomy (derived from utils/errorCatalog). */\n type: \"api_error\" | \"authentication_error\" | \"idempotency_error\" | \"invalid_request_error\" | \"permission_error\" | \"rate_limit_error\";\n };\n};\n\n/**\n * The 143 CATALOGUED error codes, generated from utils/errorCatalog.js — the same catalog that backs https://api.trillboards.com/docs/errors. This is the documented registry, NOT the complete set of codes the API can emit: a response `code` is an open string (see `TrillboardsError`). Use this list to recognise a code, never to assume a response cannot carry another.\n */\nexport type DataApi_ErrorCode = \"AUTH_REQUIRED\" | \"BRAND_CONFIGURATION_FAILED\" | \"BRAND_PROFILE_CONFLICT\" | \"BRAND_PROFILE_NOT_FOUND\" | \"CREATIVE_ADVERTISEMENT_NOT_OWNED\" | \"CREATIVE_MODERATION_UNAVAILABLE\" | \"CREATIVE_NOT_LINKED\" | \"CREATIVE_NOT_READY\" | \"CREATIVE_POLICY_CONFLICT\" | \"CREATIVE_TOO_LARGE\" | \"EXPERIMENT_COMPLETED\" | \"EXPERIMENT_NOT_FOUND\" | \"FEEDBACK_POLICY_REQUIRED\" | \"IDEMPOTENCY_CONFLICT\" | \"INVALID_BRAND_RULES\" | \"INVALID_CREATIVE_URL\" | \"INVALID_CREATIVE_WEIGHTS\" | \"INVALID_FEEDBACK_CREATIVE\" | \"INVALID_FEEDBACK_OBJECTIVE\" | \"INVALID_FEEDBACK_REQUEST\" | \"INVALID_POLICY_VERSION\" | \"INVALID_VARIANTS\" | \"MEDIA_BUY_NOT_FOUND\" | \"OPERATION_ALREADY_COMMITTED\" | \"OPERATION_IN_PROGRESS\" | \"POLICY_NOT_AVAILABLE\" | \"SOURCE_CREATIVE_NOT_FOUND\" | \"UNSUPPORTED_CREATIVE_TYPE\" | \"VARIANT_IDENTITY_CONFLICT\" | \"ad_interval_out_of_range\" | \"allocation_out_of_range\" | \"analytics_unavailable\" | \"api_key_expired\" | \"api_key_owner_missing\" | \"api_key_revoked\" | \"array_items_must_be_strings\" | \"array_too_large\" | \"auth_error\" | \"authentication_required\" | \"batch_size_exceeded\" | \"blocked_advertisers_too_large\" | \"blocked_iab_categories_too_large\" | \"client_ip_required\" | \"concurrent_request_limit\" | \"conflict\" | \"conflicting_lists\" | \"creative_policy_conflict\" | \"creative_policy_forbidden\" | \"daily_quota_exceeded\" | \"database_error\" | \"dataset_not_scopable\" | \"device_already_registered\" | \"device_identity_missing\" | \"device_identity_underivable\" | \"device_not_found\" | \"device_offline\" | \"dsp_access_denied\" | \"error\" | \"field_must_be_array\" | \"field_must_be_boolean\" | \"field_too_long\" | \"floor_price_out_of_range\" | \"forbidden\" | \"idempotency_error\" | \"idempotency_key_in_use\" | \"idempotency_key_mismatch\" | \"insufficient_data\" | \"insufficient_permissions\" | \"insufficient_scope\" | \"internal_error\" | \"invalid_ad_surface_mode\" | \"invalid_age_rating\" | \"invalid_api_key\" | \"invalid_api_key_format\" | \"invalid_array_items\" | \"invalid_creative_policy\" | \"invalid_currency\" | \"invalid_dataset\" | \"invalid_device_id\" | \"invalid_dimensions\" | \"invalid_display_mode\" | \"invalid_field_type\" | \"invalid_field_value\" | \"invalid_fingerprint\" | \"invalid_json\" | \"invalid_lbar_position\" | \"invalid_lbar_settings\" | \"invalid_measures\" | \"invalid_media_url\" | \"invalid_order_by\" | \"invalid_orientation\" | \"invalid_pip_position\" | \"invalid_pip_settings\" | \"invalid_preference_level\" | \"invalid_preferences\" | \"invalid_provider\" | \"invalid_screen_id\" | \"invalid_segment_rules\" | \"invalid_sizing_mode\" | \"invalid_stream_type\" | \"invalid_webhook_events\" | \"invalid_webhook_url\" | \"lbar_settings_must_be_object\" | \"lbar_size_out_of_range\" | \"missing_required_field\" | \"not_found\" | \"openrtb_auth_failed\" | \"openrtb_config_missing\" | \"paired_training_insert_failed\" | \"paired_training_rate_limit_exceeded\" | \"partner_inactive\" | \"pip_margin_out_of_range\" | \"pip_settings_must_be_object\" | \"pip_size_ratio_out_of_range\" | \"preferences_must_be_object\" | \"preferences_required\" | \"preset_id_required\" | \"preset_not_found\" | \"rate_limit_exceeded\" | \"resource_locked\" | \"screen_ids_required\" | \"screen_not_found\" | \"screen_not_in_scope\" | \"sdk_enrich_rate_limit_exceeded\" | \"sdk_impression_rate_limit_exceeded\" | \"sdk_qr_beacon_rate_limit_exceeded\" | \"sdk_qr_scan_rate_limit_exceeded\" | \"segment_limit_exceeded\" | \"segment_not_found\" | \"service_unavailable\" | \"stale_data\" | \"stream_content_required\" | \"stream_not_found\" | \"tier_insufficient\" | \"timeout\" | \"timeout_out_of_range\" | \"unknown_agent_type\" | \"unsupported_media_type\" | \"validation_error\" | \"webhook_limit_exceeded\" | \"webhook_not_found\" | \"webhook_secret_expired\" | \"webhook_url_unreachable\";\n\nexport type DataApi_FeedbackRewardQuery = {\n /** Opaque next_cursor from this same date scope; rewind after scan_complete. */\n cursor?: string;\n /** Inclusive first play date, YYYY-MM-DD; date range is at most 31 days. */\n from: string;\n /** Unique caller-owned billing key for this page; committed retries return the receipt, not another read. */\n idempotency_key: string;\n /** Maximum native play states returned on this metered page. */\n limit?: number;\n /** Inclusive last play date, YYYY-MM-DD; date range is at most 31 days. */\n to: string;\n};\n\nexport type DataApi_LookalikeResponse = {\n matches: Array<Record<string, unknown>>;\n matches_count: number;\n source_screen_id: string;\n};\n\nexport type DataApi_QueryDslBody = {\n /** Dataset name. Defaults to `inference_outcomes`. */\n dataset?: string;\n dimensions?: Array<string>;\n filters?: Array<DataApi_QueryFilter>;\n limit?: number;\n measures?: Array<string>;\n order_by?: Array<DataApi_QueryOrderBy>;\n};\n\nexport type DataApi_QueryDslResponse = {\n count: number;\n /** `observation_stream` when it is served from ClickHouse: the population the answer counts and the first instant the dataset holds. */\n coverage?: {\n population: string;\n since: string;\n };\n dataset: string;\n dimensions: Array<string>;\n /** `inference_outcomes` only. The `inference_source` values the query read (`null` when a range filter makes the set unstateable), and whether the camera-only default was applied because the request did not filter on `inference_source`. */\n inference_source?: {\n defaulted: boolean;\n values: Array<string> | null;\n };\n limit: number;\n measures: Array<string>;\n /** `inference_outcomes` only. `measured` when every row read is a camera measurement, `modeled` when every row is a venue-profile estimate, `mixed` when the answer aggregates both. */\n provenance?: \"measured\" | \"modeled\" | \"mixed\";\n /** Result rows. For `inference_outcomes` every row also carries `provenance` (`measured`, `modeled` or `mixed`). */\n rows: Array<Record<string, unknown>>;\n};\n\nexport type DataApi_QueryFilter = {\n field: string;\n op?: \"eq\" | \"in\" | \"gte\" | \"lte\" | \"between\";\n value?: unknown;\n};\n\nexport type DataApi_QueryOrderBy = {\n direction?: \"asc\" | \"desc\" | \"ASC\" | \"DESC\";\n field: string;\n};\n\nexport type DataApi_ScreenAudienceResponse = {\n audience: Record<string, unknown> | null;\n message?: string;\n screen_id: string;\n source?: string;\n};\n\nexport type DataApi_ScreenHistoryResponse = {\n count: number;\n metrics: Array<Record<string, unknown>>;\n screen_id: string;\n source?: \"camera\" | \"signal_derived\";\n};\n\nexport type DataApi_ScreensListResponse = {\n count: number;\n has_more: boolean;\n limit: number;\n next_offset: number | null;\n offset: number;\n screens: Array<Record<string, unknown>>;\n total: number;\n};\n\nexport type DataApi_SemanticSearchResponse = {\n query: string;\n results: Array<Record<string, unknown>>;\n results_count: number;\n time_window?: string;\n};\n\nexport type DataApi_StatsResponse = {\n active_screens: number;\n embeddings: Record<string, unknown>;\n metrics_last_24h: number;\n partner?: string;\n};\n\n/**\n * Server-Sent Events text: `event: <name>` and `data: <json>` lines per the SSE spec. `connected` first, then one `audience` event per screen window (screen_id, timestamp, metrics).\n */\nexport type DataApi_StreamResponse = string;\n\nexport type DataApi_UsageResponse = {\n data: Array<Record<string, unknown>>;\n period_days: number;\n};\n\n/**\n * Per-dataset record counts + date ranges for the partner's screens.\n * Returned by `GET /data-export/summary`.\n *\n */\nexport type DataExportSummaryResponse = {\n /** `lookback_days` is `min(?days, 400)` and defaults to 7. `screen_count` is how many screens the export is SCOPED to, not how many hold data. Each `datasets` entry is a `total_records`/`earliest`/`latest` triple, and a dataset whose count query FAILED is reported as `0` with null bounds rather than as an error. */\n data?: {\n /** Map of dataset name to record summary */\n datasets?: Record<string, {\n earliest?: string | null;\n latest?: string | null;\n total_records?: number;\n }>;\n lookback_days?: number;\n screen_count?: number;\n };\n /** Always `true`; a failure is raised to the global error handler and returns a canonical error envelope at a 4xx/5xx status. Note this response carries **no `request_id`**, unlike the sibling audience endpoints. */\n success?: boolean;\n};\n\n/**\n * Canonical INT-PK identity table for demand-side partners (DSPs/SSPs that Trillboards routes ad requests to). Wave 2 of pristine-state refactor. Replaces partner_key TEXT joins across the billing path.\n */\nexport type DemandPartners = {\n archived: boolean;\n created_at: string;\n /** demand_partner_id INT is the canonical FK going forward; partner_key TEXT is kept as the wire-format alternate-key FOREVER (external partner-API auth + admin UI rely on it). Never propose dropping ... */\n demand_partner_id?: string | null;\n display_name: string;\n partner_key: string;\n partner_type: string;\n /** public_alias UNIQUE: this is the obfuscated external alias partner-API consumers see. partnerAlias.js will read from this table after Wave 2 cutover. */\n public_alias: string;\n updated_at: string;\n};\n\nexport type DemographicsResponse = {\n /** `demographics.age_distribution` and `gender_split` are **hardcoded zeros even on the success path** — nothing computes them. `income_profile` and `group_composition` are shares in 0-1, not percentages, and `lifestyle_segments` is emitted as `{segment, percentage}` objects rather than the plain strings declared here. `data_quality.confidence` is a step function of sample size (>=100 gives 0.9, >=50 gives 0.7, >=20 gives 0.5, >=5 gives 0.3, else 0.1), not a statistical confidence, and `sample_size` counts measurement WINDOWS, not people. `period` echoes `?period=`; an unrecognised value silently falls back to 7 days while still being echoed verbatim. */\n data?: {\n data_quality?: {\n confidence?: number;\n sample_size?: number;\n };\n demographics?: {\n age_distribution?: {\n \"18-25\"?: number;\n \"26-35\"?: number;\n \"36-50\"?: number;\n \"50+\"?: number;\n };\n gender_split?: {\n female?: number;\n male?: number;\n };\n group_composition?: {\n couples?: number;\n families?: number;\n friends?: number;\n solo?: number;\n work_groups?: number;\n };\n income_profile?: {\n high?: number;\n low?: number;\n medium?: number;\n premium?: number;\n };\n lifestyle_segments?: Array<string>;\n };\n period?: string;\n screen_id?: string;\n screen_name?: string;\n timestamp?: string;\n };\n /** Per-request identifier (`req_` plus 32 hex), also returned on the `X-Request-Id` response header. */\n request_id?: string;\n /** Always `true` on a 2xx; failures return the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status. */\n success?: boolean;\n};\n\nexport type Device = {\n /** Creation time of the DEVICE row (`earner_screen_devices`), not of the linked screen, which may be created later in the same request or on a subsequent re-registration. */\n created_at?: string;\n /** Trillboards-minted 24-char Mongo ObjectId hex for the `earner_screen_devices` row (`mongo_earnerscreen_device_id`). This is NOT the `device_id` you sent at registration — that comes back as `external_device_id`; the batch endpoint calls this same value `trillboard_id`. All three of `device_id`, `fingerprint` and `external_device_id` are accepted as the `{deviceId}` path parameter, resolved in that order. */\n device_id?: string;\n /** Saved partner category, independent of advertising classification. POST with an existing device_id and PATCH accept category updates. Legacy devices without a saved declaration retain their previous numeric-derived label until explicitly updated. */\n device_type?: string;\n /** Screen display specification. `width`/`height` are pixel resolution; `width_in`/`height_in` are physical inches. Pixel-only inputs are NOT recorded as physical size — pass `width_in`/`height_in` (most accurate) or `ppi` so the server can derive inches from pixels. */\n display?: {\n /** Display resolution height in pixels */\n height?: number;\n /** Physical screen height in inches */\n height_in?: number;\n orientation?: string;\n /** Pixels per inch (required to derive physical size from width/height) */\n ppi?: number;\n /** Display resolution width in pixels */\n width?: number;\n /** Physical screen width in inches */\n width_in?: number;\n };\n /** Static player URL of the form `https://screen.trillboards.com?fp=<fingerprint>`. It is deterministic and permanent — not a signed or expiring link — so it never rotates and anyone holding it can load the player. `null` until a screen is linked. */\n embed_url?: string;\n /** Venue-enrichment state. `status` is `complete` only when a classification source exists AND `location` actually resolved (coordinates or a city), so it never reports complete over placeholder geo; a partner-supplied venue category stamps the source as `partner` at registration, which means `complete` does not imply AI classification ran. `confidence` is dead — `venue_classification_confidence` has no column and no writer anywhere in the API, so it is always undefined and omitted from the JSON. */\n enrichment?: Record<string, unknown>;\n /** Verbatim echo of the `device_id` you sent in the registration body (`earner_screen_devices.partner_external_id`). It is the idempotency key scoped to your partner account: re-POSTing the same value updates the existing device instead of creating a second one. */\n external_device_id?: string;\n /** Deterministic device key: `P_` followed by the first 24 hex chars of `md5(\"<your partner id>_<external_device_id>\")`. It never rotates — the same partner plus the same `device_id` always regenerates it — and it is both the heartbeat/player routing key and the token embedded in `embed_url`. */\n fingerprint?: string;\n /** Saved publisher-declared audience impressions per ad play; defaults to 1. Update via PATCH /v1/partner/device/{deviceId}/impression-multiplier. */\n impression_multiplier?: number;\n /** Resolved geo, read from the enriched screen row first and falling back to the raw registration-time device row, with placeholder strings (\"City\", \"Vending Machine Location\") filtered out. `lat`/`lng` coalesce as a PAIR — a half-set or null-island (0,0) screen pair is discarded whole in favour of the device's coordinates — and `venue_type` here is the OpenOOH CHILD slug, while `venue.category` carries the parent. `timezone` is the one exception to screen-first: it is read device-first. */\n location?: Record<string, unknown>;\n location_capability?: PartnerLocationCapability;\n /** Stripe-style readiness, the same contract registration returns (see https://api.trillboards.com/docs/monetization-requirements). */\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n /** The linked screen's name, falling back to the raw `external_device_id` when the screen has none. Omitting `name` at registration seeds the screen as `Partner Device: <device_id>`, so that literal string is what you get back rather than a null. */\n name?: string;\n requirements?: PartnerMonetizationRequirements;\n /** The linked screen's Mongo ObjectId hex (`earner_screens.mongo_earnerscreen_id`), minted server-side at registration. This — not `device_id` — is the id the non-device partner endpoints take (display settings, screen groups, fleet commands, analytics). Absent when no screen is linked to the device. */\n screen_id?: string;\n /** Provisioning state of the underlying screen row, not a liveness signal — a device that has stopped reporting still reads `approved`. Partner registration stamps `approved` on create (`partnerDeviceRegistrationService.js`), which is what almost every live partner device returns; `pending` is the formatter's fallback when the screen row carries no status of its own. */\n status?: \"pending\" | \"approved\" | \"active\" | \"offline\" | \"suspended\";\n /** `earner_screen_devices.updated_at`, which the device-mirror write buffer stamps `NOW()` on every flush — including heartbeat telemetry. It therefore tracks device liveness, not configuration changes; do not poll it to detect that a registration or PATCH landed. */\n updated_at?: string;\n /** OpenOOH classification of the screen, rebuilt from the typed `screen_venue_taxonomy` row. `category` is the PARENT slug and `subcategory` the child, with `openooh_venue_type_id` the unambiguous numeric child id — so a granular input like `hotel` reads back as a parent/child pair, not as what you sent. Empty until classification lands, unless your registration itself carried a resolvable `venue.category`/`subcategory`. */\n venue?: Record<string, unknown>;\n};\n\n/**\n * The device-authentication layer's refusal (missing, invalid or replayed device credential).\n */\nexport type DeviceAuthRefusal = {\n /** The HTTP status. */\n code?: number;\n /** device_token_required, invalid_device_token, device_not_found, device_identity_mismatch, device_token_subject_mismatch, device_screen_mismatch, missing_device_timestamp, missing_device_nonce, stale_device_request, replayed_device_request or replay_guard_unavailable. */\n error?: string;\n message?: string;\n status?: false;\n};\n\nexport type DeviceCapabilityPayload = {\n /** Runtime family of the agent (`fire-tv`, `android-tv`, `tablet`, `tablet-lite`, `webos`, `vidaa`, `web-browser`, `brightsign`). It is NOT read from here on the partner path — the server derives `agent_type` from `telemetry.agentType` plus hardware signals, and overrides a self-declared `web-browser` when the model/UA say otherwise, because partner SDKs running in a WebView historically reported `web-browser` for physical DOOH tablets. */\n agentType?: string | null;\n /** Agent build version. Do not use it to identify an artifact: three different Android build constants populate this one field across three unrelated numbering schemes, so the same string can mean different code. It is also not read from here on the partner path — the version the server keeps comes from the body `agent_version`/`sdk_version`, and only for heartbeats that self-identify as Trillboards SDKs. */\n agentVersion?: string | null;\n /** Camera/microphone sensing state. On the partner path ONLY the nested `cameraHealth` block is persisted (to the typed `camera_health_*` columns) — `cameraAvailable`, `cameraType`, `cameraCount`, `microphoneAvailable` and `sensingMode` reach no column on this path. The presence of `cameraHealth` is also an in-band signal that the heartbeat came from a Trillboards SDK, which is what allows `agent_version` to be stored. `cameraAvailable` self-devolves to false after a camera has been failed for over 24 h. */\n audienceSensing?: {\n cameraAvailable?: boolean | null;\n cameraCount?: number | null;\n cameraHealth?: {\n lastFailureClass?: string | null;\n lastFailureMessage?: string | null;\n lastFrameAtMs?: number | null;\n retryCount?: number | null;\n state?: string | null;\n [key: string]: unknown;\n } | null;\n cameraType?: string | null;\n microphoneAvailable?: boolean | null;\n sensingMode?: string | null;\n [key: string]: unknown;\n } | null;\n /** Declares volume and mute control. Hardcoded `true`/`true` on the Android agents — it is not probed against `AudioManager`, so it is a claim about the agent, not proof the hardware obeys. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n audioControl?: {\n mute?: boolean | null;\n volume?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Schema version of this capability block, persisted to `earner_screen_devices.capabilities_version` for drift attribution. Every shipped Android and Vega agent emits the constant `1` and nothing overrides it, so it carries no information today — but the server treats it as an arbitrary integer, not a bounded enum. Note the server only records it when an `mlCapabilities` block is present or when it is sent with no `mlCapabilities` at all. */\n capabilitiesVersion?: number | null;\n /** Declares an ambient-light and a temperature sensor. Only `ambientLight` is a real probe (`SensorManager.getDefaultSensor(TYPE_LIGHT) != null`, false on any throw); `temperature` is hardcoded `false` on the Android agents, and the actual temperature reading that does ship comes from the battery sensor via telemetry, not from here. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n environmentSensors?: {\n ambientLight?: boolean | null;\n temperature?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Declares HDMI input switching and app switching. Also hardcoded per agent build rather than probed (a tablet reports `hdmi: false`, `appSwitch: true`). Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n inputControl?: {\n appSwitch?: boolean | null;\n hdmi?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Whether the agent holds Android Device Owner (`DevicePolicyManager.isDeviceOwnerApp`) — the privilege that gates reboot, kiosk lock, APK install and wipe. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power, precisely so a partner cannot flip it and unlock those commands. */\n isDeviceOwner?: boolean | null;\n /** Declares remote restart/reboot/screenshot/cache-clear/kiosk/APK-install/wipe. On the first-party Android agents four of the seven are simply `isDeviceOwner` repeated, and the partner SDK reports the whole block `false` because \"partner hosts own their device management\". Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n managementCapabilities?: {\n clearCache?: boolean | null;\n installApk?: boolean | null;\n kioskMode?: boolean | null;\n reboot?: boolean | null;\n restart?: boolean | null;\n screenshot?: boolean | null;\n wipe?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** The hardware manifest that decides which on-device ML models a screen is offered, and one of the few capability blocks the partner path DOES persist. Two traps: every nullable integer must be sent as JSON `null`, never 0 — the server treats 0 as a probe-failure sentinel and drops it so the COALESCE upsert preserves the prior value — and `screenWidthPx`/`screenHeightPx` below 100 are rejected outright, after agents reporting inches corrupted 940+ rows. A `recommendedModelTier` of `UNKNOWN` (or NULL) excludes the device from on-device demographics entirely. */\n mlCapabilities?: {\n availableRamMb?: number | null;\n chipsetName?: string | null;\n chipsetVendor?: string | null;\n cpuAbi?: string | null;\n densityDpi?: number | null;\n gpuDelegateSupported?: boolean | null;\n gpuName?: string | null;\n hasNpu?: boolean | null;\n maxVlmSizeMb?: number | null;\n nnapiSupported?: boolean | null;\n npuName?: string | null;\n osApiLevel?: number | null;\n recommendedModelTier?: string | null;\n screenHeightPx?: number | null;\n screenWidthPx?: number | null;\n totalRamMb?: number | null;\n [key: string]: unknown;\n } | null;\n /** Declares HDMI-CEC, wake-on-LAN and soft-blackout support. On the Android agents these are HARDCODED per build, not probed (a tablet always reports `cec: false`, `wol: false`, `softBlackout: true`), so they describe the agent variant rather than the panel. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n powerControl?: {\n cec?: boolean | null;\n softBlackout?: boolean | null;\n wol?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Counts ESP32-S3 Wi-Fi CSI sensor nodes discovered on the LAN — it is a statement about the venue's network, not about this device's own radio (`csiHardwareType` is the literal `\"esp32-s3\"` when any node is found, `\"none\"` otherwise). Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power; it is also the one CSI field the ingest schema deliberately keeps, since it is a startup capability counter rather than a streaming data field. */\n wifiCsiSensing?: {\n csiAvailable?: boolean | null;\n csiHardwareType?: string | null;\n csiNodeCount?: number | null;\n [key: string]: unknown;\n } | null;\n [key: string]: unknown;\n};\n\nexport type DeviceSummary = {\n /** Creation time of the DEVICE row, not of the linked screen (which can be created later). */\n created_at?: string;\n /** Trillboards-minted 24-char Mongo ObjectId hex for the `earner_screen_devices` row (`mongo_earnerscreen_device_id`). Not the `device_id` you sent at registration — that is returned as `external_device_id`. Accepted as the `{deviceId}` path parameter, as are `fingerprint` and `external_device_id`. */\n device_id?: string;\n /** Saved mutable partner category, independent of advertising classification. Legacy devices without a saved declaration retain their previous numeric-derived label until explicitly updated. */\n device_type?: string;\n /** Emits `orientation` (from the screen, defaulting to `landscape`) and `ppi` (from the device row). `width`/`height` still read `dimension_width`/`dimension_height`, columns DROPPED from `earner_screen_devices` by migration `20260527180000`, so they resolve to undefined and are omitted from the JSON entirely — registered pixels now live in `screen_width_px`/`screen_height_px`. Physical inches you send as `width_in`/`height_in` are stored but never echoed here. */\n display?: Record<string, unknown>;\n /** Static, unsigned player URL `https://screen.trillboards.com?fp=<fingerprint>`. It never expires or rotates, and is `null` until a screen is linked. */\n embed_url?: string;\n /** Venue-enrichment state. `status` reads `complete` only when a classification source exists AND `location` actually resolved, and a partner-declared venue category alone sets that source — so `complete` does not mean AI classification ran. `confidence` is dead: `venue_classification_confidence` has no column and no writer in the API, so it is always omitted. */\n enrichment?: Record<string, unknown>;\n /** Verbatim echo of the `device_id` you sent in the registration body (`partner_external_id`). It is the per-partner idempotency key: re-registering the same value updates the existing device rather than creating another. */\n external_device_id?: string;\n /** Deterministic device key: `P_` plus the first 24 hex chars of `md5(\"<your partner id>_<external_device_id>\")`. It never rotates, and it is the token embedded in `embed_url` as well as the heartbeat routing key. */\n fingerprint?: string;\n /** Resolved geo: the enriched screen row first, falling back to the registration-time device row, with placeholder strings coalesced away. `lat`/`lng` coalesce as a pair, `venue_type` is the OpenOOH child slug, and `timezone` alone is read device-first. */\n location?: Record<string, unknown>;\n location_capability?: PartnerLocationCapability;\n /** Stripe-style readiness, the same contract registration returns (see https://api.trillboards.com/docs/monetization-requirements). */\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n /** The linked screen's name, falling back to the raw `external_device_id` when the screen has none. A registration that omits `name` seeds the screen as `Partner Device: <device_id>`. */\n name?: string;\n requirements?: PartnerMonetizationRequirements;\n /** The linked screen's Mongo ObjectId hex (`earner_screens.mongo_earnerscreen_id`). This is the id every non-device partner endpoint takes — display settings, screen groups, fleet commands, analytics. Absent when no screen is linked. */\n screen_id?: string;\n /** The linked screen's `earner_screens.status` verbatim. Partner registration auto-approves, so the live value is `approved` (`deactivated` after a DELETE, `pending` only while no screen is linked) — not the `pending`/`active`/`offline`/`suspended` vocabulary the `Device` schema declares, whose mapper has no production call site. */\n status?: string;\n /** `earner_screen_devices.updated_at`, stamped `NOW()` by the device-mirror write buffer on every flush including heartbeats — a liveness signal, not a configuration-change marker. */\n updated_at?: string;\n /** OpenOOH classification rebuilt from the typed `screen_venue_taxonomy` row: `category` is the PARENT slug, `subcategory` the child, `openooh_venue_type_id` the numeric child id. Empty until classification lands, unless registration supplied a resolvable venue category. */\n venue?: Record<string, unknown>;\n};\n\nexport type DisplaySettingsInput = {\n /** Default ad duration in seconds */\n ad_duration_default?: number;\n /** Screen brightness percentage */\n brightness?: number;\n content_fit?: ContentFitSettings;\n /** Ad display mode */\n display_mode?: \"fullscreen\" | \"l-bar\" | \"split\";\n /** What to show when no ads */\n idle_content?: \"default_stream\" | \"black\" | \"logo\";\n /** Mute audio */\n mute?: boolean;\n /** Screen orientation */\n orientation?: \"landscape\" | \"portrait\" | \"auto\";\n /** QR code position on screen */\n qr_code_position?: \"bottom-left\" | \"bottom-right\" | \"top-left\" | \"top-right\" | \"none\";\n /** Transition effect between ads */\n transition_effect?: \"fade\" | \"slide\" | \"none\";\n /** Audio volume percentage */\n volume?: number;\n};\n\nexport type DisplaySettingsResponse = {\n /** NOT EMITTED and NOT WRITABLE — the identifier does not occur anywhere in the API source. The nearest real controls are `ad_interval_seconds` on this resource (rotation cadence, 30-300s) and the slot duration the playback policy derives (clamped 5-60s). */\n ad_duration_default?: number;\n /** NOT EMITTED by this endpoint. `buildAdSurfaces` is computed on a display-settings write, but only to populate the `display_settings_updated` socket event pushed to the device — the HTTP body is the formatter's output and contains no `ad_surfaces`. The declared item shape is wrong too: real surfaces carry `id`, `surface_type`, `enabled`, `display_area_ratio`, `dimensions` and `allowed_ad_types`, never `position`/`width_percent`/`height_percent`. The L-bar PUT is the one HTTP response that does return them. */\n ad_surfaces?: Array<{\n height_percent?: number;\n id?: string;\n position?: string;\n width_percent?: number;\n }>;\n /** NOT EMITTED and NOT WRITABLE. The writer's ten-key allow-list has no `brightness`, so a PUT silently drops it, and the formatter never returns one. Brightness exists in this product only as inbound device telemetry on the heartbeat, which this resource cannot set. */\n brightness?: number;\n content_fit?: ContentFitSettings;\n /** Real and emitted: `fullscreen` (default), `l-bar` or `pip`, read from the typed `display_mode` column in preference to the legacy `display_preferences` JSONB. Note the writer validates a THREE-value enum including `pip`, while the L-bar resource's own `display_mode` accepts only `fullscreen`/`l-bar`. */\n display_mode?: string;\n /** NOT EMITTED and NOT WRITABLE — the identifier does not occur anywhere in the API source. What actually plays when no ad is available is the screen's default streams, managed through the default-streams routes. */\n idle_content?: string;\n /** NOT EMITTED and NOT WRITABLE. Use `sound_enabled: false` instead — that key the formatter does return, defaulting to `true`. */\n mute?: boolean;\n /** Always `display_settings`. The response is FLAT — no `success`/`data` envelope — and it comes from exactly one formatter shared by the GET, PUT and PATCH, so all three return an identical shape. */\n object?: string;\n /** NOT EMITTED under this name — the formatter returns `screen_orientation` instead (`landscape`, `portrait`, `mixed` or `unknown`, defaulting to `landscape`). The writer's allow-list also only accepts `screen_orientation`, so an `orientation` key in a PUT body is silently dropped. */\n orientation?: string;\n /** NOT EMITTED by this endpoint, for the same reason as `ad_surfaces` — it is computed on a write only to fill the device socket event. The declared `max_duration_seconds`/`min_break_between_ads`/`allow_skip` keys do not exist in the real policy either; `buildPlaybackPolicy` produces `policy_version`, millisecond intervals, `max_paid_share`, `surface_policy`, `schedule_policy`, `pip_settings` and `lbar_settings`. */\n playback_policy?: {\n allow_skip?: boolean;\n max_duration_seconds?: number;\n min_break_between_ads?: number;\n };\n /** NOT EMITTED and NOT WRITABLE — the identifier does not occur anywhere in the API source. */\n qr_code_position?: string;\n /** Echo of the server-assigned `req.requestId`, attached only when one exists — the key is absent, not null, otherwise. */\n request_id?: string;\n /** Echoed from the `{screenId}` path parameter rather than read from a column. */\n screen_id?: string;\n /** NOT EMITTED and NOT WRITABLE — the identifier `transition_effect` does not occur anywhere in the API source. There is no transition control on this resource. */\n transition_effect?: string;\n /** ISO-8601 of the SCREEN row's `updatedAt`, not a display-settings-specific timestamp; when the screen has none the formatter substitutes the current time, so it is never null and never proves a write landed. */\n updated_at?: string;\n /** NOT EMITTED and NOT WRITABLE — the string `volume` does not appear in the display-settings service or the formatter at all. The only audio control on this resource is the boolean `sound_enabled`. */\n volume?: number;\n};\n\n/**\n * User-owned ad screens. Each row is a logical screen that can display ads. Links user to device. PG primary with Mongo legacy mirror.\n */\nexport type EarnerScreens = {\n ad_interval_seconds?: number | null;\n ads_disabled_reasons: Array<string>;\n advertisement_sizing?: string | null;\n archetype_photo_key?: string | null;\n archetype_photo_synced_at?: string | null;\n archetype_photo_url?: string | null;\n auction_cohort?: string | null;\n auction_enabled_at?: string | null;\n auction_mode?: string | null;\n auction_type?: string | null;\n avg_dwell_time_seconds?: number | null;\n back_online_alert_sent_at?: string | null;\n billing_mode: string;\n block_group_geoid?: string | null;\n blocked_advertisers?: Array<string> | null;\n blocked_iab_categories?: Array<string> | null;\n brand_substitution_consent_at?: string | null;\n brand_substitution_consent_by?: string | null;\n brand_substitution_mode: string;\n branding_overlay_enabled: boolean;\n branding_overlay_hide_on_ads: boolean;\n branding_overlay_logo_transformed_url: string;\n branding_overlay_logo_url: string;\n /** NUMERIC(5,4). */\n branding_overlay_opacity: number;\n /** NUMERIC(5,4). */\n branding_overlay_padding_ratio: number;\n branding_overlay_placement: string;\n branding_overlay_position: string;\n /** NUMERIC(5,4). */\n branding_overlay_size_ratio: number;\n cms_payment_status: string;\n commercial_value_score?: number | null;\n content_filtering_enabled?: boolean | null;\n /** deleted_at IS NULL required — soft-delete nulls earnerscreen_device_id for partial unique index */\n deleted_at?: string | null;\n delivery_mode: string;\n device_platform_override?: string | null;\n diagonal_inches?: number | null;\n display_mode?: string | null;\n distributor_id?: number | null;\n dma_code?: string | null;\n dma_name?: string | null;\n dynamic_floor_pricing?: boolean | null;\n enrichment_attempts: number;\n enrichment_failed_at?: string | null;\n environment_type?: string | null;\n /** NUMERIC(12,6). */\n floor_price_cpm?: number | null;\n foot_traffic_multiplier?: number | null;\n gam_ad_unit_code?: string | null;\n gam_ad_unit_id?: string | null;\n gam_ad_unit_path?: string | null;\n gam_sync_status?: string | null;\n gam_synced_at?: string | null;\n geocode_source?: string | null;\n geocoded_at?: string | null;\n geocoding_raw_response?: Record<string, unknown> | null;\n hb_allocation?: number | null;\n hb_enabled?: boolean | null;\n hb_force_request?: boolean | null;\n hb_last_sync_at?: string | null;\n hb_min_interval_seconds?: number | null;\n hb_provider?: string | null;\n hb_request_mode?: string | null;\n hb_timeout_ms?: number | null;\n hb_vast_tag_url?: string | null;\n height_inches?: number | null;\n hive_stack_screen_id?: string | null;\n hive_stack_site_id?: string | null;\n hive_stack_sync_status?: string | null;\n hive_stack_synced_at?: string | null;\n hive_stack_unit_id?: string | null;\n hive_stack_unit_uuid?: string | null;\n is_demo_data: boolean;\n is_standby: boolean;\n l_bar_ads_enabled?: boolean | null;\n l_bar_position?: string | null;\n last_enrichment_attempt_at?: string | null;\n last_offline_transition_at?: string | null;\n last_programmatic_sync_at?: string | null;\n latitude?: number | null;\n longitude?: number | null;\n loop_plan_id?: number | null;\n media_capability?: \"image_video\" | \"image_only\" | \"video_only\" | null;\n mediation_priority?: number | null;\n mobile_distance_threshold_m?: number | null;\n mobile_update_interval_s?: number | null;\n mobile_vehicle_type?: string | null;\n neighborhood?: string | null;\n ntp_sync_required: boolean;\n offline_alert_sent_at?: string | null;\n offline_push_alert_sent_at?: string | null;\n operating_hours?: Record<string, unknown> | null;\n partner_mongo_id?: string | null;\n peak_hours?: Array<string> | null;\n photo_flag_notes?: string | null;\n photo_flag_reason?: string | null;\n photo_flagged: boolean;\n photo_flagged_at?: string | null;\n photo_flagged_by_mongo_id?: string | null;\n photo_notification_count: number;\n photo_notification_sent_at?: string | null;\n photo_quality_sent_at?: string | null;\n photo_review_status?: string | null;\n photos?: Record<string, unknown> | null;\n physical_size_set_at?: string | null;\n physical_size_set_by?: string | null;\n place_name?: string | null;\n placement_type?: string | null;\n places_rating?: number | null;\n places_review_count?: number | null;\n pref_allow_religious?: boolean | null;\n pref_allow_tobacco?: boolean | null;\n pref_allowed_categories?: Array<string> | null;\n pref_allowed_keywords?: Array<string> | null;\n pref_allowed_subjects?: Array<string> | null;\n pref_auto_approve_known_brands?: boolean | null;\n pref_blocked_categories?: Array<string> | null;\n pref_blocked_keywords?: Array<string> | null;\n pref_blocked_subjects?: Array<string> | null;\n pref_level?: string | null;\n pref_max_age_rating?: string | null;\n preferred_deal_ids: Array<string>;\n prog_allocation_pct?: number | null;\n prog_currency: string;\n programmatic_enabled: boolean;\n region: string;\n registration_source?: string | null;\n screen_placement?: string | null;\n serving_tenant_id?: number | null;\n slot_duration_seconds?: number | null;\n sound_enabled?: boolean | null;\n ssp_enabled?: boolean | null;\n state_iso_3166_2?: string | null;\n sync_enabled?: boolean | null;\n sync_group_name?: string | null;\n sync_is_master?: boolean | null;\n sync_last_sync_at?: string | null;\n sync_master_screen_id?: string | null;\n taggify_screen_id?: string | null;\n taxonomy_migrated_at?: string | null;\n taxonomy_spec_version?: string | null;\n venue_category?: string | null;\n venue_child?: string | null;\n venue_child_id?: string | null;\n venue_city?: string | null;\n /** enrichment_status: PG GENERATED from (venue_classification_source, enrichment_failed_at); a real classification DOMINATES a stale failure stamp (success wins). Never written directly. Values: pendi... */\n venue_classification_source?: string | null;\n venue_grandchild?: string | null;\n venue_parent?: string | null;\n venue_state?: string | null;\n venue_subcategory?: string | null;\n waterfall_optimized_at?: string | null;\n /** waterfall_partners is the ONLY pin store (order + whitelist; screen_partner_settings was never built). Serving reads it only with a screen_header_bidding_config row and ignores it once waterfall_op... */\n waterfall_partners: Array<string>;\n waterfall_total_timeout_ms?: number | null;\n /** Physical width_inches/height_inches/diagonal_inches are inches. Pixels live on earner_screen_devices; the raw screen has no resolution_width/resolution_height columns. */\n width_inches?: number | null;\n};\n\nexport type EarningsBreakdownResponse = {\n /** Keyed by `date` for `group_by=day|week` and by `screen_id` (plus a `screen_name`) for `group_by=screen`; the unused key is absent rather than null. Week rows are labelled `<year>-W<ISO week>`. `earnings_cents` is allocated cumulatively so the rows sum exactly to `summary.total_cents`. */\n breakdown?: Array<{\n /** Date or screen_id depending on group_by */\n date?: string;\n earning_sources?: EarningsSources;\n earnings_cents?: number;\n impressions?: number;\n /** Screen ID (when grouped by screen) */\n screen_id?: string;\n }>;\n /** **Both fields are hardcoded** — `estimated_cents` is always `0` and `confirmation_date` always `null`. Read `EarningsResponse.pending_confirmation_cents` for the real Net-60 pending figure. */\n pending_programmatic?: {\n confirmation_date?: string | null;\n estimated_cents?: number;\n };\n /** `start`/`end` echo the request; with neither supplied the window is the last 30 days ending now. The end bound is EXCLUSIVE in the underlying query (`period_date < end`), so passing today's date omits today. */\n period?: {\n end?: string;\n group_by?: \"day\" | \"week\" | \"screen\";\n start?: string;\n };\n /** Integer US cents for the selected period. With source reporting enabled, direct_cents is verified first-party revenue and programmatic_cents is the remainder; earning_sources supplies the business classification. Disabled reporting retains the legacy split. */\n summary?: {\n direct_cents?: number;\n earning_source_version?: 1;\n earning_sources?: EarningsSources;\n programmatic_cents?: number;\n total_cents?: number;\n total_impressions?: number;\n };\n};\n\n/**\n * Partner earnings summary with optional daily series\n * (`@trillboards/api-client` `EarningsData`).\n *\n */\nexport type EarningsData = {\n /** **Never emitted.** No partner earnings endpoint computes a CPM; the earnings chart returns impressions and cents only, so a caller must divide for itself. */\n average_cpm: number;\n /** Optional per-day earnings/impressions series. */\n daily?: Array<{\n /** Day label (YYYY-MM-DD). */\n date: string;\n earnings: number;\n impressions: number;\n }>;\n /** **Never emitted**, so its unit is undefined. Every money field the partner earnings endpoints actually return is integer US cents and carries a `_cents` suffix. */\n last_payout_amount?: number;\n /** **Never emitted.** No handler populates it — read `GET /v1/partner/earnings/transactions?type=payout`, whose rows carry `created_at` and `amount_cents`. */\n last_payout_date?: string;\n /** Balance not yet paid out. */\n pending_payout: number;\n /** Declared for the SDK type but **not emitted**: `GET /v1/partner/connect/earnings` returns `{summary, chart, period}` where `period` is an OBJECT (`days`/`start`/`end`), not this string. */\n period: string;\n /** **Not emitted under this name**, so its unit is undefined. The live earnings chart returns `summary.total_earnings_cents` — integer US cents — summed over the requested window from the payout-accounting rollup of `programmatic_earnings_daily`. */\n total_earnings: number;\n /** **Not emitted under this name.** The live earnings chart returns `summary.total_impressions`, the impression count carried on the same daily earner-revenue rows the cents are summed from. */\n total_impressions: number;\n};\n\nexport type EarningsResponse = {\n /** Amount available for immediate payout */\n available_for_payout_cents?: number;\n /** Current-month integer US cents. With source reporting enabled, direct_campaigns is verified first-party revenue and programmatic_google is the remaining aggregate, not Google-specific. programmatic_floodgates remains zero. Prefer earning_sources; disabled reporting retains the legacy all-programmatic split. */\n breakdown?: {\n direct_campaigns?: number;\n programmatic_floodgates?: number;\n programmatic_google?: number;\n };\n earning_source_version?: 1;\n earning_sources?: EarningsSources;\n /** `amount_cents` is integer US cents and simply repeats `available_for_payout_cents`; `date` is the 1st of next month, computed in the handler with no reference to any scheduled transfer; `stripe_status` is the partner's Connect account status, which must be `active` before a payout request is accepted. */\n next_payout_estimate?: {\n amount_cents?: number;\n date?: string;\n stripe_status?: string;\n };\n /** Minimum amount required for payout */\n payout_threshold_cents?: number;\n /** Programmatic earnings pending Net-60 confirmation */\n pending_confirmation_cents?: number;\n /** Partner's revenue share percentage */\n revenue_share_percent?: number;\n /** Estimated earnings for current month */\n this_month_cents?: number;\n /** Total earnings since partner started */\n total_lifetime_cents?: number;\n};\n\n/**\n * Optional reporting breakdown in integer US cents. Components sum to the existing amount. Missing evidence is Unclassified; absence of this object means reporting is unavailable.\n */\nexport type EarningsSources = {\n /** Paid first-party portal and offline IO bookings. */\n direct_bookings: number;\n /** Verified open-auction delivery outside a private deal. */\n open_exchange: number;\n /** Verified delivered DSP/SSP PMP, PG and preferred deals. */\n programmatic_deals: number;\n /** Earnings lacking supported allocation evidence. */\n unclassified: number;\n};\n\n/**\n * Legacy free-text error shape. COLLAPSED onto the shared `LegacyError`\n * definition so there is exactly one declaration of this shape across the\n * specs. Kept as a distinct NAME because hand-authored operations\n * reference it by that name; the shape is unchanged.\n *\n */\nexport type Error = LegacyError;\n\n/**\n * The 143 CATALOGUED error codes, generated from utils/errorCatalog.js — the same catalog that backs https://api.trillboards.com/docs/errors. This is the documented registry, NOT the complete set of codes the API can emit: a response `code` is an open string (see `TrillboardsError`). Use this list to recognise a code, never to assume a response cannot carry another.\n */\nexport type ErrorCode = \"AUTH_REQUIRED\" | \"BRAND_CONFIGURATION_FAILED\" | \"BRAND_PROFILE_CONFLICT\" | \"BRAND_PROFILE_NOT_FOUND\" | \"CREATIVE_ADVERTISEMENT_NOT_OWNED\" | \"CREATIVE_MODERATION_UNAVAILABLE\" | \"CREATIVE_NOT_LINKED\" | \"CREATIVE_NOT_READY\" | \"CREATIVE_POLICY_CONFLICT\" | \"CREATIVE_TOO_LARGE\" | \"EXPERIMENT_COMPLETED\" | \"EXPERIMENT_NOT_FOUND\" | \"FEEDBACK_POLICY_REQUIRED\" | \"IDEMPOTENCY_CONFLICT\" | \"INVALID_BRAND_RULES\" | \"INVALID_CREATIVE_URL\" | \"INVALID_CREATIVE_WEIGHTS\" | \"INVALID_FEEDBACK_CREATIVE\" | \"INVALID_FEEDBACK_OBJECTIVE\" | \"INVALID_FEEDBACK_REQUEST\" | \"INVALID_POLICY_VERSION\" | \"INVALID_VARIANTS\" | \"MEDIA_BUY_NOT_FOUND\" | \"OPERATION_ALREADY_COMMITTED\" | \"OPERATION_IN_PROGRESS\" | \"POLICY_NOT_AVAILABLE\" | \"SOURCE_CREATIVE_NOT_FOUND\" | \"UNSUPPORTED_CREATIVE_TYPE\" | \"VARIANT_IDENTITY_CONFLICT\" | \"ad_interval_out_of_range\" | \"allocation_out_of_range\" | \"analytics_unavailable\" | \"api_key_expired\" | \"api_key_owner_missing\" | \"api_key_revoked\" | \"array_items_must_be_strings\" | \"array_too_large\" | \"auth_error\" | \"authentication_required\" | \"batch_size_exceeded\" | \"blocked_advertisers_too_large\" | \"blocked_iab_categories_too_large\" | \"client_ip_required\" | \"concurrent_request_limit\" | \"conflict\" | \"conflicting_lists\" | \"creative_policy_conflict\" | \"creative_policy_forbidden\" | \"daily_quota_exceeded\" | \"database_error\" | \"dataset_not_scopable\" | \"device_already_registered\" | \"device_identity_missing\" | \"device_identity_underivable\" | \"device_not_found\" | \"device_offline\" | \"dsp_access_denied\" | \"error\" | \"field_must_be_array\" | \"field_must_be_boolean\" | \"field_too_long\" | \"floor_price_out_of_range\" | \"forbidden\" | \"idempotency_error\" | \"idempotency_key_in_use\" | \"idempotency_key_mismatch\" | \"insufficient_data\" | \"insufficient_permissions\" | \"insufficient_scope\" | \"internal_error\" | \"invalid_ad_surface_mode\" | \"invalid_age_rating\" | \"invalid_api_key\" | \"invalid_api_key_format\" | \"invalid_array_items\" | \"invalid_creative_policy\" | \"invalid_currency\" | \"invalid_dataset\" | \"invalid_device_id\" | \"invalid_dimensions\" | \"invalid_display_mode\" | \"invalid_field_type\" | \"invalid_field_value\" | \"invalid_fingerprint\" | \"invalid_json\" | \"invalid_lbar_position\" | \"invalid_lbar_settings\" | \"invalid_measures\" | \"invalid_media_url\" | \"invalid_order_by\" | \"invalid_orientation\" | \"invalid_pip_position\" | \"invalid_pip_settings\" | \"invalid_preference_level\" | \"invalid_preferences\" | \"invalid_provider\" | \"invalid_screen_id\" | \"invalid_segment_rules\" | \"invalid_sizing_mode\" | \"invalid_stream_type\" | \"invalid_webhook_events\" | \"invalid_webhook_url\" | \"lbar_settings_must_be_object\" | \"lbar_size_out_of_range\" | \"missing_required_field\" | \"not_found\" | \"openrtb_auth_failed\" | \"openrtb_config_missing\" | \"paired_training_insert_failed\" | \"paired_training_rate_limit_exceeded\" | \"partner_inactive\" | \"pip_margin_out_of_range\" | \"pip_settings_must_be_object\" | \"pip_size_ratio_out_of_range\" | \"preferences_must_be_object\" | \"preferences_required\" | \"preset_id_required\" | \"preset_not_found\" | \"rate_limit_exceeded\" | \"resource_locked\" | \"screen_ids_required\" | \"screen_not_found\" | \"screen_not_in_scope\" | \"sdk_enrich_rate_limit_exceeded\" | \"sdk_impression_rate_limit_exceeded\" | \"sdk_qr_beacon_rate_limit_exceeded\" | \"sdk_qr_scan_rate_limit_exceeded\" | \"segment_limit_exceeded\" | \"segment_not_found\" | \"service_unavailable\" | \"stale_data\" | \"stream_content_required\" | \"stream_not_found\" | \"tier_insufficient\" | \"timeout\" | \"timeout_out_of_range\" | \"unknown_agent_type\" | \"unsupported_media_type\" | \"validation_error\" | \"webhook_limit_exceeded\" | \"webhook_not_found\" | \"webhook_secret_expired\" | \"webhook_url_unreachable\";\n\nexport type ErrorCodeResponse = {\n code: string;\n description: string;\n doc_url: string;\n /** Example canonical error envelope for this code. */\n example_response: {\n error: {\n code: string;\n doc_url: string;\n message: string;\n param?: unknown;\n type: string;\n };\n };\n http_status: number;\n /** Always \"error_code\". */\n object: \"error_code\";\n type: string;\n};\n\n/**\n * A single partner API error-log record\n * (`@trillboards/api-client` `ErrorEntry`) — one logged error occurrence\n * scoped to the partner. Distinct from the public error *catalog* entries\n * (`ErrorListItem` / `ErrorCodeResponse`), which describe error codes in\n * the abstract.\n *\n */\nexport type ErrorEntry = {\n /** Stable machine error code (e.g. not_found). */\n code: string;\n /** Derived mechanically as `https://api.trillboards.com/docs/errors#<code>`, so it is always well-formed whether or not that anchor exists. It appears on live error envelopes and catalog entries; no per-partner error-log endpoint returns it. */\n doc_url: string;\n /** The API path that produced the error. */\n endpoint: string;\n /** **No producer.** `GET /v1/errors` returns the static error CATALOG (code definitions in the abstract), not per-partner occurrences, and the per-request metadata the API does retain is keyed by `request_id` and carries no `id`. */\n id: string;\n /** **Never emitted as part of a logged occurrence.** Human-readable text appears only on a live error envelope or a catalog entry; the retained per-request record stores `error_code`/`error_type` and no message. */\n message: string;\n /** The HTTP method of the failing request. */\n method: string;\n /** The request parameter the error concerns, if any. */\n param?: string;\n /** The `req_`-prefixed identifier of the failing request, minted server-side and returned both on the `X-Request-Id` header and inside every error envelope. It is the only handle that links a caller-side failure to server-side request metadata. */\n request_id: string;\n /** **Not emitted by any error endpoint.** The per-request metadata the API retains does stamp an ISO timestamp at response time, but it lives in a bounded in-memory LRU cache, not a queryable error log. */\n timestamp: string;\n /** Stripe-style error taxonomy (matches the SDK's ApiErrorType). */\n type: \"invalid_request_error\" | \"authentication_error\" | \"permission_error\" | \"rate_limit_error\" | \"idempotency_error\" | \"api_error\";\n};\n\n/**\n * The complete set of error envelopes this API may return. Documented on operations whose surface emits more than one — see `x-superseded-by` on each member for the migration target. New endpoints return `TrillboardsError`; switch on `error.code`, never on a message string.\n */\nexport type ErrorEnvelope = TrillboardsError | HybridError | LegacyCodedError | LegacyError;\n\nexport type ErrorListItem = {\n code: string;\n description: string;\n doc_url: string;\n http_status: number;\n type: string;\n};\n\nexport type ErrorListResponse = {\n data: Array<ErrorListItem>;\n /** Always \"list\". */\n object: \"list\";\n /** Total number of error codes. */\n total: number;\n};\n\n/**\n * Stripe-style error taxonomy. Derived from the distinct `type` values in utils/errorCatalog.js (6 values).\n */\nexport type ErrorType = \"api_error\" | \"authentication_error\" | \"idempotency_error\" | \"invalid_request_error\" | \"permission_error\" | \"rate_limit_error\";\n\n/**\n * Exact DSP-matchable audience identity kept separate from the resettable\n * OS advertising ID. `hem_sha256` is an existing SHA-256 digest: send it\n * directly (the server lowercases hexadecimal once and never hashes it\n * again). `uid2_token` is an opaque, case-sensitive UID2 advertising\n * token: send it exactly as issued and include `expires_at` so it can be\n * refreshed; tokens contain no whitespace. Use `unavailable` with no\n * `id` to clear a prior value.\n *\n */\nexport type ExtendedIdentity = {\n /** OpenRTB person-based identifier type. */\n atype: 3;\n /** When the token stops being usable — for a UID2 token this is the refresh deadline, and it is stored verbatim regardless of `status` (unlike the advertising-identity envelope, which discards `expires_at` on an `available` state). `null` means no declared expiry, not \"already expired\". */\n expires_at?: string | null;\n /** The identity value itself, up to 4096 characters and containing no whitespace. Omit it (or send `null`) with `unavailable` to CLEAR a previously stored identity — that is the only way to retract one; sending the envelope with `available` and an empty id is rejected instead. */\n id?: string | null;\n /** `hem_sha256` must be exactly 64 hexadecimal characters and is lowercased ONCE server-side and never re-hashed — send the digest, not the email. `uid2_token` is an opaque case-sensitive token forwarded byte-for-byte with only a whitespace check, so do not trim, lowercase or re-encode it. Together with `source` this pair is the row key: one identity per `(id_type, source)` per device. */\n id_type: \"hem_sha256\" | \"uid2_token\";\n /** When the device observed this identity — and it is the CONFLICT-RESOLUTION CLOCK, not just provenance: the upsert applies only when this timestamp is greater than or equal to the one already stored, so a replayed or out-of-order envelope is silently discarded with no error. An unparseable value rejects the whole array. */\n observed_at: string;\n /** Canonical top-level domain for this identity system. */\n source: string;\n /** Version of the SDK or integration that produced this identity, up to 128 characters, kept for provenance only — no server logic branches on it. It is trimmed, and a whitespace-only string is stored as `null` rather than as an empty string. */\n source_version?: string | null;\n /** `available` requires `id`; `unavailable` requires `id` to be ABSENT — sending both is a validation failure, and because normalisation is all-or-nothing across the array that single bad element discards every other identity in the same request while the heartbeat still returns 200. */\n status: \"available\" | \"unavailable\";\n};\n\nexport type FeedbackBrand = {\n advertisement_id: string;\n brand_name: string;\n profile_id: string;\n reactive_enabled: true;\n stance: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackBrandRequest = {\n /** Native brand reference assets used by creative generation. */\n brand_assets?: Array<Record<string, unknown>>;\n /** Optional brand intent supplied to the native creative generator. */\n brand_intent_text?: string | null;\n /** Advertiser brand name for the experiment’s native campaign. */\n brand_name: string;\n /** Native brand colours, typography, voice, products and required or prohibited elements. */\n brand_rules: {\n /** The advertiser brand name, e.g. \"Nike\". */\n brand_name: string;\n /** Elements that MUST appear in every creative, e.g. [\"logo top-right\",\"legal disclaimer\"]; may be empty. */\n mandatory_elements: Array<string>;\n /** Brand colour palette. */\n palette: {\n /** Accent colours; may be empty. */\n accents: Array<string>;\n /** Primary brand colour (hex or named); empty string if unknown. */\n primary: string;\n /** Secondary brand colour; empty string if none. */\n secondary: string;\n };\n /** Key products to feature; may be empty. */\n products: Array<{\n /** Short product description; empty string if none. */\n description: string;\n /** Product name. */\n name: string;\n }>;\n /** Elements that must NEVER appear, e.g. [\"competitor logos\",\"alcohol\"]; may be empty. */\n prohibited_elements: Array<string>;\n /** Preferred reactive stances for this brand; may be empty. */\n stance_preferences: Array<\"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\">;\n /** Approved taglines / slogans; may be empty. */\n taglines: Array<string>;\n /** Typography guidance. */\n typography: {\n /** Body typeface / style guidance; empty string if none. */\n body: string;\n /** Headline typeface / style guidance; empty string if none. */\n headline: string;\n };\n /** Voice + tone adjectives, e.g. [\"confident\",\"playful\"]; may be empty. */\n voice_tone: Array<string>;\n };\n /** Optional existing brand profile owned by this advertiser and advertisement. */\n profile_id?: string;\n /** Native reactive relationship used to generate or stage this creative. */\n stance?: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackBrandResponse = {\n data: FeedbackBrand;\n success: true;\n};\n\nexport type FeedbackCreateRequest = {\n /** Exact decimal policy version; zero enrolls an unclaimed native policy. */\n expected_policy_version?: string;\n /** Caller-owned key for this exact operation; do not reuse for changed inputs. */\n idempotency_key: string;\n /** Your funded native AdCP media buy ID. */\n media_buy_id: string;\n /** Name for this funded creative feedback experiment. */\n name: string;\n /** Measured objective: gaze share 0–1, gaze overlap milliseconds, or capped mean dwell milliseconds. */\n objective: \"gaze_share\" | \"gaze_overlap_ms\" | \"dwell_ms\";\n /** Native package ID within that media buy. */\n package_id: string;\n};\n\nexport type FeedbackCreativeReview = {\n success: boolean;\n};\n\nexport type FeedbackExperiment = {\n advertisement_id: string;\n advertiser_id: string;\n id: string;\n media_buy_id: string;\n name: string;\n objective: \"gaze_share\" | \"gaze_overlap_ms\" | \"dwell_ms\";\n package_id: string;\n policy_mode: \"attribution\" | \"experiment\" | \"external_agent\";\n policy_version: string;\n status: string;\n variants: Array<FeedbackVariant>;\n};\n\nexport type FeedbackExperimentDetail = FeedbackExperiment & {\n creatives: Array<FeedbackRecoveredCreative>;\n creatives_truncated: boolean;\n };\n\nexport type FeedbackExperimentDetailResponse = {\n data: FeedbackExperimentDetail;\n success: true;\n};\n\nexport type FeedbackExperimentResponse = {\n data: FeedbackExperiment;\n success: true;\n};\n\nexport type FeedbackGenerateRequest = {\n /** Image aspect ratio, such as 16:9, matched to your booked screens. */\n aspectRatio?: string;\n /** Creative direction added to your configured native brand rules. */\n brief?: string;\n /** Unique caller-owned generation key; committed retries expose creativeId and renderKey in the receipt. */\n idempotency_key: string;\n /** Native reactive relationship used to generate or stage this creative. */\n stance?: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackGenerateResponse = {\n data: FeedbackGeneratedCreative;\n success: true;\n};\n\nexport type FeedbackGeneratedCreative = {\n brandReviewStatus: string;\n cdnUrl: string;\n creativeId: string;\n deduped: boolean;\n headline?: string | null;\n moderationStatus?: string;\n renderKey: string;\n status?: string;\n success: true;\n usage_receipt: Record<string, unknown>;\n};\n\n/**\n * Exactly one native image source is required. source_creative_id resolves only within the authenticated partner. Inline bytes require content_type and are validated against the actual image MIME and byte hash by native staging.\n */\nexport type FeedbackImportRequest = {\n /** Public HTTPS image URL; provide exactly one image source. */\n asset_url?: string;\n /** Actual image MIME; required for inline bytes and checked against decoded content. */\n content_type?: \"image/png\" | \"image/jpeg\" | \"image/jpg\" | \"image/webp\";\n /** Optional headline stored with the native imported creative. */\n headline?: string;\n /** Unique caller-owned import key; a committed retry returns the existing usage receipt. */\n idempotency_key: string;\n /** Base64 PNG, JPEG or WebP bytes; provide exactly one source and content_type. */\n image_base64?: string;\n /** Existing creative ID owned by the authenticated partner; provide exactly one image source. */\n source_creative_id?: string;\n /** Native reactive relationship used to generate or stage this creative. */\n stance?: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackPolicyRequest = {\n /** Exact decimal policy version from the latest experiment; stale updates return 409. */\n expected_version: string;\n /** Replacement weights for registered variants; omitted variants are inactive. */\n weights: Array<{\n /** Registered native creative ID to assign this weight. */\n creative_id: string;\n /** Weight between zero and one; zero disables selection. Eligible weights normalize at serving. */\n weight: number;\n }>;\n};\n\nexport type FeedbackRecoveredCreative = {\n advertisement_mongo_id: string | null;\n brand_profile_id: string | null;\n brand_review_status: string;\n cdn_url: string;\n content_sha256: string | null;\n created_at: string;\n creative_id: string;\n headline: string | null;\n linked_to_experiment_ad: boolean;\n moderation_status: string | null;\n render_key: string | null;\n reviewed_at: string | null;\n stance: string | null;\n};\n\nexport type FeedbackRegisterVariantsRequest = {\n /** Exact decimal policy version from the latest experiment; stale updates return 409. */\n expected_version: string;\n /** Approved native variants; identity and bytes remain immutable. */\n variants: Array<{\n /** Approved native generated or imported creative ID. */\n creative_id: string;\n /** Your model version associated with this immutable variant. */\n model_version?: string;\n /** Stable model variant identity within this experiment. */\n variant_id: string;\n }>;\n};\n\nexport type FeedbackReviewRequest = {\n /** Owned native creative ID awaiting your explicit brand review. */\n creative_id: string;\n /** Approve or reject brand use; global AI moderation remains a separate gate. */\n decision: \"approve\" | \"reject\";\n};\n\nexport type FeedbackReviewResponse = {\n data: FeedbackCreativeReview;\n success: true;\n};\n\nexport type FeedbackRewardQuery = {\n /** Opaque next_cursor from this same date scope; rewind after scan_complete. */\n cursor?: string;\n /** Inclusive first play date, YYYY-MM-DD; date range is at most 31 days. */\n from: string;\n /** Unique caller-owned billing key for this page; committed retries return the receipt, not another read. */\n idempotency_key: string;\n /** Maximum native play states returned on this metered page. */\n limit?: number;\n /** Inclusive last play date, YYYY-MM-DD; date range is at most 31 days. */\n to: string;\n};\n\nexport type FeedbackRewardRow = {\n action: \"upsert\" | \"retract\";\n ad_id: string | null;\n build_stamp: string;\n builder_version: string;\n /** Four ordered strings: play_date, screen_mongo_id, play_source, play_key. */\n canonical_key: Array<string>;\n content_sha256: string;\n /** Lossless issued v1 JSON snapshot; empty string when unissued. Contains variant_id and creative_policy_version. */\n creative_feedback: string;\n creative_id: string | null;\n dwell_capped_ms_mean: number | null;\n dwell_overlap_ms: number | null;\n dwell_windows_n: number | null;\n gaze_face_rows_n: number | null;\n gaze_overlap_ms: number | null;\n /** Measured gaze share, 0–1; NULL when not measured. */\n gaze_pct_on_screen: number | null;\n gaze_seconds: number | null;\n gaze_windows_n: number | null;\n play_completed_at: string | null;\n play_date: string;\n play_key: string;\n play_source: string;\n play_started_at: string | null;\n request_id: string | null;\n reward_revision_id: string;\n screen_mongo_id: string;\n superseded: number;\n};\n\nexport type FeedbackRewards = {\n experiment_id: string;\n next_cursor: string | null;\n objective: \"gaze_share\" | \"gaze_overlap_ms\" | \"dwell_ms\";\n rewind_next_poll: boolean;\n rows: Array<FeedbackRewardRow>;\n scan_complete: boolean;\n usage_receipt: Record<string, unknown>;\n view: \"latest_state\";\n};\n\nexport type FeedbackRewardsResponse = {\n data: FeedbackRewards;\n success: true;\n};\n\nexport type FeedbackStopRequest = {\n /** Exact decimal policy version from the latest experiment; stale updates return 409. */\n expected_version: string;\n};\n\nexport type FeedbackVariant = {\n content_sha256?: string | null;\n creative_id: string;\n model_version?: string | null;\n variant_id: string;\n};\n\n/**\n * A fleet-command job: one batch that fanned a device command across a screen group's\n * members. Poll via GET /fleet-commands/{id}.\n *\n */\nexport type FleetCommand = {\n /** The device command that was fanned out — one of `reload`, `update_settings`, `restart`, `screenshot`, `clear_cache`, `update_content`, `refresh_ads`, `update_config`, `get_state`, `show_ad`, `play_ad`. Validated in the application against `ALLOWED_COMMANDS`, with no database constraint, so the allow-list can grow without a schema migration. */\n command_type?: string;\n /** Set on BOTH terminal states — `completed` and `failed` — so it is not a success marker. `null` only while the job has not reached a terminal state. */\n completed_at?: string | null;\n /** When the job row was inserted, i.e. when the batch was accepted. Because execution is synchronous, `created_at` and `completed_at` bracket the entire fan-out. */\n created_at?: string;\n /** The raw thrown message, set only when the JOB itself failed; `null` otherwise. Per-screen dispatch failures do NOT populate it — those live in `results[].error`, and a job whose targets all failed still reports `status: \"completed\"` with `failed` > 0. */\n error?: string | null;\n /** Screens that could not be enqueued */\n failed?: number;\n /** The `sg_<uuid>` screen group this batch fanned out to. It is a plain TEXT reference, not a foreign key: groups are only ever soft-deleted, so the job outlives its group and keeps the id as an audit record. */\n group_id?: string | null;\n /** Job id: the literal prefix `fc_` followed by a v4 UUID (`pgRepo/fleetCommands.js` mints `fc_${crypto.randomUUID()}`). Opaque — do not parse the UUID half. */\n id?: string;\n /** Constant string `fleet_command` — the Stripe-style type discriminator, present both here and inside the `data` of a `fleet_command.*` webhook. */\n object?: string;\n /** Screens the command was enqueued to */\n queued?: number;\n /** One entry per screen the dispatch touched, persisted only when the fan-out actually produced rows. `results[].status` is `queued` or `failed` — the per-screen dispatch outcome, a different vocabulary from the job's own `status` — and `device_command_id` is the queued device-command's Mongo ObjectId, or `null` when nothing was queued (e.g. `error: \"No device linked\"`). On a `fleet_command.failed` webhook this is always `[]`, because the dispatch never completed. */\n results?: Array<{\n device_command_id?: string | null;\n error?: string | null;\n screen_id?: string;\n status?: \"queued\" | \"failed\";\n }>;\n /** Execution is synchronous inside the create request — the job walks `queued` to `running` to `completed` (or `failed`) before the POST returns — so a poll will in practice only ever observe a terminal value. `queued` and `running` exist for a future async worker that claims `queued` rows. */\n status?: \"queued\" | \"running\" | \"completed\" | \"failed\";\n /** Member screens resolved for this command */\n targeted?: number;\n /** Bumped on each job state transition (`queued` to `running` to terminal), so on a completed job it is effectively the moment the fan-out finished. */\n updated_at?: string;\n};\n\n/**\n * Webhook body for a group fleet-command terminal state (`fleet_command.completed` |\n * `fleet_command.failed`). Standard `{ id, event, timestamp, data }` envelope; `data` is the\n * `fleet_command` job object (status, targeted/queued/failed counts, per-screen results; on\n * failure, an `error` message). The event type is also in the `X-Trillboards-Event` header —\n * verify the compound `X-Trillboards-Signature` over the raw body first.\n *\n */\nexport type FleetCommandEvent = {\n /** The fleet_command job object. */\n data?: Record<string, unknown>;\n /** The terminal state that fired, also sent in the `X-Trillboards-Event` header and mirrored to the SSE stream. Note `fleet_command.completed` fires even when individual screens failed — check `data.failed` and `data.results[]`. Delivery is gated by the `SCREEN_GROUP_EVENTS_ENABLED` runtime flag, off by default. */\n event?: \"fleet_command.completed\" | \"fleet_command.failed\";\n /** `evt_<base36 epoch ms>_<12 hex>`, minted once per occurrence and reused across retries of that delivery — so it is the idempotency key. The same id also goes to every endpoint subscribed to the event, so dedupe per (endpoint, id). It is not the delivery audit id and is not queryable. */\n id?: string;\n /** Stamped when the server enqueued the delivery, not when it was sent; retries keep the original value. It is the emit time of the terminal-state event, which is not the same as the job's `completed_at`. */\n timestamp?: string;\n};\n\n/**\n * Programmatic header-bidding configuration and the resolved VAST waterfall for the screen. The `vast_waterfall.sources[]` array is the programmatic demand path — fetch each source's `vast_url` in priority order and hand the returned VAST to your IMA SDK. Source names are opaque public aliases. Source-health request-pressure governance does not remove SQL/Admin-enabled sources from this catalog.\n *\n */\nexport type HeaderBiddingSettings = {\n /** `null` unless the screen falls in the ad-buffering rollout bucket. `min_buffer`, `max_buffer` and `warmup_count` are COUNTS OF PREFETCHED ADS (defaults 3 / 5 / 5), not seconds or bytes; `max_cache_age_seconds` (default 300) is how long a prefetched VAST may be held before it must be discarded. */\n ad_buffering?: {\n enabled?: boolean;\n max_buffer?: number;\n max_cache_age_seconds?: number;\n min_buffer?: number;\n warmup_count?: number;\n } | null;\n /** `null` unless the screen falls in the ad-pod experiment bucket. When present it carries `enabled`, `pod_size` (how many ads to request in a single pod) and `variant_name` (the pod-size arm this screen hashed into) — the arm is assigned server-side, not chosen by the client. */\n ad_pod?: Record<string, unknown> | null;\n /** Share of ad slots the client should give to programmatic, as a decimal FRACTION 0-1 (`0.20` = 20%), defaulting to `1.0`. Same underlying value the CMS exposes as `programmatic_allocation_percent` (0-100, i.e. this times 100). Only honoured when `request_mode` is `allocation`; under `always` it is ignored. */\n allocation?: number;\n /** One id per waterfall BUILD (one `/ads` response), shared by every entry in `vast_waterfall.sources[]`; the narrower per-source key is `request_id`. This is the value that lands in `vast_requests.auction_request_id`, so it is what groups all the source attempts belonging to a single ad opportunity. Echo it, never mint your own. */\n auction_request_id?: string;\n /** Constant `true` whenever this object is present — the whole `header_bidding_settings` object is `null` for a screen that is not programmatically eligible. This is header-bidding *configuration*, not the serving master switch: that is `programmatic_enabled` (surfaced as `ProgrammaticSettingsResponse.enabled`) plus any active ads-disabled reason, and the legacy `enabled` shadow was deliberately removed from the serving decision. */\n enabled?: boolean;\n /** `+`-joined tags for the yield experiments this screen is bucketed into (e.g. `yield_buffer_treatment+ad_pod_pod_3`), covering ad buffering, fast loop and ad pods; `null` when none is active. Assignment is a consistent hash of the screen id, so it is stable for a screen across requests. Report it back for analytics — on its own it changes no client behaviour. */\n experiment_variant?: string | null;\n /** `null` unless the screen falls in the fast-loop experiment bucket. When present it carries `enabled` and `ad_to_ad_gap_ms` — the gap to leave between consecutive ads, in MILLISECONDS (default 5000), which is the experiment's shortened alternative to the normal ~30s cadence. */\n fast_loop?: Record<string, unknown> | null;\n /** No live producer — `null` on every response. The only assignment is guarded on a partner-level `fetchMode` setting, and no demand partner in the registry defines one, so this key is never populated at either the top level or per source. Do not branch on it. */\n fetch_mode?: string | null;\n /** Legacy predecessor of `request_mode`, retained only as the fallback that selects `always` (true) versus `allocation` (false) when no explicit `request_mode` is stored. An explicit `request_mode` always wins — do not read the two independently or you will disagree with the server on screens that set both. */\n force_request?: boolean;\n /** `null` except on screens in a revenue-recovery experiment arm, where it carries `name` and `reason` plus the IMA overrides to apply for that arm — some subset of `num_redirects`, `vast_load_timeout_ms`, `load_video_timeout_ms`, `source_timeout_ms`, `mime_types`, `enable_preloading`, `sdk_version_override` and `client_hints_override`. The key set is deliberately open: apply the keys you recognise and ignore the rest. */\n ima_profile?: Record<string, unknown> | null;\n /** Minimum gap the client should leave between VAST requests, in SECONDS (not milliseconds), default `30`, accepted range 0-300. Advisory: no server-side check enforces it — the `/ads` rate limiter is a separate mechanism that does not read this value. */\n min_interval_seconds?: number;\n /** Always `null`. Every stored value for this key is JSON `null`, it has no typed home on the screen record (dropped from the typed read path), and the builder emits `hbs.prebid || null` — there is no live producer. Prebid Server demand, when it participates, is spliced into `vast_waterfall.sources[]`, not surfaced here. */\n prebid?: Record<string, unknown> | null;\n /** Opaque public alias of the first waterfall source — the same string as `variant_name` and `source_name`, not the `floodgates`/`prebid`/`other` bidding-provider value the CMS accepts on `ProgrammaticSettingsInput.provider`. The key is absent entirely when the waterfall resolved no sources. */\n provider?: string;\n /** Player tuning selected purely from the screen's `country`; today only `IN` differs from the default — `timeout_ms` 25000 vs 12000, `fallback_timeout_ms` 35000 vs 18000, `vquality` 1 vs 2, `enable_network_adaptation` true vs false, and `ad_buffer_percentage` as a 0-1 fraction of network capacity (0.25 vs 1.0). Note the wire shapes: `preferred_resolution` is an object `{width, height}` and `vquality` an integer, not the strings declared here. */\n regional_config?: {\n ad_buffer_percentage?: number;\n enable_network_adaptation?: boolean;\n fallback_timeout_ms?: number;\n preferred_resolution?: string;\n timeout_ms?: number;\n vquality?: string;\n } | null;\n /** Per-request waterfall identifier; echo it back on programmatic-event reports. */\n request_id?: string;\n /** `allocation` = request only on the `allocation` share of slots; `always` = request on every slot and ignore `allocation`. These are the only two accepted values. Defaults to `always` on the static-tag path; on the waterfall path it defaults from the legacy `force_request` boolean (`always` when true, `allocation` when false). */\n request_mode?: string;\n /** Opaque alias of the source these top-level fields describe — the first waterfall source, identical to `provider`/`variant_name`. Absent when the waterfall resolved no sources. */\n source_name?: string | null;\n /** The first source's `priority` sort key, copied up to the top level. Same semantics as `VastWaterfallSource.priority`: an opaque ascending key that may start at 0 and may be non-contiguous — it is not an index, a count, or a position you can do arithmetic on. */\n source_priority?: number | null;\n /** Opaque public alias of the first waterfall source, byte-identical to `provider` and `source_name` on the same response. Format is `src_<6 hex>` (SHA-256 of the partner key) or `var_<6 hex>` (of the variant name), plus the fixed `src_test` for the sandbox test source and `inbound_dsp` for a collapsed DSP-seat source. Never a real partner name, and it may be rotated per tenant — echo it back on `programmatic-event` reports rather than persisting it as an identity. */\n variant_name?: string;\n /** Client-side VAST/creative caching directive, `null` unless the fleet-level VAST-cache switch is on (shipped default: off). `ttl_seconds` defaults to 21600 (6 hours). `priority` is a fixed rank of `1.5` — between paid ads (1) and self-promo (2) — and is emitted as a NUMBER despite the string type declared here. */\n vast_cache?: {\n enabled?: boolean;\n priority?: string;\n ttl_seconds?: number;\n } | null;\n /** Convenience copy of `vast_waterfall.sources[0].vast_url` — the server overwrites it with the first source on every build and drops the key entirely when the waterfall resolved no sources. It is not an extra tag, so fetching only this URL is exactly the `sources[0]`-and-stop defect the `VastWaterfall` contract warns about. */\n vast_tag_url?: string;\n vast_waterfall?: VastWaterfall;\n} | null;\n\nexport type HttpProbeResult = {\n /** IP address that was probed. The target list is PARASITIC on mDNS — the hosts discovered in the same cycle plus the Wi-Fi gateway, de-duplicated and capped at 10. There is no subnet scan, so a device that advertises nothing on mDNS is never probed. */\n host: string;\n /** Always `80` — the probe only ever tries plain HTTP on port 80, and the value is a literal at the call site rather than something the scanner chose. Printer ports 515 and 9100-9102 are refused before any socket opens, because an HTTP request to a JetDirect/LPD port makes the printer physically spool the bytes. */\n port?: number | null;\n /** The HTTP `Server:` response header from a `HEAD /` request (HTTP/1.0, 1.5 s timeout). Never null in an emitted row — a probe that gets no usable header produces no row, and the value is rejected outright if it is over 256 characters or contains an `@`, angle brackets, control characters, or the words `password`/`passwd`/`secret`/`phpinfo`. Failures are counted separately in `skipReasonCounts`, so absence from this array is not evidence the host is down. */\n server?: string | null;\n [key: string]: unknown;\n};\n\n/**\n * Transitional shape: the legacy `{ success, message }` wrapper with the canonical error OBJECT under `error`. Emitted by partner routes that adopted the canonical `code`/`type` vocabulary without moving to the `TrillboardsError` envelope.\n */\nexport type HybridError = {\n error?: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code?: string;\n param?: string | null;\n type?: ErrorType;\n };\n message?: string;\n success?: boolean;\n};\n\n/**\n * A recorded ad impression / play for a partner screen\n * (`@trillboards/api-client` `Impression`).\n *\n */\nexport type Impression = {\n /** Kind of ad served (e.g. direct, programmatic, self_promo). */\n ad_type?: string;\n advertiser_name?: string;\n /** Effective CPM for the impression, in the partner's currency. */\n cpm?: number;\n /** Sent on the wire as `did`. The server accepts the device's Mongo id, its fingerprint, or the `partner_external_id` you registered for it. An unrecognised value is logged and the call still returns 200 — only a SIGNED impression 404s on an unknown device. */\n device_id: string;\n /** Play duration in seconds. */\n duration_seconds?: number;\n /** Earner revenue accrued for the impression. */\n earnings?: number;\n /** The per-serve id minted by the server on `data.ads[].impression_id` (`imp_<epoch-ms>_<8 hex>`) and echoed back as the `impid` parameter on the impression call — it is the dedup key, so never generate your own. Note that no endpoint currently returns this object: it is the `@trillboards/api-client` type describing what you SEND. */\n impression_id: string;\n /** The batch endpoint reads `timestamp`, NOT `played_at` — a `played_at` you send is ignored and the impression is stamped with server receive time instead. That matters for offline sync: send `timestamp` if the real play time has to survive the upload delay. */\n played_at: string;\n /** Your earner-screen id (24-character hex Mongo ObjectId), sent on the wire as `sid`. It is only a FALLBACK for resolving the screen — the server resolves from the device (`did`) first and reads `sid` solely when no device matched. */\n screen_id: string;\n};\n\n/**\n * Legacy error shape carrying a SCREAMING_SNAKE `code` alongside the message — emitted by the auth middlewares (`middleware/auth.js`, `middleware/partnerUserAuth.js`). Its `code` is NOT drawn from `ErrorCode`; it is a separate, older vocabulary.\n */\nexport type LegacyCodedError = {\n /** Legacy SCREAMING_SNAKE code, e.g. NO_TOKEN, TOKEN_EXPIRED, NO_API_KEY. */\n code?: string;\n message: string;\n success?: boolean;\n};\n\n/**\n * Legacy error shape returned by hand-authored routes that predate the canonical envelope (they call `res.status(n).json(...)` directly rather than routing through `globalErrorHandler`). Documented because it is what these endpoints really return; new endpoints must use `TrillboardsError`.\n */\nexport type LegacyError = {\n error?: string;\n message?: string;\n success?: boolean;\n};\n\nexport type Mcp_create_media_buy_Args = {\n brand?: {\n domain?: string;\n name?: string;\n [key: string]: unknown;\n };\n buy_spec?: {\n audience_profile?: Record<string, unknown>;\n budget?: {\n bid_cpm?: number;\n daily_usd?: number;\n total_usd?: number;\n };\n geo?: {\n city?: string;\n country?: string;\n lat?: number;\n lng?: number;\n radius_km?: number;\n state?: string;\n };\n schedule?: {\n days?: Array<number>;\n end_date?: string;\n hours?: Array<number>;\n start_date?: string;\n };\n screen_ids?: Array<string>;\n venue_types?: Array<string>;\n };\n buyer_ref?: string;\n context?: Record<string, unknown>;\n creative?: {\n duration_seconds?: number;\n height?: number;\n type?: \"video\" | \"image\" | \"vast\";\n url?: string;\n width?: number;\n };\n end_time?: string;\n idempotency_key?: string;\n name?: string;\n packages?: Array<{\n bid_price?: number;\n budget?: number | {\n amount?: number;\n currency?: string;\n [key: string]: unknown;\n };\n impressions?: number;\n pricing_option_id?: string;\n product_id?: string;\n targeting_overlay?: Record<string, unknown>;\n [key: string]: unknown;\n }>;\n start_time?: string;\n total_budget?: {\n amount?: number;\n currency?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n};\n\nexport type Mcp_discover_inventory_Args = {\n audience_profile?: {\n income?: \"high\" | \"upper_mid\" | \"mid\" | \"lower_mid\" | \"low\";\n lifestyle?: string;\n min_attention?: number;\n };\n limit?: number;\n location?: {\n city?: string;\n lat?: number;\n lng?: number;\n radius_km?: number;\n state?: string;\n };\n venue_types?: Array<string>;\n};\n\nexport type Mcp_get_media_buy_delivery_Args = {\n breakdown_by?: Array<\"screen\" | \"venue\" | \"hour\" | \"audience_segment\">;\n dimensions?: Array<\"screen\" | \"venue\" | \"hour\" | \"audience_segment\" | \"creative\" | \"day\">;\n media_buy_id: string;\n [key: string]: unknown;\n};\n\nexport type Mcp_get_media_buys_Args = {\n context?: Record<string, unknown>;\n include_snapshot?: boolean;\n media_buy_ids?: Array<string>;\n pagination?: {\n cursor?: string;\n max_results?: number;\n };\n status_filter?: \"pending_creatives\" | \"pending_start\" | \"active\" | \"paused\" | \"completed\" | \"rejected\" | \"canceled\" | Array<\"pending_creatives\" | \"pending_start\" | \"active\" | \"paused\" | \"completed\" | \"rejected\" | \"canceled\">;\n [key: string]: unknown;\n};\n\nexport type Mcp_get_products_Args = {\n audience_profile?: {\n income?: string;\n lifestyle?: string;\n min_attention?: number;\n };\n brief?: string;\n buying_mode?: \"brief\" | \"wholesale\" | \"refine\";\n filters?: {\n budget_range?: {\n currency?: string;\n max?: number;\n min?: number;\n };\n channels?: Array<string>;\n countries?: Array<string>;\n delivery_type?: string;\n format_types?: Array<string>;\n venue_types?: Array<string>;\n [key: string]: unknown;\n };\n market?: string;\n pagination?: {\n cursor?: string;\n max_results?: number;\n };\n venue_types?: Array<string>;\n [key: string]: unknown;\n};\n\nexport type Mcp_list_accounts_Args = {\n account?: {\n account_id?: string;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n operator?: string;\n sandbox?: boolean;\n };\n context?: Record<string, unknown>;\n pagination?: {\n cursor?: string;\n max_results?: number;\n };\n sandbox?: boolean;\n status?: \"active\" | \"pending_approval\" | \"rejected\" | \"payment_required\" | \"suspended\" | \"closed\";\n [key: string]: unknown;\n};\n\nexport type Mcp_sync_accounts_Args = {\n accounts: Array<{\n account?: {\n account_id?: string;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n operator?: string;\n sandbox?: boolean;\n };\n billing?: \"operator\" | \"agent\" | \"advertiser\";\n billing_entity?: Record<string, unknown>;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n notification_configs?: Array<Record<string, unknown>>;\n operator?: string;\n payment_terms?: \"net_15\" | \"net_30\" | \"net_45\" | \"net_60\" | \"net_90\" | \"prepay\";\n preferred_reporting_protocol?: string;\n sandbox?: boolean;\n }>;\n context?: Record<string, unknown>;\n delete_missing?: boolean;\n dry_run?: boolean;\n idempotency_key: string;\n push_notification_config?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport type Mcp_sync_creatives_Args = {\n account?: {\n account_id?: string;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n operator?: string;\n sandbox?: boolean;\n };\n assignments?: Array<{\n creative_id: string;\n media_buy_id?: string;\n package_id?: string;\n [key: string]: unknown;\n }>;\n context?: Record<string, unknown>;\n creative_ids?: Array<string>;\n creatives: Array<{\n assets?: Record<string, unknown>;\n creative_id?: string;\n duration_seconds?: number;\n file_size_mb?: number;\n format_id?: {\n agent_url: string;\n duration_ms?: number;\n height?: number;\n id: string;\n width?: number;\n } | string;\n format_kind?: string;\n height?: number;\n name?: string;\n type?: \"video\" | \"image\" | \"vast\";\n url?: string;\n width?: number;\n [key: string]: unknown;\n }>;\n delete_missing?: boolean;\n dry_run?: boolean;\n ext?: Record<string, unknown>;\n idempotency_key?: string;\n media_buy_id?: string;\n push_notification_config?: Record<string, unknown>;\n validation_mode?: string;\n [key: string]: unknown;\n};\n\nexport type Mcp_update_media_buy_Args = {\n account?: Record<string, unknown>;\n canceled?: boolean;\n cancellation_reason?: string;\n context?: Record<string, unknown>;\n end_time?: string;\n ext?: Record<string, unknown>;\n idempotency_key?: string;\n invoice_recipient?: Record<string, unknown>;\n media_buy_id: string;\n new_packages?: Array<Record<string, unknown>>;\n packages?: Array<{\n creative_assignments?: Array<{\n creative_id: string;\n [key: string]: unknown;\n }>;\n package_id: string;\n targeting_overlay?: Record<string, unknown> | null;\n [key: string]: unknown;\n }>;\n paused?: boolean;\n push_notification_config?: Record<string, unknown>;\n reporting_webhook?: Record<string, unknown>;\n revision?: number;\n start_time?: string | string;\n updates?: {\n budget?: {\n bid_cpm?: number;\n daily_usd?: number;\n total_usd?: number;\n };\n end_date?: string;\n name?: string;\n screen_ids?: Array<string>;\n start_date?: string;\n status?: \"active\" | \"paused\" | \"cancelled\";\n targeting?: Record<string, unknown>;\n };\n [key: string]: unknown;\n};\n\nexport type MdnsNetworkDevice = {\n /** The responder's IP address as a string — the first IPv4 address if it has one, otherwise any address. A record that resolves to no address is dropped rather than emitted with a null host, so in practice this is always populated. It is also what seeds the HTTP-probe target list for the same discovery cycle. */\n host?: string | null;\n /** The service instance name verbatim from the resolve event. A PII filter runs first and DROPS THE WHOLE ROW when the name looks like a personal name (an apostrophe-s possessive, an email, a MAC), so devices named after people disappear from the list entirely rather than appearing anonymised. */\n instanceName: string;\n /** Model string lifted from the TXT record using a per-service-type key table — `md` for Chromecast and HAP, `model`/`am` for AirPlay, `ty`/`product` for IPP, `dt` for Matter (a device-TYPE code used as a model surrogate, not a model name), with a broader default list for other types. `null` when no key in that list is present or all their values are blank. */\n mdnsModel?: string | null;\n /** Version string from the TXT record. Frequently this is `txtvers` — the TXT RECORD FORMAT version, not the device firmware version — because that key is in the fallback list for most service types. `null` when no candidate key is present. */\n mdnsSoftwareVersion?: string | null;\n /** Vendor string from the TXT record, by the same per-type key table. Two traps: Chromecast has an EMPTY vendor key list, so it is always `null` there; and for HAP this carries the HomeKit `ci` CATEGORY id (a numeric device class) while for Matter it carries the raw `VP` `vendorid+productid` pair — neither is a vendor name. */\n mdnsVendor?: string | null;\n /** TCP/UDP port advertised in the SRV record. A port of 0 is coerced to `null` rather than forwarded, so `null` means \"not advertised\", never \"port zero\". */\n port?: number | null;\n /** The mDNS service type the record resolved under, e.g. `_googlecast._tcp.`. Discovery is not open-ended — the scanner browses a FIXED list of 19 types (Roku, AirPlay, RAOP, Chromecast, Amazon WPlay, Android TV Remote, Spotify Connect, device-info, companion-link, IPP/IPPS/printer/PDL, HAP, Matter, Alexa, HTTP and the Trillboards CSI type), so a device advertising anything else is invisible here. */\n serviceType: string;\n [key: string]: unknown;\n};\n\n/**\n * Versioned public disclosure of how audience measurement is produced.\n * Describes WHAT is measured and HOW IT IS QUALIFIED — deliberately never\n * names infrastructure or source locations.\n *\n */\nexport type MeasurementMethodology = {\n /** Prose description of the happy-path pipeline: edge capture, buffered ingest, `signal_observations`, a 30-minute device-resolution pass into `resolved_device_observations`, then a 30-minute transition pass. Names the stores only — never infrastructure or source locations. */\n canonical_path?: string;\n /** What each screen observes and sends. */\n capture_stack?: Record<string, unknown>;\n /** Cross-day identity, including measured coverage (1.6% of identifiable BLE rows). An earlier revision said ~31%; that graded the presence of stable_payload_hash and ignored the sanitizer the identity expression applies, and it is withdrawn. */\n cross_day_matching?: Record<string, unknown>;\n /** The in-range contour: BLE RSSI at or above -75 dBm, empirically about 5 m line-of-sight for Class-2 radios at typical mounting. Calibration is static per screen-class — there is no per-screen ranging today — and devices inside the contour classified as stationary are excluded from the audience funnel by default. */\n display_exposure_zone?: Record<string, unknown>;\n /** What promotes a raw in-range observation to a qualifying event, one entry per qualification (`ble_engagement`, `face_attention`, `returning_visitor`), each carrying its definition, its rationale, and the ClickHouse field a reviewer re-derives it from. */\n dwell_qualification_thresholds?: Record<string, unknown>;\n /** Static disclosure of how observation confidence decays: `algorithm` (Bayesian posterior with temporal decay), `decay_window_days` (90) and `max_confidence` (0.95). These are published constants, not per-request measurements. */\n edge_confidence_model?: Record<string, unknown>;\n /** Evidence grades, which are decisionable, and person-grain resolution. */\n evidence_grade_ladder: Record<string, unknown>;\n /** Prose description of degraded ingest: observations buffer on a durable queue and replay on recovery, and after repeated failures land in a dead-letter store rather than being dropped. */\n fallback_path?: string;\n /** How identifiers are keyed, and what erasure means. */\n hashing?: Record<string, unknown>;\n /** The counting UNIT. Reach and unique-device counts are counts of distinct canonical BLE keys (identifiers); one device contributes several identifiers per window and the number grows with the window. Carries the measured identifiers-per-device per fleet type and the controlled comparison it was derived from. */\n identifier_inflation?: Record<string, unknown>;\n /** Alignment against MRC OOH Phase 2. `mrc_status_accredited` is the machine-readable answer and is **false until an MRC grant reference exists** — read that boolean rather than parsing the English `status` line. Also carries the monotonic qualification chain (`in_range` through `cross_screen`) and the interval method (Wilson score for proportions, 200-sample bootstrap for medians). */\n mrc_ooh_phase2_alignment: Record<string, unknown>;\n /** Version markers for the edge parsers that produced the disclosed fields — `ble_advertisement_parser`, `mdns_txt_extractor`, and the integer `heartbeat_payload_schema`. Hand-maintained constants, bumped when a parser changes. */\n parser_versions?: Record<string, unknown>;\n /** Per-store retention in days in active systems; `basis` states how each is counted and what the encrypted archive keeps. */\n retention: Record<string, unknown>;\n /** Tables a reviewer re-derives every published count from. */\n source_tables: Array<string>;\n /** Bumped on any disclosure change; drives the ETag. */\n version: string;\n};\n\n/**\n * Revenue per screen per hour. Aggregates gross revenue from completed impressions. Refreshed from CH via clickhouseRollupSource. PG only.\n */\nexport type OpenrtbRevenueScreenHourly = {\n actual_gross_revenue: number;\n estimated_gross_revenue: number;\n estimated_impressions: number;\n gross_revenue: number;\n hour_bucket: string;\n impressions: number;\n priced_impressions: number;\n screen_mongo_id: string;\n updated_at: string;\n};\n\nexport type Pagination = {\n /** Whether more items exist */\n has_more?: boolean;\n /** Items per page */\n limit?: number;\n /** Current offset */\n offset?: number;\n /** Total number of items */\n total?: number;\n};\n\nexport type Partner = {\n /** Defaults to the literal `lite_sdk` when unset, so it is never null, and is `lite_sdk` for effectively the whole fleet. It is load-bearing at serve time: `lite_sdk`/`full_sdk` mark the partner a video-only SDK consumer, so an image creative is swapped for the ad's partner video URL unless `sdk_config.allowed_ad_types` includes `image`. */\n integration_tier?: string;\n /** Registered company name. The same string is the buyer-facing media-owner label for this partner's inventory, so it is what advertisers see in the media-owner picker. */\n name?: string;\n /** The 24-character hex Mongo-era identifier (`partners.mongo_partner_id`), not the table's integer `partner_id`. This is the value the API key's owner id and every `partner_mongo_id` foreign key carry. */\n partner_id?: string;\n /** Legacy classification retained for existing integrations. New integrations should not branch on this field. */\n partner_type?: string;\n /** The partner's share as a percentage 0-100 (the stored rate is 0-1 and is multiplied by 100 here). Resolved from the active, currently-effective `publisher_payout_rates` rule; with no such rule it falls through to the system default and reports `60` — which is also why the `POST /register` response echoes `60` even when the caller asked for 70, since the partner row is read back before the rate row is written. */\n revenue_share_percent?: number;\n sdk_config?: SDKConfig;\n /** Lower-cased at registration and unique across all partners (a collision is rejected `409`). It appears in device embed URLs and portal links, so it is effectively permanent once devices are provisioned. */\n slug?: string;\n stats?: PartnerStats;\n /** In practice **always `active` here**: the API-key resolver refuses any partner whose status is not `active`, so a `pending`/`suspended`/`terminated` partner gets `401 invalid_api_key` and never reaches this response. Registration also always creates `active`. */\n status?: \"pending\" | \"active\" | \"suspended\" | \"terminated\";\n /** Defaults to the literal `pending` when unset. `POST /earnings/payout` refuses any value other than `active`. */\n stripe_account_status?: string;\n};\n\nexport type PartnerAdDeliveryProfile = {\n /** Android SDK API level as reported by the device; `null` when not reported, and then no Android rule fires at all. Below 23 forces `mode: vast_fallback` and turns `auto_recovery_enabled` off. 23-25 with desugaring reported off only appends a warning to `notes` and leaves the mode alone. */\n android_api_level?: number | null;\n /** Whether the SERVER may auto-enqueue recovery device commands for this device — the `refresh_ads` and `restart` it issues when a screen heartbeats online without recent VAST requests, or with stalled playback. It is not a client-side setting, and it goes false alongside every `vast_fallback` verdict so we do not restart a device whose player we already know is the wrong one. Even when true, a recovery command is queued only for a device that acts on commands, meaning one that acknowledged a command (`POST /device/{deviceId}/command/{commandId}/ack`) in the last 7 days, or that was handed none in that time. A device that let a delivered command expire unacknowledged, and acknowledged none, is sent no recovery command until that command is 7 days old. */\n auto_recovery_enabled?: boolean;\n /** Echoed back from the device's own heartbeat telemetry, or `unknown` when the device never reported one. It selects which compatibility rules run: `android_native` enables the Android API-level gate, `html5_webview` the Chromium-version checks; `disabled` and `unknown` skip both, so no mode change can result from those. */\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n /** The server's per-heartbeat verdict on how this device should play ads: `ima_sdk` is the normal IMA path, `vast_fallback` means bypass IMA entirely and play the VAST in your own fallback player. It is recomputed from the telemetry on every heartbeat, so treat it as a live instruction rather than one-time provisioning. */\n mode?: \"ima_sdk\" | \"vast_fallback\";\n /** Human-readable diagnostics accompanying the decision above; an empty array on a healthy device. They are free prose for logs and support tickets, not a stable enum — nothing in the contract depends on matching their text, and their presence alone does not imply degraded delivery. */\n notes?: Array<string>;\n /** Machine token for why `mode` was chosen: `default` (nothing disqualified the device), `sdk_reported_ima_unsupported` (your own telemetry reported `imaSupported: false`), or `android_api_below_23_for_current_ima_android_sdk`. `default` is always what accompanies `ima_sdk`. */\n reason?: string;\n /** Major Chromium version of the device's WebView, `null` when not reported. Advisory only — it never changes `mode`: below 87 appends a content-restoration note and below 80 an additional autoplay/media note. */\n webview_chromium_major?: number | null;\n};\n\n/**\n * Non-fatal advisories about the creative that was just accepted. The ad IS created and will serve — these describe problems only the uploader can fix. Empty when there is nothing to report. The most important one is an over-length video: a spot longer than the 30 second ad slot is cut off when the next ad starts, so it never reaches its completion event and its final seconds are never seen.\n */\nexport type PartnerCreativeWarnings = Array<string>;\n\nexport type PartnerDefaultStream = {\n /** The stream's 24-hex id, minted server-side with `newObjectId()` at create and stored as `default_streams.mongo_default_stream_id`. It is the value every other default-stream route takes as `{streamId}`; the shape is Mongo's but PostgreSQL is the store of record. */\n _id?: string;\n /** Accepted with no required-field check, same as `google_slides_url`. The derived `canva_design_id` is returned alongside it although this schema does not declare it. */\n canva_url?: string | null;\n /** Mapped from `default_streams.created_at`. It is the list endpoint's secondary sort key, so two streams sharing a `playback_order` play oldest-first. */\n createdAt?: string;\n /** Falls back to `name`, then to `Background content`; the upload and image routes use `Uploaded video content` / `Image carousel content` instead. */\n description?: string;\n /** Seconds one pass of this stream occupies. It is computed as `images.length x image_duration` when you send images without it; for every other type it is only ever what you sent — nothing probes a YouTube or uploaded video to fill it in on this path. */\n duration_seconds?: number | null;\n /** The URL the player actually loads into the iframe. It defaults to `generic_iframe_url` when you do not send it, so on an iframe stream the two are usually equal. */\n embed_url?: string | null;\n /** The iframe source for the `generic_iframe` type. It also seeds `embed_url` when that is omitted, so sending only this one populates both fields. */\n generic_iframe_url?: string | null;\n /** Unlike `youtube`/`twitch`/`uploaded`/`images`, the `google_slides` type has NO required-field check — a create naming that type with no URL is accepted, stores null, and the screen then renders an empty frame. */\n google_slides_url?: string | null;\n /** Only five keys survive: `auto_advance`, `slide_delay_ms`, `refresh_interval_seconds`, `sandbox_flags`, `allow_flags` — anything else is silently discarded and a non-object is discarded whole. On update it is MERGED over the stored config rather than replacing it, so a key cannot be cleared by omitting it. */\n iframe_config?: Record<string, unknown> | null;\n /** Seconds each image is held before advancing. The multipart image route defaults it to 10 when omitted and uses it to compute `duration_seconds`; the JSON create leaves it unset unless you send it. */\n image_duration?: number | null;\n /** Ordered image URLs, each held for `image_duration` seconds. Required and non-empty when `stream_type` is `images` (400 otherwise), null for every other type; the create accepts a real array, a JSON-encoded array string, or a comma-separated string. */\n images?: Array<string>;\n /** Soft-deactivation flag. The list filters `is_active = true`, so it is always `true` on anything this API returns; the partner DELETE removes the row outright rather than clearing this flag, which is instead used by the screen-wide deactivate paths. */\n is_active?: boolean;\n /** At most one stream per screen carries this — promoting or reordering clears it on every sibling first. A create sets it on the new stream, `reorder` gives it to `order[0]`, and deleting the current stream hands it to whatever the ordering resolves next. */\n is_currently_playing?: boolean;\n /** Falls back to `description`, then to the literal `Default Stream`, so it is never empty. The multipart upload route instead falls back to the uploaded file's original name, and the multi-image route to `Image Carousel (N images)`. */\n name?: string;\n /** Present ONLY on the 201 from the three create routes, which echo the in-memory document back. `default_streams` has no partner column, so list, update and read responses omit this key entirely — tenancy is enforced at the screen, not on the stream row. */\n partner_id?: string;\n /** 1-based position in the screen's rotation; the list sorts on it and breaks ties with `createdAt`. A newly created stream is promoted to 1 and every sibling shifts down, and `POST .../reorder` rewrites it to each id's index in the `order` array you send. */\n playback_order?: number;\n /** The owning screen, mapped from `default_streams.screen_mongo_id` — the same 24-hex id you passed as `{screenId}` in the path. Note the camelCase spelling inside an otherwise snake_case object. */\n screenId?: string;\n /** Accepted with no required-field check. The derived `social_wall_provider` and `social_wall_widget_id` are returned alongside it although this schema does not declare them. */\n social_wall_url?: string;\n /** Which renderer the screen uses. When omitted at create it is DERIVED from whichever content field you sent, in this fixed order: `images`, `youtube_url`, `twitch_url`, `google_slides_url`, `canva_url`, `social_wall_url`, `generic_iframe_url`/`embed_url`, `video_url` (`uploaded`), `local_file_path` (`local`) — and the create is rejected 400 if none resolves. Only `youtube`, `uploaded`, `images` and `twitch` are ever content-analyzed; the four embed types deliberately keep `gemini_analyzed_at` NULL. */\n stream_type?: string;\n /** Required when `stream_type` is `twitch` (400 otherwise). The response also carries the undeclared `twitch_embed_url`, `twitch_content_type` and `twitch_id` companions that the PG reshape returns. */\n twitch_url?: string | null;\n /** Mapped from `default_streams.updated_at`. Playback bookkeeping writes it — marking a stream current, clearing a stale current flag, or stamping `last_played_at` — so it moves without anyone editing the stream content. */\n updatedAt?: string;\n /** Required when `stream_type` is `uploaded`. The `/default-streams/upload` route sets it for you to the stored object URL of the file you posted (`req.file.location`), so you never send it on that path. */\n video_url?: string | null;\n /** Required when `stream_type` is `youtube` — the create is rejected 400 (`youtube_url is required for youtube streams`) without it. Null on every other stream type. */\n youtube_url?: string | null;\n};\n\nexport type PartnerDefaultStreamCreate = {\n /** Accepted with no required-field check, same as `google_slides_url` — a `canva` create with this omitted succeeds and renders nothing. */\n canva_url?: string;\n /** Optional. Falls back to `name` and then to `Background content`. */\n description?: string;\n /** Optional explicit duration for iframe-based streams */\n duration_seconds?: number;\n /** The URL actually loaded into the iframe. When omitted it is filled from `generic_iframe_url`, so send it only when the embeddable URL differs from the one you want recorded. */\n embed_url?: string;\n /** The iframe source. Sending it also derives `stream_type: generic_iframe` and seeds `embed_url`, so this one field is enough to create an iframe stream. */\n generic_iframe_url?: string;\n /** The `google_slides` type has NO required-field check, so a create naming that type without this URL is accepted and stores null. Send a published-to-web slides URL. */\n google_slides_url?: string;\n /** Only these five keys are kept — every other key you send is silently dropped, a non-object is dropped whole, and `slide_delay_ms`/`refresh_interval_seconds` must be finite numbers or they are dropped individually. On a later update this object is merged over the stored one rather than replacing it. */\n iframe_config?: {\n allow_flags?: string;\n auto_advance?: boolean;\n refresh_interval_seconds?: number;\n sandbox_flags?: string;\n slide_delay_ms?: number;\n };\n /** Seconds per image */\n image_duration?: number;\n /** Required and non-empty for an `images` stream. Accepted as a real array, a JSON-encoded array string, or a comma-separated string; combined with `image_duration` it also derives `duration_seconds` when you do not send one. */\n images?: Array<string>;\n /** Optional. Falls back to `description` and then to the literal `Default Stream`, so the created stream always has one. */\n name?: string;\n /** Accepted with no required-field check — a `social_wall` create with this omitted succeeds and renders nothing. */\n social_wall_url?: string;\n /** Optional — omit it and the server DERIVES it from whichever content field you sent, checking in this order: `images`, `youtube_url`, `twitch_url`, `google_slides_url`, `canva_url`, `social_wall_url`, `generic_iframe_url`/`embed_url`, `video_url` (`uploaded`), `local_file_path` (`local`). If nothing resolves the request is rejected 400 `No supported stream content provided`. */\n stream_type?: \"local\" | \"youtube\" | \"uploaded\" | \"images\" | \"twitch\" | \"google_slides\" | \"canva\" | \"social_wall\" | \"generic_iframe\";\n /** Required when the resolved `stream_type` is `twitch`; the create is rejected 400 without it. */\n twitch_url?: string;\n /** Required when the resolved `stream_type` is `uploaded`. Use `POST .../default-streams/upload` with a multipart file instead if you want us to host the video — that route fills this in for you. */\n video_url?: string;\n /** Required when the resolved `stream_type` is `youtube`; the create is rejected 400 without it. Sending it alone is enough — the type is derived. */\n youtube_url?: string;\n};\n\nexport type PartnerDefaultStreamUpdate = PartnerDefaultStreamCreate;\n\n/**\n * Batch device-registration body (`@trillboards/api-client`\n * `PartnerDeviceBatchRegistrationInput`) — up to 100 devices with optional\n * fleet-wide `defaults`. `defaults` applies to every device in the batch\n * except the per-device identifier fields (`device_id` / `device_name`).\n *\n */\nexport type PartnerDeviceBatchRegistrationInput = {\n /** Fleet-wide defaults applied to each device except its identifier fields. */\n defaults?: PartnerDeviceRegistrationInput;\n /** 1 to 100 entries; more than 100 rejects the whole request with `Maximum 100 devices per batch request`. The batch is NOT transactional — entries are registered sequentially and independently, so the call can return 2xx with some entries reported under `errors[]` while the rest committed. An entry whose `device_id` already exists is an update, counted under `summary.updated` rather than `summary.created`. */\n devices: Array<PartnerDeviceRegistrationInput>;\n};\n\n/**\n * Heartbeat payload from agent-core / agent-core-lite Android partner\n * SDKs. Only includes fields verified populated in production\n * `signal_observations` (last 30 days). Stub fields wired in Kotlin but\n * never observed in CH are intentionally excluded; re-add only after\n * telemetry confirms >1% population over 7 days.\n *\n */\nexport type PartnerDeviceHeartbeatBody = {\n /** Legacy flat advertising identifier, superseded by the `advertising_identity` envelope. It is only honoured when no canonical envelope is present AND it passes a plausibility check; a value that fails the check is dropped without an error, and it never reaches the device record through the generic device snapshot — identity has one dedicated persistence rail. */\n advertisingId?: string | null;\n /** Type of the legacy flat `advertisingId`. It is retained only when `advertisingId` itself survives the plausibility check — otherwise it is nulled with it — and the canonical `advertising_identity.id_type` enum is wider (`gaid`, `aaid`, `afai`, `rida`, `tifa`, `idfa`) than the two values allowed here. */\n advertisingIdType?: \"gaid\" | \"idfa\" | null | null;\n advertising_identity?: AdvertisingIdentity;\n /** Number of distinct BLE devices seen in the scan window, BEFORE the 50-entry cap on `nearbyBleDevices` — so it can legitimately exceed the array length (the on-device scanner tracks up to 100 groups). Omit it and the server substitutes the array length. Both this and the snake_case `ble_device_count` are accepted. */\n bleDeviceCount?: number;\n capabilities?: DeviceCapabilityPayload;\n /** mDNS/Bonjour service instances found on the LAN, capped at 50. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`discovered_network_devices`). */\n discoveredNetworkDevices?: Array<MdnsNetworkDevice> | null;\n /** Up to 16 audience identities (hashed email / UID2) keyed by `(id_type, source)`. Rejection is all-or-nothing — one bad element or a 17th entry drops the whole array — and the row-level upsert additionally refuses any envelope whose `observed_at` is older than the stored one, so a replayed batch is a silent no-op. */\n extended_identities?: Array<ExtendedIdentity>;\n /** The agent's stable device fingerprint. On this endpoint it is inert: the path parameter `deviceId` is the sole binding boundary, and the partner heartbeat controller never reads `fingerprint` from the body — it uses the fingerprint of the device the path already resolved. */\n fingerprint?: string;\n /** Hash of the LAN default-gateway IP — the venue-network join key, and the seed the HTTP probe adds to its mDNS-derived target list. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`gateway_ip_hash`). */\n gatewayIpHash?: string | null;\n /** Results of HTTP HEAD probes against at most 10 hosts — the mDNS hosts found in the same cycle plus the Wi-Fi gateway, port 80 only. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`http_probes`). */\n httpProbes?: Array<HttpProbeResult> | null;\n /** Legacy flat LAT flag. `true` alone is enough to clear a previously stored identifier — the server synthesises a `limited` identity envelope from it even with no `advertisingId` present — so do not send `true` speculatively. */\n limitAdTracking?: boolean | null;\n /** Alternate namespace for the same telemetry keys as `telemetry`, merged UNDER it (`{...metadata, ...telemetry}`), so `telemetry` wins on a collision. This is where the Android agents actually put their telemetry — `uptimeSeconds`, `agentType`, `agentVersion`, screen geometry, `sensingMode` — and where the per-heartbeat CPU/memory/thermal gauges are merged in. */\n metadata?: Record<string, unknown>;\n /** Capped at 50 devices (RSSI-sorted, strongest first). */\n nearbyBleDevices?: Array<BleScanResultData> | null;\n /** Wi-Fi scan results, capped at 50 with the joined AP pinned first. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`nearby_wifi_networks`, whose inner keys are `raw_bssid`/`signal_dbm`/`frequency_mhz` — note `signal_dbm`, not a snake_case form of `signalStrengthDbm`). */\n nearbyWifiNetworks?: Array<WifiScanResult> | null;\n /** Count of mDNS instances discovered, before the 50-entry cap (the Rust scanner itself keeps at most 30). Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`network_device_count`). */\n networkDeviceCount?: number;\n /** Heartbeat schema version (1=baseline, 2=nativeSensorSnapshot) */\n schemaVersion?: number;\n /** The screen the agent believes it is bound to. Also inert on this endpoint — the server resolves the screen from the device record, never from this value; correct a wrong binding through registration or the socket heartbeat, which returns an authoritative screen id. */\n screenId?: string | null;\n /** Per-source skip-reason counter map. Shape `{source: {reason: count}}`. */\n skipReasonCounts?: Record<string, Record<string, number>>;\n /** UPnP/SSDP responders found by one `M-SEARCH` with `ST: ssdp:all`, deduped by LOCATION and capped at 50. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`ssdp_devices`). */\n ssdpDevices?: Array<SsdpDeviceInfo> | null;\n /** Agent lifecycle word — the Android agents hardcode `\"active\"` on every heartbeat, so it carries no information. The partner heartbeat controller does not read it; online/standby state is derived from `telemetry.powerState`, not from this field. */\n status?: string;\n /** Hash of the joined access point's BSSID. This field is accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`wifi_bssid_hash`). */\n wifiBssidHash?: string | null;\n wifiEnvironment?: WifiEnvironmentSnapshot;\n /** Count of distinct access points seen, before the 50-entry cap on `nearbyWifiNetworks`. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`wifi_network_count`). */\n wifiNetworkCount?: number;\n /** Hash of the joined network's SSID. Same as `wifiBssidHash`: accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`wifi_ssid_hash`). */\n wifiSsidHash?: string | null;\n [key: string]: unknown;\n};\n\n/**\n * A play reported by the partner SDK's reportPlay. The PartnerPlay body without screen_id (the screen is the device's binding), plus the Trillboards impression id.\n */\nexport type PartnerDevicePlay = {\n /** Optional ad/line identifier; defaults to the sha-keyed creative. */\n ad_id?: string;\n /** When the play completed (device clock), within the last 7 days and at most 5 minutes ahead of the server clock. */\n completed_at: string;\n /** The classification reference from POST /creatives — `sha256:<hex>` or the bare 64-char content hash. */\n creative_ref: string;\n /** Play duration in seconds (default 30). */\n duration_seconds?: number;\n /** The Trillboards impression id, when the host played an ad Trillboards served. The Trillboards record of that play is then kept and this report is not counted twice. */\n impression_id?: string;\n /** Your unique id for this play (idempotency key, shared with POST /v1/partner/plays). */\n play_id: string;\n /** Optional request identifier. */\n request_id?: string;\n};\n\n/**\n * Request body accepted by the single-device registration endpoints\n * (`@trillboards/api-client` `PartnerDeviceRegistrationInput`). Additional\n * vendor-specific fields are accepted and forwarded to enrichment.\n *\n */\nexport type PartnerDeviceRegistrationInput = {\n /** Stable partner-owned device identifier. */\n device_id?: string;\n /** Legacy SDK alias for the device identifier, retained for backwards compatibility. */\n device_name?: string;\n /** Mutable partner category stored independently of advertising classification. Defaults to other on a new device; omission on an existing device preserves its value. Unsupported categories return HTTP 400. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Display specification (pixel resolution and/or physical size). */\n display?: Record<string, unknown>;\n display_settings?: PartnerRegistrationDisplaySettings;\n /** Location hints (lat/lng, address, venue type). */\n location?: Record<string, unknown>;\n /** Friendly name for the device. */\n name?: string;\n /** Placement hints for the screen within the venue. */\n placement?: Record<string, unknown>;\n /** Venue taxonomy hints. */\n venue?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport type PartnerHeartbeatCommand = {\n /** Command normalized for partner SDK compatibility. */\n command?: string;\n /** Opaque command identifier — echo it verbatim to `POST /device/{deviceId}/command/{commandId}/ack`. The ack is ownership-checked against the device that received it, so acknowledging another device's command is refused with 403. */\n id?: string;\n /** Command arguments, shape determined by `command` (for example a brightness level or a target URL). Always an object — commands that take no arguments carry `{}`, never null. */\n payload?: Record<string, unknown>;\n /** When the command was enqueued, not when it was dispatched to you — the gap is up to one heartbeat interval, and a large gap means the device was silent, not that the server was slow. */\n queued_at?: string;\n};\n\nexport type PartnerHeartbeatData = {\n ad_delivery_profile?: PartnerAdDeliveryProfile;\n /** Pending remote commands, at most 5 per heartbeat, drained from the PG `device_commands` store. Each is marked `sent` as it is handed to you, so it appears in exactly ONE heartbeat response and is not re-delivered — acknowledge every entry via the ack endpoint, and dedupe on `id` because delivery is at-most-once, not exactly-once. */\n commands?: Array<PartnerHeartbeatCommand>;\n /** Server-clock timestamp stamped when this heartbeat was processed — the same instant used for the liveness write, not a device-supplied time and not the time of a previous heartbeat. */\n last_seen_at?: string;\n /** Liveness verdict for the screen. In practice it is `online`, or `standby` when the heartbeat reported `power_state` of `off`/`standby` — `standby` is NOT in the declared enum, and `offline` can never be returned here because receiving this response is itself proof the device reached us. It falls back to `online` when the device is not yet linked to a screen. */\n status?: \"online\" | \"offline\";\n};\n\nexport type PartnerHeartbeatMeasurementMetadata = {\n /** Whole seconds since `receivedAt`, computed when the response was built and floored at 0 — the same number as the sibling `stalenessSeconds`. It measures the age of the HEARTBEAT, not of the cache entry; use `cachedAt` for cache age. */\n ageSeconds?: number | null;\n /** When the Redis device twin that served this response was written. It is non-null ONLY when `source` is `redis_twin`, and even then only if the twin carried a `cachedAt`/`observedAt` stamp; the `pg_fallback` and `unknown` paths always report `null`. */\n cachedAt?: string | null;\n /** ISO-8601 server-clock time the underlying heartbeat was received — byte-for-byte the same value as the sibling `lastHeartbeatAt`, not an independent measurement. `null` when no heartbeat has ever been recorded. */\n receivedAt?: string | null;\n /** Which store answered: `redis_twin` (the hot pre-computed device twin — the normal path), `pg_fallback` (the twin was cold or missing, so the persisted last-heartbeat record was used), or `unknown` (no heartbeat has ever been recorded). This is the field that determines which keys `telemetry` can contain, and it is the only signal that the twin was a miss. */\n source?: \"redis_twin\" | \"pg_fallback\" | \"unknown\";\n [key: string]: unknown;\n};\n\nexport type PartnerHeartbeatQueryData = {\n adDeliveryProfile?: PartnerAdDeliveryProfile;\n /** The device's canonical identifier, which need NOT equal the value you put in the path: the server echoes the device fingerprint, falling back to your registered `external_id` and then to the internal id. Match responses on your own request, not on this field. */\n deviceId: string;\n /** Server-clock time the most recent heartbeat was RECEIVED — never a device-supplied timestamp. `null` means this device has never sent a heartbeat that the server retained; note the value can come from the Redis twin, which expires, so a cold cache falls back to the persisted record rather than reporting null. */\n lastHeartbeatAt?: string | null;\n measurementMetadata?: PartnerHeartbeatMeasurementMetadata;\n /** Whole seconds between `lastHeartbeatAt` and the moment this response was built, floored at 0 and rounded — it is computed at read time, so two calls a minute apart return different values for the same heartbeat. `null` when `lastHeartbeatAt` is null. It duplicates `measurementMetadata.ageSeconds` exactly. */\n stalenessSeconds?: number | null;\n telemetry?: PartnerSafeHeartbeatTelemetry;\n [key: string]: unknown;\n};\n\nexport type PartnerHeartbeatQueryResponse = {\n data?: PartnerHeartbeatQueryData;\n /** Always `true` on this 200 response. The 400 (missing `deviceId`), 404 (unknown device), 403 (device belongs to another partner) and 500 paths return `success: false` with a `message` and no `data`. */\n success?: boolean;\n};\n\n/**\n * Optional heartbeat payload. Nested telemetry objects are preferred; legacy flat keys\n * are still accepted for backward compatibility. The registered\n * `deviceId` is the binding boundary for both liveness and identity; no\n * separate partner API key is required.\n *\n */\nexport type PartnerHeartbeatRequest = {\n /** Highest-precedence source for `last_vast_request_at`, `last_vast_response_at` and `proof_of_play_enabled`. All three are dead on both sides — no agent or SDK in the repo emits this block, and nothing reads the values once stored. */\n ad?: {\n last_vast_request_at?: string;\n last_vast_response_at?: string;\n proof_of_play_enabled?: boolean;\n };\n advertising_identity?: AdvertisingIdentity;\n /** Flat alias of `telemetry.agentStatus`. No producer uses this spelling; live values arrive camelCase and come from two disjoint vocabularies — `sensing`/`camera_failed`/`starting`/`idle` from the Android sensing SDK, `foreground`/`background` from the browser SDK. */\n agent_status?: string;\n /** Second-precedence source (after `telemetry.agentVersion`) for the Trillboards agent/SDK version — this is the key the Android sensing SDK actually sends on the partner heartbeat. It is kept ONLY if the heartbeat self-identifies as a Trillboards SDK; otherwise the server force-nulls it so a BYO player's app version is never recorded as ours. */\n agent_version?: string;\n /** Android SDK/API level; below 23 forces `vast_fallback` for a native-Android IMA host. The shipped browser SDK derives it from the user-agent token `Android <n>`, which is the platform RELEASE number (Android 9 gives 9), not the API level (28) — so a value under ~23 is more likely a release number than a genuinely old device. */\n android_api_level?: number;\n /** Flat alias of `telemetry.brightness`, on the platform's own 0-100 scale. Only the Tizen and webOS agents emit a brightness at all, and they put it in `metadata`, not here. */\n brightness?: number;\n /** Java 8+ library desugaring in a native-Android IMA host. Nothing in the repo emits it in any casing, so it is absent fleet-wide; it is read only when `ima_integration` is `android_native` and `android_api_level` is 25 or below, where `false` adds a crash-risk note to `ad_delivery_profile.notes`. */\n desugaring_enabled?: boolean;\n /** Hardware self-description. `os`/`osv`/`make`/`model` here rank below `telemetry`/`metadata` and above the flat body keys, while `android_api_level` and `webview_chromium_major` are read from here in snake_case. It also carries the undocumented `native_bridge` object — the Android WebView bridge's ground-truth make/model/OS/advertising identity — and the DOOH taxonomy keys `dth`/`msid`/`venuetype`/`rdid`/`idtype`/`is_lat`. */\n device?: {\n android_api_level?: number;\n make?: string;\n model?: string;\n os?: string;\n osv?: string;\n webview_chromium_major?: number;\n };\n /** Up to 16 DSP-matchable audience identities (hashed email / UID2). Normalisation is ALL-OR-NOTHING across the array: one malformed element, a duplicate `(id_type, source)` pair beyond the first, or more than 16 entries causes the ENTIRE array to be dropped and the heartbeat still answers 200. Send `[]`-worth of care — a partially valid batch stores nothing. */\n extended_identities?: Array<ExtendedIdentity>;\n /** Flat alias, outranked by `ima.integration`. `html5_webview` marks the heartbeat as coming from a Trillboards SDK (which is what permits `agent_version` to be stored); `android_native` with an API level below 23 forces `vast_fallback`. Unrecognised or absent values become `unknown`, never null. */\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n /** Flat alias with no producer — the browser SDK sends `ima.sdk_version` (from `window.google.ima.VERSION`), which outranks this key and is `null` when IMA failed to load. */\n ima_sdk_version?: string;\n /** Flat alias with no producer — the browser SDK sends `ima.support_reason`, the literal `ok` on success or its IMA load-failure reason. Stored only; the ad-delivery decision never reads it. */\n ima_support_reason?: string;\n /** Flat alias, outranked by `ima.supported` and by `telemetry`/`metadata`. An explicit `false` pins `ad_delivery_profile.mode` to `vast_fallback` and turns `auto_recovery_enabled` off, so the server stops attempting to move the device back onto IMA. */\n ima_supported?: boolean;\n /** Flat alias of `telemetry.inputSource`. Dead on both sides — no producer emits either casing, and the column has no ClickHouse mirror. */\n input_source?: string;\n /** Numeric IMA `AdError` code from the last IMA failure. The browser SDK sends it inside `ima`, which outranks this flat key; it is persisted on the device record and read by nothing. */\n last_ima_error_code?: number;\n /** Numeric VAST error code from the last tag failure (e.g. 303 for an empty wrapper chain), sent inside `ima` by the browser SDK. Persisted only, with no server-side consumer. */\n last_vast_error_code?: number;\n /** Timestamp of the last outbound VAST request. No producer exists anywhere in the repo and nothing reads the stored value, so this field is dead on both ends. */\n last_vast_request_at?: string;\n /** Timestamp of the last VAST response received. Like `last_vast_request_at`, no agent or SDK emits it and nothing consumes it. */\n last_vast_response_at?: string;\n /** Current GPS fix for a moving screen. Processed only for screens whose `mobility_type` is `mobile` or `semi_mobile` (declare it at registration or via PATCH /device/{deviceId}), OR for any screen still missing coordinates (a one-time self-heal that also kicks off venue classification). Static screens with valid coordinates ignore it. Updates live geo-targeting, geofencing and analytics. Fully optional — omit it on stationary screens. */\n location?: {\n /** Horizontal accuracy radius in meters, stored as the device reports it. */\n accuracy_m?: number;\n /** Up to 200 fixes recorded while the device was offline, replayed as a historical track. Timestamps MUST be in ascending order — a non-chronological batch is rejected with HTTP 400. Only the top-level `location` updates the live serving position. */\n buffered_locations?: Array<{\n accuracy_m?: number;\n heading?: number;\n lat: number;\n lng: number;\n speed_mps?: number;\n timestamp?: number;\n }>;\n /** Bearing in degrees (0–360, 0 = true north). Omit if unavailable. */\n heading?: number;\n /** Latitude in decimal degrees (WGS 84). */\n lat?: number;\n /** Longitude in decimal degrees (WGS 84). */\n lng?: number;\n /** `gps` — a live on-device fix. `gps_buffered` — a fix recorded while offline and replayed on reconnect. */\n source?: \"gps\" | \"gps_buffered\";\n /** Ground speed in meters per second. Omit if unavailable. */\n speed_mps?: number;\n /** Unix epoch milliseconds of the on-device fix. Send the device clock value. A fix whose timestamp is more than 60 s ahead of the server's clock, or more than 6 h behind it, is kept without a fix time. A position jump implying > 320 km/h between consecutive fixes is rejected. */\n timestamp?: number;\n };\n /** Alternate namespace for telemetry keys (legacy support). */\n metadata?: Record<string, unknown>;\n /** Flat alias of `telemetry.muted`. The TV agents fall back to `false` here when power state is unreadable while falling back to `null` for `brightness`/`volume`, so a `false` cannot be read as evidence the read succeeded. */\n muted?: boolean;\n /** Connection metrics. The server reads ONLY the camelCase keys shown here; the shipped `trillboards-lite` browser SDK sends this block snake_case (`connection_type`, `effective_type`, `bandwidth_mbps`, `latency_rtt`), so not one key matches and its entire network block is silently discarded on every heartbeat. `bandwidthMbps`/`downlinkMbps` share one slot and `latencyRtt`/`rtt` share another. */\n network?: {\n bandwidthMbps?: number;\n connectionType?: string;\n downlinkMbps?: number;\n effectiveType?: string;\n latencyRtt?: number;\n rtt?: number;\n saveData?: boolean;\n };\n /** Flat alias of `telemetry.networkStrengthDbm`, in dBm (negative). No agent or SDK populates either spelling, so it is absent fleet-wide. */\n network_strength_dbm?: number;\n /** Flat alias of `telemetry.powerState`, used only when the nested value is absent. It coerces to `unknown` rather than failing, and `off`/`standby` downgrade the screen to `standby` so it stops receiving ads. No shipped producer uses this snake_case spelling — every emitter sends the camelCase form. */\n power_state?: \"on\" | \"standby\" | \"off\" | \"unknown\";\n /** Declares that the player emits proof-of-play. No producer sends it and no server logic reads it — proof-of-play eligibility is decided server-side, not from this flag. */\n proof_of_play_enabled?: boolean;\n /** Lowest-precedence source for the IMA/build fields: `ima_supported`, `ima_integration`, `ima_sdk_version`, `android_api_level` and `webview_chromium_major` are read from here only after `ima.*`, `telemetry`/`metadata` and the flat body keys have all missed. Its `version` sub-key is NOT read at all — the SDK version the server stores comes from body `agent_version`/`sdk_version`. */\n sdk?: {\n android_api_level?: number;\n desugaring_enabled?: boolean;\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n ima_sdk_version?: string;\n ima_supported?: boolean;\n version?: string;\n webview_chromium_major?: number;\n };\n /** Third-precedence alias of `agent_version` — same destination and the same BYO-nulling rule. This is what the shipped `trillboards-lite` browser SDK sends, alongside `sdk_type: \"lite\"`, which is itself one of the signals that classify the heartbeat as ours. */\n sdk_version?: string;\n telemetry?: PartnerHeartbeatTelemetry;\n /** Flat alias of `telemetry.temperatureC`, in degrees Celsius from the Android battery thermal sensor. No producer uses this snake_case spelling, and battery-less CTV hardware omits the reading altogether rather than sending 0. */\n temperature_c?: number;\n /** Flat alias of `telemetry.uptimeSeconds`. It measures seconds since DEVICE boot (`SystemClock.elapsedRealtime()/1000` on Android — it survives an agent restart and counts through deep sleep), not agent process uptime. Producers send the camelCase form inside `telemetry`/`metadata`. */\n uptime_seconds?: number;\n /** Flat alias of `telemetry.volume`, on the platform's own scale (0-100 on Tizen/webOS), not a percentage of any documented maximum. Emitted by the Tizen and webOS agents through `metadata` only. */\n volume?: number;\n /** Chromium major version behind the WebView, parsed from the `Chrome/<n>` user-agent token. Below 87 and below 80 each append an advisory note to `ad_delivery_profile.notes`; neither changes the delivery mode. */\n webview_chromium_major?: number;\n};\n\nexport type PartnerHeartbeatResponse = {\n data?: PartnerHeartbeatData;\n /** Always `true` on this 200 response. The failure paths — 404 for an unresolvable `deviceId`, 400 for an invalid BLE payload, 500 on an internal error — return `success: false` with a `message` and no `data` key at all. */\n success?: boolean;\n};\n\nexport type PartnerHeartbeatTelemetry = {\n /** A status word whose vocabulary depends on which SDK reports it: the Android sensing SDK derives it from camera health and sends exactly `sensing` (camera open), `camera_failed`, `starting` or `idle`, while the browser SDK sends `foreground`/`background` from `document.hidden`. Those four Android values are also an in-band signal that the heartbeat came from a Trillboards SDK, which is what allows `agentVersion` to be stored. */\n agentStatus?: string;\n /** Version of the TRILLBOARDS agent/SDK only. If the heartbeat does not self-identify as one of ours (`ima.integration=html5_webview`, `sdk_type=lite`, a `capabilities.audienceSensing.cameraHealth` block, or one of the four sensing `agentStatus` values), the server discards what you send and force-nulls both casings, so a BYO player's own app version is never stamped as ours. Resolution order is `telemetry.agentVersion`, then body `agent_version`, then body `sdk_version`. */\n agentVersion?: string;\n /** Android SDK/API level (23 = Marshmallow, 28 = Pie); below 23 it forces `vast_fallback` when `ima_integration` is `android_native`. Beware the unit — the shipped browser SDK derives it from the user-agent token `Android <n>`, which is the platform RELEASE number (Android 9 gives 9), not the API level (28). */\n android_api_level?: number;\n /** Downlink bandwidth in MEGABITS PER SECOND from `navigator.connection.downlink`. It shares one destination with `downlinkMbps` (`bandwidthMbps` wins), then the same two keys inside `network`, so only one value ever survives. */\n bandwidthMbps?: number;\n /** Panel backlight level on the platform's own scale — on Samsung Tizen and LG webOS the 0-100 picture-brightness value, `null` when that picture-control service is unavailable (VIDAA hardcodes `null`, the API does not exist there). Neither partner SDK sends it; the `brightness` seen in the Android agents is a command-ACK detail, not heartbeat telemetry. */\n brightness?: number;\n /** Free-text connection label (`wifi`, `ethernet`, `cellular`…) that becomes `networkMetrics.connectionType`; `networkConnectionType` outranks it and `network.connectionType` is the fallback. It does NOT set the OpenRTB `device.connectiontype` sent in bid requests — that is the separate all-lowercase `connectiontype` key, which is an INTEGER enum (0 unknown, 1 ethernet, 2 wifi, 3 cellular, 4 2G, 5 3G, 6 4G, 7 5G), is not declared in this schema, and only passes because the object allows additional properties. */\n connectionType?: string;\n /** Whether Java 8+ library desugaring is enabled in a native-Android IMA host. No agent or SDK anywhere in the repo emits it, so it is absent fleet-wide; it is consulted only when `ima_integration` is `android_native` and `android_api_level` is 25 or below, where `false` adds a known-crash-risk note to `ad_delivery_profile.notes`. */\n desugaring_enabled?: boolean;\n /** Second-precedence spelling of `bandwidthMbps` (Mbps) filling the same `networkMetrics.bandwidthMbps` slot; ignored whenever `bandwidthMbps` is also present. The npm SDK sends both from the same `connection.downlink` reading. */\n downlinkMbps?: number;\n /** How the player reaches Google IMA. `html5_webview` is hardcoded by both Trillboards browser SDKs and is itself the signal marking the heartbeat as ours (which is what allows `agentVersion` to be stored); `android_native` with `android_api_level` below 23 forces `ad_delivery_profile.mode` to `vast_fallback`. Absent or unrecognised values normalise to `unknown`, never null, and the undocumented nested `ima.integration` key — what the shipped browser SDK actually sends — outranks this flat one. */\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n /** The IMA SDK's own version string. Nothing produces this flat spelling — the shipped browser SDK sends it as `ima.sdk_version`, read from `window.google.ima.VERSION`, which takes precedence — and it is `null` whenever IMA failed to load, so absence usually pairs with `ima_supported: false`. */\n ima_sdk_version?: string;\n /** Free-text explanation for the `ima_supported` verdict — the browser SDK sends the literal `ok` when IMA loaded and its load-failure reason otherwise, under `ima.support_reason`, which outranks this flat spelling (nothing produces the flat one). Stored only: the ad-delivery decision never reads it. */\n ima_support_reason?: string;\n /** Whether the IMA SDK is usable on this player. An explicit `false` is a hard switch, not a hint: it pins `ad_delivery_profile.mode` to `vast_fallback` AND sets `auto_recovery_enabled: false`, so the server stops trying to move the device back onto IMA. The browser SDKs compute it as `Boolean(window.google.ima)` / an IMA load-failure flag. */\n ima_supported?: boolean;\n /** Free-form active-input label (e.g. an HDMI port name), stored verbatim on the device record. It has NO producer: no agent or SDK in the repo emits either casing, the only other references are Flutter UI localisation strings, and the schema sidecar marks the column PG-only with no ClickHouse mirror. Treat it as permanently absent. */\n inputSource?: string;\n /** Numeric IMA `AdError` code from the most recent IMA failure, cached client-side between heartbeats. The shipped browser SDK sends it inside `ima`, which outranks this flat key. Persisted on the device record only — no server logic reads it. */\n last_ima_error_code?: number;\n /** Numeric VAST error code from the most recent tag failure (e.g. 303 for a wrapper chain that resolved to nothing), cached client-side and sent inside `ima` by the browser SDK. Persisted only, with no server-side consumer. */\n last_vast_error_code?: number;\n /** Timestamp of the player's last outbound VAST request. It has NO producer: a repo-wide grep finds only the server-side reader and the generated API client, so it is absent on every live device, and nothing downstream consumes the stored value. */\n last_vast_request_at?: string;\n /** Timestamp of the last VAST response the player received. Like `last_vast_request_at` it has no producer in any agent or SDK, and the persisted value has no consumer. */\n last_vast_response_at?: string;\n /** Round-trip time in MILLISECONDS from `navigator.connection.rtt`. Shares one destination with `rtt` (`latencyRtt` wins); the read-side schema bounds the stored value to 0-60000. */\n latencyRtt?: number;\n /** Device manufacturer. Written to the device column but not authoritative — every heartbeat runs a device-identity fusion pass that can replace `make`/`model`/`os` from the user agent and 51Degrees specs, and the corrected value is what is persisted and read back. */\n make?: string;\n /** Device model, subject to the same identity-fusion overwrite as `make`. The browser SDK has no real model string and sends the full user agent in this field instead. */\n model?: string;\n /** Audio mute state. Note the asymmetry with `brightness`/`volume`: when the Tizen/webOS agent cannot read power state it still sends `false` here while sending `null` for the other two, so `false` does not distinguish \"not muted\" from \"could not be read\". The `muted` the browser SDK sends elsewhere belongs to the ad request, not the heartbeat. */\n muted?: boolean;\n /** Highest-precedence spelling of the free-text connection label that becomes `networkMetrics.connectionType`. No agent or SDK emits it, so in practice the value comes from `connectionType` or `network.connectionType`. Sending any of the six network keys makes the server stamp `networkMetrics.measuredAt` and increment `networkMetrics.measurementCount`. */\n networkConnectionType?: string;\n /** Highest-precedence spelling of the Network Information API `effectiveType` bucket (`slow-2g`/`2g`/`3g`/`4g`) — a round-trip-time and downlink classification, not the physical bearer. No producer emits this spelling; live values arrive as `effectiveType` or `network.effectiveType`. */\n networkEffectiveType?: string;\n /** Wi-Fi/cellular RSSI in dBm (negative; the read-side schema bounds it to -120..0). No agent or SDK populates it — the field exists on the Kotlin model and the only value in the tree is a hardcoded test literal — so it is absent fleet-wide. Per-AP signal is instead carried by `nearbyWifiNetworks[].signalStrengthDbm` and `wifiEnvironment.connectedSignalDbm`. */\n networkStrengthDbm?: number;\n /** Operating-system family, written straight to the device column `os` — the Android agents send the full `\"Android <release>\"` string, not a bare family name. It is an input to the identity-fusion pass that runs on every heartbeat, so what the read endpoint later returns may be a corrected value rather than what you sent. */\n os?: string;\n /** Lower-precedence alias of `osv`: both resolve to the same normalized value and the same `osv` device column, with `osv` winning when both are present. */\n osVersion?: string;\n /** OS version string. `osv` and `osVersion` are two spellings of ONE value — the normalizer takes `osv` first and falls back to `osVersion`, and both land in the single device column `osv`, so sending different values in the two keys silently keeps only `osv`. */\n osv?: string;\n /** Display power as the device reports it. Never null and never rejected: any unrecognised or absent value is coerced to `unknown`, and `off`/`standby` make the server record the screen `standby` rather than `online`, which stops ad delivery. Producers use this camelCase spelling only — the browser SDK derives it from `document.hidden` (`standby` when hidden, else `on`), the Fire TV / Android TV agents send their `PowerController` state; the flat `power_state` alias has no producer at all. */\n powerState?: \"on\" | \"standby\" | \"off\" | \"unknown\";\n /** Whether the player is configured to emit proof-of-play. No agent or SDK sends it, so it is absent fleet-wide, and nothing reads the stored value — actual proof-of-play eligibility is decided server-side, never from this flag. */\n proof_of_play_enabled?: boolean;\n /** Second-precedence spelling of `latencyRtt` (milliseconds), ignored when `latencyRtt` is also present. */\n rtt?: number;\n /** The browser's Data Saver preference (`navigator.connection.saveData`). Accepted as a boolean or the strings `\"true\"`/`\"false\"`; anything else becomes `null` rather than `false`. */\n saveData?: boolean;\n /** Degrees Celsius from the BATTERY thermal sensor — the only real °C reading a non-system Android app can obtain. Battery-less CTV hardware (Fire TV sticks, TV boxes) omits the key entirely rather than sending 0, so absence means \"no battery sensor\", not \"cool\"; the derived ClickHouse `cpu_temp_c` was measured above zero on ZERO rows. */\n temperatureC?: number;\n /** Seconds since the DEVICE booted, not since the agent process started: the Android producers send `SystemClock.elapsedRealtime() / 1000`, which keeps counting through deep sleep and resets only on reboot, so an agent crash-loop leaves this climbing. It is also the sole camelCase survivor in the ClickHouse heartbeat blob — every other gauge there is snake_case. */\n uptimeSeconds?: number;\n /** Speaker volume on the platform's own scale — 0-100 on Tizen (`tizen.tvaudiocontrol.getVolume()`) and webOS, `null` when the audio-control service is unavailable or (on VIDAA) does not exist. It is not normalised to a percentage of any maximum, and neither partner SDK sends it. */\n volume?: number;\n /** Major version of the Chromium engine backing the WebView, parsed from the `Chrome/<n>` user-agent token by both browser SDKs. Below 87 adds a content-restoration warning to `ad_delivery_profile.notes` and below 80 an autoplay/media warning; neither changes the delivery mode. */\n webview_chromium_major?: number;\n [key: string]: unknown;\n};\n\n/**\n * What a rider did with the screen, reported by the partner SDK's reportInteraction. (partner, device, interaction_id) is the event's identity.\n */\nexport type PartnerInteraction = {\n /** The creative on screen, as the host names it. */\n creative_id?: string;\n /** The host app's id for this interaction (idempotency key, per device). */\n interaction_id: string;\n /** When it happened (device clock), within the last 7 days and at most 5 minutes ahead of the server clock. */\n occurred_at: string;\n /** Milliseconds into the creative's playback when it happened. */\n t_ms?: number;\n /** What happened. seatbelt_reminder_shown = the host app showed a SeatbeltReminder that agent-core 1.24 delivered to its safety-event listener; send the reminder's eventId as interaction_id. Never a programmatic ad-lifecycle event (those are POST /device/{deviceId}/programmatic-event). */\n type: \"tap\" | \"qr_shown\" | \"qr_scanned\" | \"dwell_prompt\" | \"seatbelt_reminder_shown\";\n};\n\nexport type PartnerLBarContent = {\n /** The venue name rendered in the L-bar; empty string when unset. One of only three scalar keys (`enabled`, `business_name`, `current_promotion`) the PUT copies straight across — every other key here is an object that gets shallow-merged. */\n business_name?: string;\n /** Holds `phone`, `email`, `website`, `address` and `wifi_password`, all free text and all empty-string when unset, shallow-merged on PUT. `wifi_password` is rendered on the screen, so treat it as public. */\n contact_info?: Record<string, unknown>;\n /** The promo line shown in the L-bar. It is also writable through the much lighter `PUT .../l-bar/live-updates` endpoint as its `promotion` field, which is the path to use for frequent changes. */\n current_promotion?: string;\n /** Free-text lines rotated in the L-bar. Unlike every nested object above, this is REPLACED wholesale whenever it is present in the body, so send the complete list each time. */\n custom_messages?: Array<string>;\n /** The L-bar's own cosmetics — NOT the screen display-settings resource. Holds `background_color` (`#000000`), `text_color` (`#FFFFFF`), `accent_color` (`#4A90E2`), the widget toggles `show_weather`/`show_time`/`show_date`/`show_store_hours` (default true) and `show_contact_info`/`show_social_media`/`show_sports_scores`/`show_stock_market` (default false), plus `selected_sports_leagues`. Shallow-merged on PUT. */\n display_settings?: Record<string, unknown>;\n /** Whether the L-bar content region is drawn; defaults `false`. It is COUPLED to `display_preferences.display_mode` on the PUT — sending `display_mode: \"fullscreen\"` forces this to `false`, and `\"l-bar\"` forces it to `true` unless you send an explicit boolean in the same request. */\n enabled?: boolean;\n /** Exactly three sub-objects are merged — `queue_management` (`enabled`, `current_number`, `queue_message`, default `Now Serving`), `wait_time` (`enabled`, `current_wait_minutes`, `wait_message`, default `Current Wait Time`) and `custom_status` (`enabled`, `status_message`); any other key nested here is silently dropped. The live-updates endpoint sets `enabled` for you as a side effect of writing a value, and clears `custom_status.enabled` when you send an empty message. */\n live_updates?: Record<string, unknown>;\n /** Holds `facebook`, `instagram`, `twitter` and `google_reviews`, free text and empty-string when unset, shallow-merged on PUT. */\n social_media?: Record<string, unknown>;\n /** Free-text opening hours: one string per lowercase day name (`monday`..`sunday`) plus a `timezone` defaulting to `America/New_York`. The strings are displayed verbatim — nothing parses them into open/close times — and the PUT shallow-merges them, so you can send a single day. */\n store_hours?: Record<string, unknown>;\n};\n\nexport type PartnerLBarDisplayPreferences = {\n /** Which surfaces ads may occupy; `null` by default, in which case it is derived from `display_mode` + `l_bar_ads_enabled`. Setting `lbar` also flips `display_mode` to `l-bar` when the same request does not set it, and narrows the fullscreen surface to `self_promo` only — paid and programmatic demand stops running full screen. */\n ad_surface_mode?: \"fullscreen\" | \"lbar\" | \"pip\" | \"all\" | null | null;\n /** Default `fullscreen`. Writing it has side effects: `fullscreen` also forces `l_bar_ads_enabled` and `l_bar_content.enabled` to `false`, and `l-bar` forces both to `true` unless the same request sets them explicitly. A change also emits a `refresh` control event so the kiosk reloads and swaps surfaces. */\n display_mode?: \"fullscreen\" | \"l-bar\";\n /** Seconds one L-bar ad is held; default 8, accepted range 3-30. It must be strictly LESS than `l_bar_ad_interval`, and the check falls back to the stored interval when this request does not send one. */\n l_bar_ad_duration?: number;\n /** Seconds between L-bar ad plays; default 25, accepted range 10-120. It must be strictly GREATER than `l_bar_ad_duration`, and the pair is cross-checked against the STORED values, so lowering this alone can fail on a duration set by an earlier request. */\n l_bar_ad_interval?: number;\n /** Whether ads may fill the L-bar slots. When it has never been set it is DERIVED as `display_mode === \"l-bar\"`, so it reads `true` on an L-bar screen and `false` on a fullscreen one. Accepts a boolean or the strings `\"true\"`/`\"false\"`; anything else is 400. */\n l_bar_ads_enabled?: boolean;\n /** Which edge the L-bar occupies; default `bottom`. It decides ad-slot geometry — `bottom` lays slots out horizontally and `right` vertically — and the slot COUNT is derived from it, so switching sides changes how many `lbar_slot_*` surfaces exist. This endpoint does not validate the value against any enum (the display-settings resource's `l_bar.position` does, and accepts `top`/`bottom`/`left`/`right`). */\n l_bar_position?: \"bottom\" | \"right\";\n /** Share of the screen the L-bar occupies, as a PERCENT; default 20. This endpoint accepts it with no range check at all, while the equivalent `l_bar.size_percent` on the display-settings resource clamps to 10-50. It is also not what sizes ad slots — `buildAdSurfaces` uses a fixed 25%. */\n l_bar_size?: number;\n /** Picture-in-picture ad window: `enabled` (default false), `position` (default `bottom-right`), `size_ratio` as a FRACTION of the screen 0.15-0.45 (default 0.3), `aspect_ratio` as width/height 0.5-3 (default 16/9), and `margin` in PIXELS 8-64 (default 24). A PiP surface is only produced when `ad_surface_mode` is `pip` or `all` AND `enabled` is true. */\n pip_settings?: {\n aspect_ratio?: number;\n enabled?: boolean;\n margin?: number;\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n size_ratio?: number;\n };\n};\n\nexport type PartnerLBarSettings = {\n /** The resolved renderable ad surfaces, one entry per surface (`fullscreen`, `lbar_slot_1..N`, `pip`). Present ONLY on the PUT response; the GET does not compute it. */\n ad_surfaces?: Array<{\n allowed_ad_types?: Array<string>;\n dimensions?: {\n height?: number;\n width?: number;\n };\n display_area_ratio?: number;\n display_mode?: string;\n enabled?: boolean;\n id?: string;\n surface_group?: string;\n surface_type?: string;\n }>;\n display_preferences?: PartnerLBarDisplayPreferences;\n l_bar_content?: PartnerLBarContent;\n /** The screen's resolved pacing contract, present only on the PUT response. `policy_version` is `v1` and every interval is in MILLISECONDS (`paid_interval_ms`, `self_promo_interval_ms`, `image_ad_total_ms`, `image_ad_min_ms`); it also carries `max_paid_share` (null unless a loop share cap is enabled), `surface_policy`, `schedule_policy`, `pip_settings` and `lbar_settings`. */\n playback_policy?: Record<string, unknown>;\n};\n\n/**\n * Where the screen's location comes from, and, per rail, whether that rail\n * has the location it needs. Location is a readiness capability, never a\n * registration rule: a device without one is registered, and this says\n * which rails serve it until a position arrives. `monetization_status` is\n * computed over `inventory_feed` and `geo_targeted_demand`.\n *\n */\nexport type PartnerLocationCapability = {\n /** `precise` — the screen or its device has coordinates; `fleet_market` — none of its own, your account's declared fleet market location lists it; `none`. */\n position?: \"precise\" | \"fleet_market\" | \"none\";\n rails?: {\n geo_targeted_demand?: PartnerLocationRail;\n inventory_feed?: PartnerLocationRail;\n visit_attribution?: PartnerLocationRail;\n };\n};\n\nexport type PartnerLocationRail = {\n /** Where a ready rail's location comes from; null when blocked. Only `inventory_feed` reads `fleet_market`. */\n location_source?: \"screen\" | \"device\" | \"fleet_market\" | null | null;\n /** Why a blocked rail has no location; null when ready. See https://api.trillboards.com/docs/monetization-requirements#location-capability. */\n reason?: \"awaiting_device_gps\" | \"no_location_provided\" | \"city_without_state\" | \"geocode_failed\" | \"screen_position_pending\" | \"country_unknown\" | \"country_not_supported\" | null | null;\n status?: \"ready\" | \"blocked\";\n};\n\n/**\n * Stripe-style monetization requirements (account.requirements analogue).\n * Returned on device register / update / get / batch so bulk partners can\n * detect and self-remediate missing data instead of discovering silent\n * gaps later. `currently_due` blocks or limits monetization now;\n * `eventually_due` improves serving but isn't blocking.\n *\n */\nexport type PartnerMonetizationRequirements = {\n /** Requirements blocking or limiting monetization right now. */\n currently_due?: Array<PartnerRequirement>;\n /** Non-blocking improvements (e.g. display dimensions). */\n eventually_due?: Array<PartnerRequirement>;\n};\n\nexport type PartnerNetworkConfig = {\n /** Partner-level ad pacing and identity controls applied to every screen you own; on the `/ads` path they OUTRANK the screen's own `ad_interval_seconds` and the partner's `sdk_config.max_ads_per_hour`. A PATCH merges key-by-key and rejects unknown keys with a 400, and sending `null` for `identity_mode` or `self_promo_priority_mode` DELETES the key rather than storing null, so those two come back absent rather than as `null`. */\n ad_delivery?: {\n /** `/ads` response cache lifetime. Zero requires a fresh response for every request. */\n cache_max_age_seconds?: number;\n /** Delegates resettable advertising identity to the native Google IMA SDK; the API never fabricates one. Set null to restore the platform default identity path. */\n identity_mode?: \"ima_sdk\" | null;\n /** Fleet-wide hourly ad cap returned in `settings.max_ads_per_hour`. */\n max_ads_per_hour?: number;\n /** Requests non-personalized demand when true. Never provide an advertising identifier unless the OS legitimately exposes it. */\n non_personalized_ads?: boolean;\n /** Returned as both `settings.ad_interval` and `header_bidding_settings.min_interval_seconds`; the player should request each monetizable slot at this cadence. */\n request_interval_seconds?: number;\n /** Controls whether a scheduled self-promo/house slot may lead the VAST waterfall. `scheduled_primary` preserves the bounded house cadence; `fallback_only` keeps self-promo behind paid programmatic demand; `disabled` removes the self-promo/house creative from your screens entirely — it is served on neither `ads[]` nor the VAST waterfall, and no new house creative is generated for your screens. Paid-direct guarantees always retain priority and are never affected. Set null to restore `scheduled_primary`. */\n self_promo_priority_mode?: \"scheduled_primary\" | \"fallback_only\" | \"disabled\" | null;\n };\n /** White-label presentation for your buyer-facing advertiser portal. These values are read and written directly against the branding your portal renders — a GET returns what a buyer currently sees, and a write takes effect on their next page load. Omitted entirely if no white-label portal is linked to your partner account; writing branding in that state returns `409` `white_label_distributor_not_linked` rather than accepting values that would render nowhere. Contact Trillboards to have one linked. */\n branding?: {\n /** Shown as the portal name and the browser tab title. */\n display_name?: string;\n /** Absolute HTTPS URL. */\n favicon_url?: string;\n font_body?: string;\n font_heading?: string;\n /** Absolute HTTPS URL. Rendered in the portal header. */\n logo_url?: string;\n /** CSS color. HSL triplets (\"210 90% 40%\") and hex are both accepted. */\n primary_color?: string;\n secondary_color?: string;\n tagline?: string;\n };\n /** Default content preferences inherited by newly provisioned screens. */\n default_content_preferences?: Record<string, unknown>;\n /** Partner-level (fleet-wide) demand-source ordering; there is no per-screen override for these keys. A PATCH merges key-by-key into what is stored, and any key other than `source_order`/`total_timeout_ms` is rejected with a 400 naming it. The GET omits this object entirely when nothing has been stored, so absence means \"never configured\" — it is not a rendering of the effective defaults. */\n default_waterfall?: {\n /** Preferred opaque source aliases from the `/ads` response. Sources not listed here remain enabled and are appended. Internal demand names and `sort_by: cpm` are rejected. */\n source_order?: Array<string>;\n /** Total deadline for one waterfall snapshot, in milliseconds. */\n total_timeout_ms?: number;\n };\n /** Limits your branded buyer portal to YOUR OWN screens. Off by default: a branded portal otherwise sells the whole Trillboards network, which is what most white-label partners want. The screen set is DERIVED from the media-owner identity your screens already carry — both the ones we host and the ones resold through partner exchanges — so it stays correct as you add inventory and there is no list to maintain. It cannot be set to another operator's inventory. */\n storefront?: {\n /** When true, every inventory surface in your buyers' portal — search, map, forecasts, quotes, bookings and proposals — is limited to your own screens. */\n enabled?: boolean;\n };\n};\n\n/**\n * Partner-safe partial update. Internal `partners`, `supply_chain`, seller\n * IDs, direct demand names, and CPM-sort controls are rejected.\n *\n */\nexport type PartnerNetworkConfigUpdate = PartnerNetworkConfig;\n\n/**\n * A log-level play for a partner-served ad.\n */\nexport type PartnerPlay = {\n /** Optional ad/line identifier; defaults to the sha-keyed creative when creative_ref is sent. */\n ad_id?: string;\n /** ISO 8601 timestamp when the play completed. */\n completed_at: string;\n /** Optional. The classification reference from POST /creatives — `sha256:<hex>` or the bare 64-char content hash. Omit it for a play of an ad you hold no content hash for; the play is then recorded with its `ad_id`, or with none. */\n creative_ref?: string;\n /** Play duration in seconds (default 30). */\n duration_seconds?: number;\n /** Your unique id for this play (idempotency key). */\n play_id: string;\n /** Optional partner request identifier. */\n request_id?: string;\n /** One of your registered earner-screen ids. */\n screen_id: string;\n};\n\n/**\n * Partner-reported impression and revenue counts for reconciliation against deduped completed_impressions. Ingested from VidVerto SSP API and Adipolo API / JustBaat CSV reports. PG only.\n */\nexport type PartnerReconciliationReports = {\n adjustment_id?: number | null;\n applied_at?: string | null;\n /** applied_report_hash/applied_at (mig 449) gate the hourly pricing re-apply: syncs skip the CI re-stamp + PED rebuild when the applied tuple is unchanged. Written ONLY by partnerPricingApplyGate.reco... */\n applied_report_hash?: string | null;\n created_at: string;\n /** Wave 2 B added demand_partner_id INT + variant_id INT FKs. Legacy partner_key TEXT kept as wire-format alternate-key. Backfill via follow-up Wave 2 B-backfill PR. */\n demand_partner_id?: number | null;\n /** VidVerto synced daily via vidvertoRevenueSync before programmatic earnings aggregation. */\n id?: number | null;\n imported_by?: string | null;\n /** NUMERIC(8,4). */\n impression_variance?: number | null;\n /** NUMERIC(10,4). */\n our_ecpm?: number | null;\n our_impressions?: number | null;\n our_requests?: number | null;\n /** NUMERIC(14,6). */\n our_revenue?: number | null;\n provider_name: string;\n /** Adipolo publisher revenue requires a completed vast_requests lifecycle plus latest screens_live source='owned'. ID shape/event alone is insufficient; shared, external, and unjoined bundles are excl... */\n raw_data?: Record<string, unknown> | null;\n report_date: string;\n report_type: \"partner_api\" | \"manual_upload\" | \"email_extract\" | \"dashboard_snapshot\";\n /** NUMERIC(10,4). */\n request_variance?: number | null;\n resolution_notes?: string | null;\n /** NUMERIC(8,4). */\n revenue_variance?: number | null;\n reviewed_at?: string | null;\n reviewed_by?: string | null;\n status: \"pending\" | \"matched\" | \"flagged\" | \"disputed\" | \"resolved\" | \"accepted\";\n /** NUMERIC(10,4). */\n their_ecpm?: number | null;\n /** NUMERIC(6,4). */\n their_fill_rate?: number | null;\n their_impressions?: number | null;\n their_requests?: number | null;\n /** NUMERIC(14,6). */\n their_revenue?: number | null;\n updated_at: string;\n variant_id?: number | null;\n};\n\n/**\n * Optional display behavior applied while registering or re-registering a device.\n */\nexport type PartnerRegistrationDisplaySettings = {\n content_fit?: ContentFitSettings;\n};\n\nexport type PartnerRequirement = {\n /** Stable machine code, e.g. location_unresolvable, location_awaiting_device_gps, enrichment_failed, display_size_missing. */\n code?: string;\n /** Built mechanically as `https://api.trillboards.com/docs/monetization-requirements#<code>`, so the anchor always matches `code`. A bare `docs.` subdomain is deliberately NOT used — it resolves to an unrelated portal SPA rather than documentation — and a CI guard blocks reintroducing it. */\n doc_url?: string;\n /** The request field this concerns (location, venue, display). */\n field?: string;\n /** Human-readable, actionable remediation. */\n message?: string;\n /** Specific reason variant, e.g. city_without_state, no_location_provided, geocode_failed, awaiting_device_gps. */\n reason?: string;\n};\n\n/**\n * Partner-safe subset of device telemetry. Strips MDM compliance,\n * Vertex embeddings, identity-correction internals, partner identifiers,\n * and Mongo `_id` so partners only see what they need to decide\n * whether a device is healthy enough to receive ads.\n *\n */\nexport type PartnerSafeHeartbeatTelemetry = {\n /** Agent lifecycle word, with two disjoint vocabularies depending on the reporting SDK (`sensing`/`camera_failed`/`starting`/`idle` from the Android sensing SDK, `foreground`/`background` from the browser SDK). Absent on the primary `redis_twin` path — the device twin has no such field, so it surfaces only on the `pg_fallback` path. */\n agentStatus?: string | null;\n /** Trillboards agent/SDK version. Never present here on either path: the heartbeat writes it to the device record root, not into the last-heartbeat telemetry blob, and the device twin does not carry it either. It is also nulled at write time for any heartbeat that does not self-identify as a Trillboards SDK. */\n agentVersion?: string | null;\n /** Downlink bandwidth in Mbps. Never present on either path: the write path stores it under `networkMetrics.bandwidthMbps`, a sibling of the last-heartbeat blob this endpoint reads, and the device twin has no such field. */\n bandwidthMbps?: number | null;\n /** Panel brightness on the platform's own scale (0-100 on Tizen/webOS, `null` where no picture-control API exists). Absent on the primary `redis_twin` path — the device twin has no such field, so it can only appear on the `pg_fallback` path and only for the TV agents that emit it. */\n brightness?: number | null;\n /** Free-text connection label. Not present on either path — the write path stores it as `networkMetrics.connectionType`, and while the device twin does carry a `connectiontype`, that is the all-lowercase OpenRTB INTEGER enum, a different quantity under a different key. */\n connectionType?: string | null;\n /** Running count of back-to-back ad failures the player has seen, from the heartbeat's `playback.consecutive_failures`; it is what drives the server's stalled-playback recovery. Absent on the primary `redis_twin` path — the device twin has no such field, so it appears only on the `pg_fallback` path. */\n consecutiveAdFailures?: number | null;\n /** Network Information API `effectiveType` bucket (`slow-2g`/`2g`/`3g`/`4g`) — a latency/throughput classification, not the physical bearer. Stored under `networkMetrics.effectiveType` and carried by neither source object, so it never appears here. */\n effectiveType?: string | null;\n /** Round-trip time in MILLISECONDS (bounded 0-60000 by the read-side schema). Like `bandwidthMbps` it is stored under `networkMetrics.*` and is on neither of this endpoint's two source objects. */\n latencyRtt?: number | null;\n /** Device manufacturer, after the identity-fusion correction pass — so it can differ from what the device reported. Present only on the `redis_twin` path: it is a device-record field, and the `pg_fallback` path returns just the last-heartbeat telemetry blob. */\n make?: string | null;\n /** Device model, after identity-fusion correction. Like `make`, it is a twin-only field and is absent whenever `measurementMetadata.source` is `pg_fallback`. */\n model?: string | null;\n /** Mute state. Absent on the primary `redis_twin` path — the device twin has no such field. On the agents that do report it, `false` is also the fallback used when the power state could not be read at all, so it does not prove a successful read. */\n muted?: boolean | null;\n /** RSSI in dBm, bounded -120..0. Doubly absent: no shipped agent produces it in the first place, and absent on the primary `redis_twin` path — the device twin has no such field. */\n networkStrengthDbm?: number | null;\n /** Declared but NEVER POPULATED on either source path: nothing writes an `onlineStatus` into the last-heartbeat telemetry blob and the device twin has no such field. The equivalent state lives on the screen row (`earner_screens.online_status`), which this endpoint does not read — use `stalenessSeconds` to judge liveness instead. */\n onlineStatus?: \"online\" | \"offline\" | \"standby\" | \"unknown\" | null;\n /** Operating-system family after correction — the Android agents report the full `\"Android <release>\"` string. Twin-only, so absent on the `pg_fallback` path. */\n os?: string | null;\n /** OS version string after correction; the heartbeat collapses the `osv` and `osVersion` request spellings into this one value. Twin-only, so absent on the `pg_fallback` path. */\n osv?: string | null;\n /** Last reported display power (`on`/`standby`/`off`/`unknown`). Absent on the primary `redis_twin` path — the device twin has no such field, so it appears only when `measurementMetadata.source` is `pg_fallback`, which reads the persisted last-heartbeat telemetry blob. */\n powerState?: string | null;\n /** Degrees Celsius from the Android BATTERY thermal sensor (bounded -50..150 by the read schema). Absent on the primary `redis_twin` path — the device twin has no such field, and battery-less CTV hardware never reports it at all, so absence carries no thermal information. */\n temperatureC?: number | null;\n /** User agent, resolved with a three-tier fallback — the corrected device UA, then the stored device UA, then the `User-Agent` header of the heartbeat request that built the twin — so it can reflect the HTTP client rather than the player. Twin-only. */\n ua?: string | null;\n /** Seconds since the DEVICE booted, not since the agent started — it survives an agent restart and counts through deep sleep. Absent on the primary `redis_twin` path — the device twin has no such field, so it surfaces only on the `pg_fallback` path. */\n uptimeSeconds?: number | null;\n /** The browser `document.visibilityState` of the player page (`visible`/`hidden`), sourced from the heartbeat's `content.visibility_state`. One of only two telemetry-derived fields that survive onto the Redis device twin, so it is the one health signal available on BOTH source paths. */\n visibilityState?: string | null;\n /** Speaker volume on the platform's own scale, not a normalised percentage. Absent on the primary `redis_twin` path — the device twin has no such field; only the Tizen and webOS agents ever supply it. */\n volume?: number | null;\n [key: string]: unknown;\n};\n\nexport type PartnerSelfPromoAd = {\n /** The 24-hex advertisement id, minted server-side with `newObjectId()`, and the `ad_id` the schedule and disable endpoints take. Partner self-promo rows carry no `user_mongo_id`, so this id is only resolvable through the partner's own `partner-self-promo` placements — an owner-keyed lookup structurally cannot find it. */\n _id?: string;\n /** Click-through / QR destination; empty string, not null, when it was never set — the PG read coalesces it the same way. */\n campaign_link?: string;\n /** When the advertisement row was written. It is the rotation order for a screen's self-promo pool: the placements read sorts `instant_ad_qr` first, then oldest `created_at` first. */\n createdAt?: string;\n /** Defaults to `name` at create, never null. Note the placements listing trims the embedded advertisement to `_id`, `name`, `video`, `photos`, `status` — this field is absent there. */\n description?: string;\n /** Required at create. It is also copied onto each placement as `advertisement_name`. */\n name?: string;\n /** Image creatives. A JSON create puts `image_url` here as the single element; the multipart route puts the uploaded file here when its MIME type is `image/*`. Empty array for a video-only promo. */\n photos?: Array<string>;\n /** Minted as `approved` — self-promo skips review entirely. The disable endpoint sets it to `deactivated`, and that is the ONLY thing that stops delivery: placements stay `booked` so the disable is idempotent, and every serve-path read has to gate on this field. The listings additionally hide `deleted` and `rejected`. */\n status?: string;\n /** URL of the video creative, or `null` for an image-only promo. This is the field the `trillboards_direct` VAST bridge serves from, which is why the advertisement row is written and awaited BEFORE any placement is created. */\n video?: string;\n /** Measured length of the `video` creative in whole seconds, probed when the ad is created. This is the real media length and is what the served VAST declares as `<Duration>`. `null` means the media could not be measured, in which case the VAST declares the 30 second ad-slot default instead. */\n video_duration_seconds?: number | null;\n};\n\nexport type PartnerSelfPromoCreate = {\n /** Click-through / QR destination. Stored as an empty string, not null, when omitted. */\n campaign_link?: string;\n /** Optional; defaults to `name` rather than staying null. */\n description?: string;\n /** Last day the promo may serve, in each screen's own timezone. Omitting it leaves the placement OPEN-ENDED (`preserveOpenEnd: true`) — it runs until you disable the ad — and leaves `end_time` null rather than 23:59. */\n end_date?: string;\n /** The image creative, stored as a single-element `photos` array. At least one of `image_url` or `video_url` is required (400 `Provide image_url or video_url`); sending both stores both. */\n image_url?: string;\n /** Required — the create is rejected 400 without it. It is also written onto every placement as `advertisement_name`, so it is what appears in delivery bookkeeping. */\n name: string;\n /** Which of YOUR screens the promo is placed on. Accepts a real array, a JSON-encoded array string, or a comma-separated string; the list is intersected with the partner's own non-deactivated screens so a foreign id is dropped silently, but if you send ids and NONE survive the create fails 404. Omitting it entirely creates the advertisement with no placements, so it serves nowhere until you call the schedule endpoint. */\n screen_ids?: Array<string>;\n /** First day the promo may serve, resolved PER SCREEN in that screen's own timezone. A window that is already open lands the placement `active` and fires an immediate `self_promo_active` push to the screen; a future one lands it `scheduled`. Serving times are fixed at 00:00-23:59 local and are not derived from this value. */\n start_date?: string;\n /** The video creative. Its length is PROBED at create time and returned as `video_duration_seconds`, which is what the served VAST declares as `<Duration>`; a spot longer than the 30-second slot also comes back as a non-fatal entry in the response `warnings` array. The probe never blocks the create — on failure the duration stays null and the VAST falls back to a flat 30s. */\n video_url?: string;\n};\n\nexport type PartnerSelfPromoPlacement = {\n /** One entry per `partner-self-promo` placement on that screen, each carrying `allocation_id`, `status`, `start_date`, `end_date` and a TRIMMED `advertisement` (`_id`, `name`, `video`, `photos`, `status` only — no `description`, `campaign_link` or `createdAt`). The underlying read filters out `deactivated`/`deleted`/`rejected` advertisements, so a disabled promo disappears from here even though its placement row still exists. */\n ads?: Array<{\n advertisement?: PartnerSelfPromoAd;\n allocation_id?: string;\n end_date?: string;\n start_date?: string;\n status?: string;\n }>;\n /** Trimmed to `_id` and `name` only. EVERY non-deactivated screen the partner owns appears in this listing, including ones with an empty `ads` array — the response is a full screen roster, not just the placed subset. */\n screen?: {\n _id?: string;\n name?: string;\n };\n};\n\nexport type PartnerStats = {\n /** Recomputed by the daily stats cron as the count of the partner's screens in status `approved`/`active` — an APPROVAL count, not a liveness count. The identically-named field on `GET /v1/partner/analytics` is instead derived live from `online_status`, so the two measure different things. */\n active_devices?: number;\n /** ISO timestamp stamped by the partner impression-record endpoints on each recorded impression. Only those endpoints write it, so it does not move for revenue booked through other rails. */\n last_impression_at?: string;\n /** Integer US cents already reserved by an in-flight payout request. Sourced from the typed `partners.pending_payout_cents` column (the JSONB key was dropped) and subtracted from the available balance so repeat payout requests cannot double-spend. */\n pending_payout_cents?: number;\n /** Read from the `partners.stats` JSONB cache, maintained by signed-delta counters on device register/delete. `GET /v1/partner/analytics` publishes the same field name from a LIVE device count instead, so the two can disagree. */\n total_devices?: number;\n /** Incremented per impression by the partner impression-record path, then OVERWRITTEN by the daily reconcile with `SUM(impressions_count)` over `programmatic_earnings_daily` — two different denominators writing one key, so its meaning depends on when in the cron cycle you read it. */\n total_impressions?: number;\n /** Integer US cents. Recomputed daily as `SUM(earner_revenue) * 100` across ALL of the partner's non-demo `programmatic_earnings_daily` rows, with no payable-source filter and no Net-60 maturity gate — so it can exceed `EarningsResponse.total_lifetime_cents`, which applies the payable filter. */\n total_revenue_cents?: number;\n};\n\n/**\n * One taxi-meter state change reported by the partner SDK's setTripState. (partner, device, trip_id, event_seq) is the event's identity.\n */\nexport type PartnerTripState = {\n /** The host's destination text or zone. */\n destination?: string;\n /** The event's position in the trip. Increases within a trip; a retry re-sends the same value (idempotency key with trip_id, per device). */\n event_seq: number;\n /** Fare so far, in the smallest currency unit. */\n fare_cents?: number;\n /** true while the meter runs (a hired trip). */\n meter_on: boolean;\n /** Riders the host counted. */\n passenger_count?: number;\n /** The host's payment type (stored trimmed and lowercased). */\n payment_type?: string;\n /** When the meter changed state (device clock), within the last 7 days and at most 5 minutes ahead of the server clock. */\n state_at: string;\n /** Tip, in the smallest currency unit. */\n tip_cents?: number;\n /** The host app's trip id. Unique per device, not per partner. */\n trip_id: string;\n};\n\n/**\n * Canonical INT-PK identity for partner variants (e.g. adipolo_lower_floor_tablet). Wave 2 of pristine-state refactor. variant_name TEXT remains as the wire-format alternate-key indefinitely.\n */\nexport type PartnerVariants = {\n archived: boolean;\n created_at: string;\n /** NUMERIC(10,2). */\n daily_budget_cap?: number | null;\n daily_impression_cap?: number | null;\n daily_request_cap?: number | null;\n /** Backfill is 1:N from demand_partner_config.variant_names[]. Rows with NULL demand_partner_id at apply time are silently skipped — deploy-controller previous-tick guard ensures Wave 2 A1 has populat... */\n demand_partner_id: number;\n /** vast_tag_variants JSONB on demand_partner_config still co-exists during transition. Backfill UPDATE pulls display_name from the JSONB if present (no-op today; forward-compatible). */\n display_name?: string | null;\n /** public_alias is the obfuscation alias for partner-API responses (matches partnerAlias.encodeAlias pattern: 'var_' || sha256(variant_name)[0..5]). */\n public_alias: string;\n request_pressure_base_interval_seconds?: number | null;\n /** NUMERIC(12,8). */\n request_pressure_completion_rate_floor?: number | null;\n /** NUMERIC(6,3). */\n request_pressure_confidence_level?: number | null;\n request_pressure_defer_seconds?: number | null;\n /** request_pressure_enabled=false fails open for pressure shaping only. It must not be treated as demand-source enablement. */\n request_pressure_enabled?: boolean | null;\n request_pressure_max_multiplier?: number | null;\n request_pressure_min_pair_requests?: number | null;\n request_pressure_min_source_requests?: number | null;\n request_pressure_probe_interval_seconds?: number | null;\n request_pressure_probe_modulo?: number | null;\n /** NUMERIC(10,4). */\n request_pressure_probe_target_per_minute?: number | null;\n updated_at: string;\n /** feeds_into lists tables that will gain a nullable variant_id INT FK in Wave 2 Stream B. Each is a separate PR — this PR mints the dimension only. */\n variant_id?: string | null;\n /** variant_name TEXT is the wire-format alternate-key (kept forever) — internal logs and partner integrations rely on it. Never propose dropping variant_name. */\n variant_name: string;\n};\n\n/**\n * Per-zone per-day CPM rates from partner APIs. Used for revenue estimation and settled partner-truth allocation when partner_reconciliation_reports does not provide a newer manual/API row. PG only.\n */\nexport type PartnerZoneCpmDaily = {\n created_at: string;\n /** Wave 2 B added demand_partner_id INT + variant_id INT FKs. Legacy partner_key TEXT kept as wire-format alternate-key. Backfill via follow-up Wave 2 B-backfill PR. */\n demand_partner_id?: number | null;\n /** NUMERIC(10,4). */\n ecpm: number;\n fetched_at: string;\n /** NUMERIC(6,4). */\n fill_rate?: number | null;\n /** NUMERIC(14,6). */\n gross_revenue?: number | null;\n id?: string | null;\n impressions?: number | null;\n partner_key: string;\n period_date: string;\n requests?: number | null;\n /** Daily earnings aggregation may use these rows to settle gross revenue, but completed_impressions remains the event-count source for programmatic_earnings_daily.impressions_count. */\n source: string;\n updated_at: string;\n variant_id?: number | null;\n zone_id: string;\n zone_label?: string | null;\n};\n\nexport type PayoutResponse = {\n /** Integer US cents actually reserved: `min(requested, available)`, where available is CONFIRMED earnings minus anything already pending. It must clear the partner's `payout_threshold_cents` (default 2500, i.e. $25.00) or the request is rejected `400`. */\n amount_cents?: number;\n /** Today plus 5 CALENDAR days, computed in the handler with no reference to banking days, the Stripe payout schedule, or whether any transfer exists. It is a display placeholder. */\n estimated_arrival?: string;\n /** Generated in the handler as `po_<epoch_ms>_<random>` and **not persisted anywhere** — no row, no Stripe object. It cannot be used to look the payout up afterwards. */\n payout_id?: string;\n /** Always the literal `processing` on a successful request — the other enum values are never returned by this endpoint. The only side effect is a bump to the partner's `pending_payout_cents` counter; no Stripe transfer is created here. */\n status?: \"pending\" | \"processing\" | \"completed\" | \"failed\";\n /** **Always `null`.** The handler returns a hardcoded null because it creates no transfer; a real transfer id appears only later on the corresponding `payout` row from `GET /earnings/transactions`. */\n stripe_transfer_id?: string | null;\n};\n\nexport type PlaygroundResult = {\n /** Whether the operation is safe for autonomous agents. */\n agent_safe: boolean;\n /** Billing tier: free, metered, or paid. */\n cost_tier: string;\n /** Whether the operation is idempotent. */\n idempotent: boolean;\n /** Object type identifier. */\n object: \"playground_result\";\n operation_id: string;\n /** Declared side effects of the operation. */\n side_effects: Array<string>;\n /** Whether the request body passed validation. */\n valid: boolean;\n /** The parsed/coerced body on success, null on failure. */\n validated_body?: unknown;\n /** Array of validation issues on failure, null on success. */\n validation_errors: Array<PlaygroundValidationError> | null;\n /** The HTTP method and path this operation maps to. */\n would_call: {\n method: string;\n path: string;\n };\n};\n\nexport type PlaygroundValidationError = {\n /** Zod issue code. */\n code: string;\n /** Human-readable validation message. */\n message: string;\n /** Dot-delimited path to the invalid field. */\n path: string;\n};\n\nexport type ProgrammaticSettingsInput = {\n /** Enable programmatic ads */\n enabled?: boolean;\n /** Minimum CPM in dollars */\n floor_price_cpm?: number;\n /** Accepted by this schema but silently discarded. The write path keeps only an explicit whitelist — `enabled`, `provider`, `vast_tag_url`, `timeout_ms`, `programmatic_allocation_percent`, `floor_price_cpm`, `currency`, `dynamic_floor_pricing`, `blocked_advertisers`, `blocked_iab_categories`, `preferred_deal_ids` — and `google_ima` is not in it. A body containing only this key persists nothing and still returns 200. */\n google_ima?: {\n ad_tag_url?: string;\n enabled?: boolean;\n max_duration?: number;\n };\n /** Accepted by this schema but silently discarded — not in the write whitelist, never persisted, and never read back (`header_bidding_settings.prebid` is JSON `null` on every row). A body containing only this key persists nothing and still returns 200. */\n prebid?: {\n bidders?: Array<{\n name?: string;\n params?: Record<string, unknown>;\n }>;\n enabled?: boolean;\n };\n /** Ad source priority */\n priority?: \"direct_first\" | \"programmatic_first\" | \"highest_bid\";\n};\n\nexport type ProgrammaticSettingsResponse = {\n /** The master serving gate `earner_screens.programmatic_enabled`, which is `NOT NULL DEFAULT true` — so it reads `true` for a screen nobody has ever configured — and NOT the legacy `header_bidding_settings.enabled` shadow. Setting it false stops programmatic serving for the screen; the write invalidates the serving caches, and a missed invalidation still drains within the 120s hot-cache TTL. */\n enabled?: boolean;\n /** Minimum clearing price in DOLLARS per thousand impressions (not cents), default `0.50`, accepted range 0.01-100, denominated in the screen's `currency`. It is a floor only: the auction clears at the `max()` of this, any floor rule, the dynamic floor and any matched deal floor, so a low value here does not guarantee cheap fill and can never lower a rule-derived floor. */\n floor_price_cpm?: number;\n /** Never emitted. The response formatter builds the entire body and has no `google_ima` key, and the string appears nowhere on this API's request or response surface — there is no producer. Configure the IMA tag through the screen's `vast_tag_url` / VAST waterfall instead. */\n google_ima?: {\n ad_tag_url?: string;\n enabled?: boolean;\n max_duration?: number;\n };\n /** Constant discriminator `programmatic_settings` (Stripe-style envelope). It is present on the GET, the PUT and the PATCH alike, so it identifies the resource type and tells you nothing about which verb produced the response. */\n object?: string;\n /** Never emitted. The response formatter has no `prebid` key, and the underlying `header_bidding_settings.prebid` is JSON `null` on every stored row with no typed home — nothing populates it on either side. */\n prebid?: {\n bidders?: Array<Record<string, unknown>>;\n enabled?: boolean;\n };\n /** Never emitted, and not settable. The response formatter has no `priority` key and the field is absent from the write whitelist, so `direct_first` / `programmatic_first` / `highest_bid` can neither be stored through this endpoint nor read back from it. */\n priority?: string;\n /** Server-minted per HTTP request in the form `req_<32 hex>`, and also returned in the `X-Request-Id` response header. A client-supplied `X-Request-Id` is echoed back separately as `X-Client-Request-Id` and never becomes this value. Unrelated to `HeaderBiddingSettings.request_id`, which identifies a VAST waterfall attempt. */\n request_id?: string;\n /** Echoed straight back from the path parameter — it is not re-read from the stored row. Must be a 24-character hex Mongo ObjectId; anything else is rejected before any lookup happens. */\n screen_id?: string;\n /** Never emitted — the response formatter has no `stats` key, so `impressions_today`, `fill_rate_percent` and `avg_cpm` have no producer here; use the partner analytics endpoints for delivery numbers. When you do, note that partner-rail impression counts are delivery accounting, not billing: only `completed_impressions` settles revenue. */\n stats?: {\n avg_cpm?: number;\n fill_rate_percent?: number;\n impressions_today?: number;\n };\n /** The SCREEN row's `updated_at`, so any change to the screen moves it — not just a programmatic-settings change. When the row carries no timestamp the server substitutes the current time, so this can never be relied on as 'when these settings last changed' or used as a change-detection cursor. */\n updated_at?: string;\n};\n\nexport type RequestMetadataResponse = {\n duration_ms: number;\n /** Present only when the original request resulted in an error. */\n error?: {\n code: string;\n type: string;\n };\n method: string;\n /** Object type identifier. */\n object: \"request\";\n path: string;\n request_id: string;\n status_code: number;\n timestamp: string;\n};\n\n/**\n * The EFFECTIVE content policy for a screen + its provenance. Whole-layer\n * coalescing: the effective policy comes from exactly ONE layer.\n *\n */\nexport type ResolvedContentPolicy = {\n /** All content_preferences keys + blocked_iab_categories. */\n effective?: Record<string, unknown>;\n /** Always `resolved_content_policy`. This resource is read-only introspection — a \"why is this screen serving what it serves\" preview — and unlike the content-preferences response it IS wrapped in `{ success, data }`. */\n object?: string;\n /** Which single layer supplied the whole `effective` object. `source` is `screen` when the screen's OWN policy is explicit — specifically `content_filtering_enabled === true`, or any of the six content lists non-empty, or a non-empty `programmatic_settings.blocked_iab_categories`; the `allow_*` toggles and the two scalars NEVER make it explicit because they always carry a default. Otherwise it is `group` (lowest `group_id` wins, and `group_id` is present only then), then `network` (the partner's `network_config.default_content_preferences`, used only when it has at least one populated key and merged onto the system baseline), then `default`. */\n provenance?: {\n /** Present only when source=group. */\n group_id?: string;\n source?: \"screen\" | \"group\" | \"network\" | \"default\";\n };\n /** The screen whose effective policy this is, echoed from the path parameter as a string. Ownership is checked first, so a screen you do not own returns 404 rather than an empty policy. */\n screen_id?: string;\n};\n\n/**\n * The EFFECTIVE sensing view for a screen + its provenance (screen\n * deployment ?? group sensing config ?? default).\n *\n */\nexport type ResolvedSensingConfig = {\n /** The profile scalars actually in force after resolution. When the winning layer is a group, the base profile is hydrated first and only the group's NON-null overrides are laid over it, so this is always a complete view rather than a sparse patch. */\n effective?: {\n capture_interval_ms?: number | null;\n estimated_fps_impact?: number | null;\n min_confidence?: number | null;\n profile_name?: string | null;\n report_interval_ms?: number | null;\n };\n /** Stripe-style type discriminator; always the literal `resolved_sensing_config`, so it is safe to switch on. */\n object?: string;\n /** Which layer won: `screen` (the screen's own active deployment), `group_default` (a group sensing config, with `group_id` naming it), or `default` (nothing bound). Resolution is whole-layer — `effective` never mixes values from two sources. */\n provenance?: {\n /** Present only when source=group_default. */\n group_id?: string;\n source?: \"screen\" | \"group_default\" | \"default\";\n };\n /** The screen's Mongo id — the same identifier the route surfaces call `screenMongoId`. Echoes the path parameter. */\n screen_id?: string;\n};\n\n/**\n * Permission flags for each role. Owners have all permissions,\n * admins have operational permissions, viewers have read-only access.\n *\n */\nexport type RolePermissions = {\n /** Can configure webhooks */\n configure_webhooks?: boolean;\n /** Can edit screen settings */\n edit_screens?: boolean;\n /** Can invite/remove team members */\n manage_team?: boolean;\n /** Can request payouts */\n request_payouts?: boolean;\n /** Can rotate API keys */\n rotate_api_keys?: boolean;\n /** Can view impression analytics */\n view_analytics?: boolean;\n /** Can view earnings/revenue */\n view_earnings?: boolean;\n /** Can view impression data */\n view_impressions?: boolean;\n /** Can view payout history */\n view_payouts?: boolean;\n /** Can view online/offline status */\n view_screen_status?: boolean;\n /** Can view screen list */\n view_screens?: boolean;\n};\n\nexport type SDKConfig = {\n /** Seconds between ads */\n ad_interval?: number;\n /** The only `sdk_config` key that changes what is SERVED: if it contains `image`, the server stops substituting a transcoded MP4 for an image creative on `lite_sdk`/`full_sdk` tiers, because you are declaring the client can render images itself. Frozen at the quick-start default `[\"video\", \"image\"]` — there is no partner-facing endpoint that writes `sdk_config`. */\n allowed_ad_types?: Array<string>;\n /** Maximum number of ads the `trillboards-connect` client retains for offline playback (`cacheAdsOffline`). Client-side hint only — the server never reads it — and it is frozen at the quick-start default of 10 because no partner-facing endpoint writes `sdk_config`. */\n cache_size?: number;\n /** Seconds to display image ads */\n image_duration?: number;\n /** Fleet-wide hourly ad cap echoed as `settings.max_ads_per_hour` in the `/ads` response, but only as the FALLBACK behind `network_config.ad_delivery.max_ads_per_hour` — that is the writable control, and this one is frozen at the quick-start default of 20 because no partner-facing endpoint writes `sdk_config`. */\n max_ads_per_hour?: number;\n /** Label the lite SDK paints on the tap-to-continue overlay; when absent the SDK falls back to the literal `TAP TO CONTINUE`, which is also the quick-start default stored for every partner. Frozen — there is no partner-facing endpoint that writes `sdk_config`. */\n overlay_button_text?: string;\n /** Has no reader anywhere in the server or the shipped SDKs — the `settings.sound_enabled` a player actually obeys is resolved per screen from `earner_screens.sound_enabled` / display preferences, not from this partner-level value. Frozen at the quick-start default `false`. */\n sound_enabled?: boolean;\n};\n\n/**\n * A partner screen — the client-facing projection of a registered\n * device+screen pair (`@trillboards/api-client` `Screen`). The screens\n * resource reads the partner device endpoints.\n *\n */\nexport type Screen = {\n /** City resolved at registration by reverse/forward geocoding or taken from your own `location.city`, with placeholder strings (\"City\", \"Vending Machine Location\") coalesced to null rather than stored. The screens resource reads the partner device endpoints, whose payload carries this as `location.city`. */\n city?: string;\n /** Country of the screen, taken from the enriched screen row with a fallback to the device row. The device row DEFAULTS this to `\"US\"` when registration could not resolve a country, so it is effectively never null and a `US` value can mean \"unresolved\". The screens resource reads the partner device endpoints, whose payload carries this as `location.country`. */\n country?: string;\n /** Creation time of the DEVICE row backing the screen, not of the screen record itself — the screens resource is a projection of the partner device endpoints, and the screen can be created later than its device. */\n created_at: string;\n /** The paired device identifier. */\n device_id?: string;\n /** Player embed URL for the screen. */\n embed_url?: string;\n /** Friendly screen/venue name. */\n name: string;\n /** Display resolution label (e.g. \"1920x1080\") when known. */\n resolution?: string;\n /** Stable screen identifier. */\n screen_id: string;\n /** Screen lifecycle status (e.g. pending, active, offline, suspended). */\n status: string;\n /** IANA zone, and it is ONLY ever what you supplied as `location.timezone` at registration — nothing derives it from the resolved coordinates, so a large share of screens carry null. The screens resource reads the partner device endpoints, whose payload carries this as `location.timezone`, and it is the one geo field read device-first rather than screen-first. */\n timezone?: string;\n /** `earner_screen_devices.updated_at` of the backing device, which the device-mirror write buffer stamps `NOW()` on every flush including heartbeats. It moves continuously on a live screen, so it cannot be used to detect a configuration change. */\n updated_at: string;\n /** Granular OpenOOH venue type of the screen's location. */\n venue_type?: string;\n};\n\nexport type ScreenAnalyticsResponse = {\n /** `total` is deduped, GIVT-passed `completed_impressions` over the period. `daily_average` divides by the number of days that RETURNED A ROW, not by the period length, so zero-impression days do not dilute it. `trend_percent` compares the second half of the returned rows against the first half and is `0` whenever the earlier half is zero. */\n impressions?: {\n daily_average?: number;\n total?: number;\n /** Percentage change compared to previous period */\n trend_percent?: number;\n };\n /** `days` is 7, 30 or 90; any other `?period=` value silently becomes 7. `start` is midnight (API-server local time) that many days back and `end` is the moment the request was served, so the window is not a whole number of days. */\n period?: {\n days?: number;\n end?: string;\n start?: string;\n };\n /** `location` is a `City, State` string or `null` when either part is missing. `online_status` comes from the live heartbeat mirror and is `online`/`offline`/`unknown`, where `unknown` means the screen has never heartbeated — it is not a synonym for offline. `status` is the separate approval state. */\n screen?: {\n id?: string;\n location?: string;\n name?: string;\n online_status?: string;\n status?: string;\n };\n /** One entry per day that had impressions — days with none are absent, not zero-filled, which is why `daily_average` and this array can disagree with the period length. **`avg_duration_ms` is always `0`**: it is a hardcoded literal in both the ClickHouse query and the Postgres fallback. */\n timeline?: Array<{\n avg_duration_ms?: number;\n date?: string;\n impressions?: number;\n }>;\n};\n\n/**\n * A reusable, named, partner-scoped set of screens that analytics,\n * moderation policy, sensing/model deployment, fleet commands, and\n * sensing routes can target. Members are always a subset of the\n * partner's own screens.\n *\n */\nexport type ScreenGroup = {\n created_at?: string;\n /** Free-text note. Returned as an explicit `null` rather than omitted when unset, and an empty string supplied at create is stored as `null`. A PATCH writes only the keys you actually send, so omitting it preserves the current value. */\n description?: string | null;\n /** Screen group id: the literal prefix `sg_` followed by a v4 UUID (`pgRepo/screenGroups.js` mints `sg_${crypto.randomUUID()}`). Treat it as an opaque string; do not parse the UUID half. */\n id?: string;\n /** Required, non-empty label. It is NOT unique and has no length constraint in the database, so two of your groups may share a name; `id` (`sg_<uuid>`) is the only stable handle. */\n name?: string;\n /** Constant string `screen_group` — the Stripe-style type discriminator. It is present on every group payload, including inside a webhook's `data`, so a single handler can switch on it. */\n object?: string;\n /** Distinct member screens (COUNT and member list share one junction — they cannot diverge). */\n screen_count?: number;\n /** Bumped by membership changes as well as metadata edits — `addMembers`, `removeMembers` and the soft delete all set `updated_at = NOW()` on the group row — so it is a change marker for the group INCLUDING its member set, not just its name and description. */\n updated_at?: string;\n};\n\n/**\n * The typed content/moderation policy a screen group carries (Phase 4 live\n * policy). `null` when the group has no policy of its own. Member screens\n * inherit it at read/serve time when they have no explicit own policy\n * (screen ?? group ?? partner network default ?? system default). Mirrors\n * the per-screen content_preferences keys 1:1; blocked_iab_categories is\n * first-class here (the auction bcat).\n *\n */\nexport type ScreenGroupContentPolicy = {\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_adult_content`. A `false` also adds `IAB25` plus `IAB25-2`..`IAB25-5` to the `bcat` and `sexually_suggestive`/`sexual_health`/`sensationalism` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_adult_content?: boolean;\n /** Rejects a direct ad only when set to `false` AND the ad's classification carries `contains_alcohol`. A `false` also adds `IAB8-5`/`IAB8-18` to the outgoing OpenRTB `bcat` and `alcohol` to the GAM `excl_cat`; when the key is unset that list-building step uses the platform default, which for alcohol is `true` (not blocked). */\n allow_alcohol?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_gambling`. A `false` also adds `IAB9-7` to the `bcat` and `gambling`/`online_gambling` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_gambling?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_political`. A `false` also adds `IAB11-4` to the `bcat` and `politics` to the GAM `excl_cat`; unset falls back to the platform default of `true` (allowed). */\n allow_political?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_profanity`. A `false` also adds `IAB25-2` to the `bcat` and `sensationalism` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_profanity?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_religious`. A `false` also adds `IAB23` to the `bcat` and `religion` to the GAM `excl_cat`; unset falls back to the platform default of `true` (allowed). */\n allow_religious?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_tobacco`. A `false` also adds `IAB25-6` to the `bcat` and `drugs_tobacco` to the GAM `excl_cat`; unset falls back to the platform default of `false`, so tobacco is blocked on the programmatic side even when you never configure it. */\n allow_tobacco?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_violence`. A `false` also adds `IAB25-3`/`IAB25-4` to the `bcat` and `violence`/`military_conflict` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_violence?: boolean;\n /** Consulted only when non-empty, and matched against the ad's typed `iab_categories` with `categoriesMatch`, so IAB codes and human-readable names both work (categories are inferred from subjects/keywords when the ad carries none). Under `lenient` and `permissive` a non-match is allowed through anyway, which makes the list inert at those levels; it also adds +10 per match to the content match score. */\n allowed_categories?: Array<string>;\n /** A SOFT preference, not a filter: it never rejects anything. Matching keywords add +3 each to the content match score used for prioritisation, and the approval path explicitly skips this list. */\n allowed_keywords?: Array<string>;\n /** Matched by case-insensitive SUBSTRING containment against the ad's `moderation.analysis.subjects`, not equality. Consulted only when non-empty and inert under `lenient`/`permissive`, like `allowed_categories`; it also adds +5 per match to the content match score. */\n allowed_subjects?: Array<string>;\n /** When `true` and the ad's classification says `is_known_brand`, approval returns IMMEDIATELY — the `blocked_categories`, `blocked_subjects`, `blocked_keywords` and every `allowed_*` check below it never run. The `allow_*` toggles and the age-rating check sit above it and still apply. */\n auto_approve_known_brands?: boolean;\n /** Same matching as `allowed_categories` (IAB code or human-readable name, via `categoriesMatch`), but a single hit rejects the ad at every `preference_level`. The rejection reason reports the human-readable name rather than the code you stored. */\n blocked_categories?: Array<string>;\n /** The auction `bcat` sent on OpenRTB bid requests for member screens. It is NOT part of `content_preferences`: on an individual screen the same list lives on `programmatic_settings.blocked_iab_categories`, and a non-empty one there is one of the three conditions that makes the screen layer explicit and bypasses this group policy entirely. */\n blocked_iab_categories?: Array<string>;\n /** The keyword list that DOES block, unlike `allowed_keywords`. Case-insensitive substring containment against the ad's `moderation.analysis.keywords`, so a short entry matches inside longer words. */\n blocked_keywords?: Array<string>;\n /** Case-insensitive substring containment against the ad's `moderation.analysis.subjects` — `bar` therefore also blocks `barbecue`, so use whole distinctive words. A hit is a hard reject. */\n blocked_subjects?: Array<string>;\n /** When `false`, direct-ad moderation short-circuits and every ad is auto-approved for member screens. It does NOT disable brand safety on the programmatic side — the `allow_*` toggles are still translated into the OpenRTB `bcat` and GAM `excl_cat` regardless of this flag. */\n content_filtering_enabled?: boolean;\n /** The group this row belongs to. It is also the tiebreak: a screen that is a member of more than one policy-bearing group inherits from the LOWEST `group_id`, so a screen should be in at most one. */\n group_id?: string;\n /** Highest ad classification a member screen accepts. `G` is deliberately NOT the strictest setting — the matcher silently rewrites it to `PG-13` for backwards compatibility — and `preference_level` then adds its buffer on top, so `lenient` with `PG-13` actually admits `R`. */\n max_age_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\" | \"NC-17\";\n /** Always the literal `screen_group_content_policy`. The policy is returned as `data.content_policy`, and a group carrying no policy of its own returns a bare `null` there — so on that path there is no `object` to branch on at all. */\n object?: string;\n /** Selects a strictness profile, not a label. It sets the age-rating buffer (`strict`/`moderate` 0, `lenient` +1, `permissive` +2 notches above `max_age_rating`), whether an ad with no AI classification is auto-approved (`lenient`/`permissive` yes; `strict`/`moderate` reject and queue re-moderation), and how the `allowed_*` lists behave on a non-match — `strict` rejects, `moderate` lets common business categories through, `lenient`/`permissive` make them inert. */\n preference_level?: \"strict\" | \"moderate\" | \"lenient\" | \"permissive\";\n /** ISO-8601 timestamp of the last write to this policy row, or `null` when the row has none. Member screens read the resolved policy through a screen-keyed Redis cache that a policy, membership or group-delete write busts, so an edit here reaches serving immediately rather than after the 60-second TTL. */\n updated_at?: string;\n} | null;\n\n/**\n * Partial, non-clobbering — only the fields present are written. Same keys\n * the per-screen content-preferences PUT accepts, plus blocked_iab_categories.\n *\n */\nexport type ScreenGroupContentPolicyInput = {\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25` and `IAB25-2`..`IAB25-5` to the member screens' `bcat`; unset already blocks it via the platform default. */\n allow_adult_content?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` both rejects classified alcohol creatives on member screens and adds `IAB8-5`/`IAB8-18` to their outgoing `bcat`. */\n allow_alcohol?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB9-7` to the member screens' `bcat`; unset already blocks gambling programmatically via the platform default. */\n allow_gambling?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB11-4` to the member screens' `bcat`; the platform default here is `true`, so political ads run unless you set this. */\n allow_political?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25-2` to the member screens' `bcat`; unset already blocks it via the platform default. */\n allow_profanity?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB23` to the member screens' `bcat`; the platform default here is `true`, so religious ads run unless you set this. */\n allow_religious?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25-6` to the member screens' `bcat`; leaving it unset already blocks tobacco programmatically via the platform brand-safety default. */\n allow_tobacco?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25-3`/`IAB25-4` to the member screens' `bcat`; unset already blocks it via the platform default. */\n allow_violence?: boolean;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and the allow/block pair is conflict-checked case-insensitively against this patch MERGED onto the stored row, so it can 400 with `conflicting_lists` on a term you set in an earlier request. */\n allowed_categories?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and it is conflict-checked against `blocked_keywords`, even though at serve time this list never rejects anything — it only contributes to the content match score. */\n allowed_keywords?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and the Subjects allow/block pair is conflict-checked against the stored row merged with this patch. Note these are matched by substring at serve time, not equality. */\n allowed_subjects?: Array<string>;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Setting it `true` makes a known-brand ad bypass every category, subject and keyword check on member screens, so treat it as a widening, not a convenience. */\n auto_approve_known_brands?: boolean;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and blocking a category an earlier PUT allowed fails with `conflicting_lists` even though this request names only one side of the pair. */\n blocked_categories?: Array<string>;\n /** Array of strings capped at 100 by a DIFFERENT constant from the other lists (`PROGRAMMATIC_SETTINGS_LIMITS.max_blocked_iab_categories`), reported as `blocked_iab_categories_too_large`. It is not conflict-checked, because there is no `allowed_iab_categories` counterpart. */\n blocked_iab_categories?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and unlike `allowed_keywords` this one really does reject, by case-insensitive substring match against the ad's analysed keywords. */\n blocked_keywords?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and it is a hard reject at serve time, matched by case-insensitive substring — so a short entry blocks more than you intend. */\n blocked_subjects?: Array<string>;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Omitting the key leaves the stored value untouched; there is no way to reset a key back to \"inherit\". */\n content_filtering_enabled?: boolean;\n /** One of `G`, `PG`, `PG-13`, `R`, `NC-17`; anything else is `invalid_age_rating`. Writing `G` does not give you the strictest policy — the matcher later treats `G` as `PG-13`. */\n max_age_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\" | \"NC-17\";\n /** One of `strict`, `moderate`, `lenient`, `permissive`; anything else is rejected with `invalid_preference_level`. Validated against the same constant the per-screen content-preferences PUT uses, so the two surfaces cannot drift. */\n preference_level?: \"strict\" | \"moderate\" | \"lenient\" | \"permissive\";\n};\n\n/**\n * Webhook body for a Screen Group lifecycle event (`screen_group.created` | `updated` |\n * `deleted` | `member.added` | `member.removed` | `content_policy.updated` |\n * `sensing_config.updated`). Standard `{ id, event, timestamp, data }` envelope: `id` (`evt_…`)\n * is the idempotency key, and `data` is the Stripe-style `screen_group` /\n * `screen_group_content_policy` / `screen_group_sensing_config` object the REST API returns.\n * The event type is also in the `X-Trillboards-Event` header — verify the compound\n * `X-Trillboards-Signature` over the raw body first.\n *\n */\nexport type ScreenGroupEvent = {\n /** The screen_group / content-policy / sensing-config object. */\n data?: Record<string, unknown>;\n /** The event type, also sent in the `X-Trillboards-Event` header and mirrored to the SSE stream at `GET /v1/partner/events/stream`. This whole event family is gated by the `SCREEN_GROUP_EVENTS_ENABLED` runtime flag, which is OFF by default — when off, nothing is enqueued at all. */\n event?: \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\";\n /** `evt_<base36 epoch ms>_<12 hex>`, minted once per occurrence. Use it as the idempotency key: a retried delivery of the same occurrence reuses it, but the same id is also sent to EVERY endpoint you have subscribed to that event, so dedupe per (endpoint, id). It is not the server-side delivery audit id and cannot be looked up. */\n id?: string;\n /** Stamped when the server ENQUEUED the delivery, not when it was sent, so a retried delivery still carries the original value and can trail wall-clock by the retry backoff. It is not the resource's own `updated_at`. */\n timestamp?: string;\n};\n\n/**\n * A screen group's sensing profile binding (profile_name) + typed\n * performance overrides. `null` when the group has none. Member screens\n * inherit via the sensing resolver's group step when they have no\n * screen-specific deployment.\n *\n */\nexport type ScreenGroupSensingConfig = {\n /** Edge frame-capture cadence overrides pushed to member screens (SensingConfig.capture keys, milliseconds). Group wins over the profile default per-key when set. */\n capture?: {\n faceTriggeredIntervalMs?: number | null;\n minCaptureIntervalMs?: number | null;\n periodicIntervalMs?: number | null;\n vehicleTriggeredIntervalMs?: number | null;\n } | null;\n /** Group override of the profile's declared frame-capture cadence in milliseconds; `null` inherits the base profile's value. Treat it as advisory - this legacy scalar does not reach the device capture loop (the edge `FrameCaptureManager` reads the nested `capture` block), and observed cadence was measured at ~12x the declared value against a fleet floor of one analysis per 30 s. */\n capture_interval_ms?: number | null;\n /** When `false` the whole group step is a no-op and member screens fall straight through to the next layer of the resolver — the row is retained but contributes nothing, which is how you disable group sensing without losing the overrides. */\n enabled?: boolean;\n /** Advisory workload cost of the profile, normally derived server-side as the sum of the selected models' registry `fps_cost` (built-ins run 5.5-12.0). It is display metadata only — no device or pipeline code reads it, so overriding it throttles nothing. */\n estimated_fps_impact?: number | null;\n /** The `sg_`-prefixed Screen Group this config belongs to; echoes the `groupId` path parameter. */\n group_id?: string;\n /** Detection-confidence floor in 0..1, overlaid onto the resolved profile's `thresholds.min_confidence`; built-in profiles ship 0.35-0.45. `null` inherits the base profile's value. */\n min_confidence?: number | null;\n /** Stripe-style type discriminator; always the literal `screen_group_sensing_config`, so it is safe to switch on. */\n object?: string;\n /** The sensing profile members inherit, bound by NAME (a builtin or an existing custom profile) rather than by `profile_id`, because `setDeployment` clones a fresh `profile_id` per screen on every redeploy. `null` means the group binds no profile. */\n profile_name?: string | null;\n /** Group override of how often the device batches observations back to the server, in milliseconds; `null` inherits the base profile's value. Built-in profiles ship 15000-30000. */\n report_interval_ms?: number | null;\n /** When this group's sensing config row was last written. The write also busts the resolver caches for the members as they stood at that instant and emits a `screen_group.sensing_config.updated` webhook, so a screen added to the group afterwards picks the config up on its own next cache miss instead. */\n updated_at?: string;\n /** Per-screen cloud-vision budget for member screens. screen_hourly_pace wins when both are set; otherwise derived from screen_daily_calls. null = no group budget (fleet keeps platform-default caps). */\n vision_budget?: {\n screen_daily_calls?: number | null;\n screen_hourly_pace?: number | null;\n } | null;\n} | null;\n\n/**\n * Partial, non-clobbering. A null override means \"inherit that field from\n * the base profile\". profile_name must resolve to a builtin or an existing\n * custom profile (else 400).\n *\n */\nexport type ScreenGroupSensingConfigInput = {\n /** Edge frame-capture cadence block (milliseconds); null clears it. Unknown keys are rejected (400). */\n capture?: {\n faceTriggeredIntervalMs?: number | null;\n minCaptureIntervalMs?: number | null;\n periodicIntervalMs?: number | null;\n vehicleTriggeredIntervalMs?: number | null;\n } | null;\n /** Frame-capture cadence override in milliseconds (100..3600000); `null` means inherit from the base profile. Advisory in practice: this legacy scalar does not reach the device capture loop (the edge reads the nested `capture` block), the fleet floors at one analysis per 30 s, and observed cadence was measured at ~12x the declared value. */\n capture_interval_ms?: number | null;\n /** Set `false` to make the group step a no-op — members fall through to the next resolver layer while the overrides stay stored, so this is the reversible way to switch group sensing off. */\n enabled?: boolean;\n /** Advisory workload-cost number (must be >= 0); `null` inherits the profile's own value, which the server derives from the selected models' registry `fps_cost`. Purely descriptive — setting it changes what readback and operator surfaces display and throttles nothing. */\n estimated_fps_impact?: number | null;\n /** Detection-confidence floor in 0..1 written into the resolved profile's `thresholds.min_confidence`; `null` inherits the base profile's value (built-ins are 0.35-0.45). */\n min_confidence?: number | null;\n /** Bind the group to a builtin or existing custom profile BY NAME; a name that resolves to neither is a 400. `null` clears the binding. Never a `profile_id` — that is re-minted per screen on each redeploy. */\n profile_name?: string | null;\n /** Observation-reporting cadence override in milliseconds (100..3600000); `null` means inherit from the base profile. */\n report_interval_ms?: number | null;\n /** Per-screen cloud-vision budget block; null clears it. Unknown keys are rejected (400). */\n vision_budget?: {\n screen_daily_calls?: number | null;\n screen_hourly_pace?: number | null;\n } | null;\n};\n\n/**\n * High-level sensing workload intent. Hardware tier and device telemetry are read-only server facts.\n */\nexport type SensingPerformanceMode = \"auto\" | \"presence_only\" | \"demographics\" | \"advanced\";\n\n/**\n * A Sense Anything Route — a (condition → channel actions) alert/automation rule.\n */\nexport type SensingRoute = {\n /** Every channel action fired when the route matches; 1 to 10 per route, each with its own `enabled` flag so one can be muted without deleting the route. `webhook` is the only channel with no external side effect — `whatsapp`, `sms`, `email` and `slack` deliver a real message to a real person, so point a test route at `webhook`. */\n actions?: Array<SensingRouteAction>;\n /** One bit per weekday (127 = always). */\n activeDaysMask?: number;\n /** Inclusive end of the daily active window, in minutes past local midnight in `activeTz` (0..1439). When it is LESS than `activeStartMinute` the window is read as overnight — 1200 to 360 means 20:00 through 06:00 — rather than as an empty range. */\n activeEndMinute?: number | null;\n /** Inclusive start of the daily active window, in minutes past local midnight in `activeTz` (0..1439; 1200 = 20:00). Ignored unless `activeTz` is set, and a `null` on either end makes the window whole-day. */\n activeStartMinute?: number | null;\n /** IANA zone name (e.g. `America/New_York`) the active window is evaluated in, trimmed to 64 characters. `null` disables the ENTIRE active-window check — `activeStartMinute`, `activeEndMinute` and `activeDaysMask` do nothing without it — and a zone the runtime cannot parse fails OPEN (always active) rather than silently dropping alerts. */\n activeTz?: string | null;\n /** `null` on a `count`-metric digest route (there is nothing to aggregate over). On an `avg`/`max` digest it carries only `field`, with `op` and `value` absent — only a `threshold`-mode route has a complete condition. */\n condition?: SensingRouteCondition | null;\n createdAt?: string;\n /** Minimum gap in seconds between alerts for the same (route, screen) episode; clamped to 0..86400 and defaulting to 300. It also caps the falling-edge clear window (60 s maximum), so a shorter debounce re-arms the route sooner as well as spacing alerts more tightly. */\n debounceSeconds?: number;\n /** Scheduled-aggregate configuration; `null` on `threshold` routes. `nextRunAt` is a server-held cursor the digest cron advances after every send, so it moves on its own without any edit from you. */\n digest?: {\n intervalMinutes?: number;\n metric?: \"count\" | \"avg\" | \"max\";\n nextRunAt?: string;\n windowMinutes?: number;\n } | null;\n /** Whether the evaluator considers this route at all. A disabled route keeps its condition, actions and screen set and is simply skipped by every hot-path read; deleting a route also sets this `false` (rows are soft-deleted, never removed). */\n enabled?: boolean;\n /** `threshold` evaluates `condition` against each incoming observation. `digest` ignores the condition and instead sends a scheduled aggregate driven by the `digest.nextRunAt` cursor; focus regions and explicit review timing are rejected on digest routes. */\n mode?: \"threshold\" | \"digest\";\n /** Operator-supplied label, trimmed and capped at 200 characters. It is delivered verbatim as `route_name` on every fire but is not the alert text — the human-readable message is composed separately from the screen's sensing intent. */\n name?: string;\n /** The owning principal's id, compared against your credential on every read and write — a mismatch answers 404 (existence-hidden), never 403. Equal to your partner id for routes created here. */\n ownerId?: string;\n /** Which principal created the route: `partner` for anything created through this API, `earner_user` for a route the screen's own operator created in the earner portal. The Partner API only ever lists or edits `partner` routes, but an `earner_user` route on your screen still delivers webhooks to you. */\n ownerKind?: string;\n /** The partner the route was created under. Equal to `ownerId` for partner-created routes and `null` for a route an earner created in the portal, so it is not a reliable join key for the screen's partner. */\n partnerId?: string;\n /** Binds the route to a sensing profile BY NAME, never by `profile_id` — redeploying a profile mints a fresh `profile_id` per screen, which would orphan the binding. `null` means unbound; when set, the route stays dormant on any screen whose active profile has a different name. */\n profileName?: string | null;\n reviewTimingMode?: SensingRouteReviewTimingMode;\n reviewWaitSeconds?: SensingRouteReviewWaitSeconds;\n /** Server-minted immutable id: the literal prefix `rt_` followed by a UUID. Webhook consumers should key on this rather than `route_name`, which the owner can rename at any time. */\n routeId?: string;\n /** Per-camera areas, at most one entry per screen. The legacy cloud path converts geometry into prompt text and is not geometrically enforced (measured 2026-08-25 on gemini-3.1-flash-lite). The retained local connector masks actual pixels separately for each declared scope; original unmasked JPEGs remain alert evidence. Retained installation and model accuracy require separate qualification. */\n screenFocusRegions?: Array<SensingRouteScreenFocusRegion>;\n /** The screens this route watches — deduped and capped at 250. For a group-targeted route these are the group's LIVE members resolved at read time, not a stored set, so the list can change between two GETs without any edit. */\n screenMongoIds?: Array<string>;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainMinSamples?: number;\n /** How long the condition must hold before the FIRST alert, in seconds (600 = ten minutes). Omit to alert on the first true reading. Cadence-independent, because the evaluator compares timestamps - correct however often the screen reports, including when that rate changes while the condition holds. */\n sustainSeconds?: number | null;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainWindowSeconds?: number;\n /** The sg_ Screen Group this route targets. When set, the route fires on the group's LIVE members (screenMongoIds reflects the resolved members at read time) and no explicit screens are stored. */\n targetGroupId?: string | null;\n /** Last write to the route row — NOT a configuration-change stamp. The digest cron bumps it every time it advances a digest route's next-run cursor, and a soft delete bumps it too, so it moves on rows nobody edited. */\n updatedAt?: string;\n};\n\n/**\n * One channel action fired when the route matches.\n */\nexport type SensingRouteAction = {\n /** Attach the evidence frame/clip (people-facing channels). */\n attachClip?: boolean;\n /** Selects a strict per-channel shape: `webhook` requires `webhookId`, `whatsapp`/`sms` require `recipientE164`, `email` requires `recipientEmail`, `slack` requires `slackChannelId`, and `clip` needs no destination. Any other destination field on the action is rejected, and `webhook` is the only channel that does not deliver to a person — use it for test routes. */\n channel: \"webhook\" | \"whatsapp\" | \"sms\" | \"slack\" | \"email\" | \"clip\";\n /** E.164 phone number (channel=whatsapp|sms). */\n recipientE164?: string;\n /** Recipient email (channel=email). */\n recipientEmail?: string | null;\n /** Slack channel id (channel=slack). */\n slackChannelId?: string | null;\n /** Message template name (managed WhatsApp/SMS). */\n templateName?: string;\n /** Target webhook endpoint id (channel=webhook). */\n webhookId?: string | null;\n};\n\n/**\n * A threshold condition — the route fires when the sensed field crosses the value.\n */\nexport type SensingRouteCondition = {\n /** The sensed field key (snake_case) to evaluate. */\n field: string;\n /** How the observed value is compared with `value`. `gt`/`gte`/`lt`/`lte` match ONLY when both sides parse as finite numbers; `eq`/`neq` fall back to strict equality for booleans and non-numeric strings. A missing or null observation never matches — including `neq`, which does not fire on absence. */\n op: \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"eq\" | \"neq\";\n /** The threshold value (numeric, string, or boolean depending on the field). */\n value?: number | string | boolean;\n};\n\n/**\n * Threshold-alert timing. NULL preserves legacy behavior; immediate adds no check delay; wait_recheck requires distinct first/follow-up positive images at least reviewWaitSeconds apart on capture time, not uninterrupted activity or message grouping.\n */\nexport type SensingRouteReviewTimingMode = \"immediate\" | \"wait_recheck\" | null | null;\n\n/**\n * Whole seconds before a fresh follow-up check. Required only for wait_recheck; must be NULL for immediate or unspecified timing. These two settings must be updated together.\n */\nexport type SensingRouteReviewWaitSeconds = number | null;\n\n/**\n * A normalized camera area used only by this alert. The rectangle is the compatibility bounding box; optional ordered points define the exact lasso perimeter. Omitted cameras use the whole view.\n */\nexport type SensingRouteScreenFocusRegion = {\n /** Rectangle height as a fraction of frame height, at least 0.05. When `points` is supplied this is DERIVED from the lasso's bounding box. Note the region is only ever sent to the model as prompt text and is not geometrically enforced — measured 2026-08-25, both shapes leaked 100% at every anchor, so a focused alert reacts to the whole frame. */\n height: number;\n /** Ordered non-self-intersecting lasso vertices, normalized to a 0.01 coordinate grid so the saved perimeter is represented exactly in model instructions. The perimeter closes from the last point to the first. */\n points?: Array<{\n x: number;\n y: number;\n }>;\n /** Which of the route's cameras this area applies to. It must appear in the route's explicit `screenMongoIds` and may appear at most once across the array, or the write is a 400; cameras with no entry are watched whole-view. */\n screenMongoId: string;\n /** Rectangle width as a fraction of frame width, at least 0.05. When `points` is supplied this is DERIVED from the lasso's bounding box rather than read from the request, so older readers keep a safe approximation of the polygon. */\n width: number;\n /** Left edge of the bounding rectangle as a fraction of frame width, origin top-left. Stored rounded to 4 decimal places, and capped at 0.95 because `width` has a 0.05 minimum and `x + width` may not exceed 1. */\n x: number;\n /** Top edge of the bounding rectangle as a fraction of frame height, origin top-left. Stored rounded to 4 decimal places, and capped at 0.95 because `height` has a 0.05 minimum and `y + height` may not exceed 1. */\n y: number;\n};\n\nexport type SensingSettingsResponse = {\n /** Summary of the profile row currently deployed and active on this screen (id, name, cadences and derived capabilities). `null` when the screen has never had a profile deployed, in which case the response's mode fields describe the default rather than anything running. */\n active_profile?: {\n capabilities?: Array<string>;\n capture_interval_ms?: number | null;\n profile_id?: string | null;\n profile_name?: string | null;\n report_interval_ms?: number | null;\n } | null;\n desired_mode?: SensingPerformanceMode;\n /** Read-only latest device telemetry used for safety checks. */\n device_capability?: {\n agent_version?: string | null;\n gpu_delegate_supported?: boolean | null;\n gpu_name?: string | null;\n model_tier?: string | null;\n recent_failure_count?: number;\n soc_name?: string | null;\n soc_vendor?: string | null;\n telemetry_fresh?: boolean;\n };\n effective_mode?: SensingPerformanceMode;\n /** Despite the name this is not an apply OUTCOME and carries no device acknowledgement: it is `null` when the screen has no active profile and otherwise always `{ status: \"active_profile_loaded\", profile_id, updated_at }` describing the profile row that is loaded now. */\n last_apply_status?: Record<string, unknown> | null;\n /** The full selectable set with human labels (`auto` = \"Auto recommended\", `presence_only` = \"Viewer count only\", and so on). It is a static list, NOT filtered by this screen's hardware — a mode listed here can still be refused; read `safety.blocks` before offering it. */\n modes?: Array<{\n label?: string;\n value?: SensingPerformanceMode;\n }>;\n /** Hardware pre-flight for `effective_mode`. `allowed` is simply `blocks.length === 0`; `warnings` never block (stale telemetry, recent device failures), while a `block` — missing fresh telemetry for a load-increasing mode, or FLOOR-tier/CPU-only hardware for `advanced` — makes a PUT of that mode answer 409 with this object under `error.details.safety`. */\n safety?: {\n allowed?: boolean;\n blocks?: Array<{\n code?: string;\n message?: string;\n }>;\n warnings?: Array<{\n code?: string;\n message?: string;\n }>;\n };\n /** The screen's Mongo id — the same identifier the route surfaces call `screenMongoId`. Echoes the path parameter. */\n screen_id?: string;\n};\n\n/**\n * Webhook request BODY delivered when a Sense Anything Route fires. Unlike the\n * device/programmatic events, a Route fire delivers a FLAT, self-describing\n * payload (no `{event,timestamp,data}` wrapper) — the event type is in the\n * `X-Trillboards-Event` request header (`sensing.threshold_crossed` for a custom\n * sensed field, or the matching `audience.*` / `venue.*` event for a known\n * semantic; a scheduled-digest Route delivers `venue.traffic_summary`). All Route\n * events share this same body shape. Verify the `X-Trillboards-Signature` header\n * over the raw body before trusting it.\n *\n */\nexport type SensingThresholdCrossedEvent = {\n /** The sensed field key evaluated (null for count-only digests). */\n field?: string | null;\n /** Server clock when the evaluator fired — not when the camera saw it. On the cloud path it was measured 8.2 s median and 15.3 s p95 behind the frame's shutter, so use the payload's `captured_at` (the device's own shutter instant) whenever the fire carried a frame. */\n fired_at?: string;\n /** The observed value that crossed the threshold. */\n observed?: unknown;\n /** The comparison the evaluator applied. `null` for a scheduled digest, which aggregates rather than comparing. Numeric operators only ever match when both the observed value and the threshold parse as finite numbers. */\n op?: \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"eq\" | \"neq\" | null;\n /** Who owns the route that fired. Webhooks are dispatched to the SCREEN's partner regardless of who created the route, so a partner endpoint legitimately receives `earner_user` fires for routes the screen's own operator configured and which are not visible through the Partner API. */\n owner_kind?: \"earner_user\" | \"partner\";\n /** The Route that fired. */\n route_id?: string;\n /** The route's operator-supplied label at the time of the fire. It is mutable and not unique — match on `route_id` for idempotency and routing. */\n route_name?: string;\n /** The screen (mongo id) whose observation crossed the threshold. */\n screen_id?: string;\n /** The configured threshold value (number, string, or boolean). May be null. */\n threshold?: unknown;\n};\n\nexport type SsdpDeviceInfo = {\n /** The `<friendlyName>` element from the fetched description XML. If it looks like a personal name (possessive apostrophe-s, an email, a MAC) the ENTIRE row is discarded rather than the field being blanked, so consumer devices named after their owner never appear at all. */\n friendlyName?: string | null;\n /** The `LOCATION:` header from the M-SEARCH response — the URL of the device description XML, and the de-duplication key for the whole list (one row per distinct LOCATION, last response wins). A response without it produces no row at all. */\n location: string;\n /** The `<manufacturer>` element from the description XML. `null` whenever the description fetch was skipped, timed out or failed — which is common, since fetching is bounded to half the listen window with a 1.5 s per-host timeout — so absence says nothing about the device. */\n manufacturer?: string | null;\n /** The `<modelName>` element from the description XML, field-stripped (not row-dropped) if it contains an email or a MAC. Absent on every row whose description fetch did not complete. */\n modelName?: string | null;\n /** The raw `SERVER:` response header, an RFC 2616 product token such as `Linux UPnP/1.0 Sonos/72.6-31040`. It comes from the M-SEARCH response itself, so unlike the XML-derived fields below it is present even when the description fetch fails — and it is deliberately neither PII-filtered nor hashed server-side, being treated as a low-cardinality vendor hint. */\n server?: string | null;\n /** The `ST:` search-target header of the response, e.g. `urn:schemas-upnp-org:device:ZonePlayer:1`. The probe searches with `ST: ssdp:all`, so this reflects what the device chose to answer as, not what we asked for. It arrives with the M-SEARCH response, so it survives a failed description fetch; an empty string means the responder omitted the header. */\n st: string;\n /** The `<UDN>` element — the device's self-declared Unique Device Name, typically a `uuid:` URN and the most stable per-device key SSDP offers. It is hashed server-side, and it is absent whenever the description fetch did not complete. */\n udn?: string | null;\n [key: string]: unknown;\n};\n\nexport type TeamInviteResponse = {\n /** The invited address, lower-cased and trimmed. Once the invitation is accepted the listing reports the accepting user account's email instead, which may differ from this one. */\n email?: string;\n /** When the invitation expires (7 days from creation) */\n expires_at?: string;\n /** A freshly minted 24-character hex ObjectId held as the membership's legacy id — NOT the `memberships` UUID primary key. It is the value the team routes take as the member path parameter. */\n membership_id?: string;\n /** Only `admin` and `viewer` can be invited — `owner` is the membership created with the partner account and cannot be granted through this endpoint. */\n role?: \"admin\" | \"viewer\";\n /** `active` when the invited email already had a Trillboards account: the membership is auto-accepted at invite time, `accepted_at` is set immediately, no token is issued and `expires_at` is `null`. `pending` otherwise, with a 7-day invite token. Either way the team is capped at 50 active-or-pending members. */\n status?: \"pending\" | \"active\";\n};\n\nexport type TeamMember = {\n /** `null` while `status` is `pending`. Set at INVITE time rather than click time when the invitee already had a Trillboards account and the membership was auto-activated. */\n accepted_at?: string | null;\n /** The linked user account's email once the invitation is accepted; the address the invitation was SENT to while `status` is `pending`. The two differ if the invitee accepts with a different account. */\n email?: string;\n /** When the invitation row was created. Re-inviting the same address rotates the token and moves this timestamp forward. */\n invited_at?: string;\n /** Name and email of the inviting user, resolved by join. `null` for the owner membership created with the partner account, and for any invitation whose inviter row no longer resolves. */\n invited_by?: {\n email?: string;\n name?: string;\n } | null;\n /** **Always `null`.** The column has no counterpart in `memberships` after the tenant-membership cutover, so the canonical reader projects a literal `NULL::timestamptz` and nothing writes it. */\n last_portal_access?: string | null;\n /** Unique membership record ID */\n membership_id?: string;\n /** The linked user account's display name. Undefined — and so omitted from the JSON — while `status` is `pending`, because no user row is attached until the invitation is accepted. */\n name?: string;\n permissions?: RolePermissions;\n /** Profile photo URL from the linked user account, and null/absent while the invitation is pending for the same reason as `name`. */\n photo?: string | null;\n /** `owner` is the membership created with the partner account and can never be invited or granted — only `admin` and `viewer` are grantable. Role alone determines `permissions`. */\n role?: \"owner\" | \"admin\" | \"viewer\";\n /** The listing returns `active` + `pending` only; `revoked` rows appear only when `?status=revoked` is passed explicitly. An invitation to an email that already has a Trillboards account is auto-accepted and lands `active` immediately. */\n status?: \"active\" | \"pending\" | \"revoked\";\n /** User ID (null if pending invitation) */\n user_id?: string;\n};\n\nexport type Transaction = {\n /** Integer US cents. Earnings rows are allocated cumulatively so the list sums EXACTLY to the lifetime total — an individual row can therefore differ by one cent from rounding that day's dollars on its own. */\n amount_cents?: number;\n /** For a `payout`, the real creation timestamp. For an `earning` it is `new Date(period_date)` — midnight UTC of the accounting day, a value derived from the date key rather than the time anything happened. */\n created_at?: string;\n /** For an `earning` row, the `YYYY-MM-DD` accounting period the aggregate covers. For a `payout` row it is the payout record's creation timestamp, so it carries a time component despite the declared `date` format. */\n date?: string;\n earning_source_version?: 1;\n earning_sources?: EarningsSources;\n /** Synthetic and namespaced by origin, never a ledger primary key: earnings rows are `daily_<YYYY-MM-DD>` (one per accounting day, not per impression); payouts are `admin_batch:<ledger_id>`, `earner_withdrawal:<withdrawal_id>` or `legacy_transfer:<id>`. */\n id?: string;\n /** Number of impressions (for earning transactions) */\n impressions?: number;\n /** Source of the transaction (e.g., impressions, payout) */\n source?: string;\n /** Stripe transfer ID (for payout transactions) */\n stripe_transfer_id?: string;\n /** `earning` rows are daily revenue aggregates from `programmatic_earnings_daily`; `payout` rows are money leaving, unioned from three sources and deduplicated by provider transfer id. `?type=all` (the default) merges both and sorts newest-first. */\n type?: \"earning\" | \"payout\";\n};\n\n/**\n * The canonical Trillboards error envelope. Emitted by `middleware/globalErrorHandler.js` for every error that reaches it: `utils/apiErrors.ts` `toJSON()` builds the inner object and the handler wraps it in `{ error }` and stamps `request_id`.\n */\nexport type TrillboardsError = {\n error: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code: string;\n /** Per-field violations (populated from Zod errors). */\n details?: Array<{\n code?: string;\n message?: string;\n param?: string;\n }>;\n /** Documentation for this code — https://api.trillboards.com/docs/errors#<code>. */\n doc_url?: string;\n /** Agent-facing hints and suggestions. */\n help?: {\n portal_url?: string;\n suggestions?: Array<string>;\n summary?: string;\n try_next?: string;\n };\n /** Human-readable error message. Safe to surface to end-users. */\n message: string;\n /** Offending parameter name, or null when the error is not field-scoped. */\n param?: string | null;\n /** Echoed X-Request-Id. Quote this to support for log correlation. */\n request_id: string;\n type: ErrorType;\n };\n};\n\n/**\n * Partial, non-clobbering update — include only the fields to change. Update reviewTimingMode and reviewWaitSeconds together; omit both to preserve existing timing. Explicit timing cannot be added to a digest, and changing to a digest clears the prior event check timing.\n */\nexport type UpdatePartnerSensingRouteRequest = {\n /** REPLACES the entire action list (1..10 entries); the existing rows are deleted and reinserted. Omit the key to leave actions untouched — there is no way to add or remove a single action. */\n actions?: Array<SensingRouteAction>;\n /** Seven-bit weekday mask evaluated in `activeTz`: bit 0 is Monday through bit 6 is Sunday, so 127 is every day and 0 never fires. Requires `activeTz`, like the rest of the active window. */\n activeDaysMask?: number;\n /** Inclusive end of the daily active window, minutes past local midnight in `activeTz` (0..1439). A value below `activeStartMinute` is read as an overnight window, not an empty one. */\n activeEndMinute?: number;\n /** Inclusive start of the daily active window, minutes past local midnight in `activeTz` (0..1439). Requires `activeTz` to have any effect. */\n activeStartMinute?: number;\n /** IANA zone name the active window is evaluated in. Setting the minute/day fields without this leaves the window inert, and an unparseable zone fails open (always active) rather than suppressing alerts. */\n activeTz?: string;\n condition?: SensingRouteCondition;\n /** Minimum gap in seconds between alerts for the same (route, screen) episode, clamped to 0..86400. `0` means fire on every rising edge with no spacing at all. */\n debounceSeconds?: number;\n /** Replaces the digest block and, as a side effect, rewrites `condition` to `{ field }` or `null`. `field` is required for `avg` and `max`; `intervalMinutes` must be at least 5 because the digest cron only runs every 5 minutes. */\n digest?: {\n field?: string;\n intervalMinutes?: number;\n metric?: \"count\" | \"avg\" | \"max\";\n windowMinutes?: number;\n };\n /** Only the JSON literal `true` enables the route here — every other value, including the string `\"true\"` and `1`, is written as `false`. This is the mirror image of create, where only the literal `false` disables, so send a real boolean. */\n enabled?: boolean;\n /** Replaces the label. Must be a non-empty string after trimming and at most 200 characters; sending an empty or whitespace-only name is a 400 rather than a clear. */\n name?: string;\n /** Rebinds the route to a different named sensing profile; send `null` (or an empty/whitespace string) to unbind it. Always a profile NAME — a `profile_id` is re-minted on every redeploy and would orphan the binding. */\n profileName?: string | null;\n reviewTimingMode?: SensingRouteReviewTimingMode;\n reviewWaitSeconds?: SensingRouteReviewWaitSeconds;\n /** Replace all selected rectangles or polygon lassos for the route; send [] to return every camera to whole view. Entries must target the route's explicit screenMongoIds. */\n screenFocusRegions?: Array<SensingRouteScreenFocusRegion>;\n /** REPLACES the watched screen set (1..250, deduped); mutually exclusive with `targetGroupId` in one request. Focus regions for cameras that survive the swap are PRESERVED unless you also send `screenFocusRegions` (including `[]` to clear them). */\n screenMongoIds?: Array<string>;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainMinSamples?: number;\n /** How long the condition must hold before the FIRST alert, in seconds (600 = ten minutes). Omit to alert on the first true reading. Cadence-independent, because the evaluator compares timestamps - correct however often the screen reports, including when that rate changes while the condition holds. */\n sustainSeconds?: number;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainWindowSeconds?: number;\n /** Set to a sg_ group id to (re)target the group's live members, or null to switch back to an explicit screenMongoIds set. Mutually exclusive with screenMongoIds in one request. */\n targetGroupId?: string | null;\n};\n\n/**\n * The resolved programmatic VAST waterfall. `sources` is an ORDERED ARRAY and clients MUST iterate ALL of it — by `priority` ascending, skipping `enabled: false` — advancing to the next source on no-fill, empty VAST, timeout, IMA load error AND playback error (VAST 303 / 300 / 301 / 1009 all mean \"try the next source\", never \"stop\"). Reading `sources[0]` and stopping is the most common integration defect and reads as \"no demand\" when demand exists further down. Apply each source's own `timeout_ms`, and cap the whole loop at `total_timeout_ms`. Always handle player error and never leave the screen black; always fire the VAST `<Error>` beacon with `[ERRORCODE]` substituted. Full contract: docs/integrations/partner-native-ima-sdk.md §0 and §4.1. SQL/Admin-enabled sources remain visible; request-pressure decisions are enforced, when enabled, at first-party upstream fetch seams rather than by removing sources from this catalog.\n *\n */\nexport type VastWaterfall = {\n /** Derived, not configured: it is simply `sources.length > 0`. `false` means no demand source resolved for this screen on this request, so fall back to your own content. It is not a partner-settable toggle and it does not mean programmatic serving is switched off for the screen. */\n enabled?: boolean;\n /** Every source must be attempted, by `priority` ascending, until one actually plays. Not a preference list. */\n sources?: Array<VastWaterfallSource>;\n /** Budget in ms for the ENTIRE waterfall loop, across all sources. When it is spent, stop trying sources and return to your own content. */\n total_timeout_ms?: number;\n} | null;\n\n/**\n * One demand source in the VAST waterfall. Fetch `vast_url` (already a Trillboards vast-wrap URL — use as-is) and pass the response to your IMA SDK. A failure here means \"advance to the next source\", not \"the request had no demand\".\n */\nexport type VastWaterfallSource = {\n /** Identical across every source in this response — one id per waterfall build, so it groups all of a single ad opportunity's source attempts, while `request_id` identifies this source alone. Echo it back; never mint your own. */\n auction_request_id?: string;\n /** The source's effective FLOOR CPM in dollars per thousand impressions (never cents) — the configured tag floor (`NUMERIC(8,2)`) or the partner's default, after any demand price action. It is an expectation used to order the waterfall, not a cleared price and not what the screen earns; `null` when the partner has no floor configured. */\n cpm?: number | null;\n /** High recent error rate measured server-side. Degraded sources are already pushed to the tail of the array for you — do NOT skip a source because of this flag. */\n degraded?: boolean;\n /** Whole seconds of the creative THIS source will serve, so you can schedule continuous loop playback without first fetching the VAST and probing the MP4. Present only on the first-party `trillboards_direct` source (a programmatic source's length is not known until its own VAST is fetched). It is the same number as the `<Duration>` in the VAST that `vast_url` returns, so use either — they cannot disagree. NOT a playback control: IMA still takes its real timing from the media, so treat this as scheduling metadata and keep honouring the actual quartile/complete events. A creative longer than your ad slot will still be cut off by the next poll; we warn the uploader at upload time when that is the case. */\n duration_seconds?: number;\n /** When false, skip this source entirely. Present-but-disabled sources may appear in the array. */\n enabled?: boolean;\n /** Recent non-response rate for this demand source as a PERCENT 0-100 (not a 0-1 fraction). It is fleet-wide rather than per-screen, derived from an hourly rollup that can be ~15 minutes stale, and it is present only on sources that also carry `degraded: true`. Advisory: it never means skip the source. */\n error_rate_pct?: number;\n /** No live producer — `null` on every source. The only assignment is guarded on a partner-level `fetchMode` setting that no demand partner in the registry defines. Do not branch on it. */\n fetch_mode?: string | null;\n /** Opaque public alias for the demand source. Echo it back as `variant_name` on `programmatic-event` reports. */\n name?: string;\n /** Opaque ascending sort key — lowest is tried first. Do NOT treat it as an index: it may start at 0 (a source we want to win outright — the `?test=1` source, an injected first-party bid, an auction winner — is stamped `priority: 0`), and values may be non-contiguous (some paths renumber survivors 1..N, others keep catalog values). Only the relative order is meaningful; sort ascending and do no arithmetic on it. */\n priority?: number;\n /** Per-source request identifier. Report against the source you actually used, not `sources[0]`. */\n request_id?: string;\n /** Per-source budget in ms for fetching and loading THIS source. Distinct from the waterfall-wide `total_timeout_ms`. */\n timeout_ms?: number;\n /** Fetch verbatim. The server has already appended this source's `request_id` and rewritten every partner-identifying path segment and query parameter to an opaque alias, so editing, re-ordering or re-signing the query breaks impression attribution. A `data:` URL can appear here for an inbound-DSP source that carries its VAST inline. */\n vast_url?: string;\n};\n\nexport type Webhook = {\n /** When webhook was created */\n created_at?: string;\n /** Subscribed event types */\n events?: Array<\"device.online\" | \"device.offline\" | \"impression.recorded\" | \"creative.rewards_ready\" | \"campaign.allocated\" | \"payout.processed\" | \"sensing.threshold_crossed\" | \"audience.spike\" | \"audience.venue_busy\" | \"audience.purchase_intent\" | \"audience.demographics_update\" | \"venue.traffic_summary\" | \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\" | \"fleet_command.completed\" | \"fleet_command.failed\">;\n /** Total failed deliveries */\n failure_count?: number;\n /** Last time webhook was triggered */\n last_triggered_at?: string;\n /** Webhook signing secret (whsec_…). Returned when the webhook is created so partners can verify the compound `X-Trillboards-Signature` header over the raw payload (see the SDK's Webhooks.constructEvent). Treat as a credential — store it securely and never expose it client-side. */\n secret?: string;\n /** Webhook status */\n status?: \"active\" | \"inactive\";\n /** Total successful deliveries */\n success_count?: number;\n /** Webhook endpoint URL */\n url?: string;\n /** Unique webhook identifier */\n webhook_id?: string;\n};\n\nexport type WebhookDelivery = {\n /** When delivery was first attempted */\n attempted_at?: string;\n /** When delivery succeeded */\n delivered_at?: string;\n /** Error message if failed */\n error_message?: string;\n /** Event that triggered this delivery */\n event_type?: string;\n /** HTTP status code from endpoint */\n http_status?: number;\n /** Delivery record ID */\n id?: string;\n /** Response time in milliseconds */\n response_time_ms?: number;\n /** Number of retry attempts */\n retry_count?: number;\n /** Delivery status */\n status?: \"pending\" | \"success\" | \"failed\" | \"retrying\";\n};\n\n/**\n * Standard webhook event payload sent to your endpoint.\n * All events follow this structure.\n *\n */\nexport type WebhookEvent = {\n /** Event-specific data */\n data?: Record<string, unknown>;\n /** Event type */\n event?: string;\n /** When event occurred */\n timestamp?: string;\n};\n\nexport type WifiEnvironmentSnapshot = {\n /** Dimensionless 0.0-1.0: visible APs whose centre frequency is within ±10 MHz of the joined AP, divided by ALL visible APs in the capped list. Because the joined AP is itself in the numerator it is never 0 while connected — a literal `0.0` means not connected (or an empty scan), not an empty channel. Above ~0.5 indicates a dense venue, below ~0.2 an isolated one. */\n channelCongestionRatio?: number | null;\n /** Channel width of the joined AP in MHz — but it is APPROXIMATE by construction: the producer returns the width of the FIRST entry in the scan list, which is only usually the joined AP, rather than matching on BSSID. `null` when not connected, on Android below API 23, or for an 80+80 MHz AP, which the width mapping does not cover. */\n connectedChannelWidthMhz?: number | null;\n /** Centre frequency of the joined AP's primary 20 MHz channel, in MHz. `0` means not connected / unavailable, and that zero also zeroes `channelCongestionRatio` and forces `frequencyBand` to `unknown`. */\n connectedFrequencyMhz?: number | null;\n /** Negotiated PHY link speed of the joined AP in Mbps (`WifiInfo.getLinkSpeed()`) — a link-rate ceiling, not measured throughput. `null` rather than 0 when not connected or when the platform reports a non-positive value. */\n connectedLinkSpeedMbps?: number | null;\n /** RSSI of the JOINED access point in dBm. `-100` is a SENTINEL, not a measurement: it is the literal default when `WifiInfo` is unavailable or the device is not on Wi-Fi, so a genuinely weak link and no link at all are indistinguishable here. */\n connectedSignalDbm?: number | null;\n /** Band of the JOINED AP: `2.4ghz`, `5ghz`, `6ghz` or `unknown`. It is derived from `connectedFrequencyMhz`, so a device that is not on Wi-Fi reports `unknown` rather than null — and the 5900-5924 MHz range falls into `unknown` too, because the classifier's 5 GHz and 6 GHz windows do not meet. */\n frequencyBand?: string | null;\n /** Median RSSI in dBm across ALL visible APs (not just the joined one). It is the UPPER median for an even-sized list — the two middle values are not averaged — and falls back to the `-100` sentinel on an empty list. */\n medianSignalDbm?: number | null;\n /** Distinct BSSIDs in the scan, after the 50-entry cap. It is literally the SAME value as `uniqueBssidCount` — both are assigned from one field — so the two never disagree and neither is a count of the uncapped scan. */\n networkCount?: number | null;\n /** Population VARIANCE of the joined AP's RSSI in dBm SQUARED — not a standard deviation, and the divisor is N, not N-1. The window is the last 5 HEARTBEAT cycles held in a process-lifetime buffer, not the current scan, so it reads `0.0` on the first cycle after an agent restart; the `-100` not-connected sentinel is admitted into that history and skews it. Intended as a coarse motion indicator, not occupancy. */\n rssiVariance?: number | null;\n /** UNIX EPOCH milliseconds (`System.currentTimeMillis()`) stamped when the scan COMPLETED — wall clock, not boot-relative, and not the scan start. It is a different clock from Android's own per-result `ScanResult.timestamp`, which is microseconds since boot and never reaches the wire. */\n scanTimestampMs?: number | null;\n /** Strongest minus weakest visible RSSI, in dB — a positive difference, not an absolute level. It is `0` when fewer than two APs are visible, which is indistinguishable from a genuinely uniform RF environment. Used as a venue-openness hint. */\n signalSpreadDbm?: number | null;\n /** Distinct BSSIDs after de-duplication and the 50-entry cap — the identical value to `networkCount` above, assigned from the same field, so it adds no independent information. */\n uniqueBssidCount?: number | null;\n [key: string]: unknown;\n} | null;\n\nexport type WifiScanResult = {\n /** Bonded channel width in MHz, mapped from Android's width enum to a literal 20, 40, 80 or 160. `null` on Android below API 23, on any read failure, AND for an 80+80 MHz AP — that variant has no mapping, so `null` does not mean narrow. */\n channelWidthMhz?: number | null;\n /** Centre frequency of the AP's PRIMARY 20 MHz channel in MHz (2400-7200 accepted, covering 2.4/5/6 GHz) — not the centre of a wider bonded channel. Convert to a channel number yourself; the wire carries only the frequency. */\n frequencyMhz: number;\n /** The AP's BSSID exactly as Android reports it, unhashed on the device; Trillboards stores it as received and as a keyed HMAC-SHA256 hash. Rows are de-duplicated by BSSID keeping the strongest reading, and the literal `02:00:00:00:00:00` — Android's redaction placeholder for a caller without location permission — is dropped rather than forwarded, so a permission-less device produces an empty list, not a list of placeholders. */\n rawBssid: string;\n /** AP signal level in dBm (negative, bounded -120..0), from `ScanResult.level`. Note the wire key the Android agent actually sends is `signal_dbm`, not a snake_case form of this name — a mismatch of exactly this kind left the ClickHouse `rssi` column NULL on 100% of Wi-Fi rows until 2026-08-08. */\n signalStrengthDbm: number;\n [key: string]: unknown;\n};\n\n\n// ─── Operations ──────────────────────────────────────────────────────────\n\n/**\n * The whole still a sighted ad was read off, face-blurred.\n * GET /v1/ad-sighting-frames/{token}\n */\nexport interface getAdSightingFrameOperation {\n readonly path: \"/v1/ad-sighting-frames/{token}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The signed capability in the record's photo_url / frame_url. */\n token: string;\n};\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * The photo of a sighted ad: the close-up, or the ad cut from its still at request time.\n * GET /v1/ad-sighting-photos/{token}\n */\nexport interface getAdSightingPhotoOperation {\n readonly path: \"/v1/ad-sighting-photos/{token}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The signed capability in the record's photo_url / frame_url. */\n token: string;\n};\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * Ad-sighting records for a signed-in portal buyer (the Creatives lens).\n * GET /v1/advertiser/measurement/ad-sightings\n */\nexport interface listAdSightingsInPortalOperation {\n readonly path: \"/v1/advertiser/measurement/ad-sightings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** A board the sighting was matched to, repeatable. */\n board_id?: Array<string> | null;\n /** A brand, repeatable for a brand set (competitors). Matched however it is typed: \"McDonald's\", \"mcdonalds\" and \"Mc Donalds\" find the same records. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. Combined with `brand` as either-or. */\n brand_id?: Array<string> | null;\n /** The brand's IAB tier-1 category (IAB1..IAB25), repeatable: the records whose resolved brand votes in it (brand_knowledge_graph.iab_category, the `category` field). */\n category?: Array<string> | null;\n /** A sighted creative (the campaign artwork), repeatable. */\n creative_id?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** Start (inclusive), YYYY-MM-DD or an ISO-8601 instant. Default: 30 days before `to`. */\n from?: string;\n /** true returns only records that carry a photo (photo_url set): a record without a shareable face-blurred picture is skipped, so it is never returned or billed. The page can hold fewer than limit records; keep following next_cursor until it is null. */\n has_photo?: \"true\" | \"false\";\n /** The reading instrument (ssr-v2, ssr-v1, vlmtext-v1, edge_ocr_v1), repeatable. */\n instrument?: Array<string> | null;\n /** Records per page, 1..500 (default 50). The page limit is reserved; the records returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE (US DMA or CA CMA), repeatable. */\n market?: Array<string> | null;\n /** A media owner, repeatable: the records matched to a face whose owner (`publisher_name`, the registry's) holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)). */\n media_owner?: Array<string> | null;\n /** The surface kind as read (billboard, storefront, bus_shelter, ...), repeatable. */\n surface?: Array<string> | null;\n /** End (exclusive). Default: now. The span is at most 400 days. */\n to?: string;\n};\n response: DataApi_AdSightingsResponse;\n}\n\n/**\n * Brand x market x month creative history for a signed-in portal buyer.\n * GET /v1/advertiser/measurement/ad-sightings/history\n */\nexport interface listAdSightingHistoryInPortalOperation {\n readonly path: \"/v1/advertiser/measurement/ad-sightings/history\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Narrow to brands this agency holds as agency of record (Winmo), by name in any case, repeatable. */\n agency?: Array<string> | null;\n /** Narrow to faces by face key, repeatable for a set of boards: f:<board id>:<face index> (a registered face) or p:<point id> (an unregistered board point), the `face_key` a board slice answers with. */\n board?: Array<string> | null;\n /** A brand by name, repeatable (competitors). Resolved to its brand id the way the brand search does. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. */\n brand_id?: Array<string> | null;\n /** Narrow to brands of an IAB tier-1 category (IAB1..IAB25), repeatable. A slice filter narrows the denominators with the rows: the shares are within the categories named. */\n category?: Array<string> | null;\n /** Narrow to faces in a Census CBSA (5-digit code, OMB July 2023 delineation), repeatable. */\n cbsa?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** A slice the rows are cut by, repeatable: category, parent, agency (what the brand is), media_owner, format, surface, board, cbsa (where it ran). Each row is a brand within its slice, and every share is over its slice: a slice recomputes every denominator, and every distinct count is counted within it. The market vacancy is cut by where-it-ran slices only. */\n dimension?: Array<string> | null;\n /** Narrow to static or digital faces, repeatable. */\n format?: Array<string> | null;\n /** First month (YYYY-MM) or day. Default: 12 months before `to`. */\n from?: string;\n /** market_month (default) or fleet_month; market_week or fleet_week (ISO weeks from their Monday, each counted whole, every week the from..to span touches); market_window or fleet_window (the from..to span as one period). A fleet grain drops the market: with dimension=cbsa it is the CBSA geography. */\n grain?: \"market_month\" | \"fleet_month\" | \"market_week\" | \"fleet_week\" | \"market_window\" | \"fleet_window\";\n /** Rows per page, 1..500 (default 100). The page limit is reserved; the rows returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE, repeatable. */\n market?: Array<string> | null;\n /** Narrow to faces whose registry owner holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)), repeatable. */\n media_owner?: Array<string> | null;\n /** Narrow to brands whose parent company is in this brand graph id's family (the `parent_id` a parent slice answers with), repeatable. */\n parent?: Array<string> | null;\n /** Narrow to faces of a reader surface (billboard, digital_board, bus_shelter, kiosk), repeatable. */\n surface?: Array<string> | null;\n /** Last month (YYYY-MM, inclusive) or day. Default: this month. */\n to?: string;\n};\n response: DataApi_AdSightingsHistoryResponse;\n}\n\n/**\n * Every measured board in a bbox as a map point, with the ads our cab cameras read on it.\n * GET /v1/advertiser/measurement/boards.geojson\n */\nexport interface listMeasuredBoardsOperation {\n readonly path: \"/v1/advertiser/measurement/boards.geojson\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** An audience measured at the face to carry on every numbered point, as `<dimension>:<value>` (age, gender, cohort, intent; e.g. gender:female): its share, riders and prior level, to rank faces by. */\n audience?: string;\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** A brand to count per board and to narrow the sighting layer to. */\n brand?: string;\n /** A face format, as `format_label` spells it. Repeat the parameter for several (`format=A&format=B`); a value is never split on a comma. */\n format?: string | Array<string>;\n /** Extra layers: `sightings`. */\n layers?: string;\n /** A media owner, any case. Repeat the parameter for several (`owner=A&owner=B`); a value is never split on a comma, since owner names hold commas. */\n owner?: string | Array<string>;\n /** A curated set key: draw only its members. */\n set?: string;\n /** Comma-separated face types: `digital`, `static`. */\n type?: string;\n /** Comma-separated OpenOOH venue type ids (301 billboard, 302 urban panel, 303 shelter, 201 fueling station, ...). */\n venue?: string;\n};\n response: DataApi_DataProducts_BoardPointCollection;\n}\n\n/**\n * Who passes a board: occupancy, age, gender, activity and mood shares by daypart.\n * GET /v1/advertiser/measurement/boards/{boardId}/audience\n */\nexport interface getMeasuredBoardAudienceOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/audience\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Window end. Absent: the newest. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardAudienceResponse;\n}\n\n/**\n * Measured impressions per spot for one board face, by daypart, light, weather or speed.\n * GET /v1/advertiser/measurement/boards/{boardId}/currency\n */\nexport interface getMeasuredBoardCurrencyOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/currency\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Split the cells by daypart (default), light, weather or speed. */\n by?: \"daypart\" | \"light\" | \"weather\" | \"speed\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Measurement window end (YYYY-MM-DD). Absent: the newest published window. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardCurrencyResponse;\n}\n\n/**\n * How much of the time passengers were turned toward a board, per instrument.\n * GET /v1/advertiser/measurement/boards/{boardId}/looked-share\n */\nexport interface getMeasuredBoardLookedShareOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/looked-share\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First local date. Absent: 27 days before `to`. */\n from?: string;\n /** Last local date. Absent: the current currency window end. */\n to?: string;\n};\n response: DataApi_DataProducts_BoardLookedShareResponse;\n}\n\n/**\n * The buildings around a board that shape its viewshed.\n * GET /v1/advertiser/measurement/boards/{boardId}/occluders.geojson\n */\nexport interface getMeasuredBoardOccludersOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/occluders.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_OccluderCollection;\n}\n\n/**\n * Every pass our fleet made of a board on one day, second by second.\n * GET /v1/advertiser/measurement/boards/{boardId}/passes/replay\n */\nexport interface getMeasuredBoardPassReplayOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/passes/replay\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Local day to replay. */\n date: string;\n /** Page offset. */\n offset?: number;\n};\n response: DataApi_DataProducts_PassReplayResponse;\n}\n\n/**\n * Passes, legible seconds and facing seconds per week and daypart for one board.\n * GET /v1/advertiser/measurement/boards/{boardId}/tiles\n */\nexport interface getMeasuredBoardTilesOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/tiles\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First week (snaps to its Monday). */\n from?: string;\n /** Last week (snaps to its Monday). */\n to?: string;\n};\n response: DataApi_DataProducts_BoardTilesResponse;\n}\n\n/**\n * The legible and visible viewshed of each face of a board, with its measured figures.\n * GET /v1/advertiser/measurement/boards/{boardId}/viewshed.geojson\n */\nexport interface getMeasuredBoardViewshedOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/viewshed.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_ViewshedCollection;\n}\n\n/**\n * Brand typeahead over the outdoor ads our cab cameras read, with each brand's reads and metros.\n * GET /v1/advertiser/measurement/brands\n */\nexport interface searchSightedBrandsOperation {\n readonly path: \"/v1/advertiser/measurement/brands\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Brands to return. */\n limit?: number;\n /** Brand name as typed. Empty: the most-read brands. */\n q?: string;\n};\n response: DataApi_DataProducts_BrandSearchResponse;\n}\n\n/**\n * The calibration panel: P(readable) and P(facing) per format, road class, speed, daypart and bearing.\n * GET /v1/advertiser/measurement/calibration\n */\nexport interface getMeasurementCalibrationOperation {\n readonly path: \"/v1/advertiser/measurement/calibration\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One calibration. */\n calibration?: \"readable\" | \"facing\";\n /** A version id (mcal-2026-09-26-cv3-pa6-b1). Absent: the newest. */\n calibration_id?: string;\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** One instrument. */\n instrument?: string;\n /** One unit. */\n unit?: string;\n};\n response: DataApi_DataProducts_CalibrationResponse;\n}\n\n/**\n * Every verified calibration version, to pin a calibration_id from.\n * GET /v1/advertiser/measurement/calibration/versions\n */\nexport interface listMeasurementCalibrationVersionsOperation {\n readonly path: \"/v1/advertiser/measurement/calibration/versions\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Versions to return (default 52). */\n limit?: number;\n};\n response: DataApi_DataProducts_CalibrationVersionsResponse;\n}\n\n/**\n * The curated board sets (approved packages) with their measured coverage.\n * GET /v1/advertiser/measurement/curation-sets\n */\nexport interface listCurationSetsOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Page size (default 200). */\n limit?: number;\n /** Page offset. */\n offset?: number;\n /** Search the set names. */\n q?: string;\n};\n response: DataApi_DataProducts_CurationSetListResponse;\n}\n\n/**\n * The measured coverage of one curated set.\n * GET /v1/advertiser/measurement/curation-sets/{setKey}/coverage\n */\nexport interface getCurationSetCoverageOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets/{setKey}/coverage\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A curated set key, as listed by /curation-sets. */\n setKey: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_SetCoverageEnvelope;\n}\n\n/**\n * The roads that serve a curated set, with the traffic index and speeds.\n * GET /v1/advertiser/measurement/curation-sets/{setKey}/roads.geojson\n */\nexport interface getCurationSetRoadsOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets/{setKey}/roads.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A curated set key, as listed by /curation-sets. */\n setKey: string;\n};\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** Day-of-week type (default weekday). */\n dow_type?: \"weekday\" | \"saturday\" | \"sunday\" | \"all\";\n /** Local hour 0-23. Absent: every hour. */\n hour?: number;\n /** traversal_index (default), speed or speed_ratio. */\n metric?: \"traversal_index\" | \"speed\" | \"speed_ratio\";\n /** Comma-separated OSM classes: motorway, motorway_link, trunk, trunk_link, primary, primary_link, secondary, secondary_link, tertiary, tertiary_link, unclassified, residential, living_street, service. */\n road_class?: string;\n};\n response: DataApi_DataProducts_RoadCollection;\n}\n\n/**\n * The viewsheds and face points of every member of a curated set.\n * GET /v1/advertiser/measurement/curation-sets/{setKey}/viewsheds.geojson\n */\nexport interface getCurationSetViewshedsOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets/{setKey}/viewsheds.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A curated set key, as listed by /curation-sets. */\n setKey: string;\n};\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox?: string;\n};\n response: DataApi_DataProducts_ViewshedCollection;\n}\n\n/**\n * The measured multiplier file for an SSP: per-face impression multipliers, or per-face demographics.\n * GET /v1/advertiser/measurement/feeds/multipliers\n */\nexport interface getMeasuredMultiplierFeedOperation {\n readonly path: \"/v1/advertiser/measurement/feeds/multipliers\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** multipliers (default), faces or demographics. */\n dataset?: \"multipliers\" | \"faces\" | \"demographics\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Three-digit DMA code. */\n dma?: string;\n /** Feed date. Absent: the newest. */\n feed_date?: string;\n /** json (default) or csv (text/csv attachment). */\n format?: \"json\" | \"csv\";\n /** SSP whose venue ids key the file: vistar (default), place_exchange, broadsign, hivestack, viooh, magnite, lmx. */\n ssp?: string;\n};\n response: DataApi_DataProducts_MultiplierFeedResponse;\n}\n\n/**\n * The DMA x format index: passes per board-week, legible seconds per pass and facing share against the US base.\n * GET /v1/advertiser/measurement/index\n */\nexport interface getMeasuredDmaFormatIndexOperation {\n readonly path: \"/v1/advertiser/measurement/index\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One DMA. */\n dma?: string;\n /** First week. */\n from?: string;\n /** Last week. */\n to?: string;\n};\n response: DataApi_DataProducts_DmaFormatIndexResponse;\n}\n\n/**\n * The approved metrics: every governed audience, camera, creative, seatbelt, board and panel answer you can buy.\n * GET /v1/advertiser/measurement/metrics\n */\nexport interface listApprovedMetricsOperation {\n readonly path: \"/v1/advertiser/measurement/metrics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: DataApi_DataProducts_MetricCatalogResponse;\n}\n\n/**\n * Measured impressions per spot (OOH board)\n * GET /v1/advertiser/measurement/metrics/board_measured_impressions_per_spot\n */\nexport interface getMetricBoardMeasuredImpressionsPerSpotOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/board_measured_impressions_per_spot\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Board face id (board metrics). */\n board_id?: string;\n /** Condition scope (board metrics): daypart, light, weather or speed. */\n by?: string;\n /** Daypart filter (board metrics). */\n daypart?: string;\n /** Currency window end (board metrics). */\n window_end?: string;\n};\n response: DataApi_DataProducts_MetricBoardMeasuredImpressionsPerSpotResponse;\n}\n\n/**\n * Who was in the cab during a board pass\n * GET /v1/advertiser/measurement/metrics/board_pass_audience\n */\nexport interface getMetricBoardPassAudienceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/board_pass_audience\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Board face id (board metrics). */\n board_id?: string;\n /** Daypart filter (board metrics). */\n daypart?: string;\n /** Currency window end (board metrics). */\n window_end?: string;\n};\n response: DataApi_DataProducts_MetricBoardPassAudienceResponse;\n}\n\n/**\n * Capped dwell per camera window\n * GET /v1/advertiser/measurement/metrics/camera_dwell_capped_ms\n */\nexport interface getMetricCameraDwellCappedMsOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_dwell_capped_ms\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraDwellCappedMsResponse;\n}\n\n/**\n * Gaze on screen per camera window\n * GET /v1/advertiser/measurement/metrics/camera_gaze_pct\n */\nexport interface getMetricCameraGazePctOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_gaze_pct\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraGazePctResponse;\n}\n\n/**\n * Head-pose index per camera window\n * GET /v1/advertiser/measurement/metrics/camera_head_pose_index\n */\nexport interface getMetricCameraHeadPoseIndexOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_head_pose_index\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** Comma-separated statistics (mean, p50, ...), from the metric's allowed stats. This metric's: `mean`, `spread`; default `mean`. */\n stats?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraHeadPoseIndexResponse;\n}\n\n/**\n * Camera people per screen-hour\n * GET /v1/advertiser/measurement/metrics/camera_people_per_screen_hour\n */\nexport interface getMetricCameraPeoplePerScreenHourOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_people_per_screen_hour\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_hour`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** Comma-separated statistics (mean, p50, ...), from the metric's allowed stats. This metric's: `mean`, `p95`, `spread`; default `mean`, `p95`. */\n stats?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraPeoplePerScreenHourResponse;\n}\n\n/**\n * Outdoor creative history by brand, metro and month (camera creative ledger)\n * GET /v1/advertiser/measurement/metrics/creative_brand_history\n */\nexport interface getMetricCreativeBrandHistoryOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_brand_history\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Agency names, |-separated (or repeated): the brands one of them holds as agency of record (Winmo), any case. */\n agencies?: string;\n /** Face keys, |-separated (or repeated): f:<board id>:<face index> or p:<point id>. */\n boards?: string;\n /** Comma-separated resolved brand ids. */\n brands?: string;\n /** Comma-separated IAB tier-1 codes (IAB1..IAB25): the brands of those categories. A slice filter narrows the denominators with the rows. */\n categories?: string;\n /** Comma-separated 5-digit Census CBSA codes (OMB July 2023 delineation). */\n cbsas?: string;\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Comma-separated dimensions (dimension= is the one-value spelling): the audience dimensions of a demographics metric (default all), or the slices creative_brand_history cuts its rows by (category, parent, agency, media_owner, format, surface, board, cbsa; default none), every share over its slice. This metric's: `category`, `parent`, `agency`, `media_owner`, `format`, `surface`, `board`, `cbsa`. */\n dimensions?: string;\n /** Comma-separated face formats: static, digital. */\n formats?: string;\n /** The answer grain; default `market_month`. */\n grain?: \"market_month\" | \"fleet_month\" | \"market_week\" | \"fleet_week\" | \"market_window\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** Media owner names, |-separated (or repeated): the faces whose registry owner holds a name's letters and digits, any case and punctuation. */\n media_owners?: string;\n /** Comma-separated brand graph ids: the brands whose parent company is in one of those Wikidata families. */\n parents?: string;\n /** Comma-separated reader surfaces: billboard, digital_board, bus_shelter, kiosk. */\n surfaces?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeBrandHistoryResponse;\n}\n\n/**\n * Outdoor share of voice by brand (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_share_of_voice\n */\nexport interface getMetricCreativeShareOfVoiceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_share_of_voice\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeShareOfVoiceResponse;\n}\n\n/**\n * Outdoor ad sightings (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_sightings\n */\nexport interface getMetricCreativeSightingsOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_sightings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_day`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeSightingsResponse;\n}\n\n/**\n * Street presence by brand and surface (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_street_presence\n */\nexport interface getMetricCreativeStreetPresenceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_street_presence\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeStreetPresenceResponse;\n}\n\n/**\n * Outdoor vacancy rate (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_vacancy_rate\n */\nexport interface getMetricCreativeVacancyRateOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_vacancy_rate\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeVacancyRateResponse;\n}\n\n/**\n * Demographic share\n * GET /v1/advertiser/measurement/metrics/demographic_share\n */\nexport interface getMetricDemographicShareOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/demographic_share\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Comma-separated dimensions (dimension= is the one-value spelling): the audience dimensions of a demographics metric (default all), or the slices creative_brand_history cuts its rows by (category, parent, agency, media_owner, format, surface, board, cbsa; default none), every share over its slice. This metric's: `activity_state`, `age`, `apparel_tier`, `attire`, `carried_items`, `cohort`, `device_engagement`, `diet`, `exposure_quality`, `gender`, `head_turn`, `income`, `intent`, `lifestage`, `lifestyle`, `mood`, `occupant_position`, `seatbelt_state`, `tech`, `venue`. */\n dimensions?: string;\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricDemographicShareResponse;\n}\n\n/**\n * Radio identifiers per person (in-cab calibration)\n * GET /v1/advertiser/measurement/metrics/radio_identifiers_per_person\n */\nexport interface getMetricRadioIdentifiersPerPersonOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/radio_identifiers_per_person\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `fleet_window`. */\n grain?: \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricRadioIdentifiersPerPersonResponse;\n}\n\n/**\n * Same-panel index (screen panel, month over month)\n * GET /v1/advertiser/measurement/metrics/same_panel_index\n */\nexport interface getMetricSamePanelIndexOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/same_panel_index\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `fleet_month`. */\n grain?: \"fleet_month\";\n /** The population the shares are over. */\n population?: \"camera\" | \"radio\";\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricSamePanelIndexResponse;\n}\n\n/**\n * Rear-seat seatbelt compliance (in-cab camera)\n * GET /v1/advertiser/measurement/metrics/seatbelt_compliance\n */\nexport interface getMetricSeatbeltComplianceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/seatbelt_compliance\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `screen_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\" | \"screen_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricSeatbeltComplianceResponse;\n}\n\n/**\n * Unbuckled-ride rate (in-cab camera, per ride)\n * GET /v1/advertiser/measurement/metrics/seatbelt_unbuckled_ride_rate\n */\nexport interface getMetricSeatbeltUnbuckledRideRateOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/seatbelt_unbuckled_ride_rate\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `screen_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\" | \"screen_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricSeatbeltUnbuckledRideRateResponse;\n}\n\n/**\n * Camera and sensing screen census\n * GET /v1/advertiser/measurement/metrics/sensing_census\n */\nexport interface getMetricSensingCensusOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/sensing_census\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `fleet_day`. */\n grain?: \"fleet_day\" | \"screen\";\n /** The population the shares are over. */\n population?: \"camera\" | \"radio\" | \"sensing\";\n};\n response: DataApi_DataProducts_MetricSensingCensusResponse;\n}\n\n/**\n * One approved metric answered for a day or window, at its grain.\n * GET /v1/advertiser/measurement/metrics/{metric}\n */\nexport interface getApprovedMetricOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/{metric}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** An approved metric name. */\n metric: \"camera_people_per_screen_hour\" | \"camera_dwell_capped_ms\" | \"camera_head_pose_index\" | \"camera_gaze_pct\" | \"demographic_share\" | \"sensing_census\" | \"board_measured_impressions_per_spot\" | \"board_pass_audience\" | \"same_panel_index\" | \"radio_identifiers_per_person\" | \"creative_sightings\" | \"creative_share_of_voice\" | \"creative_street_presence\" | \"creative_vacancy_rate\" | \"creative_brand_history\" | \"seatbelt_compliance\" | \"seatbelt_unbuckled_ride_rate\";\n};\n query: {\n /** Agency names, |-separated (or repeated): the brands one of them holds as agency of record (Winmo), any case. Taken by: creative_brand_history. */\n agencies?: string;\n /** Board face id (board metrics). Taken by: board_measured_impressions_per_spot, board_pass_audience. */\n board_id?: string;\n /** Face keys, |-separated (or repeated): f:<board id>:<face index> or p:<point id>. Taken by: creative_brand_history. */\n boards?: string;\n /** Comma-separated resolved brand ids. Taken by: creative_brand_history. */\n brands?: string;\n /** Condition scope (board metrics): daypart, light, weather or speed. Taken by: board_measured_impressions_per_spot. */\n by?: string;\n /** Comma-separated IAB tier-1 codes (IAB1..IAB25): the brands of those categories. A slice filter narrows the denominators with the rows. Taken by: creative_brand_history. */\n categories?: string;\n /** Comma-separated 5-digit Census CBSA codes (OMB July 2023 delineation). Taken by: creative_brand_history. */\n cbsas?: string;\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, sensing_census, same_panel_index, radio_identifiers_per_person, creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n day?: string;\n /** Daypart filter (board metrics). Taken by: board_measured_impressions_per_spot, board_pass_audience. */\n daypart?: string;\n /** Comma-separated dimensions (dimension= is the one-value spelling): the audience dimensions of a demographics metric (default all), or the slices creative_brand_history cuts its rows by (category, parent, agency, media_owner, format, surface, board, cbsa; default none), every share over its slice. Taken by: demographic_share, creative_brand_history. */\n dimensions?: string;\n /** Comma-separated face formats: static, digital. Taken by: creative_brand_history. */\n formats?: string;\n /** Camera evidence grade: face_backed or person_backed. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct. */\n grade?: string;\n /** The answer grain (screen_hour, screen_day, fleet_day, market_day, market_month, ...): one of the metric's grains. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, sensing_census, same_panel_index, radio_identifiers_per_person, creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n grain?: string;\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). Taken by: creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n markets?: string;\n /** Media owner names, |-separated (or repeated): the faces whose registry owner holds a name's letters and digits, any case and punctuation. Taken by: creative_brand_history. */\n media_owners?: string;\n /** Comma-separated brand graph ids: the brands whose parent company is in one of those Wikidata families. Taken by: creative_brand_history. */\n parents?: string;\n /** The population the shares are over. Taken by: sensing_census, same_panel_index. */\n population?: string;\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n screens?: string;\n /** Comma-separated statistics (mean, p50, ...), from the metric's allowed stats. Taken by: camera_people_per_screen_hour, camera_head_pose_index. */\n stats?: string;\n /** Comma-separated reader surfaces: billboard, digital_board, bus_shelter, kiosk. Taken by: creative_brand_history. */\n surfaces?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, same_panel_index, radio_identifiers_per_person, creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n window?: string;\n /** Currency window end (board metrics). Taken by: board_measured_impressions_per_spot, board_pass_audience. */\n window_end?: string;\n};\n response: DataApi_DataProducts_MetricAnswerResponse;\n}\n\n/**\n * The release registry: every monthly release of measured multipliers and every feed published from it.\n * GET /v1/advertiser/measurement/releases\n */\nexport interface listMeasurementReleasesOperation {\n readonly path: \"/v1/advertiser/measurement/releases\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Releases to return (default 24). */\n limit?: number;\n};\n response: DataApi_DataProducts_ReleaseRegistryResponse;\n}\n\n/**\n * The roads our fleet drove in a bbox, with the traffic index and speeds.\n * GET /v1/advertiser/measurement/roads.geojson\n */\nexport interface listMeasuredRoadsOperation {\n readonly path: \"/v1/advertiser/measurement/roads.geojson\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** Day-of-week type (default weekday). */\n dow_type?: \"weekday\" | \"saturday\" | \"sunday\" | \"all\";\n /** Local hour 0-23. Absent: every hour. */\n hour?: number;\n /** traversal_index (default), speed or speed_ratio. */\n metric?: \"traversal_index\" | \"speed\" | \"speed_ratio\";\n /** Comma-separated OSM classes: motorway, motorway_link, trunk, trunk_link, primary, primary_link, secondary, secondary_link, tertiary, tertiary_link, unclassified, residential, living_street, service. */\n road_class?: string;\n /** A curated set key. */\n set?: string;\n};\n response: DataApi_DataProducts_RoadCollection;\n}\n\n/**\n * Passes, legible and facing seconds summed per geohash cell over the entitled boards in a bbox.\n * GET /v1/advertiser/measurement/tiles.geojson\n */\nexport interface listMeasuredGeohashTilesOperation {\n readonly path: \"/v1/advertiser/measurement/tiles.geojson\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** First week. */\n from?: string;\n /** Geohash precision: 5 (default), 6 or 7. */\n precision?: number;\n /** Last week. */\n to?: string;\n};\n response: DataApi_DataProducts_GeohashTileCollection;\n}\n\n/**\n * Query API changelog\n * GET /v1/changelog\n */\nexport interface queryChangelogOperation {\n readonly path: \"/v1/changelog\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Only entries dated on or after this date (YYYY-MM-DD). Unreleased entries always included. */\n since?: string;\n /** Filter by change category: \"breaking\" (changed+removed), \"additive\" (added), \"deprecation\" (deprecated), \"fix\" (fixed). Comma-separated for multiple. */\n type?: string;\n};\n response: ChangelogResponse;\n}\n\n/**\n * Ad-sighting records: outdoor ads our cab cameras read, each with a signed photo link.\n * GET /v1/data/ad-sightings\n */\nexport interface dataApiAdSightingsOperation {\n readonly path: \"/v1/data/ad-sightings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** A board the sighting was matched to, repeatable. */\n board_id?: Array<string> | null;\n /** A brand, repeatable for a brand set (competitors). Matched however it is typed: \"McDonald's\", \"mcdonalds\" and \"Mc Donalds\" find the same records. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. Combined with `brand` as either-or. */\n brand_id?: Array<string> | null;\n /** The brand's IAB tier-1 category (IAB1..IAB25), repeatable: the records whose resolved brand votes in it (brand_knowledge_graph.iab_category, the `category` field). */\n category?: Array<string> | null;\n /** A sighted creative (the campaign artwork), repeatable. */\n creative_id?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** Start (inclusive), YYYY-MM-DD or an ISO-8601 instant. Default: 30 days before `to`. */\n from?: string;\n /** true returns only records that carry a photo (photo_url set): a record without a shareable face-blurred picture is skipped, so it is never returned or billed. The page can hold fewer than limit records; keep following next_cursor until it is null. */\n has_photo?: \"true\" | \"false\";\n /** The reading instrument (ssr-v2, ssr-v1, vlmtext-v1, edge_ocr_v1), repeatable. */\n instrument?: Array<string> | null;\n /** Records per page, 1..500 (default 50). The page limit is reserved; the records returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE (US DMA or CA CMA), repeatable. */\n market?: Array<string> | null;\n /** A media owner, repeatable: the records matched to a face whose owner (`publisher_name`, the registry's) holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)). */\n media_owner?: Array<string> | null;\n /** The surface kind as read (billboard, storefront, bus_shelter, ...), repeatable. */\n surface?: Array<string> | null;\n /** End (exclusive). Default: now. The span is at most 400 days. */\n to?: string;\n};\n response: DataApi_AdSightingsResponse;\n}\n\n/**\n * Outdoor creative history by brand, market and month, from the creative ledger.\n * GET /v1/data/ad-sightings/history\n */\nexport interface dataApiAdSightingsHistoryOperation {\n readonly path: \"/v1/data/ad-sightings/history\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Narrow to brands this agency holds as agency of record (Winmo), by name in any case, repeatable. */\n agency?: Array<string> | null;\n /** Narrow to faces by face key, repeatable for a set of boards: f:<board id>:<face index> (a registered face) or p:<point id> (an unregistered board point), the `face_key` a board slice answers with. */\n board?: Array<string> | null;\n /** A brand by name, repeatable (competitors). Resolved to its brand id the way the brand search does. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. */\n brand_id?: Array<string> | null;\n /** Narrow to brands of an IAB tier-1 category (IAB1..IAB25), repeatable. A slice filter narrows the denominators with the rows: the shares are within the categories named. */\n category?: Array<string> | null;\n /** Narrow to faces in a Census CBSA (5-digit code, OMB July 2023 delineation), repeatable. */\n cbsa?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** A slice the rows are cut by, repeatable: category, parent, agency (what the brand is), media_owner, format, surface, board, cbsa (where it ran). Each row is a brand within its slice, and every share is over its slice: a slice recomputes every denominator, and every distinct count is counted within it. The market vacancy is cut by where-it-ran slices only. */\n dimension?: Array<string> | null;\n /** Narrow to static or digital faces, repeatable. */\n format?: Array<string> | null;\n /** First month (YYYY-MM) or day. Default: 12 months before `to`. */\n from?: string;\n /** market_month (default) or fleet_month; market_week or fleet_week (ISO weeks from their Monday, each counted whole, every week the from..to span touches); market_window or fleet_window (the from..to span as one period). A fleet grain drops the market: with dimension=cbsa it is the CBSA geography. */\n grain?: \"market_month\" | \"fleet_month\" | \"market_week\" | \"fleet_week\" | \"market_window\" | \"fleet_window\";\n /** Rows per page, 1..500 (default 100). The page limit is reserved; the rows returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE, repeatable. */\n market?: Array<string> | null;\n /** Narrow to faces whose registry owner holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)), repeatable. */\n media_owner?: Array<string> | null;\n /** Narrow to brands whose parent company is in this brand graph id's family (the `parent_id` a parent slice answers with), repeatable. */\n parent?: Array<string> | null;\n /** Narrow to faces of a reader surface (billboard, digital_board, bus_shelter, kiosk), repeatable. */\n surface?: Array<string> | null;\n /** Last month (YYYY-MM, inclusive) or day. Default: this month. */\n to?: string;\n};\n response: DataApi_AdSightingsHistoryResponse;\n}\n\n/**\n * Aggregate audience analytics for a time window.\n * GET /v1/data/aggregate\n */\nexport interface dataApiAggregateOperation {\n readonly path: \"/v1/data/aggregate\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Dimension to group aggregations by. */\n group_by?: \"venue_type\" | \"daypart\" | \"day_of_week\" | \"income_estimated_level\" | \"primary_mood\";\n /** Metric to aggregate on. */\n metric?: \"avg_face_count\" | \"avg_attention\" | \"income_confidence\" | \"max_face_count\";\n /** Relative time window (e.g. \"24h\", \"7d\"). */\n since?: string;\n};\n response: DataApi_AggregateResponse;\n}\n\n/**\n * Find screens with similar audience profiles.\n * GET /v1/data/lookalike\n */\nexport interface dataApiLookalikeScreensOperation {\n readonly path: \"/v1/data/lookalike\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Matches to return, 1-100. */\n limit?: number;\n /** The lowest similarity a match may have, 0-1 (default 0.7; 0 keeps every match that is not opposite). */\n min_similarity?: number;\n /** Internal screen identifier. */\n screen_id: string;\n};\n response: DataApi_LookalikeResponse;\n}\n\n/**\n * Composable query DSL over approved datasets.\n * POST /v1/data/query\n */\nexport interface dataApiQueryDslOperation {\n readonly path: \"/v1/data/query\";\n readonly method: \"POST\";\n request: DataApi_QueryDslBody;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: DataApi_QueryDslResponse;\n}\n\n/**\n * List screens visible to the caller.\n * GET /v1/data/screens\n */\nexport interface dataApiListScreensOperation {\n readonly path: \"/v1/data/screens\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** ISO-3166 alpha-2 country code. */\n country?: string;\n /** Screens per page, 1-200. */\n limit?: number;\n /** Screens to skip; the previous page's `next_offset`. */\n offset?: number;\n /** Filter by venue taxonomy type (e.g. bar, restaurant). */\n venue_type?: string;\n};\n response: DataApi_ScreensListResponse;\n}\n\n/**\n * Real-time audience snapshot for a screen.\n * GET /v1/data/screens/{screenId}/audience\n */\nexport interface dataApiScreenAudienceLiveOperation {\n readonly path: \"/v1/data/screens/{screenId}/audience\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Internal screen identifier. */\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_ScreenAudienceResponse;\n}\n\n/**\n * Historical audience_metrics rows for a screen.\n * GET /v1/data/screens/{screenId}/history\n */\nexport interface dataApiScreenAudienceHistoryOperation {\n readonly path: \"/v1/data/screens/{screenId}/history\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Internal screen identifier. */\n screenId: string;\n};\n query: {\n /** Windows to return, newest first, 1-1000 (default 100). */\n limit?: number;\n /** ISO-8601 start timestamp. */\n since?: string;\n /** ISO-8601 end timestamp. */\n until?: string;\n};\n response: DataApi_ScreenHistoryResponse;\n}\n\n/**\n * Similarity search over scene embeddings.\n * GET /v1/data/semantic-search\n */\nexport interface dataApiSemanticSearchOperation {\n readonly path: \"/v1/data/semantic-search\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Matches to return, 1-100. */\n limit?: number;\n /** The lowest cosine similarity a match may have, 0-1. */\n min_similarity?: number;\n /** What to find, in words (3-512 characters): \"people waiting for a train\". */\n q: string;\n /** Relative time window (e.g. \"24h\", \"7d\"). */\n since?: string;\n};\n response: DataApi_SemanticSearchResponse;\n}\n\n/**\n * Platform-wide counters.\n * GET /v1/data/stats\n */\nexport interface dataApiStatsOperation {\n readonly path: \"/v1/data/stats\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: DataApi_StatsResponse;\n}\n\n/**\n * Server-Sent Events stream of live audience/observation events.\n * GET /v1/data/stream\n */\nexport interface dataApiStreamOperation {\n readonly path: \"/v1/data/stream\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Only events of this observation family (screen_audience, ...). */\n observation_family?: string;\n /** Only events from screens of this venue type (transit, retail, ...). */\n venue_type?: string;\n};\n response: unknown;\n}\n\n/**\n * API usage for the authenticated key (billing dashboard).\n * GET /v1/data/usage\n */\nexport interface dataApiUsageOperation {\n readonly path: \"/v1/data/usage\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Days of usage to sum, 1-90. */\n days?: number;\n};\n response: DataApi_UsageResponse;\n}\n\n/**\n * List all error codes\n * GET /v1/errors\n */\nexport interface listErrorCodesOperation {\n readonly path: \"/v1/errors\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: ErrorListResponse;\n}\n\n/**\n * Look up a single error code\n * GET /v1/errors/{code}\n */\nexport interface getErrorCodeOperation {\n readonly path: \"/v1/errors/{code}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A stable error code from the catalog. See GET /v1/errors for the full list. */\n code: string;\n};\n query: Record<string, unknown>;\n response: ErrorCodeResponse;\n}\n\n/**\n * The pass audience of an owned face.\n * GET /v1/owner/measurement/boards/{boardId}/audience\n */\nexport interface getOwnerBoardAudienceOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/audience\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardAudienceResponse;\n}\n\n/**\n * The currency of an owned face, with the owner comparison, yield and money.\n * GET /v1/owner/measurement/boards/{boardId}/currency\n */\nexport interface getOwnerBoardCurrencyOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/currency\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Split the cells by daypart (default), light, weather or speed. */\n by?: \"daypart\" | \"light\" | \"weather\" | \"speed\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Measurement window end (YYYY-MM-DD). Absent: the newest published window. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardCurrencyResponse;\n}\n\n/**\n * The DOOH delivery report: what one face aired over a flight and the measured impressions it delivered.\n * GET /v1/owner/measurement/boards/{boardId}/delivery-report\n */\nexport interface getOwnerDeliveryReportOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/delivery-report\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** json or csv. */\n format?: \"json\" | \"csv\";\n /** First flight day. */\n from?: string;\n /** Last flight day. */\n to?: string;\n};\n response: DataApi_DataProducts_DeliveryReportResponse;\n}\n\n/**\n * How much of the time passengers were turned toward an owned face, per instrument.\n * GET /v1/owner/measurement/boards/{boardId}/looked-share\n */\nexport interface getOwnerBoardLookedShareOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/looked-share\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First local date. */\n from?: string;\n /** Last local date. */\n to?: string;\n};\n response: DataApi_DataProducts_BoardLookedShareResponse;\n}\n\n/**\n * The week x daypart tiles of an owned face.\n * GET /v1/owner/measurement/boards/{boardId}/tiles\n */\nexport interface getOwnerBoardTilesOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/tiles\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First week (snaps to its Monday). */\n from?: string;\n /** Last week (snaps to its Monday). */\n to?: string;\n};\n response: DataApi_DataProducts_BoardTilesResponse;\n}\n\n/**\n * The viewshed of an owned face.\n * GET /v1/owner/measurement/boards/{boardId}/viewshed.geojson\n */\nexport interface getOwnerBoardViewshedOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/viewshed.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_ViewshedCollection;\n}\n\n/**\n * Every face the media owner holds, measured: impressions per spot beside its own figure, yield, money, facing and rank.\n * GET /v1/owner/measurement/faces\n */\nexport interface listOwnerFacesOperation {\n readonly path: \"/v1/owner/measurement/faces\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** Window end. Absent: the newest. */\n window_end?: string;\n};\n response: DataApi_DataProducts_OwnerFacesResponse;\n}\n\n/**\n * One owned face in full: currency, audience, spec, SSP venue ids, benchmark and release cells.\n * GET /v1/owner/measurement/faces/{boardId}\n */\nexport interface getOwnerFaceOperation {\n readonly path: \"/v1/owner/measurement/faces/{boardId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_OwnerFaceResponse;\n}\n\n/**\n * The measured multiplier file for the owner's faces.\n * GET /v1/owner/measurement/feeds/multipliers\n */\nexport interface getOwnerMultiplierFeedOperation {\n readonly path: \"/v1/owner/measurement/feeds/multipliers\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** multipliers (default), faces or demographics. */\n dataset?: \"multipliers\" | \"faces\" | \"demographics\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Three-digit DMA code. */\n dma?: string;\n /** Feed date. Absent: the newest. */\n feed_date?: string;\n /** json (default) or csv (text/csv attachment). */\n format?: \"json\" | \"csv\";\n /** SSP whose venue ids key the file: vistar (default), place_exchange, broadsign, hivestack, viooh, magnite, lmx. */\n ssp?: string;\n};\n response: DataApi_DataProducts_MultiplierFeedResponse;\n}\n\n/**\n * Send a proof-of-play log or an ad server flight schedule (CSV) for your faces.\n * POST /v1/owner/measurement/logs\n */\nexport interface uploadOwnerPlayLogsOperation {\n readonly path: \"/v1/owner/measurement/logs\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** The file holds every play of each face-day it names. */\n complete?: \"true\" | \"false\";\n /** Answer the plan, write nothing. */\n dry_run?: \"true\" | \"false\";\n /** The file's name (or send X-Filename). */\n filename?: string;\n /** The reader. */\n format?: \"generic\" | \"flight\";\n};\n response: DataApi_DataProducts_OwnerUploadResponse;\n}\n\n/**\n * The publisher yield report, the publisher named in the query string.\n * GET /v1/owner/measurement/publishers/yield\n */\nexport interface getOwnerPublisherYieldByQueryOperation {\n readonly path: \"/v1/owner/measurement/publishers/yield\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** One DMA. */\n dma?: string;\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** Publisher name. */\n publisher: string;\n /** OpenOOH venue type id. */\n venue_type?: string;\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_YieldReportResponse;\n}\n\n/**\n * The publisher yield report: every face measured against the owner's own figure.\n * GET /v1/owner/measurement/publishers/{publisher}/yield\n */\nexport interface getOwnerPublisherYieldOperation {\n readonly path: \"/v1/owner/measurement/publishers/{publisher}/yield\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Publisher name. */\n publisher: string;\n};\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** One DMA. */\n dma?: string;\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** OpenOOH venue type id. */\n venue_type?: string;\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_YieldReportResponse;\n}\n\n/**\n * The release registry, on the owner mount.\n * GET /v1/owner/measurement/releases\n */\nexport interface listOwnerMeasurementReleasesOperation {\n readonly path: \"/v1/owner/measurement/releases\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Releases to return. */\n limit?: number;\n};\n response: DataApi_DataProducts_ReleaseRegistryResponse;\n}\n\n/**\n * Send a face specification sheet (CSV): size, mount, facing, format, illumination and SSP venue ids per face.\n * POST /v1/owner/measurement/specs\n */\nexport interface uploadOwnerFaceSpecsOperation {\n readonly path: \"/v1/owner/measurement/specs\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Answer the plan, write nothing. */\n dry_run?: \"true\" | \"false\";\n};\n response: DataApi_DataProducts_OwnerUploadResponse;\n}\n\n/**\n * List self-promo ads\n * GET /v1/partner/ads/self-promo\n */\nexport interface listPartnerSelfPromoAdsOperation {\n readonly path: \"/v1/partner/ads/self-promo\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<PartnerSelfPromoAd>;\n success?: boolean;\n};\n}\n\n/**\n * Create self-promo ad (URL-based)\n * POST /v1/partner/ads/self-promo\n */\nexport interface createPartnerSelfPromoAdOperation {\n readonly path: \"/v1/partner/ads/self-promo\";\n readonly method: \"POST\";\n request: PartnerSelfPromoCreate;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: PartnerSelfPromoAd;\n success?: boolean;\n warnings?: PartnerCreativeWarnings;\n};\n}\n\n/**\n * List self-promo placements by screen\n * GET /v1/partner/ads/self-promo/placements\n */\nexport interface listPartnerSelfPromoPlacementsOperation {\n readonly path: \"/v1/partner/ads/self-promo/placements\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<PartnerSelfPromoPlacement>;\n success?: boolean;\n};\n}\n\n/**\n * Schedule existing self-promo ad to screens\n * POST /v1/partner/ads/self-promo/schedule\n */\nexport interface schedulePartnerSelfPromoOperation {\n readonly path: \"/v1/partner/ads/self-promo/schedule\";\n readonly method: \"POST\";\n request: {\n ad_id: string;\n end_date?: string;\n screen_ids: Array<string>;\n start_date?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Create self-promo ad (upload)\n * POST /v1/partner/ads/self-promo/upload\n */\nexport interface createPartnerSelfPromoUploadOperation {\n readonly path: \"/v1/partner/ads/self-promo/upload\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: PartnerSelfPromoAd;\n success?: boolean;\n warnings?: PartnerCreativeWarnings;\n};\n}\n\n/**\n * Disable a self-promo ad\n * POST /v1/partner/ads/self-promo/{ad_id}/disable\n */\nexport interface disableSelfPromoAdOperation {\n readonly path: \"/v1/partner/ads/self-promo/{ad_id}/disable\";\n readonly method: \"POST\";\n request: never;\n params: {\n ad_id: string;\n};\n query: Record<string, unknown>;\n response: {\n ad_id?: string;\n status?: \"disabled\";\n};\n}\n\n/**\n * Register an AI agent\n * POST /v1/partner/agent/register\n */\nexport interface registerAgentOperation {\n readonly path: \"/v1/partner/agent/register\";\n readonly method: \"POST\";\n request: {\n /** Type of agent being registered */\n agent_type: \"dsp_agent\" | \"ssp_agent\" | \"trading_desk\" | \"analytics_platform\" | \"developer\";\n /** Company name (optional) */\n company?: string;\n /** Brief description of the agent's purpose */\n description?: string;\n /** Contact email */\n email: string;\n /** Agent or company name */\n name: string;\n /** Mint an AdCP **sandbox account** (`account.sandbox` in `get_adcp_capabilities`). Media buys made with the returned key validate end to end — screen resolution, published CPM/floor, flight parsing, derived impression goal, every error path — and return a well-formed response marked `sandbox: true`, but persist **no advertisements and no placements**. Nothing can serve, deliver, bill, or pay a venue. Use this for conformance and no-spend testing; register without it for a live account. */\n sandbox?: boolean;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** The AdCP **account** this key is bound to. Distinct from the `sandbox` block below, which describes auto-provisioned test SCREENS (supply); this is the account-level buying contract (demand) declared as `account.sandbox` in `get_adcp_capabilities`. */\n account?: {\n /** Seller-assigned account id. Same value as `partner_id`. */\n account_id?: string;\n note?: string;\n /** True when this is a sandbox account: its media buys write no advertisements and no placements, and every media-buy tool response is marked `sandbox: true`. */\n sandbox?: boolean;\n };\n agent_type?: string;\n /** API key for authentication (display once — save it!) */\n api_key?: string;\n /** MCP tools available to this agent */\n available_tools?: Array<string>;\n /** Exact same-key handoff for buyer/OpenRTB control-plane capabilities. */\n control_plane_onboarding?: {\n authorization?: string;\n endpoint?: string;\n method?: string;\n purpose?: string;\n reuses_api_key?: boolean;\n };\n docs_url?: string;\n /** Free tier limits per product */\n free_tiers?: Record<string, unknown>;\n mcp_endpoint?: string;\n mcp_transport?: string;\n /** Guidance for getting started */\n next_steps?: Array<string>;\n object?: string;\n /** Unique partner ID */\n partner_id?: string;\n pricing_url?: string;\n request_id?: string;\n /** Auto-provisioned test SCREENS (supply side). Unrelated to `account.sandbox`. */\n sandbox?: {\n note?: string;\n screens?: Array<{\n device_id?: string;\n name?: string;\n venue_type?: string;\n }>;\n };\n tools_url?: string;\n};\n}\n\n/**\n * Get partner analytics\n * GET /v1/partner/analytics\n */\nexport interface getAnalyticsOperation {\n readonly path: \"/v1/partner/analytics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n end_date?: string;\n start_date?: string;\n};\n response: {\n data?: {\n devices_by_status?: Array<Record<string, unknown>>;\n impressions_by_day?: Array<{\n /** Date (YYYY-MM-DD) */\n _id?: string;\n impressions?: number;\n }>;\n partner?: {\n active_devices?: number;\n pending_payout_cents?: number;\n total_devices?: number;\n total_impressions?: number;\n total_revenue_cents?: number;\n };\n period?: {\n end?: string;\n start?: string;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * Visitor-flow continuity graph across the partner's screens\n * GET /v1/partner/analytics/audience-continuity\n */\nexport interface getAudienceContinuityOperation {\n readonly path: \"/v1/partner/analytics/audience-continuity\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n windowMinutes?: number;\n};\n response: {\n data?: {\n confidence?: string;\n sampleSize?: number;\n topPaths?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Audience composition for the partner's screens\n * GET /v1/partner/analytics/audience-profile\n */\nexport interface getAudienceProfileOperation {\n readonly path: \"/v1/partner/analytics/audience-profile\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n sampleSize?: number;\n segments?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * BLE device discovery summary\n * GET /v1/partner/analytics/ble-summary\n */\nexport interface getBleSummaryOperation {\n readonly path: \"/v1/partner/analytics/ble-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n totalObservations?: number;\n uniqueDevices?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Content performance — ad lineage and measured audience reactions\n * GET /v1/partner/analytics/content-performance\n */\nexport interface getContentPerformanceOperation {\n readonly path: \"/v1/partner/analytics/content-performance\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n groupBy?: \"canonical\" | \"wrapper\";\n includeUnclassified?: boolean;\n limit?: number;\n offset?: number;\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n byScreen?: Record<string, unknown>;\n creativeResponse?: Array<{\n adId?: string;\n advertiserName?: string;\n ageRating?: string;\n attentiveSeconds?: number;\n audioTerms?: Array<string>;\n avgAttention?: number;\n brandName?: string;\n confidence?: number;\n firstSeen?: string;\n iabCategories?: Array<string>;\n lastSeen?: string;\n moderationStatus?: string;\n plays?: number;\n viewers?: number;\n }>;\n /** Whether another page of creativeResponse exists after this one. */\n has_more?: boolean;\n nextOffset?: number | null;\n topAdvertisers?: Array<Record<string, unknown>>;\n /** Exact number of cards the cursor walks: the feed statement's count over every filter, taken before the page slice. Every page holds exactly `limit` cards except the last, so a walk at any page size reaches the end in ceil(total / limit) pages, and `nextOffset`/`has_more` describe the same set. Null when the feed could not be read (`degraded_fields` then lists `creativeResponse`). Describes the programmatic cursor; the offset-0 all-content block is additive. */\n total?: number | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Free-text search across the partner's creative catalogue\n * GET /v1/partner/analytics/creative-catalog\n */\nexport interface searchCreativeCatalogOperation {\n readonly path: \"/v1/partner/analytics/creative-catalog\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n q?: string;\n};\n response: {\n data?: {\n creatives?: Array<{\n adId?: string;\n advertiserName?: string;\n assetUrl?: string | null;\n brandName?: string;\n iabCategories?: Array<string>;\n moderationStatus?: string;\n }>;\n /** Whether another page of results exists after this one. */\n has_more?: boolean;\n nextOffset?: number | null;\n /** Always null for catalogue search: the read over-fetches limit+1 for a free `has_more`, but an exact total would need a second COUNT round-trip the search path deliberately avoids. Page to completion via `has_more`. */\n total?: number | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Everything your screens measured while a creative played\n * GET /v1/partner/analytics/creative-observations\n */\nexport interface getCreativeObservationsOperation {\n readonly path: \"/v1/partner/analytics/creative-observations\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n adId?: string;\n adIds?: string;\n contentSha256?: string;\n creativeId?: string;\n exact?: boolean;\n families?: string;\n from?: string;\n identity?: string;\n playLimit?: number;\n screenId?: string;\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\" | \"historical\";\n to?: string;\n};\n response: {\n code?: number;\n data?: {\n /** One rollup per creative (identity_key), every family with its count. */\n creatives?: Array<Record<string, unknown>>;\n /** Families that could not be read this time (their values are null). Absent when every family answered. */\n degraded_fields?: Array<string>;\n /** Why each family in degraded_fields was not read, keyed by family: `read_failed` (with its `code`); `pg_budget` for verified attention read on its Postgres home that did not finish within its budget (`budget_ms`), with the plays it read (`plays_read_n` of `plays_total_n`, `page_plays_read_n` of `page_plays_total_n`; a part read is never returned as the whole); `over_play_limit` with `limit` and `plays_total_n`. Absent when every family answered. */\n degraded_reasons?: Record<string, {\n budget_ms?: number;\n code?: string;\n limit?: number;\n page_plays_read_n?: number;\n page_plays_total_n?: number;\n plays_read_n?: number;\n plays_total_n?: number;\n reason: \"read_failed\" | \"pg_budget\" | \"over_play_limit\";\n }>;\n families?: Array<string>;\n /** The keys read, whether the read was exact, and the files and canonicals they resolved to. */\n identity?: Record<string, unknown>;\n /** The newest plays, each with its creative and every family read for it. */\n plays?: Array<Record<string, unknown>>;\n /** Every play of the creatives in the window, programmatic and supplied. */\n plays_total?: number;\n screen_ids?: Array<string>;\n /** The supplied plays read (plays_n, evidence_plays_n); null when the family was not read. */\n supplied?: Record<string, unknown> | null;\n window?: {\n from?: string;\n to?: string;\n };\n };\n message?: string;\n status?: boolean;\n};\n}\n\n/**\n * Scene-level observations for a played creative\n * GET /v1/partner/analytics/creative-scenes\n */\nexport interface getCreativeScenesOperation {\n readonly path: \"/v1/partner/analytics/creative-scenes\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n adId?: string;\n cursor?: string;\n exact?: boolean;\n identity?: string;\n limit?: number;\n screenId?: string;\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n /** The adId read; absent on an identity read. */\n adId?: string;\n /** The identity keys read (an identity read only). */\n identity?: string;\n nextCursor?: string | null;\n scenes?: Array<Record<string, unknown>>;\n /** The screen read; absent on an identity read across all your screens. */\n screenId?: string;\n timeRange?: string;\n total?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Per-pair flow directionality + transition heatmap\n * GET /v1/partner/analytics/cross-screen-flow\n */\nexport interface getCrossScreenFlowOperation {\n readonly path: \"/v1/partner/analytics/cross-screen-flow\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n edges?: Array<Record<string, unknown>>;\n screens?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Unified portfolio dashboard (earnings, ads, audience, screens, insights)\n * GET /v1/partner/analytics/dashboard\n */\nexport interface getPartnerAnalyticsDashboardOperation {\n readonly path: \"/v1/partner/analytics/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n endDate?: string;\n period?: \"7d\" | \"30d\" | \"90d\" | \"custom\";\n startDate?: string;\n};\n response: {\n data?: {\n ads?: Record<string, unknown>;\n audience?: Record<string, unknown>;\n earnings?: {\n change?: Record<string, unknown>;\n current?: Record<string, unknown>;\n previous?: Record<string, unknown>;\n sparkline?: Array<Record<string, unknown>>;\n };\n insights?: Array<Record<string, unknown>>;\n period?: {\n endDate?: string | null;\n label?: string;\n startDate?: string | null;\n };\n screens?: Record<string, unknown>;\n topScreens?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Device-type / OS / browser-class distribution among repeat visitors\n * GET /v1/partner/analytics/device-suite-signature\n */\nexport interface getDeviceSuiteSignatureOperation {\n readonly path: \"/v1/partner/analytics/device-suite-signature\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n deviceTypes?: Array<Record<string, unknown>>;\n totalDevices?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * CSV export of partner-scope analytics (summary / daily / per-screen)\n * GET /v1/partner/analytics/export\n */\nexport interface exportPartnerAnalyticsOperation {\n readonly path: \"/v1/partner/analytics/export\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n endDate?: string;\n period?: \"7d\" | \"30d\" | \"90d\" | \"custom\";\n startDate?: string;\n type?: \"summary\" | \"daily-breakdown\" | \"screen-breakdown\";\n};\n response: unknown;\n}\n\n/**\n * Per-ad daily breakdown for the partner fleet\n * GET /v1/partner/analytics/export/ads-by-day\n */\nexport interface exportPartnerAdsByDayOperation {\n readonly path: \"/v1/partner/analytics/export/ads-by-day\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n endDate: string;\n format?: \"csv\" | \"json\";\n startDate: string;\n};\n response: {\n data?: Array<{\n ad_name?: string;\n advertiser_name?: string;\n campaign_type?: string;\n completion_rate?: number;\n date?: string;\n gross_revenue_cents?: number;\n plays_completed?: number;\n publisher_revenue_cents?: number;\n publisher_share_rate?: number;\n screen_name?: string;\n }>;\n status?: boolean;\n};\n}\n\n/**\n * 24-hour distribution across the partner's fleet\n * GET /v1/partner/analytics/fleet-hourly\n */\nexport interface getFleetHourlyOperation {\n readonly path: \"/v1/partner/analytics/fleet-hourly\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n /** One entry per hour of the day. A partner with no screens gets the empty form `{ hours: [], timeRange }` instead of an array. */\n data?: Array<Record<string, unknown>> | {\n hours?: Array<Record<string, unknown>>;\n timeRange?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * 4-stage discovery → awareness → engagement → conversion funnel\n * GET /v1/partner/analytics/halo-funnel\n */\nexport interface getHaloFunnelOperation {\n readonly path: \"/v1/partner/analytics/halo-funnel\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n stages?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * 24-hour returning-vs-first-timer audience clock\n * GET /v1/partner/analytics/loyalty-clock\n */\nexport interface getLoyaltyClockOperation {\n readonly path: \"/v1/partner/analytics/loyalty-clock\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n hours?: Array<{\n firstTimerShare?: number;\n hour?: number;\n returningShare?: number;\n sampleSize?: number;\n }>;\n sampleSize?: number;\n timeRange?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * Fleet-wide audience summary for the partner's screens\n * GET /v1/partner/analytics/network-summary\n */\nexport interface getNetworkSummaryOperation {\n readonly path: \"/v1/partner/analytics/network-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n dataAvailable?: boolean;\n queriedAt?: string;\n timeRange?: string;\n totalScreens?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Daily/hourly fleet-wide audience timeseries\n * GET /v1/partner/analytics/network-trend\n */\nexport interface getNetworkTrendOperation {\n readonly path: \"/v1/partner/analytics/network-trend\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n interval?: \"1h\" | \"1d\";\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n /** One bucket per `interval`. A partner with no screens gets the empty form `{ series: [], interval, timeRange }` instead of an array. */\n data?: Array<Record<string, unknown>> | {\n interval?: string;\n series?: Array<Record<string, unknown>>;\n timeRange?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * Cross-screen proximity-graph summary\n * GET /v1/partner/analytics/proximity-summary\n */\nexport interface getProximitySummaryOperation {\n readonly path: \"/v1/partner/analytics/proximity-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n continuityEdges?: Array<Record<string, unknown>>;\n crossScreenSignals?: number;\n gateDiagnostic?: Record<string, unknown>;\n repeatSignals?: number;\n sourceBreakdown?: Record<string, unknown>;\n topPaths?: Array<Record<string, unknown>>;\n uniqueSignals?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Per-creative scatter of avg-attention vs revenue-per-impression\n * GET /v1/partner/analytics/revenue-attention-correlation\n */\nexport interface getRevenueAttentionCorrelationOperation {\n readonly path: \"/v1/partner/analytics/revenue-attention-correlation\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n points?: Array<Record<string, unknown>>;\n trendLine?: Record<string, unknown> | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Paginated chronological feed of scene observations\n * GET /v1/partner/analytics/scene-feed\n */\nexport interface getSceneFeedOperation {\n readonly path: \"/v1/partner/analytics/scene-feed\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n /** Distinct calendar days with observations over the last 90 days. */\n activeDays?: number;\n /** Whether another page exists after this one. */\n has_more?: boolean;\n nextOffset?: number | null;\n scenes?: Array<Record<string, unknown>>;\n /** Distinct observations within the feed window — the exact set the feed pages over. */\n total?: number;\n /** Distinct (screen, scene-prefix) observations over the last 90 days (gamification stat; independent of the page window). */\n totalObservations?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Latest scene description per screen\n * GET /v1/partner/analytics/scene-intelligence\n */\nexport interface getSceneIntelligenceOperation {\n readonly path: \"/v1/partner/analytics/scene-intelligence\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Present on EVERY response, success included. A field that appeared only on failure would make its absence the signal, and an absent field is indistinguishable from an old client or a version skew. */\n sceneDiagnostic: {\n /** True when the scene read completed and `scenes` reflects the fleet. False when it did not run to completion — `scenes` is then empty for want of an answer, not because the fleet is quiet. */\n measured: boolean;\n /** Null when `measured` is true. Otherwise names the operational failure. */\n reason: \"timeout\" | \"error\" | \"dependency_disabled\" | \"unknown\" | null | null;\n };\n scenes: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Rotate API key\n * POST /v1/partner/api-key/rotate\n */\nexport interface rotateApiKeyOperation {\n readonly path: \"/v1/partner/api-key/rotate\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** New API key — shown only once! */\n api_key?: string;\n grace_period_hours?: number;\n message?: string;\n /** When the old key stops working */\n previous_key_expires_at?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get partner-wide audience analytics\n * GET /v1/partner/audience-analytics\n */\nexport interface getAudienceAnalyticsOperation {\n readonly path: \"/v1/partner/audience-analytics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n period?: \"24h\" | \"7d\" | \"30d\";\n};\n response: AudienceAnalyticsResponse;\n}\n\n/**\n * Export audience data\n * GET /v1/partner/audience-export\n */\nexport interface exportAudienceDataOperation {\n readonly path: \"/v1/partner/audience-export\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n aggregation?: \"hourly\" | \"daily\" | \"weekly\";\n end_date?: string;\n format?: \"json\" | \"csv\";\n screen_ids: string;\n start_date?: string;\n};\n response: AudienceExportResponse;\n}\n\n/**\n * Get audience heatmap data\n * GET /v1/partner/audience/heatmap\n */\nexport interface getAudienceHeatmapOperation {\n readonly path: \"/v1/partner/audience/heatmap\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n days?: number;\n screen_ids?: string;\n};\n response: {\n cells?: number;\n heatmap?: Array<Record<string, unknown>>;\n lookback_days?: number;\n object?: string;\n request_id?: string;\n screens_included?: number;\n};\n}\n\n/**\n * Get live audience data for a screen\n * GET /v1/partner/audience/live/{screenId}\n */\nexport interface getLiveAudienceOperation {\n readonly path: \"/v1/partner/audience/live/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n /** Null when screen is offline */\n audience?: {\n ad_receptivity?: number | null;\n attention_score?: number;\n crowd_density?: number;\n dominant_ambience?: string | null;\n dwell_time_ms?: number | null;\n emotional_engagement?: number | null;\n face_count?: number;\n income_level?: string | null;\n lifestyle_segment?: string | null;\n mood?: string | null;\n noise_level?: number | null;\n occupancy?: string | null;\n /** The speech classifier's reading when the screen reported one (`BROWSING`, `RESEARCHING`, `COMPARING`, `READY_TO_BUY`, `POST_PURCHASE`, `COMPLAINING`, `NONE`), otherwise the segment the purchase-journey stage maps to (`high`, `medium`, `low`), otherwise null. */\n purchase_intent?: \"BROWSING\" | \"RESEARCHING\" | \"COMPARING\" | \"READY_TO_BUY\" | \"POST_PURCHASE\" | \"COMPLAINING\" | \"NONE\" | \"high\" | \"medium\" | \"low\" | null | null;\n } | null;\n last_updated?: string | null;\n /** Present when screen is offline */\n message?: string;\n object?: string;\n request_id?: string;\n screen_id?: string;\n status?: \"live\" | \"offline\";\n};\n}\n\n/**\n * Find lookalike screens\n * GET /v1/partner/audience/lookalikes/{screenId}\n */\nexport interface getLookalikeScreensOperation {\n readonly path: \"/v1/partner/audience/lookalikes/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n country?: string;\n limit?: number;\n min_similarity?: number;\n venue_type?: string;\n};\n response: {\n filters?: {\n country?: string | null;\n min_similarity?: number;\n venue_type?: string | null;\n };\n matches?: Array<Record<string, unknown>>;\n matches_count?: number;\n object?: string;\n request_id?: string;\n source_screen_id?: string;\n};\n}\n\n/**\n * Predict screen audience\n * GET /v1/partner/audience/predict/{screenId}\n */\nexport interface predictScreenAudienceOperation {\n readonly path: \"/v1/partner/audience/predict/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n day: number;\n hour: number;\n lookback_days?: number;\n};\n response: {\n day_of_week?: number;\n hour_utc?: number;\n lookback_days?: number;\n /** Present when prediction is null */\n message?: string;\n object?: string;\n /** Null if insufficient historical data */\n prediction?: Record<string, unknown> | null;\n request_id?: string;\n screen_id?: string;\n};\n}\n\n/**\n * Resolved household reach for a campaign\n * GET /v1/partner/audience/resolved-household-reach/{campaignId}\n */\nexport interface getResolvedHouseholdReachOperation {\n readonly path: \"/v1/partner/audience/resolved-household-reach/{campaignId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n campaignId: string;\n};\n query: Record<string, unknown>;\n response: {\n audience_composition?: Array<Record<string, unknown>>;\n campaign_id?: string;\n confidence_interval?: {\n lower?: number;\n upper?: number;\n };\n households_reached?: number;\n overlap_with_first_party?: number | null;\n};\n}\n\n/**\n * List audience segments\n * GET /v1/partner/audience/segments\n */\nexport interface listAudienceSegmentsOperation {\n readonly path: \"/v1/partner/audience/segments\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<AudienceSegment>;\n has_more?: boolean;\n object?: string;\n request_id?: string;\n total_count?: number;\n};\n}\n\n/**\n * Create audience segment\n * POST /v1/partner/audience/segments\n */\nexport interface createAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments\";\n readonly method: \"POST\";\n request: {\n description?: string;\n /** Segment name */\n name: string;\n rules: Array<{\n /** Rule field (e.g., venue_type, country, city, state) */\n field: string;\n /** Comparison operator (e.g., eq, neq, in, gt, lt) */\n operator: string;\n /** Rule value */\n value: unknown;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: AudienceSegment;\n}\n\n/**\n * Delete audience segment\n * DELETE /v1/partner/audience/segments/{segmentId}\n */\nexport interface deleteAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: {\n deleted?: boolean;\n id?: string;\n object?: string;\n request_id?: string;\n};\n}\n\n/**\n * Get audience segment\n * GET /v1/partner/audience/segments/{segmentId}\n */\nexport interface getAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: AudienceSegment;\n}\n\n/**\n * Update audience segment\n * PATCH /v1/partner/audience/segments/{segmentId}\n */\nexport interface updateAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}\";\n readonly method: \"PATCH\";\n request: {\n description?: string;\n is_active?: boolean;\n name?: string;\n rules?: Array<{\n field?: string;\n operator?: string;\n value?: unknown;\n }>;\n};\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: AudienceSegment;\n}\n\n/**\n * Match screens to segment\n * POST /v1/partner/audience/segments/{segmentId}/match\n */\nexport interface matchAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}/match\";\n readonly method: \"POST\";\n request: never;\n params: {\n segmentId: string;\n};\n query: {\n limit?: number;\n own_screens_only?: \"true\" | \"false\";\n};\n response: {\n matched_count?: number;\n matches?: Array<Record<string, unknown>>;\n object?: string;\n own_screens_only?: boolean;\n request_id?: string;\n segment_id?: string;\n segment_name?: string;\n};\n}\n\n/**\n * Estimate segment reach\n * POST /v1/partner/audience/segments/{segmentId}/reach\n */\nexport interface estimateSegmentReachOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}/reach\";\n readonly method: \"POST\";\n request: never;\n params: {\n segmentId: string;\n};\n query: {\n own_screens_only?: \"true\" | \"false\";\n};\n response: {\n country_breakdown?: Record<string, number>;\n estimated_daily_cpm?: number;\n estimated_daily_impressions?: number;\n estimated_daily_revenue?: number;\n has_historical_data?: boolean;\n matched_screens?: number;\n object?: string;\n online_screens?: number;\n segment_id?: string;\n segment_name?: string;\n venue_breakdown?: Record<string, number>;\n};\n}\n\n/**\n * Generate VAST tag for segment\n * POST /v1/partner/audience/segments/{segmentId}/vast-tag\n */\nexport interface generateSegmentVastTagOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}/vast-tag\";\n readonly method: \"POST\";\n request: {\n /** Click-through landing page URL */\n click_through?: string;\n /** Video creative URL */\n creative_url: string;\n /** Video duration in seconds */\n duration?: number;\n own_screens_only?: boolean;\n};\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: {\n creative?: {\n click_through?: string | null;\n duration?: number;\n url?: string;\n };\n cust_params?: Array<string>;\n object?: string;\n screen_ids?: Array<string>;\n segment_id?: string;\n segment_name?: string;\n targeted_screens?: number;\n vast_tag_url?: string;\n};\n}\n\n/**\n * Get audience data statistics\n * GET /v1/partner/audience/stats\n */\nexport interface getAudienceStatsOperation {\n readonly path: \"/v1/partner/audience/stats\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data_access_tier?: \"basic\" | \"developer\" | \"enterprise\";\n newest_data?: string | null;\n object?: string;\n oldest_data?: string | null;\n request_id?: string;\n screens_with_data?: number;\n total_screens?: number;\n total_vectors?: number;\n};\n}\n\n/**\n * Cancel the partner's subscription at period end\n * POST /v1/partner/billing/cancel\n */\nexport interface cancelBillingSubscriptionOperation {\n readonly path: \"/v1/partner/billing/cancel\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n effective_at?: string;\n status?: \"canceled\" | \"scheduled_for_cancellation\";\n};\n}\n\n/**\n * Purchase committed-use credits\n * POST /v1/partner/billing/credits\n */\nexport interface purchaseCreditsOperation {\n readonly path: \"/v1/partner/billing/credits\";\n readonly method: \"POST\";\n request: {\n /** Credit purchase tier */\n tier: \"tier_500\" | \"tier_2000\" | \"tier_5000\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** Amount charged in cents */\n charged_cents?: number;\n /** Present when Stripe confirmation requires action; handle as a secret */\n client_secret?: string;\n /** Verified credit added in exact decimal cents; zero until capture settles */\n credits_added_cents?: string;\n /** Legacy field name: additional credit as a percentage of the charged amount */\n discount_pct?: number;\n object?: string;\n /** Durable purchase operation identifier */\n operation_id?: string;\n /** Stripe PaymentIntent ID */\n payment_intent_id?: string;\n request_id?: string;\n /** Complete Stripe confirmation before credit can settle */\n requires_action?: boolean;\n /** Native Stripe PaymentIntent status */\n status?: string;\n};\n}\n\n/**\n * Create Stripe Checkout session for credits\n * POST /v1/partner/billing/credits/checkout\n */\nexport interface createCreditCheckoutOperation {\n readonly path: \"/v1/partner/billing/credits/checkout\";\n readonly method: \"POST\";\n request: {\n /** URL to redirect if payment is cancelled */\n cancel_url?: string;\n /** URL to redirect after successful payment */\n success_url?: string;\n tier: \"tier_500\" | \"tier_2000\" | \"tier_5000\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** Stripe Checkout URL — redirect user here */\n checkout_url?: string;\n message?: string;\n object?: string;\n /** Durable credit-purchase operation identifier */\n operation_id?: string;\n request_id?: string;\n /** Stripe Checkout session ID */\n session_id?: string;\n};\n}\n\n/**\n * List available partner billing plans\n * GET /v1/partner/billing/plans\n */\nexport interface listBillingPlansOperation {\n readonly path: \"/v1/partner/billing/plans\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n plans?: Array<{\n included_ads?: number;\n included_impressions?: number;\n overage_per_1k_impressions_cents?: number;\n price_cents_monthly?: number;\n tier?: string;\n }>;\n};\n}\n\n/**\n * Set up usage-based billing\n * POST /v1/partner/billing/setup\n */\nexport interface setupBillingOperation {\n readonly path: \"/v1/partner/billing/setup\";\n readonly method: \"POST\";\n request: {\n /** Stripe payment method token obtained from Stripe.js or Stripe Elements */\n payment_method_id: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n billing_status?: string;\n message?: string;\n object?: string;\n request_id?: string;\n stripe_customer_id?: string;\n};\n}\n\n/**\n * Subscribe the partner to a billing plan\n * POST /v1/partner/billing/subscribe\n */\nexport interface createBillingSubscriptionOperation {\n readonly path: \"/v1/partner/billing/subscribe\";\n readonly method: \"POST\";\n request: {\n tier: \"developer\" | \"enterprise\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n checkout_url?: string | null;\n status?: \"active\" | \"requires_payment\";\n};\n}\n\n/**\n * Get the partner's current subscription\n * GET /v1/partner/billing/subscription\n */\nexport interface getBillingSubscriptionOperation {\n readonly path: \"/v1/partner/billing/subscription\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n current_period_end?: string;\n status?: \"active\" | \"past_due\" | \"canceled\" | \"trialing\";\n stripe_customer_id?: string | null;\n tier?: string;\n};\n}\n\n/**\n * Get the partner's current-period usage\n * GET /v1/partner/billing/usage\n */\nexport interface getBillingUsageOperation {\n readonly path: \"/v1/partner/billing/usage\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n ads_served?: number;\n audience_api_calls?: number;\n impressions?: number;\n overage_projection_cents?: number;\n period_end?: string;\n period_start?: string;\n};\n}\n\n/**\n * Get current billing period usage\n * GET /v1/partner/billing/usage-summary\n */\nexport interface getBillingUsageSummaryOperation {\n readonly path: \"/v1/partner/billing/usage-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n billing_status: \"free\" | \"none\" | \"active\" | \"suspended\";\n /** Committed credit balance in cents, with eight decimal places */\n credit_balance_cents: string;\n /** Credit held by in-flight reservations, in cents with eight decimal places */\n credit_reserved_cents: string;\n object: string;\n /** Partner billing account identifier */\n partner_mongo_id: string;\n /** Exclusive end of the current UTC calendar month */\n period_end: string;\n period_start: string;\n products: Record<string, {\n meters: Record<string, {\n cost_cents: string;\n free_quantity: string;\n legacy_unknown_cents: string;\n paid_quantity: string;\n postpaid_cents: string;\n prepaid_cents: string;\n /** Total quantity in the published meter unit */\n total_quantity: string;\n }>;\n /** Product cost in cents with eight decimal places */\n total_cost_cents: string;\n }>;\n request_id: string;\n /** Period cost in cents with eight decimal places */\n total_cost_cents: string;\n};\n}\n\n/**\n * Stripe webhook callback\n * POST /v1/partner/billing/webhook\n */\nexport interface stripeWebhookCallbackOperation {\n readonly path: \"/v1/partner/billing/webhook\";\n readonly method: \"POST\";\n request: Record<string, unknown>;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * Get partner dashboard overview\n * GET /v1/partner/connect/dashboard\n */\nexport interface getConnectDashboardOperation {\n readonly path: \"/v1/partner/connect/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n period?: \"7d\" | \"30d\" | \"90d\";\n};\n response: {\n data?: {\n charts?: {\n daily_impressions?: Array<{\n date?: string;\n earnings_cents?: number;\n impressions?: number;\n }>;\n hourly_today?: Array<{\n hour?: number;\n impressions?: number;\n }>;\n };\n earnings?: {\n available_cents?: number;\n daily_average_cents?: number;\n lifetime_cents?: number;\n pending_payout_cents?: number;\n period_cents?: number;\n today_cents?: number;\n };\n impressions?: {\n all_time?: number;\n daily_average?: number;\n period?: number;\n today?: number;\n trend_percent?: number;\n };\n partner?: {\n cpm_cents?: number;\n name?: string;\n revenue_share_percent?: number;\n slug?: string;\n status?: string;\n stripe_status?: \"pending\" | \"active\" | \"restricted\" | \"not_connected\";\n };\n period?: {\n days?: number;\n end?: string;\n start?: string;\n };\n screens?: {\n offline?: number;\n online?: number;\n pending?: number;\n total?: number;\n };\n top_screens?: Array<{\n earnings_cents?: number;\n impressions?: number;\n location?: string | null;\n name?: string;\n screen_id?: string;\n status?: \"online\" | \"offline\" | \"unknown\";\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get earnings chart data\n * GET /v1/partner/connect/earnings\n */\nexport interface getConnectEarningsChartOperation {\n readonly path: \"/v1/partner/connect/earnings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n group_by?: \"day\" | \"week\";\n period?: \"7d\" | \"30d\" | \"90d\";\n};\n response: {\n data?: {\n chart?: Array<{\n avg_view_duration_ms?: number;\n date?: string;\n earnings_cents?: number;\n impressions?: number;\n label?: string;\n unique_screens?: number;\n }>;\n period?: {\n days?: number;\n end?: string;\n start?: string;\n };\n summary?: {\n data_points?: number;\n group_by?: string;\n total_earnings_cents?: number;\n total_impressions?: number;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * Get screen health status\n * GET /v1/partner/connect/health\n */\nexport interface getConnectScreenHealthOperation {\n readonly path: \"/v1/partner/connect/health\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n status?: \"online\" | \"offline\" | \"all\";\n};\n response: {\n data?: {\n checked_at?: string;\n filter?: string;\n screens?: Array<{\n device_id?: string;\n external_device_id?: string;\n fingerprint?: string;\n last_heartbeat?: string | null;\n last_seen?: string | null;\n location?: {\n city?: string | null;\n lat?: number | null;\n lng?: number | null;\n state?: string | null;\n };\n name?: string;\n registered_at?: string;\n screen_id?: string | null;\n screen_status?: \"pending\" | \"active\" | \"inactive\";\n status?: \"online\" | \"offline\" | \"never_connected\" | \"unknown\";\n time_since_last_seen_seconds?: number | null;\n uptime_24h_percent?: number | null;\n venue_type?: string | null;\n }>;\n summary?: {\n never_connected?: number;\n offline?: number;\n online?: number;\n total?: number;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * List content presets\n * GET /v1/partner/content-presets\n */\nexport interface listContentPresetsOperation {\n readonly path: \"/v1/partner/content-presets\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<ContentPreset>;\n has_more?: boolean;\n object?: string;\n total_count?: number;\n url?: string;\n};\n}\n\n/**\n * Get content preset\n * GET /v1/partner/content-presets/{presetId}\n */\nexport interface getContentPresetOperation {\n readonly path: \"/v1/partner/content-presets/{presetId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n presetId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreset;\n}\n\n/**\n * Create an experiment on a funded native media-buy placement\n * POST /v1/partner/creative-experiments\n */\nexport interface createCreativeFeedbackExperimentOperation {\n readonly path: \"/v1/partner/creative-experiments\";\n readonly method: \"POST\";\n request: FeedbackCreateRequest;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Read your native experiment, policy and latest 500 owned creative recovery records\n * GET /v1/partner/creative-experiments/{experiment_id}\n */\nexport interface getCreativeFeedbackExperimentOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentDetailResponse;\n}\n\n/**\n * Configure your native brand profile and enable its booked reactive campaign\n * POST /v1/partner/creative-experiments/{experiment_id}/brand\n */\nexport interface configureCreativeFeedbackBrandOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/brand\";\n readonly method: \"POST\";\n request: FeedbackBrandRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackBrandResponse;\n}\n\n/**\n * Generate a native brand creative for explicit review and moderation\n * POST /v1/partner/creative-experiments/{experiment_id}/creatives/generate\n */\nexport interface generateCreativeFeedbackCreativeOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/creatives/generate\";\n readonly method: \"POST\";\n request: FeedbackGenerateRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackGenerateResponse;\n}\n\n/**\n * Import an AI model’s image through native bytes, moderation and brand review\n * POST /v1/partner/creative-experiments/{experiment_id}/creatives/import\n */\nexport interface importCreativeFeedbackCreativeOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/creatives/import\";\n readonly method: \"POST\";\n request: FeedbackImportRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackGenerateResponse;\n}\n\n/**\n * Approve or reject your generated creative using native brand review\n * POST /v1/partner/creative-experiments/{experiment_id}/creatives/review\n */\nexport interface reviewCreativeFeedbackCreativeOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/creatives/review\";\n readonly method: \"POST\";\n request: FeedbackReviewRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackReviewResponse;\n}\n\n/**\n * Replace native creative weights at the expected policy version\n * PUT /v1/partner/creative-experiments/{experiment_id}/policy\n */\nexport interface updateCreativeFeedbackPolicyOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/policy\";\n readonly method: \"PUT\";\n request: FeedbackPolicyRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Read a metered page of latest measured native play states\n * GET /v1/partner/creative-experiments/{experiment_id}/rewards\n */\nexport interface getCreativeFeedbackRewardsOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/rewards\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: {\n /** Opaque next_cursor from this same date scope; rewind after scan_complete. */\n cursor?: string;\n /** Inclusive first play date, YYYY-MM-DD; date range is at most 31 days. */\n from: string;\n /** Unique caller-owned billing key for this page; committed retries return the receipt, not another read. */\n idempotency_key: string;\n /** Maximum native play states returned on this metered page. */\n limit?: number;\n /** Inclusive last play date, YYYY-MM-DD; date range is at most 31 days. */\n to: string;\n};\n response: FeedbackRewardsResponse;\n}\n\n/**\n * Stop the native experiment at the expected policy version\n * POST /v1/partner/creative-experiments/{experiment_id}/stop\n */\nexport interface stopCreativeFeedbackExperimentOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/stop\";\n readonly method: \"POST\";\n request: FeedbackStopRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Register approved native generated creative variants\n * POST /v1/partner/creative-experiments/{experiment_id}/variants\n */\nexport interface registerCreativeFeedbackVariantsOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/variants\";\n readonly method: \"POST\";\n request: FeedbackRegisterVariantsRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Submit a creative for classification\n * POST /v1/partner/creatives\n */\nexport interface submitPartnerCreativeOperation {\n readonly path: \"/v1/partner/creatives\";\n readonly method: \"POST\";\n request: {\n /** Optional advertiser/brand label to attach. */\n advertiser_name?: string;\n /** Public http(s) URL of the creative image or video. Must resolve to a public address — private/internal/cloud-metadata addresses are rejected. */\n media_url: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: CreativeClassification;\n}\n\n/**\n * Get a creative classification\n * GET /v1/partner/creatives/{ref}\n */\nexport interface getPartnerCreativeOperation {\n readonly path: \"/v1/partner/creatives/{ref}\";\n readonly method: \"GET\";\n request: never;\n params: {\n ref: string;\n};\n query: Record<string, unknown>;\n response: CreativeClassification;\n}\n\n/**\n * Get dashboard overview\n * GET /v1/partner/dashboard\n */\nexport interface getDashboardOperation {\n readonly path: \"/v1/partner/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: DashboardResponse;\n success?: boolean;\n};\n}\n\n/**\n * Export the cross-screen proximity graph edge list\n * GET /v1/partner/data-export/proximity-graph-edges\n */\nexport interface exportProximityGraphEdgesOperation {\n readonly path: \"/v1/partner/data-export/proximity-graph-edges\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n cursor?: string;\n days?: number;\n limit?: number;\n};\n response: {\n data?: {\n limit: number;\n lookback_days: number;\n /** The `cursor` of the next page, or `null` on the last page. */\n next_cursor: string | null;\n rows: Array<{\n destination_screen_id: string;\n /** Distinct transitions from the source screen to the destination screen. */\n edge_count: number;\n /** Median minutes between the source and destination sightings. */\n lag_p50: number;\n source_screen_id: string;\n /** Distinct devices behind those transitions. */\n unique_devices: number;\n }>;\n /** Number of edges in this page. */\n total: number;\n /** `true` when more edges follow this page: pass `next_cursor` back as `cursor`. */\n truncated: boolean;\n /** The UTC second the window ends at (`YYYY-MM-DD HH:MM:SS`), pinned by the first page. */\n window_end: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * List available datasets and per-dataset record counts\n * GET /v1/partner/data-export/summary\n */\nexport interface getDataExportSummaryOperation {\n readonly path: \"/v1/partner/data-export/summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n days?: number;\n};\n response: DataExportSummaryResponse;\n}\n\n/**\n * Export a partner-scoped dataset\n * GET /v1/partner/data-export/{dataset}\n */\nexport interface exportDatasetOperation {\n readonly path: \"/v1/partner/data-export/{dataset}\";\n readonly method: \"GET\";\n request: never;\n params: {\n dataset: \"audience_metrics\" | \"signal_audience\" | \"attention_ledger\" | \"impression_ledger\" | \"waterfall_events\" | \"intent_signals\" | \"audience_loyalty_features\" | \"screen_metadata\";\n};\n query: {\n days?: number;\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n lookback_days?: number;\n /** Row shape depends on the requested `dataset`. For `audience_loyalty_features` see `AudienceLoyaltyFeaturesRow`. For other datasets the row shape is documented per-dataset in the Trillboards data dictionary. */\n rows?: Array<AudienceLoyaltyFeaturesRow | Record<string, unknown>>;\n total?: number;\n truncated?: boolean;\n };\n success?: boolean;\n};\n}\n\n/**\n * Geographic audience panel (data-licensing)\n * GET /v1/partner/data/geohash-audience-panel\n */\nexport interface getGeohashAudiencePanelOperation {\n readonly path: \"/v1/partner/data/geohash-audience-panel\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n date?: string;\n geohash_prefix?: string;\n limit?: number;\n offset?: number;\n venue_category?: string;\n};\n response: {\n data?: {\n /** The build of the day this page read (UTC, `YYYY-MM-DD HH:MM:SS.mmm`). A day with no build is answered `404` `day_not_built`. */\n built_at: string;\n /** Day exported (UTC). */\n date: string;\n /** The panel's definition (2 since 2026-10-19). */\n definition_version: number;\n /** Rows per page this response was read with. */\n limit: number;\n /** The `offset` of the next page, or `null` on the last page. */\n next_offset: number | null;\n /** Rows skipped before this page. */\n offset: number;\n /** Integer partner_id (`partners.partner_id`). */\n partner_id: number;\n /** One row per (hour, geohash6, venue_category), every cell with its counts. */\n rows: Array<{\n /** Mean device head-pose index 0-1 over the camera windows. `null` when the cell-hour holds no camera window. */\n avg_attention: number | null;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). `null`: No window of the row carries a start time (dwell_capped_windows = 0). */\n avg_dwell_ms: number | null;\n /** Mean capped dwell per camera window, seconds (`avg_dwell_ms` / 1000). `null` when no camera window of the cell-hour carries a start time. */\n avg_dwell_seconds: number | null;\n /** Mean faces per camera window. `null` when the cell-hour holds no camera window. */\n avg_face_count: number | null;\n /** The windows avg_dwell_ms averages: camera windows that carry a start time. */\n dwell_capped_windows: number;\n /** Of those, the face-backed windows. */\n face_backed_windows: number;\n /** Of those, the identifiers whose strongest signal was below it: the devices around the screen. Sources that report no signal strength (mDNS, SSDP, HTTP probe) are in neither split. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_key_slots: number | null;\n /** far_key_slots / radio_slots. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_keys_per_slot: number | null;\n /** Median age of those fixes at the window's instant. `null`: No camera window of the row was placed by a trail fix. */\n fix_age_p50_s: number | null;\n /** 90th-percentile age of those fixes. `null`: No camera window of the row was placed by a trail fix. */\n fix_age_p90_s: number | null;\n /** Camera windows of a fixed screen with no trail fix in the lookback, placed at its registered site. */\n fixed_site_positioned_windows: number;\n /** Geohash-6 cell (about 1.2 x 0.6 km) where the screen was at the unit's instant: on its map-matched path, else at its last GPS trail fix, else (a fixed screen) at its registered site. */\n geohash6: string;\n /** Start of the UTC hour, `YYYY-MM-DD HH:MM:SS`. A camera window counts in the hour it closed, a radio slot in the hour of its midpoint. */\n hour: string;\n /** `null` on every row: no income source joins the panel (definition 1 wrote `unknown`). */\n income_tier: string | null;\n /** Camera windows placed at the screen's last GPS fix at or before their instant. */\n last_fix_positioned_windows: number;\n /** The near-field boundary of the row's day: the active pass_audience method register's rf_near_rssi_dbm, the boundary the in-cab radio uses. */\n near_field_rssi_dbm: number;\n /** Of those, the identifiers whose strongest signal in the slot was at or above near_field_rssi_dbm: in the vehicle or against the screen. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_key_slots: number | null;\n /** near_key_slots / radio_slots: near-field identifiers concurrent in one slot. The approved metric radio_identifiers_per_person converts near-field passenger Bluetooth identifiers to people: it is measured in the cab, where the driver's phone and the vehicle's own devices are removed by role. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_keys_per_slot: number | null;\n /** Radio observations (pings) of those identifiers in the cell-hour (`radio_pings`). `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n observation_count: number | null;\n /** Camera-graded windows (face- or person-backed, ~10 s each) placed in the cell. */\n observation_windows: number;\n /** Exact 95th percentile of the per-window face reading over the row's windows. `null`: No camera window in the row. */\n p95_face_count: number | null;\n /** Camera windows placed on the map-matched vehicle path at their instant. */\n path_positioned_windows: number;\n /** Of those, the person-backed windows. */\n person_backed_windows: number;\n /** The windows persons_per_window averages. */\n person_reading_windows: number;\n /** Mean people in view per camera window, faced or not: per window the larger of its mean person count and its mean face count (the in-cab panel's persons reading), over the windows that carry one. `null`: No camera window of the row carries a persons reading (person_reading_windows = 0). */\n persons_per_window: number | null;\n /** Radio slots of a fixed screen with no trail fix in the lookback, placed at its registered site. */\n radio_fixed_site_positioned_slots: number;\n /** Radio slots placed at the screen's last GPS fix at or before their midpoint. */\n radio_last_fix_positioned_slots: number;\n /** Radio slots placed on the map-matched path at their midpoint. */\n radio_path_positioned_slots: number;\n /** Radio observations of the visitor identifiers in the row's slots. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_pings: number | null;\n /** Distinct screens whose radio slots the row holds. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_screens: number | null;\n /** 6-minute radio slots of screens placed in the cell: a slot in which the screen's visitor radio read an identifier (a slot in which the scanner reported only the screen's own Wi-Fi access point does not show the visitor radio ran, and is no slot here). 0 when only camera windows fell in the row. */\n radio_slots: number;\n /** Distinct screens whose radio slots the cell-hour holds (`radio_screens`). `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n screen_count: number | null;\n /** Distinct screens whose camera windows the row holds. */\n screens: number;\n /** Distinct visitor-source radio identifiers (BLE, mDNS, SSDP, HTTP probe) over the cell-hour's radio slots, exact. A distinct count: rows do not add. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n unique_devices: number | null;\n /** The screen's registered venue category (`transit` for a vehicle screen); empty when the registry holds none. */\n venue_category: string;\n /** Visitor-source radio identifiers (BLE, mDNS, SSDP, HTTP probe) distinct within each slot, summed over the slots. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_key_slots: number | null;\n /** visitor_key_slots / radio_slots: identifiers concurrent in one 6-minute slot, every visitor source and both fields. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_keys_per_slot: number | null;\n }>;\n /** `true` when more cells follow this page: request `next_offset`. */\n truncated: boolean;\n };\n success?: boolean;\n};\n}\n\n/**\n * Outcome-attribution export (data-licensing)\n * GET /v1/partner/data/outcome-attribution\n */\nexport interface getOutcomeAttributionOperation {\n readonly path: \"/v1/partner/data/outcome-attribution\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n creative_id?: string;\n cursor?: string;\n days?: number;\n grain?: \"person\" | \"device\";\n limit?: number;\n};\n response: {\n data?: {\n /** The reach grain applied (echoes the `grain` query param; defaults to `person`). */\n grain: \"person\" | \"device\";\n /** Rows per page this response was read with. */\n limit: number;\n /** The validated lookback window used. */\n lookback_days: number;\n /** The `cursor` of the next page, or `null` on the last page. */\n next_cursor: string | null;\n /** Per-(creative, screen) outcome aggregates, every cell with its counts. */\n rows: Array<{\n /** Average exposures per reach-identity within the (creative, screen) cell (count of detail rows / distinct reach keys). A frequency over PEOPLE under person grain, over devices under device grain. */\n avg_frequency: number;\n /** Creative identifier from `completed_impressions.creative_id`. */\n creative_id: string;\n /** Count of exposed identities also seen on another screen. */\n cross_screen_devices: number;\n /** Count of distinct devices exposed to the creative on the screen. */\n exposed_devices: number;\n /** returned_devices / exposed_devices. */\n return_rate: number;\n /** Count of exposed devices that returned (≤ exposed_devices). */\n returned_devices: number;\n /** The partner's own screen identifier. */\n screen_mongo_id: string;\n }>;\n /** Number of rows in this page. */\n total: number;\n /** `true` when more cells follow this page: pass `next_cursor` back as `cursor`. */\n truncated: boolean;\n /** The UTC date the window ends on, pinned by the first page; the window is `window_end - lookback_days` through `window_end`. */\n window_end: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Register a device\n * POST /v1/partner/device\n */\nexport interface registerDeviceOperation {\n readonly path: \"/v1/partner/device\";\n readonly method: \"POST\";\n request: {\n /** Any additional metadata for your records */\n custom_metadata?: Record<string, unknown>;\n /** Screen or venue description for enrichment */\n description?: string;\n /** Your internal device identifier */\n device_id: string;\n /** Mutable partner category; defaults to other only on a new registration. Omit it to preserve an existing device's category. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Screen display specification. `width`/`height` are pixel resolution; `width_in`/`height_in` are physical inches. For accurate floor pricing we need physical inches — pass `width_in` + `height_in` if you've measured the screen, OR `ppi` so the server can derive inches from the pixel resolution. Pixel-only inputs (no `ppi`, no `*_in`) will NOT be recorded as physical size; they're still used for orientation detection and DSP slot dimensions. */\n display?: {\n /** Display resolution height in pixels (e.g. 1080) */\n height?: number;\n /** Physical screen height in INCHES. Pairs with `width_in`. */\n height_in?: number;\n orientation?: \"landscape\" | \"portrait\";\n /** Pixels per inch. Required if you want physical screen size derived from `width`/`height` (server computes widthInches = width / ppi). Typical: 40 (large TV), 96 (desktop monitor), 264 (tablet). */\n ppi?: number;\n /** Display resolution width in pixels (e.g. 1920) */\n width?: number;\n /** Physical screen width in INCHES. Overrides ppi-based derivation. Use this when you've measured the actual screen (most accurate for pricing). */\n width_in?: number;\n };\n display_settings?: PartnerRegistrationDisplaySettings;\n location?: {\n address?: string;\n city?: string;\n country?: string;\n lat?: number;\n lng?: number;\n state?: string;\n timezone?: string;\n venue_name?: string;\n venue_type?: \"mall\" | \"airport\" | \"retail\" | \"restaurant\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"other\";\n zip?: string;\n };\n /** Reporting hints for moving screens (mobility_type mobile/semi_mobile). */\n mobile_settings?: {\n /** Minimum displacement before a fix is sent (device-side hint). */\n distance_threshold_meters?: number;\n /** Target GPS reporting interval (floor — the platform adapts to speed/battery). */\n update_interval_seconds?: number;\n vehicle_type?: \"taxi\" | \"rideshare\" | \"delivery\" | \"bus\" | \"food_truck\" | \"other\";\n };\n /** Declare a moving screen. `mobile` (taxi-top, transit) and `semi_mobile` (food truck, pop-up) screens report GPS via the heartbeat `location` field; `static` (default) screens ignore it. */\n mobility_type?: \"static\" | \"mobile\" | \"semi_mobile\";\n /** Friendly name for the device */\n name?: string;\n /** Photo URL for enrichment context */\n photo_url?: string;\n /** Optional additional photos for enrichment */\n photos?: Array<{\n /** photo type (context, close, angle, other) */\n type?: string;\n url?: string;\n }>;\n /** Physical placement details (optional) */\n placement?: {\n height_from_floor_ft?: number;\n mounting_type?: \"wall\" | \"ceiling\" | \"tabletop\" | \"window\" | \"stand\" | \"freestanding\" | \"floor_stand\" | \"counter\" | \"pole\" | \"vehicle\" | \"other\" | \"unknown\";\n orientation?: \"landscape\" | \"portrait\";\n viewing_distance_ft?: number;\n };\n /** Venue classification details (optional). Subcategory is free text and may be auto-enriched by AI. */\n venue?: {\n business_name?: string;\n category?: \"retail\" | \"restaurant\" | \"bar\" | \"cafe\" | \"hotel\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"mall\" | \"airport\" | \"gas_station\" | \"convenience_store\" | \"laundromat\" | \"salon\" | \"auto_shop\" | \"other\";\n context_notes?: string;\n environment_type?: \"indoor\" | \"outdoor\" | \"semi_outdoor\" | \"transit\";\n placement_type?: \"digital_signage\" | \"point_of_sale\" | \"waiting_area\" | \"window_display\" | \"kiosk\" | \"other\";\n /** Free text subcategory (may be auto-enriched by AI) */\n subcategory?: string;\n };\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Our internal device ID */\n device_id?: string;\n /** Saved partner category, independent of advertising classification. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Load this URL in your WebView */\n embed_url?: string;\n /** Enrichment completion state */\n enrichment_status?: string;\n /** Your device ID */\n external_device_id?: string;\n /** Device fingerprint for SDK */\n fingerprint?: string;\n location_capability?: PartnerLocationCapability;\n /** Stripe-style readiness. `ready` — the screen has its own coordinates and its venue is classified. `limited` — servable, but not on every rail: the venue is not yet classified, or the screen has no position of its own and is listed in inventory feeds at your fleet's market location. `blocked` — no rail has a location, or classification permanently failed. A device is never refused registration for missing location. */\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n requirements?: PartnerMonetizationRequirements;\n /** Linked screen ID */\n screen_id?: string;\n status?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Delete a device\n * DELETE /v1/partner/device/{deviceId}\n */\nexport interface deleteDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get device info\n * GET /v1/partner/device/{deviceId}\n */\nexport interface getDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: Device;\n success?: boolean;\n};\n}\n\n/**\n * Update device metadata\n * PATCH /v1/partner/device/{deviceId}\n */\nexport interface updateDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}\";\n readonly method: \"PATCH\";\n request: {\n /** Any additional metadata for your records */\n custom_metadata?: Record<string, unknown>;\n /** Screen or venue description */\n description?: string;\n /** Mutable partner category. Omit it to preserve the current value; changing it does not alter advertising classification. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Screen display specification. `width`/`height` are pixels; pass `width_in`/`height_in` (inches) or `ppi` to record physical screen size for floor pricing. See POST /device for full unit semantics. */\n display?: {\n /** Display resolution height in pixels */\n height?: number;\n /** Physical screen height in inches (pairs with width_in) */\n height_in?: number;\n orientation?: \"landscape\" | \"portrait\";\n /** Pixels per inch (required to derive physical size from width/height) */\n ppi?: number;\n /** Display resolution width in pixels */\n width?: number;\n /** Physical screen width in inches (overrides ppi-based derivation) */\n width_in?: number;\n };\n /** Partner-owned device ID used for idempotent lookup and reconciliation */\n external_device_id?: string;\n location?: {\n address?: string;\n city?: string;\n country?: string;\n lat?: number;\n lng?: number;\n state?: string;\n timezone?: string;\n /** Alias for `venue.category` — a granular venue type. Accepted on PATCH (previously documented on register only). When both are sent, `venue.category` wins. On the response this field returns the OpenOOH CHILD slug (e.g. \"hotels\"/\"malls\"); `venue.category` returns the parent. */\n venue_type?: \"mall\" | \"airport\" | \"retail\" | \"restaurant\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"other\";\n zip?: string;\n };\n /** Reporting hints for moving screens. Merges with existing settings. */\n mobile_settings?: {\n distance_threshold_meters?: number;\n update_interval_seconds?: number;\n vehicle_type?: \"taxi\" | \"rideshare\" | \"delivery\" | \"bus\" | \"food_truck\" | \"other\";\n };\n /** Update the screen's mobility. Set `mobile`/`semi_mobile` to have the heartbeat `location` field accepted for a moving screen. */\n mobility_type?: \"static\" | \"mobile\" | \"semi_mobile\";\n /** Friendly name for the device */\n name?: string;\n photo_url?: string;\n photos?: Array<{\n type?: string;\n url?: string;\n }>;\n placement?: {\n height_from_floor_ft?: number;\n mounting_type?: \"wall\" | \"ceiling\" | \"tabletop\" | \"window\" | \"stand\" | \"freestanding\" | \"floor_stand\" | \"counter\" | \"pole\" | \"vehicle\" | \"other\" | \"unknown\";\n orientation?: \"landscape\" | \"portrait\";\n viewing_distance_ft?: number;\n };\n venue?: {\n business_name?: string;\n /** Granular venue type on WRITE (child-level slug). On READ this returns the resolved OpenOOH PARENT (e.g. \"hotel\" write -> \"entertainment\" read); the child slug rides `venue.subcategory` and the numeric child id rides `venue.openooh_venue_type_id`. */\n category?: \"retail\" | \"restaurant\" | \"bar\" | \"cafe\" | \"hotel\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"mall\" | \"airport\" | \"gas_station\" | \"convenience_store\" | \"laundromat\" | \"salon\" | \"auto_shop\" | \"other\";\n context_notes?: string;\n environment_type?: \"indoor\" | \"outdoor\" | \"semi_outdoor\" | \"transit\";\n /** Response-only. Canonical OpenOOH child id to reconcile the declared venue type against (e.g. 807 for hotels). */\n openooh_venue_type_id?: number;\n placement_type?: \"digital_signage\" | \"point_of_sale\" | \"waiting_area\" | \"window_display\" | \"kiosk\" | \"other\";\n /** OpenOOH child slug (e.g. \"hotels\"). Free text on write; resolved on read. */\n subcategory?: string;\n };\n};\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: Device;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get ads for device\n * GET /v1/partner/device/{deviceId}/ads\n */\nexport interface getAdsForDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}/ads\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: {\n autoplay?: boolean;\n ipd?: string;\n lang?: string;\n muted?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n slot_h?: number;\n slot_w?: number;\n test?: \"1\" | \"true\";\n ua?: string;\n};\n response: {\n data?: {\n ads?: Array<Ad>;\n cache_until?: string;\n /** Pending device commands to execute (remote management). */\n commands?: Array<{\n command?: string;\n id?: string;\n payload?: Record<string, unknown>;\n queued_at?: string;\n }>;\n /** Venue/content keywords for contextual targeting. Omitted from the response when empty. */\n content_keywords?: Array<string>;\n device?: {\n display?: {\n height?: number | null;\n width?: number | null;\n };\n fingerprint?: string;\n };\n /** DOOH context signals (venue type, geo, audience) forwarded to demand. */\n dooh_signals?: Record<string, unknown>;\n header_bidding_settings?: HeaderBiddingSettings;\n /** URL of the Trillboards-hosted IMA renderer for this screen, or null when the IMA player is not enabled for this deployment / there is no waterfall source. */\n ima_player_url?: string | null;\n screen_dimensions?: {\n height?: number;\n orientation?: \"portrait\" | \"landscape\";\n width?: number;\n };\n screen_id?: string;\n /** Serve locale derived from the venue country (e.g. \"en\", \"fr\"). */\n screen_locale?: string;\n screen_name?: string | null;\n screen_orientation?: \"portrait\" | \"landscape\";\n settings?: AdSettings;\n };\n success?: boolean;\n};\n}\n\n/**\n * Acknowledge a device command\n * POST /v1/partner/device/{deviceId}/commands/{commandId}/ack\n */\nexport interface ackDeviceCommandOperation {\n readonly path: \"/v1/partner/device/{deviceId}/commands/{commandId}/ack\";\n readonly method: \"POST\";\n request: {\n /** Command execution result */\n result?: Record<string, unknown>;\n /** Acknowledgment status */\n status?: string;\n};\n params: {\n commandId: string;\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Read live device heartbeat state\n * GET /v1/partner/device/{deviceId}/heartbeat\n */\nexport interface getDeviceHeartbeatOperation {\n readonly path: \"/v1/partner/device/{deviceId}/heartbeat\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: PartnerHeartbeatQueryResponse;\n}\n\n/**\n * Device heartbeat\n * POST /v1/partner/device/{deviceId}/heartbeat\n */\nexport interface heartbeatOperation {\n readonly path: \"/v1/partner/device/{deviceId}/heartbeat\";\n readonly method: \"POST\";\n request: PartnerHeartbeatRequest | PartnerDeviceHeartbeatBody;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: PartnerHeartbeatResponse;\n}\n\n/**\n * Update a device's publisher impression multiplier\n * PATCH /v1/partner/device/{deviceId}/impression-multiplier\n */\nexport interface updateDeviceImpressionMultiplierOperation {\n readonly path: \"/v1/partner/device/{deviceId}/impression-multiplier\";\n readonly method: \"PATCH\";\n request: {\n /** Publisher-declared audience impressions per ad play; stored to four decimal places */\n impression_multiplier: number;\n};\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n device_id?: string;\n external_device_id?: string;\n impression_multiplier?: number;\n screen_id?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Report a rider interaction from the partner SDK (reportInteraction)\n * POST /v1/partner/device/{deviceId}/interactions\n */\nexport interface recordPartnerDeviceInteractionOperation {\n readonly path: \"/v1/partner/device/{deviceId}/interactions\";\n readonly method: \"POST\";\n request: PartnerInteraction;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data: {\n interaction_id: string;\n /** The screen this device is bound to. */\n screen_id: string;\n status: \"accepted\" | \"duplicate\";\n type: \"tap\" | \"qr_shown\" | \"qr_scanned\" | \"dwell_prompt\" | \"seatbelt_reminder_shown\";\n };\n success: true;\n};\n}\n\n/**\n * Report a play from the partner SDK (reportPlay)\n * POST /v1/partner/device/{deviceId}/plays\n */\nexport interface recordPartnerDevicePlayOperation {\n readonly path: \"/v1/partner/device/{deviceId}/plays\";\n readonly method: \"POST\";\n request: PartnerDevicePlay;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data: {\n content_sha256: string;\n play_id: string;\n /** The screen this device is bound to. */\n screen_id: string;\n status: \"accepted\" | \"duplicate\";\n };\n success: true;\n};\n}\n\n/**\n * Record programmatic ad event (Server-side Analytics)\n * POST /v1/partner/device/{deviceId}/programmatic-event\n */\nexport interface recordProgrammaticEventOperation {\n readonly path: \"/v1/partner/device/{deviceId}/programmatic-event\";\n readonly method: \"POST\";\n request: {\n ad_id?: string;\n error_code?: string;\n error_message?: string;\n event: \"ad_started\" | \"ad_ended\" | \"no_fill\" | \"error\";\n reason?: string;\n request_id?: string;\n screen_orientation?: \"portrait\" | \"landscape\";\n slot_height?: number;\n slot_width?: number;\n variant_name?: string;\n};\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Report a taxi-meter state change from the partner SDK (setTripState)\n * POST /v1/partner/device/{deviceId}/trips\n */\nexport interface recordPartnerDeviceTripStateOperation {\n readonly path: \"/v1/partner/device/{deviceId}/trips\";\n readonly method: \"POST\";\n request: PartnerTripState;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data: {\n event_seq: number;\n /** The screen this device is bound to. */\n screen_id: string;\n status: \"accepted\" | \"duplicate\";\n trip_id: string;\n };\n success: true;\n};\n}\n\n/**\n * Get fresh VAST for a registered device\n * GET /v1/partner/device/{deviceId}/vast\n */\nexport interface getVastForDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}/vast\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: {\n autoplay?: boolean;\n connection_type?: string;\n content_id?: string;\n device_memory?: number;\n dpr?: number;\n ipd?: string;\n lang?: string;\n make?: string;\n model?: string;\n muted?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n os?: string;\n platform_hint?: string;\n screen_h?: number;\n screen_w?: number;\n sdk_type?: string;\n sdk_version?: string;\n slot_h?: number;\n slot_w?: number;\n stream_type?: string;\n test?: \"1\" | \"true\";\n ua?: string;\n vp_h?: number;\n vp_w?: number;\n};\n response: unknown;\n}\n\n/**\n * List all devices\n * GET /v1/partner/devices\n */\nexport interface listDevicesOperation {\n readonly path: \"/v1/partner/devices\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n status?: \"pending\" | \"active\" | \"offline\" | \"suspended\";\n};\n response: {\n data?: {\n devices?: Array<DeviceSummary>;\n limit?: number;\n offset?: number;\n total?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Register a device (V2 single-call onboarding)\n * POST /v1/partner/devices\n */\nexport interface registerDeviceV2Operation {\n readonly path: \"/v1/partner/devices\";\n readonly method: \"POST\";\n request: {\n /** Optional display dimensions. One of three modes — the `mode` discriminator is required. */\n display?: {\n /** Physical screen height in INCHES. Pairs with `width_in`. */\n height_in: number;\n mode: \"inches\";\n /** Physical screen width in INCHES. No upper bound — large-format / billboard inventory is valid. */\n width_in: number;\n } | {\n height: number;\n mode: \"pixels_with_ppi\";\n ppi: number;\n width: number;\n } | {\n height: number;\n mode: \"pixels_only\";\n width: number;\n };\n /** Your stable per-device identifier (e.g. \"REC00005\"). */\n external_id: string;\n /** Optional hardware identity — improves DSP device matching. */\n hardware?: {\n make?: string;\n model?: string;\n os?: \"Android\" | \"iOS\" | \"Tizen\" | \"WebOS\" | \"Linux\" | \"FireOS\" | \"Other\";\n osv?: string;\n };\n /** Optional venue location — either lat/lng coordinates or a street address. */\n location?: {\n lat: number;\n lng: number;\n } | {\n address: string;\n };\n /** The device's real WebView User-Agent. Must include a Build fingerprint and be unique per device. */\n ua: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n device_id?: string;\n diagnostics_url?: string;\n /** Paste into an iframe to start serving. */\n embed_url?: string;\n /** Server-derived canonical device identity. */\n identity?: {\n derivation_confidence?: number | null;\n derivation_source?: string | null;\n device_class?: string | null;\n make?: string | null;\n model?: string | null;\n os?: string | null;\n osv?: string | null;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * Bulk register devices\n * POST /v1/partner/devices/batch\n */\nexport interface registerDevicesBatchOperation {\n readonly path: \"/v1/partner/devices/batch\";\n readonly method: \"POST\";\n request: {\n /** Default fields applied to each device */\n defaults?: {\n display_settings?: PartnerRegistrationDisplaySettings;\n };\n devices: Array<{\n device_id: string;\n device_type?: string;\n display?: Record<string, unknown>;\n display_settings?: PartnerRegistrationDisplaySettings;\n location?: Record<string, unknown>;\n name?: string;\n placement?: Record<string, unknown>;\n venue?: Record<string, unknown>;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n devices?: Array<{\n device_id?: string;\n fingerprint?: string;\n location_capability?: PartnerLocationCapability;\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n requirements?: PartnerMonetizationRequirements;\n screen_id?: string;\n status?: string;\n trillboard_id?: string;\n }>;\n errors?: Array<{\n device_id?: string;\n error?: string;\n /** Stable code, e.g. DEVICE_ID_CLAIMED (409 — a device that already reports to Trillboards under this id is registered to another account), REGISTRATION_CHECK_UNAVAILABLE (503 — retry), INVALID_COUNTRY (400). */\n error_code?: string;\n status?: string;\n }>;\n success?: boolean;\n summary?: {\n created?: number;\n failed?: number;\n total?: number;\n updated?: number;\n };\n};\n}\n\n/**\n * Batch update screen orientation\n * POST /v1/partner/devices/batch/orientation\n */\nexport interface batchUpdateDeviceOrientationOperation {\n readonly path: \"/v1/partner/devices/batch/orientation\";\n readonly method: \"POST\";\n request: {\n device_ids: Array<string>;\n screen_orientation: \"portrait\" | \"landscape\" | \"mixed\" | \"unknown\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n matched_devices?: number;\n missing_device_ids?: Array<string>;\n success?: boolean;\n total_devices?: number;\n updated_screens?: number;\n};\n}\n\n/**\n * Reconcile device fleet\n * POST /v1/partner/devices/reconcile\n */\nexport interface reconcileDevicesOperation {\n readonly path: \"/v1/partner/devices/reconcile\";\n readonly method: \"POST\";\n request: {\n /** Your device external IDs to reconcile. */\n external_ids: Array<string>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n duplicate?: Array<Record<string, unknown>>;\n malformed?: Array<Record<string, unknown>>;\n matched?: Array<Record<string, unknown>>;\n missing?: Array<string>;\n orphan?: Array<Record<string, unknown>>;\n success?: boolean;\n summary?: {\n duplicate?: number;\n malformed?: number;\n matched?: number;\n missing?: number;\n orphan?: number;\n registered_active?: number;\n requested?: number;\n };\n truncated?: Record<string, unknown>;\n};\n}\n\n/**\n * Browsable HTML documentation index\n * GET /v1/partner/docs\n */\nexport interface partnerDocsBrowserOperation {\n readonly path: \"/v1/partner/docs\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * Get earnings summary\n * GET /v1/partner/earnings\n */\nexport interface getEarningsOperation {\n readonly path: \"/v1/partner/earnings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: EarningsResponse;\n success?: boolean;\n};\n}\n\n/**\n * Get detailed earnings breakdown\n * GET /v1/partner/earnings/breakdown\n */\nexport interface getEarningsBreakdownOperation {\n readonly path: \"/v1/partner/earnings/breakdown\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n end_date?: string;\n group_by?: \"day\" | \"week\" | \"screen\";\n start_date?: string;\n};\n response: {\n data?: EarningsBreakdownResponse;\n success?: boolean;\n};\n}\n\n/**\n * Request a payout\n * POST /v1/partner/earnings/payout\n */\nexport interface requestPayoutOperation {\n readonly path: \"/v1/partner/earnings/payout\";\n readonly method: \"POST\";\n request: {\n /** Amount to payout in cents (optional, defaults to available balance) */\n amount_cents?: number;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: PayoutResponse;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get transaction history\n * GET /v1/partner/earnings/transactions\n */\nexport interface getTransactionsOperation {\n readonly path: \"/v1/partner/earnings/transactions\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n type?: \"all\" | \"earning\" | \"payout\";\n};\n response: {\n data?: {\n pagination?: Pagination;\n transactions?: Array<Transaction>;\n };\n success?: boolean;\n};\n}\n\n/**\n * List active SSE connections\n * GET /v1/partner/events/connections\n */\nexport interface getActiveSSEConnectionsOperation {\n readonly path: \"/v1/partner/events/connections\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n connections?: Array<{\n connected_at?: string;\n connection_id?: string;\n ip?: string;\n subscribed_events?: Array<string>;\n }>;\n count?: number;\n max_connections?: number;\n object?: string;\n};\n}\n\n/**\n * Subscribe to real-time events (SSE)\n * GET /v1/partner/events/stream\n */\nexport interface subscribeToEventsOperation {\n readonly path: \"/v1/partner/events/stream\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n events?: string;\n};\n response: unknown;\n}\n\n/**\n * Poll a fleet-command job\n * GET /v1/partner/fleet-commands/{id}\n */\nexport interface getFleetCommandOperation {\n readonly path: \"/v1/partner/fleet-commands/{id}\";\n readonly method: \"GET\";\n request: never;\n params: {\n id: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n fleet_command?: FleetCommand;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get fleet analytics\n * GET /v1/partner/fleet/analytics\n */\nexport interface getFleetAnalyticsOperation {\n readonly path: \"/v1/partner/fleet/analytics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Average attention score (0-1) over the fleet's audience windows in the last 24 hours. Omitted when it was not measured — no screen in scope had an audience window, or the audience read failed (see `avg_attention_outcome`); never a `0` that stands in for a missing measurement. */\n avg_attention?: number;\n /** Whether the attention average above was measured. `kind: ok` — the read ran (the average is omitted only when no screen had an audience window); `kind: unavailable` — the audience read failed, so the average is omitted. Independent of the other fields, which are served either way. */\n avg_attention_outcome?: {\n kind?: \"ok\" | \"unavailable\";\n message?: string;\n };\n /** Average CPM in dollars */\n avg_cpm?: number;\n /** Fill rate percentage (0-100) */\n fill_rate_pct?: number;\n impressions_24h?: number;\n screen_count?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Push command to fleet\n * POST /v1/partner/fleet/command\n */\nexport interface pushFleetCommandOperation {\n readonly path: \"/v1/partner/fleet/command\";\n readonly method: \"POST\";\n request: {\n command: {\n /** Command-specific data */\n payload?: Record<string, unknown>;\n type: \"reload\" | \"update_settings\" | \"restart\" | \"screenshot\" | \"clear_cache\" | \"update_content\" | \"refresh_ads\" | \"update_config\" | \"get_state\" | \"show_ad\" | \"play_ad\";\n };\n /** Optional filter to target specific devices */\n filter?: {\n country?: string;\n /** A screen group id (sg_) whose members are targeted (unioned with screenIds). */\n group?: string;\n screenIds?: Array<string>;\n venueType?: string;\n };\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n errors?: Array<{\n error?: string;\n screenId?: string;\n }>;\n /** Devices successfully queued */\n queued?: number;\n /** Total devices matching filter */\n targeted?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get fleet overview\n * GET /v1/partner/fleet/overview\n */\nexport interface getFleetOverviewOperation {\n readonly path: \"/v1/partner/fleet/overview\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n countries?: Record<string, number>;\n offline?: number;\n online?: number;\n programmatic_enabled?: number;\n total_devices?: number;\n venue_types?: Record<string, number>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Update fleet-wide settings\n * POST /v1/partner/fleet/settings\n */\nexport interface updateFleetSettingsOperation {\n readonly path: \"/v1/partner/fleet/settings\";\n readonly method: \"POST\";\n request: {\n filter?: {\n country?: string;\n /** A screen group id (sg_) whose members are targeted (unioned with screenIds). */\n group?: string;\n screenIds?: Array<string>;\n venueType?: string;\n };\n /** Settings to update (merged with existing) */\n settings: {\n content_preferences?: Record<string, unknown>;\n display_settings?: Record<string, unknown>;\n header_bidding_settings?: {\n allocation?: number;\n enabled?: boolean;\n force_request?: boolean;\n min_interval_seconds?: number;\n };\n };\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n errors?: Array<Record<string, unknown>>;\n targeted?: number;\n updated?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Record impression (pixel)\n * GET /v1/partner/impression\n */\nexport interface recordImpressionGetOperation {\n readonly path: \"/v1/partner/impression\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n adid: string;\n aid?: string;\n completed?: boolean;\n did?: string;\n display_area_ratio?: number;\n display_mode?: \"fullscreen\" | \"l-bar\" | \"pip\";\n duration?: number;\n impid: string;\n lbar_position?: \"bottom\" | \"right\";\n lbar_size?: number;\n lbar_slot_count?: number;\n lbar_slot_index?: number;\n sid?: string;\n sig?: string;\n sig_ts?: number;\n};\n response: {\n duplicate?: boolean;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Record impression (POST)\n * POST /v1/partner/impression\n */\nexport interface recordImpressionPostOperation {\n readonly path: \"/v1/partner/impression\";\n readonly method: \"POST\";\n request: {\n adid: string;\n aid?: string;\n completed?: boolean;\n did?: string;\n display_area_ratio?: number;\n display_mode?: \"fullscreen\" | \"l-bar\" | \"pip\";\n duration?: number;\n impid: string;\n lbar_position?: \"bottom\" | \"right\";\n lbar_size?: number;\n lbar_slot_count?: number;\n lbar_slot_index?: number;\n sid?: string;\n sig?: string;\n sig_ts?: number;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n duplicate?: boolean;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Batch record impressions\n * POST /v1/partner/impressions/batch\n */\nexport interface recordImpressionsBatchOperation {\n readonly path: \"/v1/partner/impressions/batch\";\n readonly method: \"POST\";\n request: {\n impressions: Array<{\n adid: string;\n aid?: string;\n completed?: boolean;\n device_fingerprint?: string;\n did?: string;\n display_area_ratio?: number;\n display_mode?: \"fullscreen\" | \"l-bar\" | \"pip\";\n duration?: number;\n impid: string;\n lbar_position?: \"bottom\" | \"right\";\n lbar_size?: number;\n lbar_slot_count?: number;\n lbar_slot_index?: number;\n sid?: string;\n sig?: string;\n sig_ts?: number;\n timestamp?: string;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n errors?: Array<{\n error?: string;\n impid?: string;\n }>;\n failed?: number;\n recorded?: number;\n skipped?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get partner info\n * GET /v1/partner/info\n */\nexport interface getPartnerInfoOperation {\n readonly path: \"/v1/partner/info\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Partner;\n success?: boolean;\n};\n}\n\n/**\n * List intent categories\n * GET /v1/partner/intent/categories\n */\nexport interface listIntentCategoriesOperation {\n readonly path: \"/v1/partner/intent/categories\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n count?: number;\n data?: Array<{\n description?: string;\n id?: string;\n /** Minimum intent score to match this category */\n min_intent_score?: number;\n name?: string;\n /** CPM multiplier applied when this intent is detected */\n premium_multiplier?: number;\n purchase_stages?: Array<\"READY_TO_BUY\" | \"COMPARING\" | \"CONSIDERING\" | \"BROWSING\">;\n }>;\n object?: string;\n};\n}\n\n/**\n * Get intent category details\n * GET /v1/partner/intent/categories/{categoryId}\n */\nexport interface getIntentCategoryOperation {\n readonly path: \"/v1/partner/intent/categories/{categoryId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n categoryId: string;\n};\n query: Record<string, unknown>;\n response: {\n description?: string;\n iab_segments?: Array<Record<string, unknown>>;\n id?: string;\n min_intent_score?: number;\n name?: string;\n object?: string;\n premium_multiplier?: number;\n purchase_stages?: Array<string>;\n triggers?: Array<string>;\n};\n}\n\n/**\n * Get intent-based pricing for a screen\n * GET /v1/partner/intent/pricing/{screenId}\n */\nexport interface getIntentPricingOperation {\n readonly path: \"/v1/partner/intent/pricing/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n category_match?: {\n category_id?: string;\n category_name?: string;\n intent_score?: number;\n premium_multiplier?: number;\n purchase_stage?: string;\n } | null;\n current_intent?: {\n categories?: Array<string>;\n purchase_stage?: \"NONE\" | \"BROWSING\" | \"CONSIDERING\" | \"COMPARING\" | \"READY_TO_BUY\";\n /** Intent confidence score (0-1) */\n score?: number;\n /** Whether an ad swap should be triggered */\n should_trigger?: boolean;\n };\n object?: string;\n pricing?: {\n base_cpm?: number;\n category_id?: string;\n category_name?: string;\n /** Effective CPM after intent premium */\n intent_cpm?: number;\n /** Additional CPM from intent detection */\n intent_premium?: number;\n premium_multiplier?: number;\n };\n screen_id?: string;\n};\n}\n\n/**\n * Trillboards measurement methodology disclosure\n * GET /v1/partner/measurement-methodology\n */\nexport interface getMeasurementMethodologyOperation {\n readonly path: \"/v1/partner/measurement-methodology\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n format?: \"json\";\n};\n response: MeasurementMethodology;\n}\n\n/**\n * Measurement methodology disclosure (JSON, no negotiation)\n * GET /v1/partner/measurement-methodology.json\n */\nexport interface getMeasurementMethodologyJsonOperation {\n readonly path: \"/v1/partner/measurement-methodology.json\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: MeasurementMethodology;\n}\n\n/**\n * Get network configuration\n * GET /v1/partner/network-config\n */\nexport interface getNetworkConfigOperation {\n readonly path: \"/v1/partner/network-config\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n network_config?: PartnerNetworkConfig;\n object?: string;\n parent_partner_id?: string | null;\n};\n}\n\n/**\n * Partial update network configuration\n * PATCH /v1/partner/network-config\n */\nexport interface patchNetworkConfigOperation {\n readonly path: \"/v1/partner/network-config\";\n readonly method: \"PATCH\";\n request: PartnerNetworkConfigUpdate;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n network_config?: PartnerNetworkConfig;\n object?: string;\n parent_partner_id?: string | null;\n};\n}\n\n/**\n * Update network configuration\n * PUT /v1/partner/network-config\n */\nexport interface updateNetworkConfigOperation {\n readonly path: \"/v1/partner/network-config\";\n readonly method: \"PUT\";\n request: PartnerNetworkConfigUpdate;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n network_config?: PartnerNetworkConfig;\n object?: string;\n parent_partner_id?: string | null;\n};\n}\n\n/**\n * Network-wide audience and inventory trends\n * GET /v1/partner/network/trends\n */\nexport interface getNetworkTrendsOperation {\n readonly path: \"/v1/partner/network/trends\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n days?: number;\n};\n response: {\n audience_shift?: Array<Record<string, unknown>>;\n days?: number;\n venue_type_mix?: Array<Record<string, unknown>>;\n};\n}\n\n/**\n * Unauthenticated liveness probe\n * GET /v1/partner/ping\n */\nexport interface partnerPingOperation {\n readonly path: \"/v1/partner/ping\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n ok?: boolean;\n service?: string;\n};\n}\n\n/**\n * Authenticated liveness probe\n * GET /v1/partner/ping/auth\n */\nexport interface partnerPingAuthOperation {\n readonly path: \"/v1/partner/ping/auth\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n ok?: boolean;\n partner_id?: string;\n tier?: \"basic\" | \"developer\" | \"enterprise\";\n};\n}\n\n/**\n * Record a log-level play\n * POST /v1/partner/plays\n */\nexport interface recordPartnerPlayOperation {\n readonly path: \"/v1/partner/plays\";\n readonly method: \"POST\";\n request: PartnerPlay;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** The content hash the play named. Absent when the play sent no creative_ref. */\n content_sha256?: string;\n object?: string;\n play_id?: string;\n status?: \"accepted\" | \"duplicate\";\n};\n}\n\n/**\n * Record a batch of log-level plays\n * POST /v1/partner/plays/batch\n */\nexport interface recordPartnerPlaysBatchOperation {\n readonly path: \"/v1/partner/plays/batch\";\n readonly method: \"POST\";\n request: {\n plays: Array<PartnerPlay>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n accepted?: number;\n duplicate?: number;\n errors?: Array<{\n play_id?: string | null;\n reason?: string;\n }>;\n object?: string;\n rejected?: number;\n total?: number;\n};\n}\n\n/**\n * Get machine-readable pricing\n * GET /v1/partner/pricing\n */\nexport interface getPricingOperation {\n readonly path: \"/v1/partner/pricing\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n agent_register_url?: string;\n billing_setup_url?: string;\n /** Volume discount tiers for prepaid credits */\n committed_use?: Record<string, {\n credits_usd?: number;\n discount_pct?: number;\n price_usd?: number;\n }>;\n currency?: string;\n description?: string;\n /** Free tier limits per product and meter */\n free_tiers?: Record<string, unknown>;\n model?: string;\n object?: string;\n /** Pricing details per product */\n products?: {\n attribution?: {\n description?: string;\n meters?: Record<string, {\n first_campaign_free?: boolean;\n per_unit?: string;\n unit_price_usd?: number;\n }>;\n name?: string;\n };\n data_api?: {\n description?: string;\n name?: string;\n notes?: string;\n tiers?: Array<{\n unit_price_usd?: number;\n /** null means unlimited (final tier) */\n up_to?: number | null;\n }>;\n unit?: string;\n };\n data_marketplace?: {\n description?: string;\n meters?: Record<string, {\n free_quota_per_month?: number;\n per_unit?: string;\n unit_price_usd?: number;\n }>;\n name?: string;\n notes?: string;\n revenue_share?: Record<string, unknown>;\n };\n fein_edge_ai?: {\n description?: string;\n name?: string;\n pricing?: string;\n };\n partner_platform?: {\n description?: string;\n name?: string;\n pricing?: string;\n revenue_share?: {\n distributor?: number;\n earner?: number;\n platform?: number;\n };\n };\n programmatic?: {\n description?: string;\n name?: string;\n pricing?: string;\n };\n proof_of_play?: {\n description?: string;\n name?: string;\n notes?: string;\n tiers?: Array<{\n unit_price_usd?: number;\n up_to?: number | null;\n }>;\n unit?: string;\n };\n };\n request_id?: string;\n};\n}\n\n/**\n * Record programmatic ad event (legacy SDK alias)\n * POST /v1/partner/programmatic-event\n */\nexport interface recordProgrammaticEventLegacyAliasOperation {\n readonly path: \"/v1/partner/programmatic-event\";\n readonly method: \"POST\";\n request: {\n ad_id?: string;\n /** Device fingerprint or external device ID */\n device_id?: string;\n /** Short legacy device identifier alias */\n did?: string;\n error_code?: string;\n error_message?: string;\n event: \"ad_started\" | \"ad_ended\" | \"no_fill\" | \"error\";\n reason?: string;\n request_id?: string;\n type?: \"ad_started\" | \"ad_ended\" | \"no_fill\" | \"error\";\n variant_name?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Quick start — register partner and first device in one call\n * POST /v1/partner/quick-start\n */\nexport interface quickStartOperation {\n readonly path: \"/v1/partner/quick-start\";\n readonly method: \"POST\";\n request: {\n /** Company or partner name */\n company_name: string;\n /** Display configuration for the first device */\n device_display?: Record<string, unknown>;\n /** Location for the first device */\n device_location?: Record<string, unknown>;\n /** Name for the first device */\n device_name?: string;\n email: string;\n /** Optional legacy classification. Omit for the default self-serve Partner API key. */\n partner_type?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n credentials?: {\n /** Store securely — shown only once! */\n api_key?: string;\n api_key_prefix?: string;\n warning?: string;\n };\n device?: {\n device_id?: string;\n embed_url?: string;\n external_device_id?: string;\n fingerprint?: string;\n name?: string;\n screen_id?: string;\n status?: string;\n };\n integration?: {\n api_base?: string;\n docs_url?: string;\n embed_url?: string;\n iframe_snippet?: string;\n sdk_snippet?: string;\n sdk_url?: string;\n };\n next_steps?: Array<string>;\n partner?: {\n name?: string;\n partner_id?: string;\n revenue_share_percent?: number;\n slug?: string;\n status?: string;\n };\n sdk_config?: {\n ad_interval?: number;\n allowed_ad_types?: Array<string>;\n cache_size?: number;\n image_duration?: number;\n max_ads_per_hour?: number;\n sound_enabled?: boolean;\n };\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Register a new partner\n * POST /v1/partner/register\n */\nexport interface registerPartnerOperation {\n readonly path: \"/v1/partner/register\";\n readonly method: \"POST\";\n request: {\n /** Whitelist of allowed referrer domains */\n allowed_domains?: Array<string>;\n contact_email: string;\n contact_name?: string;\n /** Company or partner name */\n name: string;\n /** Optional legacy classification. Omit this field — it does not change which API key you receive. Existing integrations may continue sending historical values (including `ctv_publisher`) for backward compatibility; every partner_type mints the same self-serve Partner API key. */\n partner_type?: \"vending_machine\" | \"kiosk\" | \"digital_signage\" | \"retail_display\" | \"ctv_publisher\" | \"other\";\n /** Partner's revenue share percentage (negotiated per partner) */\n revenue_share_percent?: number;\n /** URL-safe identifier (lowercase, no spaces) */\n slug: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Store this securely - only shown once. This ONE self-serve Partner API key authenticates the general Partner API surface in this spec AND the CTV Measurement SDK ingestion surface (`/v2/sdk/*`, `/v2/csi`) — it carries `sdk:*` and `mcp:tools` by default, so no separate CTV or MCP key is issued. Reuse it during OpenRTB onboarding to add buyer capabilities. */\n api_key?: string;\n partner_id?: string;\n /** Optional portal onboarding details for the partner owner account */\n portal_access?: {\n claim_complete_endpoint?: string;\n claim_request_endpoint?: string;\n claim_required?: boolean;\n claim_verify_endpoint?: string;\n email?: string;\n message?: string;\n new_account?: boolean;\n portal_auth_url?: string;\n portal_url?: string;\n user_id?: string;\n };\n revenue_share_percent?: number;\n slug?: string;\n status?: \"pending\" | \"active\";\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Generate a test event\n * POST /v1/partner/sandbox/event\n */\nexport interface generateSandboxEventOperation {\n readonly path: \"/v1/partner/sandbox/event\";\n readonly method: \"POST\";\n request: {\n /** Event type to generate */\n event_type: string;\n /** Target sandbox screen (auto-selects first if omitted) */\n screen_id?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** Event payload (varies by event type) */\n data?: Record<string, unknown>;\n event?: string;\n event_id?: string;\n is_sandbox?: boolean;\n object?: string;\n screen_id?: string | null;\n /** Number of SSE connections that received this event */\n sse_delivered?: number;\n timestamp?: string;\n};\n}\n\n/**\n * Reset sandbox data\n * POST /v1/partner/sandbox/reset\n */\nexport interface resetSandboxOperation {\n readonly path: \"/v1/partner/sandbox/reset\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n events_cleared?: number;\n object?: string;\n reset_at?: string;\n screens_cleared?: number;\n success?: boolean;\n};\n}\n\n/**\n * Create a sandbox screen\n * POST /v1/partner/sandbox/screen\n */\nexport interface createSandboxScreenOperation {\n readonly path: \"/v1/partner/sandbox/screen\";\n readonly method: \"POST\";\n request: {\n /** Custom screen name */\n name?: string;\n /** Override venue type */\n venue_type?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n audience?: {\n avg_dwell_time_sec?: number;\n current_viewers?: number;\n demographics?: Record<string, unknown>;\n };\n created_at?: string;\n device_id?: string;\n display_settings?: Record<string, unknown>;\n fingerprint?: string;\n id?: string;\n is_sandbox?: boolean;\n last_heartbeat?: string;\n location?: {\n city?: string;\n latitude?: number;\n longitude?: number;\n name?: string;\n state?: string;\n venue_type?: string;\n };\n name?: string;\n object?: string;\n partner_id?: string;\n screen_id?: string;\n status?: string;\n};\n}\n\n/**\n * Get sandbox status\n * GET /v1/partner/sandbox/status\n */\nexport interface getSandboxStatusOperation {\n readonly path: \"/v1/partner/sandbox/status\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n last_activity?: string | null;\n object?: string;\n recent_events?: Array<{\n event?: string;\n event_id?: string;\n timestamp?: string;\n }>;\n sandbox_screens?: Array<{\n created_at?: string;\n id?: string;\n last_heartbeat?: string;\n location?: Record<string, unknown>;\n name?: string;\n status?: string;\n }>;\n total_screens?: number;\n total_test_events?: number;\n};\n}\n\n/**\n * List screen groups\n * GET /v1/partner/screen-groups\n */\nexport interface listScreenGroupsOperation {\n readonly path: \"/v1/partner/screen-groups\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n has_more?: boolean;\n object?: string;\n screen_groups?: Array<ScreenGroup>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create a screen group\n * POST /v1/partner/screen-groups\n */\nexport interface createScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups\";\n readonly method: \"POST\";\n request: {\n description?: string;\n name: string;\n screen_ids?: Array<string>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n screen_group?: ScreenGroup;\n };\n success?: boolean;\n};\n}\n\n/**\n * Delete (archive) a screen group\n * DELETE /v1/partner/screen-groups/{groupId}\n */\nexport interface deleteScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n deleted?: boolean;\n id?: string;\n object?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Retrieve a screen group\n * GET /v1/partner/screen-groups/{groupId}\n */\nexport interface getScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n screen_group?: ScreenGroup;\n };\n success?: boolean;\n};\n}\n\n/**\n * Update a screen group\n * POST /v1/partner/screen-groups/{groupId}\n */\nexport interface updateScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}\";\n readonly method: \"POST\";\n request: {\n description?: string;\n name?: string;\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n screen_group?: ScreenGroup;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get analytics for a screen group\n * GET /v1/partner/screen-groups/{groupId}/analytics\n */\nexport interface getScreenGroupAnalyticsOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/analytics\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n /** Fleet analytics scoped to the group's live member screens — the same payload as GET /fleet/analytics (which also returns an average attention score alongside the fields below). */\n data?: {\n avg_cpm?: number;\n fill_rate_pct?: number;\n group_id?: string;\n impressions_24h?: number;\n screen_count?: number;\n [key: string]: unknown;\n };\n success?: boolean;\n};\n}\n\n/**\n * Run a fleet command against a screen group\n * POST /v1/partner/screen-groups/{groupId}/commands\n */\nexport interface createScreenGroupCommandOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/commands\";\n readonly method: \"POST\";\n request: {\n command: {\n payload?: Record<string, unknown>;\n type: \"reload\" | \"update_settings\" | \"restart\" | \"screenshot\" | \"clear_cache\" | \"update_content\" | \"refresh_ads\" | \"update_config\" | \"get_state\" | \"show_ad\" | \"play_ad\";\n };\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n fleet_command?: FleetCommand;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get a screen group's content policy\n * GET /v1/partner/screen-groups/{groupId}/content-policy\n */\nexport interface getScreenGroupContentPolicyOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/content-policy\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n content_policy?: ScreenGroupContentPolicy;\n };\n success?: boolean;\n};\n}\n\n/**\n * Set a screen group's content policy\n * PUT /v1/partner/screen-groups/{groupId}/content-policy\n */\nexport interface updateScreenGroupContentPolicyOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/content-policy\";\n readonly method: \"PUT\";\n request: ScreenGroupContentPolicyInput;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n content_policy?: ScreenGroupContentPolicy;\n };\n success?: boolean;\n};\n}\n\n/**\n * Remove members from a screen group\n * DELETE /v1/partner/screen-groups/{groupId}/members\n */\nexport interface removeScreenGroupMembersOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/members\";\n readonly method: \"DELETE\";\n request: {\n screen_ids: Array<string>;\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n removed?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * List a screen group's members\n * GET /v1/partner/screen-groups/{groupId}/members\n */\nexport interface listScreenGroupMembersOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/members\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: {\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n data?: Array<{\n id?: string;\n object?: string;\n }>;\n has_more?: boolean;\n object?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Add members to a screen group\n * POST /v1/partner/screen-groups/{groupId}/members\n */\nexport interface addScreenGroupMembersOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/members\";\n readonly method: \"POST\";\n request: {\n screen_ids: Array<string>;\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n added?: number;\n rejected?: Array<{\n id?: string;\n reason?: string;\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get a screen group's sensing config\n * GET /v1/partner/screen-groups/{groupId}/sensing-config\n */\nexport interface getScreenGroupSensingConfigOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/sensing-config\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n sensing_config?: ScreenGroupSensingConfig;\n };\n success?: boolean;\n};\n}\n\n/**\n * Set a screen group's sensing config\n * PUT /v1/partner/screen-groups/{groupId}/sensing-config\n */\nexport interface updateScreenGroupSensingConfigOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/sensing-config\";\n readonly method: \"PUT\";\n request: ScreenGroupSensingConfigInput;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n sensing_config?: ScreenGroupSensingConfig;\n };\n success?: boolean;\n};\n}\n\n/**\n * OpenRTB SDA payload for a screen\n * GET /v1/partner/screen/{external_code}/audience-segments\n */\nexport interface getScreenAudienceSegmentsOperation {\n readonly path: \"/v1/partner/screen/{external_code}/audience-segments\";\n readonly method: \"GET\";\n request: never;\n params: {\n external_code: string;\n};\n query: Record<string, unknown>;\n response: {\n external_code?: string;\n segtax_4?: Array<{\n confidence?: number;\n id?: string;\n }>;\n segtax_600?: Array<{\n confidence?: number;\n id?: string;\n }>;\n};\n}\n\n/**\n * Batch update content preferences\n * POST /v1/partner/screens/batch/content-preferences\n */\nexport interface batchUpdateContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/batch/content-preferences\";\n readonly method: \"POST\";\n request: {\n preferences?: ContentPreferencesInput;\n /** Preset ID to apply (alternative to preferences) */\n preset_id?: string;\n /** Array of screen IDs to update */\n screen_ids: Array<string>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: BatchResult;\n}\n\n/**\n * Batch update display settings\n * POST /v1/partner/screens/batch/display-settings\n */\nexport interface batchUpdateDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/batch/display-settings\";\n readonly method: \"POST\";\n request: {\n screen_ids: Array<string>;\n settings: DisplaySettingsInput;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: BatchResult;\n}\n\n/**\n * Batch update programmatic settings\n * POST /v1/partner/screens/batch/programmatic-settings\n */\nexport interface batchUpdateProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/batch/programmatic-settings\";\n readonly method: \"POST\";\n request: {\n screen_ids: Array<string>;\n settings: ProgrammaticSettingsInput;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: BatchResult;\n}\n\n/**\n * Resolve screen ID by device identifier\n * GET /v1/partner/screens/resolve\n */\nexport interface resolvePartnerScreenOperation {\n readonly path: \"/v1/partner/screens/resolve\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n device_id?: string;\n external_device_id?: string;\n fingerprint?: string;\n};\n response: {\n data?: {\n device_id?: string;\n external_device_id?: string;\n fingerprint?: string;\n screen_id?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get per-screen analytics\n * GET /v1/partner/screens/{screenId}/analytics\n */\nexport interface getScreenAnalyticsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n period?: \"7d\" | \"30d\" | \"90d\";\n};\n response: {\n data?: ScreenAnalyticsResponse;\n success?: boolean;\n};\n}\n\n/**\n * Current atmosphere (mood, noise, crowd density)\n * GET /v1/partner/screens/{screenId}/analytics/atmosphere\n */\nexport interface getPartnerScreenAtmosphereOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/atmosphere\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n crowdDensity?: string | null;\n currentViewers?: number | null;\n dataAge?: string;\n engagement?: number | null;\n lastUpdated?: string | null;\n mood?: string | null;\n noiseLevel?: string | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Time-bucketed venue intelligence with Lincoln-Petersen dedup\n * GET /v1/partner/screens/{screenId}/analytics/intelligence\n */\nexport interface getPartnerScreenIntelligenceOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/intelligence\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n from: string;\n interval?: \"5min\" | \"15min\" | \"1h\" | \"1d\";\n to: string;\n};\n response: {\n data?: {\n dedup?: {\n camera_count?: number;\n method?: string;\n raw_total?: number;\n unique_total?: number;\n };\n from?: string;\n interval?: string;\n screen_id?: string;\n summary?: {\n avg_attention?: number;\n buckets?: number;\n total_unique_viewers?: number;\n };\n timeseries?: Array<Record<string, unknown>>;\n to?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * Per-screen taste profile + top-5 creative categories\n * GET /v1/partner/screens/{screenId}/analytics/taste-profile\n */\nexport interface getPartnerScreenTasteProfileOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/taste-profile\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n computedAt?: string | null;\n daypartDistribution?: Record<string, unknown> | null;\n ready?: boolean;\n sampleCount?: number;\n screenId?: string;\n tasteVersionHash?: string | null;\n topCategories?: Array<Record<string, unknown>>;\n updatedAt?: string | null;\n venueType?: string | null;\n windowEnd?: string | null;\n windowStart?: string | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Hourly foot-traffic patterns for a screen\n * GET /v1/partner/screens/{screenId}/analytics/traffic\n */\nexport interface getPartnerScreenTrafficOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/traffic\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n};\n response: {\n data?: {\n busyScore?: number;\n hourlyTraffic?: Array<Record<string, unknown>>;\n periodDays?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Verified Attention Seconds + CPM tier for a screen\n * GET /v1/partner/screens/{screenId}/analytics/vas\n */\nexport interface getPartnerScreenVASOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/vas\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n avgAttentionScore?: number;\n avgFaceCount?: number;\n avgVasWeighted?: number;\n lastMeasurement?: string | null;\n medianVas?: number;\n multiplier?: number;\n p90Vas?: number;\n tier?: string;\n totalMeasurements?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Apply content preset to screen\n * POST /v1/partner/screens/{screenId}/apply-preset\n */\nexport interface applyContentPresetOperation {\n readonly path: \"/v1/partner/screens/{screenId}/apply-preset\";\n readonly method: \"POST\";\n request: {\n /** ID of the preset to apply */\n preset_id: string;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse & {\n preset_applied?: string;\n };\n}\n\n/**\n * Get real-time audience metrics\n * GET /v1/partner/screens/{screenId}/audience-metrics\n */\nexport interface getAudienceMetricsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/audience-metrics\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n include_history?: boolean;\n period?: \"1h\" | \"6h\" | \"24h\";\n};\n response: AudienceMetricsResponse;\n}\n\n/**\n * Get screen content preferences\n * GET /v1/partner/screens/{screenId}/content-preferences\n */\nexport interface getContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/content-preferences\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse;\n}\n\n/**\n * Update content preferences (partial)\n * PATCH /v1/partner/screens/{screenId}/content-preferences\n */\nexport interface patchContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/content-preferences\";\n readonly method: \"PATCH\";\n request: ContentPreferencesInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse;\n}\n\n/**\n * Update content preferences (full)\n * PUT /v1/partner/screens/{screenId}/content-preferences\n */\nexport interface updateContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/content-preferences\";\n readonly method: \"PUT\";\n request: ContentPreferencesInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse;\n}\n\n/**\n * List default streams for a screen\n * GET /v1/partner/screens/{screenId}/default-streams\n */\nexport interface listPartnerDefaultStreamsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n current?: PartnerDefaultStream;\n streams?: Array<PartnerDefaultStream>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create a default stream (URL-based)\n * POST /v1/partner/screens/{screenId}/default-streams\n */\nexport interface createPartnerDefaultStreamOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams\";\n readonly method: \"POST\";\n request: PartnerDefaultStreamCreate;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Upload image carousel default stream\n * POST /v1/partner/screens/{screenId}/default-streams/images\n */\nexport interface createPartnerDefaultStreamImagesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/images\";\n readonly method: \"POST\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Reorder default streams\n * PUT /v1/partner/screens/{screenId}/default-streams/order\n */\nexport interface reorderPartnerDefaultStreamsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/order\";\n readonly method: \"PUT\";\n request: {\n order: Array<string>;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Upload a video default stream\n * POST /v1/partner/screens/{screenId}/default-streams/upload\n */\nexport interface createPartnerDefaultStreamUploadOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/upload\";\n readonly method: \"POST\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Delete a default stream\n * DELETE /v1/partner/screens/{screenId}/default-streams/{streamId}\n */\nexport interface deletePartnerDefaultStreamOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/{streamId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n screenId: string;\n streamId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Update a default stream\n * PUT /v1/partner/screens/{screenId}/default-streams/{streamId}\n */\nexport interface updatePartnerDefaultStreamOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/{streamId}\";\n readonly method: \"PUT\";\n request: PartnerDefaultStreamUpdate;\n params: {\n screenId: string;\n streamId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Get screen demographics\n * GET /v1/partner/screens/{screenId}/demographics\n */\nexport interface getScreenDemographicsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/demographics\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n period?: \"24h\" | \"7d\" | \"30d\";\n};\n response: DemographicsResponse;\n}\n\n/**\n * Get display settings\n * GET /v1/partner/screens/{screenId}/display-settings\n */\nexport interface getDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/display-settings\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DisplaySettingsResponse;\n}\n\n/**\n * Update display settings (partial)\n * PATCH /v1/partner/screens/{screenId}/display-settings\n */\nexport interface patchDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/display-settings\";\n readonly method: \"PATCH\";\n request: DisplaySettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DisplaySettingsResponse;\n}\n\n/**\n * Update display settings (full)\n * PUT /v1/partner/screens/{screenId}/display-settings\n */\nexport interface updateDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/display-settings\";\n readonly method: \"PUT\";\n request: DisplaySettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DisplaySettingsResponse;\n}\n\n/**\n * Get L-Bar settings\n * GET /v1/partner/screens/{screenId}/l-bar\n */\nexport interface getPartnerLBarSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/l-bar\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerLBarSettings;\n success?: boolean;\n};\n}\n\n/**\n * Update L-Bar settings\n * PUT /v1/partner/screens/{screenId}/l-bar\n */\nexport interface updatePartnerLBarSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/l-bar\";\n readonly method: \"PUT\";\n request: {\n display_preferences?: PartnerLBarDisplayPreferences;\n l_bar_content?: PartnerLBarContent;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerLBarSettings;\n success?: boolean;\n};\n}\n\n/**\n * Update L-Bar live updates\n * PUT /v1/partner/screens/{screenId}/l-bar/live-updates\n */\nexport interface updatePartnerLBarLiveUpdatesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/l-bar/live-updates\";\n readonly method: \"PUT\";\n request: {\n custom_status?: string;\n promotion?: string;\n queue_number?: string;\n wait_time_minutes?: number;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Get programmatic settings\n * GET /v1/partner/screens/{screenId}/programmatic-settings\n */\nexport interface getProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/programmatic-settings\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ProgrammaticSettingsResponse;\n}\n\n/**\n * Update programmatic settings (partial)\n * PATCH /v1/partner/screens/{screenId}/programmatic-settings\n */\nexport interface patchProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/programmatic-settings\";\n readonly method: \"PATCH\";\n request: ProgrammaticSettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ProgrammaticSettingsResponse;\n}\n\n/**\n * Update programmatic settings (full)\n * PUT /v1/partner/screens/{screenId}/programmatic-settings\n */\nexport interface updateProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/programmatic-settings\";\n readonly method: \"PUT\";\n request: ProgrammaticSettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ProgrammaticSettingsResponse;\n}\n\n/**\n * Resolve the effective content policy for a screen\n * GET /v1/partner/screens/{screenId}/resolved-content-policy\n */\nexport interface getResolvedContentPolicyOperation {\n readonly path: \"/v1/partner/screens/{screenId}/resolved-content-policy\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: ResolvedContentPolicy;\n success?: boolean;\n};\n}\n\n/**\n * Resolve the effective sensing config for a screen\n * GET /v1/partner/screens/{screenId}/resolved-sensing-config\n */\nexport interface getResolvedSensingConfigOperation {\n readonly path: \"/v1/partner/screens/{screenId}/resolved-sensing-config\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: ResolvedSensingConfig;\n success?: boolean;\n};\n}\n\n/**\n * Read the custom sensing chips a screen is producing\n * GET /v1/partner/screens/{screenId}/sensing/chips\n */\nexport interface getScreenSensingChipsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/chips\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n /** The custom field_keys this screen senses (from its active profile) */\n fields?: Array<{\n description?: string;\n field_key?: string;\n type?: string;\n }>;\n /** Recent chip observations (one row per field_key per observation) */\n rows?: Array<Record<string, unknown>>;\n screen_id?: string;\n total?: number;\n truncated?: boolean;\n };\n success?: boolean;\n};\n}\n\n/**\n * Generate a custom sensing profile from a natural-language intent\n * POST /v1/partner/screens/{screenId}/sensing/interpret-intent\n */\nexport interface interpretScreenSensingIntentOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/interpret-intent\";\n readonly method: \"POST\";\n request: {\n /** Optional device-capability hint for model selection */\n deviceTier?: string;\n /** Natural-language description of what to sense */\n intent: string;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n /** The generated profile — pass to /sensing/profile to deploy */\n profile?: Record<string, unknown>;\n screen_id?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Deploy a custom sensing profile to a screen\n * POST /v1/partner/screens/{screenId}/sensing/profile\n */\nexport interface deployScreenSensingProfileOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/profile\";\n readonly method: \"POST\";\n request: {\n /** The sensing profile object returned by interpret-intent */\n profile: Record<string, unknown>;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n command?: Record<string, unknown>;\n profile?: Record<string, unknown>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Read a screen's AI sensing performance settings\n * GET /v1/partner/screens/{screenId}/sensing/settings\n */\nexport interface getScreenSensingSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/settings\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: SensingSettingsResponse;\n success?: boolean;\n};\n}\n\n/**\n * Update a screen's AI sensing performance mode\n * PATCH /v1/partner/screens/{screenId}/sensing/settings\n */\nexport interface updateScreenSensingSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/settings\";\n readonly method: \"PATCH\";\n request: {\n performance_mode: SensingPerformanceMode;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n command?: Record<string, unknown>;\n profile?: Record<string, unknown>;\n settings?: SensingSettingsResponse;\n };\n success?: boolean;\n};\n}\n\n/**\n * List your Sense Anything Routes\n * GET /v1/partner/sensing/routes\n */\nexport interface listPartnerSensingRoutesOperation {\n readonly path: \"/v1/partner/sensing/routes\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n includeDisabled?: boolean;\n};\n response: {\n data?: {\n routes?: Array<SensingRoute>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create a Sense Anything Route (threshold or scheduled-digest alert)\n * POST /v1/partner/sensing/routes\n */\nexport interface createPartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes\";\n readonly method: \"POST\";\n request: CreatePartnerSensingRouteRequest;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n route?: SensingRoute;\n };\n success?: boolean;\n};\n}\n\n/**\n * Delete (soft) a Sense Anything Route\n * DELETE /v1/partner/sensing/routes/{routeId}\n */\nexport interface deletePartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes/{routeId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n routeId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n routeId?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get one Sense Anything Route\n * GET /v1/partner/sensing/routes/{routeId}\n */\nexport interface getPartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes/{routeId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n routeId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n route?: SensingRoute;\n };\n success?: boolean;\n};\n}\n\n/**\n * Update a Sense Anything Route (partial, non-clobbering)\n * PATCH /v1/partner/sensing/routes/{routeId}\n */\nexport interface updatePartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes/{routeId}\";\n readonly method: \"PATCH\";\n request: UpdatePartnerSensingRouteRequest;\n params: {\n routeId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n route?: SensingRoute;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create Stripe Connect account\n * POST /v1/partner/stripe/connect\n */\nexport interface createStripeConnectAccountOperation {\n readonly path: \"/v1/partner/stripe/connect\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string;\n charges_enabled?: boolean;\n country?: string;\n default_currency?: string;\n details_submitted?: boolean;\n next_step?: string | null;\n payouts_enabled?: boolean;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get Stripe dashboard login link\n * GET /v1/partner/stripe/login-link\n */\nexport interface getStripeLoginLinkOperation {\n readonly path: \"/v1/partner/stripe/login-link\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string;\n instructions?: string;\n login_url?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get Stripe onboarding link\n * GET /v1/partner/stripe/onboarding-link\n */\nexport interface getStripeOnboardingLinkOperation {\n readonly path: \"/v1/partner/stripe/onboarding-link\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string;\n expires_at?: string;\n instructions?: string;\n onboarding_url?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Request a payout\n * POST /v1/partner/stripe/payout\n */\nexport interface requestStripePayoutOperation {\n readonly path: \"/v1/partner/stripe/payout\";\n readonly method: \"POST\";\n request: {\n /** Payout amount in cents (minimum $5.00) */\n amount_cents: number;\n /** Optional description for the payout */\n description?: string;\n /** Deduplication key to prevent duplicate payouts */\n idempotency_key?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n amount_cents?: number;\n created?: string;\n currency?: string;\n description?: string;\n destination?: string;\n /** Estimated arrival date (2-3 business days) */\n estimated_arrival?: string;\n status?: \"pending\" | \"reversed\";\n transfer_id?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get payout history\n * GET /v1/partner/stripe/payouts\n */\nexport interface getStripePayoutHistoryOperation {\n readonly path: \"/v1/partner/stripe/payouts\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n};\n response: {\n data?: {\n has_more?: boolean;\n total?: number;\n transfers?: Array<{\n amount_cents?: number;\n created?: string;\n currency?: string;\n description?: string;\n status?: \"completed\" | \"reversed\";\n transfer_id?: string;\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get Stripe account status\n * GET /v1/partner/stripe/status\n */\nexport interface getStripeAccountStatusOperation {\n readonly path: \"/v1/partner/stripe/status\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string | null;\n charges_enabled?: boolean;\n country?: string;\n default_currency?: string;\n details_submitted?: boolean;\n has_account?: boolean;\n payouts_enabled?: boolean;\n requirements?: {\n currently_due?: Array<string>;\n disabled_reason?: string | null;\n eventually_due?: Array<string>;\n past_due?: Array<string>;\n };\n status?: \"not_connected\" | \"pending\" | \"active\" | \"restricted\";\n };\n success?: boolean;\n};\n}\n\n/**\n * Stripe webhook receiver\n * POST /v1/partner/stripe/webhook\n */\nexport interface handleStripeWebhookOperation {\n readonly path: \"/v1/partner/stripe/webhook\";\n readonly method: \"POST\";\n request: Record<string, unknown>;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n event_type?: string;\n received?: boolean;\n};\n}\n\n/**\n * List team members\n * GET /v1/partner/team\n */\nexport interface listTeamMembersOperation {\n readonly path: \"/v1/partner/team\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n status?: \"active\" | \"pending\" | \"all\";\n};\n response: {\n data?: {\n members?: Array<TeamMember>;\n partner?: {\n name?: string;\n slug?: string;\n };\n total?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Accept team invitation\n * POST /v1/partner/team/accept\n */\nexport interface acceptInvitationOperation {\n readonly path: \"/v1/partner/team/accept\";\n readonly method: \"POST\";\n request: {\n /** Invitation token from email link */\n token: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n partner?: {\n id?: string;\n name?: string;\n slug?: string;\n };\n permissions?: RolePermissions;\n portal_url?: string;\n role?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Invite a team member\n * POST /v1/partner/team/invite\n */\nexport interface inviteTeamMemberOperation {\n readonly path: \"/v1/partner/team/invite\";\n readonly method: \"POST\";\n request: {\n /** Email address of the invitee */\n email: string;\n /** Optional name of the invitee */\n name?: string;\n /** Role to assign to the team member */\n role?: \"admin\" | \"viewer\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: TeamInviteResponse;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get invitation details\n * GET /v1/partner/team/invite/{token}\n */\nexport interface getInvitationByTokenOperation {\n readonly path: \"/v1/partner/team/invite/{token}\";\n readonly method: \"GET\";\n request: never;\n params: {\n token: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n email?: string;\n expires_at?: string;\n invited_at?: string;\n partner?: {\n name?: string;\n slug?: string;\n };\n role?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Resend invitation\n * POST /v1/partner/team/{membershipId}/resend\n */\nexport interface resendInvitationOperation {\n readonly path: \"/v1/partner/team/{membershipId}/resend\";\n readonly method: \"POST\";\n request: never;\n params: {\n membershipId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n email?: string;\n expires_at?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Remove a team member\n * DELETE /v1/partner/team/{userId}\n */\nexport interface removeTeamMemberOperation {\n readonly path: \"/v1/partner/team/{userId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n userId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Change team member role\n * PATCH /v1/partner/team/{userId}/role\n */\nexport interface changeTeamMemberRoleOperation {\n readonly path: \"/v1/partner/team/{userId}/role\";\n readonly method: \"PATCH\";\n request: {\n role: \"admin\" | \"viewer\";\n};\n params: {\n userId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n new_role?: string;\n old_role?: string;\n permissions?: RolePermissions;\n user_id?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get public key for proof verification\n * GET /v1/partner/tracking/.well-known/public-key\n */\nexport interface getTrackingPublicKeyOperation {\n readonly path: \"/v1/partner/tracking/.well-known/public-key\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Signature algorithm (ed25519 for public key, sha256 for HMAC fallback) */\n algorithm?: \"ed25519\" | \"sha256\";\n documentation?: string;\n /** Key identifier for rotation support */\n keyId?: string;\n /** Hex-encoded Ed25519 public key (null if using HMAC fallback) */\n publicKey?: string | null;\n verificationUrl?: string;\n version?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Record batch impressions with proof generation\n * POST /v1/partner/tracking/batch\n */\nexport interface recordTrackingBatchOperation {\n readonly path: \"/v1/partner/tracking/batch\";\n readonly method: \"POST\";\n request: {\n impressions: Array<{\n /** Ad identifier from VAST response */\n ad_id: string;\n /** Optional audience metrics */\n audience?: {\n /** Attention score (0-1) */\n attention?: number;\n /** How long viewers were present */\n dwell_time_ms?: number;\n /** Number of viewers detected */\n face_count?: number;\n };\n /** Partner's device identifier */\n device_id: string;\n /** Video duration played in milliseconds */\n duration_ms?: number;\n /** VAST event type */\n event?: \"start\" | \"complete\" | \"error\" | \"firstQuartile\" | \"midpoint\" | \"thirdQuartile\";\n /** Optional client-generated ID (auto-generated if not provided) */\n impression_id?: string;\n /** When the event occurred (defaults to now) */\n timestamp?: string;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Number of duplicate impressions skipped */\n duplicates?: number;\n /** Details of failed impressions (max 10 shown) */\n errors?: Array<{\n error?: string;\n impression_id?: string;\n }>;\n /** Number of impressions that failed validation */\n failed?: number;\n /** Number of impressions successfully recorded */\n processed?: number;\n /** Time to process the batch */\n processing_time_ms?: number;\n /** Cryptographic proofs for each processed impression */\n proofs?: Array<{\n impression_id?: string;\n public_key_id?: string;\n /** Ed25519 signature (or SHA256 fallback) */\n signature?: string;\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get API usage summary\n * GET /v1/partner/usage\n */\nexport interface getUsageSummaryOperation {\n readonly path: \"/v1/partner/usage\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n end_date?: string;\n start_date?: string;\n};\n response: {\n /** Average response time in milliseconds */\n avgResponseTime?: number;\n dailyBreakdown?: Array<{\n avg_response_ms?: number;\n /** The UTC day, sent as the timestamp of its midnight. */\n date?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n /** Error rate percentage (0-100) */\n errorRate?: number;\n object?: string;\n period?: {\n end_date?: string;\n start_date?: string;\n };\n topEndpoints?: Array<{\n endpoint?: string;\n method?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n totalCalls?: number;\n totalErrors?: number;\n};\n}\n\n/**\n * Get real-time usage dashboard\n * GET /v1/partner/usage/dashboard\n */\nexport interface getUsageDashboardOperation {\n readonly path: \"/v1/partner/usage/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n last_7_days?: {\n avg_response_ms?: number;\n daily_breakdown?: Array<{\n avg_response_ms?: number;\n /** The UTC day, sent as the timestamp of its midnight. */\n date?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n error_rate?: number;\n total_calls?: number;\n total_errors?: number;\n };\n object?: string;\n rate_limit?: {\n current_rate?: number;\n max_rate?: number;\n percent_used?: number;\n window_reset?: string;\n window_seconds?: number;\n };\n today?: {\n avg_response_ms?: number;\n error_rate?: number;\n top_endpoints?: Array<{\n avg_response_ms?: number;\n endpoint?: string;\n method?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n total_calls?: number;\n total_errors?: number;\n };\n};\n}\n\n/**\n * Get rate limit status\n * GET /v1/partner/usage/rate-limit\n */\nexport interface getRateLimitStatusOperation {\n readonly path: \"/v1/partner/usage/rate-limit\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n current_rate?: number;\n max_rate?: number;\n object?: string;\n percent_used?: number;\n tier?: \"basic\" | \"developer\" | \"enterprise\";\n window_reset?: string;\n window_seconds?: number;\n};\n}\n\n/**\n * Get VAST configuration for direct Google integration\n * GET /v1/partner/vast/config\n */\nexport interface getVastConfigOperation {\n readonly path: \"/v1/partner/vast/config\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n device_id?: string;\n screen_id?: string;\n};\n response: {\n data?: {\n /** Google Ad Manager ad unit path */\n ad_unit?: string;\n /** IAB content categories to block */\n blocked_categories?: Array<string>;\n /** How long to cache this config */\n cache_ttl_seconds?: number;\n /** Floor price in cents (CPM) */\n floor_price_cpm?: number;\n integration_guide?: string;\n parameters?: {\n height?: number;\n /** Maximum ad duration in seconds */\n max_duration?: number;\n /** Minimum ad duration in seconds */\n min_duration?: number;\n /** Venue type code for targeting */\n venuetype?: number;\n width?: number;\n };\n /** Recommended VAST fetch timeout */\n timeout_ms?: number;\n tracking?: {\n batch_endpoint?: string;\n max_batch_size?: number;\n single_endpoint?: string;\n };\n /** Configuration variant name for debugging */\n variant?: string;\n /** VAST URL template with placeholders for {width} and {height}. Partner replaces placeholders and appends correlator. */\n vast_tag_template?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * List nearby Trillboards venues\n * GET /v1/partner/venues/nearby\n */\nexport interface getVenuesNearbyOperation {\n readonly path: \"/v1/partner/venues/nearby\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n lat: number;\n lng: number;\n radius_km?: number;\n};\n response: {\n count?: number;\n venues?: Array<{\n distance_m?: number;\n screen_id?: string;\n venue_type?: string;\n }>;\n};\n}\n\n/**\n * Real-world atmosphere signals for a venue\n * GET /v1/partner/venues/{screenId}/atmosphere\n */\nexport interface getVenueAtmosphereOperation {\n readonly path: \"/v1/partner/venues/{screenId}/atmosphere\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n};\n response: {\n days?: number;\n dominant_ambience?: string;\n lighting_band?: \"dark\" | \"dim\" | \"lit\" | \"bright\";\n motion_intensity?: number;\n noise_level_db?: number;\n screen_id?: string;\n};\n}\n\n/**\n * Foot-traffic profile for a venue\n * GET /v1/partner/venues/{screenId}/traffic\n */\nexport interface getVenueTrafficOperation {\n readonly path: \"/v1/partner/venues/{screenId}/traffic\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n};\n response: {\n daily?: Array<Record<string, unknown>>;\n hourly?: Array<{\n face_count_avg?: number;\n hour?: number;\n }>;\n screen_id?: string;\n};\n}\n\n/**\n * Get venue intelligence report\n * GET /v1/partner/venues/{venueId}/intelligence\n */\nexport interface getVenueIntelligenceOperation {\n readonly path: \"/v1/partner/venues/{venueId}/intelligence\";\n readonly method: \"GET\";\n request: never;\n params: {\n venueId: string;\n};\n query: {\n from: string;\n interval?: \"5min\" | \"15min\" | \"1h\" | \"1d\";\n to: string;\n};\n response: {\n dedup?: {\n camera_count?: number;\n method?: \"lincoln_petersen\" | \"single_camera\";\n raw_total?: number;\n unique_total?: number;\n };\n from?: string;\n interval?: string;\n summary?: {\n avg_attention?: number;\n buckets?: number;\n total_unique_viewers?: number;\n };\n timeseries?: Array<{\n age_distribution?: Record<string, number>;\n avg_attention?: number;\n avg_engagement?: number;\n avg_noise_level?: number | null;\n brand_mention_windows?: number;\n bucket?: string;\n gender_distribution?: {\n female?: number;\n male?: number;\n };\n income_level?: string | null;\n measurements?: number;\n mood?: string | null;\n peak_viewers?: number;\n raw_viewers?: number;\n screen_count?: number;\n /** Deduplicated viewer count */\n viewers?: number;\n weather?: {\n condition?: string | null;\n is_raining?: boolean;\n temperature_f?: number | null;\n };\n }>;\n to?: string;\n venue_id?: string;\n};\n}\n\n/**\n * List webhooks\n * GET /v1/partner/webhooks\n */\nexport interface listWebhooksOperation {\n readonly path: \"/v1/partner/webhooks\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n webhooks?: Array<Webhook>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create webhook subscription\n * POST /v1/partner/webhooks\n */\nexport interface createWebhookOperation {\n readonly path: \"/v1/partner/webhooks\";\n readonly method: \"POST\";\n request: {\n /** Events to subscribe to */\n events: Array<\"device.online\" | \"device.offline\" | \"device.requirements_updated\" | \"impression.recorded\" | \"creative.rewards_ready\" | \"campaign.allocated\" | \"payout.processed\" | \"sensing.threshold_crossed\" | \"audience.spike\" | \"audience.venue_busy\" | \"audience.purchase_intent\" | \"audience.demographics_update\" | \"venue.traffic_summary\" | \"programmatic.ad_started\" | \"programmatic.ad_ended\" | \"programmatic.no_fill\" | \"programmatic.error\" | \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\" | \"fleet_command.completed\" | \"fleet_command.failed\">;\n /** Webhook endpoint URL (HTTPS required in production) */\n url: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n events?: Array<string>;\n /** Webhook signing secret (shown only once!) */\n secret?: string;\n status?: \"active\" | \"inactive\";\n url?: string;\n webhook_id?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Delete webhook\n * DELETE /v1/partner/webhooks/{webhookId}\n */\nexport interface deleteWebhookOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n webhookId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Update webhook\n * PATCH /v1/partner/webhooks/{webhookId}\n */\nexport interface updateWebhookOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}\";\n readonly method: \"PATCH\";\n request: {\n events?: Array<\"device.online\" | \"device.offline\" | \"device.requirements_updated\" | \"impression.recorded\" | \"creative.rewards_ready\" | \"campaign.allocated\" | \"payout.processed\" | \"sensing.threshold_crossed\" | \"audience.spike\" | \"audience.venue_busy\" | \"audience.purchase_intent\" | \"audience.demographics_update\" | \"venue.traffic_summary\" | \"programmatic.ad_started\" | \"programmatic.ad_ended\" | \"programmatic.no_fill\" | \"programmatic.error\" | \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\" | \"fleet_command.completed\" | \"fleet_command.failed\">;\n status?: \"active\" | \"inactive\";\n url?: string;\n};\n params: {\n webhookId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: Webhook;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get delivery history\n * GET /v1/partner/webhooks/{webhookId}/deliveries\n */\nexport interface getWebhookDeliveriesOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}/deliveries\";\n readonly method: \"GET\";\n request: never;\n params: {\n webhookId: string;\n};\n query: {\n limit?: number;\n};\n response: {\n data?: {\n deliveries?: Array<WebhookDelivery>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Test webhook\n * POST /v1/partner/webhooks/{webhookId}/test\n */\nexport interface testWebhookOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}/test\";\n readonly method: \"POST\";\n request: never;\n params: {\n webhookId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n error?: string | null;\n response_time_ms?: number;\n status?: number;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Dry-run validate a request body against an operation schema\n * POST /v1/playground/{operation_id}\n */\nexport interface playgroundDryRunOperation {\n readonly path: \"/v1/playground/{operation_id}\";\n readonly method: \"POST\";\n request: never;\n params: {\n /** The operationId of the endpoint to validate against. */\n operation_id: string;\n};\n query: Record<string, unknown>;\n response: PlaygroundResult;\n}\n\n/**\n * Look up metadata for a recent API request\n * GET /v1/requests/{request_id}\n */\nexport interface getRequestMetadataOperation {\n readonly path: \"/v1/requests/{request_id}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Server-generated request ID to look up. */\n request_id: string;\n};\n query: Record<string, unknown>;\n response: RequestMetadataResponse;\n}\n\n\n// ─── Type registry ───────────────────────────────────────────────────────\n\nexport const generatedTypes = {\n schemaCount: 329,\n operationCount: 298,\n schemas: [\"Ad\",\"AdSettings\",\"AdvertisingIdentity\",\"AnalyticsData\",\"AudienceAnalyticsResponse\",\"AudienceAttentionPrediction\",\"AudienceData\",\"AudienceExportResponse\",\"AudienceLoyaltyFeaturesRow\",\"AudienceMetricsResponse\",\"AudienceSegment\",\"AudienceSocialAttention\",\"BatchResult\",\"BillingInfo\",\"BleScanResultData\",\"CanonicalError\",\"ChangelogEntry\",\"ChangelogResponse\",\"CompletedImpressions\",\"ContentFitSettings\",\"ContentPreferencesInput\",\"ContentPreferencesResponse\",\"ContentPreset\",\"CreatePartnerSensingRouteRequest\",\"CreativeClassification\",\"CreativeRewardsReadyEvent\",\"DashboardResponse\",\"DataApi_AdSightingRecord\",\"DataApi_AdSightingsHistoryResponse\",\"DataApi_AdSightingsResponse\",\"DataApi_AggregateResponse\",\"DataApi_CreativeBrandHistoryRow\",\"DataApi_DataDelivery_ad_delivery_hourly\",\"DataApi_DataDelivery_attention_ledger\",\"DataApi_DataDelivery_auction_results\",\"DataApi_DataDelivery_audience_composition_weekly\",\"DataApi_DataDelivery_audience_metrics\",\"DataApi_DataDelivery_board_creative_sighting\",\"DataApi_DataDelivery_board_currency_multiweek\",\"DataApi_DataDelivery_board_flow_hourly\",\"DataApi_DataDelivery_board_pass_daily\",\"DataApi_DataDelivery_camera_frame_corpus\",\"DataApi_DataDelivery_camera_video_corpus\",\"DataApi_DataDelivery_completed_impressions\",\"DataApi_DataDelivery_creative_flights\",\"DataApi_DataDelivery_cross_screen_edges_daily\",\"DataApi_DataDelivery_curated_inventory_packages\",\"DataApi_DataDelivery_device_exposure_hourly\",\"DataApi_DataDelivery_device_exposure_windows\",\"DataApi_DataDelivery_dim_screen\",\"DataApi_DataDelivery_event_tracking\",\"DataApi_DataDelivery_geohash_activity_hourly\",\"DataApi_DataDelivery_impression_events\",\"DataApi_DataDelivery_inference_outcomes\",\"DataApi_DataDelivery_ip_geo_observations\",\"DataApi_DataDelivery_mobility_flows_daily\",\"DataApi_DataDelivery_observation_demographics\",\"DataApi_DataDelivery_omsdk_sessions\",\"DataApi_DataDelivery_panel_segment_cells\",\"DataApi_DataDelivery_place_activity_hourly\",\"DataApi_DataDelivery_play_audience\",\"DataApi_DataDelivery_play_audience_window\",\"DataApi_DataDelivery_play_device_exposure\",\"DataApi_DataDelivery_proximity_graph_edges_hourly\",\"DataApi_DataDelivery_public_attention_city_venue_hourly\",\"DataApi_DataDelivery_ride_places\",\"DataApi_DataDelivery_screen_hourly_presence\",\"DataApi_DataDelivery_screen_panel_monthly\",\"DataApi_DataDelivery_sighted_creatives\",\"DataApi_DataDelivery_vast_requests\",\"DataApi_DataProducts_AudienceRow\",\"DataApi_DataProducts_AuthError\",\"DataApi_DataProducts_Benchmark\",\"DataApi_DataProducts_BoardAudience\",\"DataApi_DataProducts_BoardAudienceResponse\",\"DataApi_DataProducts_BoardCurrency\",\"DataApi_DataProducts_BoardCurrencyResponse\",\"DataApi_DataProducts_BoardLookedShare\",\"DataApi_DataProducts_BoardLookedShareResponse\",\"DataApi_DataProducts_BoardPointCollection\",\"DataApi_DataProducts_BoardPointMeta\",\"DataApi_DataProducts_BoardPointProperties\",\"DataApi_DataProducts_BoardTiles\",\"DataApi_DataProducts_BoardTilesResponse\",\"DataApi_DataProducts_BrandMarket\",\"DataApi_DataProducts_BrandSearch\",\"DataApi_DataProducts_BrandSearchResponse\",\"DataApi_DataProducts_Calibration\",\"DataApi_DataProducts_CalibrationCell\",\"DataApi_DataProducts_CalibrationResponse\",\"DataApi_DataProducts_CalibrationVersion\",\"DataApi_DataProducts_CalibrationVersions\",\"DataApi_DataProducts_CalibrationVersionsResponse\",\"DataApi_DataProducts_CurationSet\",\"DataApi_DataProducts_CurationSetList\",\"DataApi_DataProducts_CurationSetListResponse\",\"DataApi_DataProducts_CurrencyAbsent\",\"DataApi_DataProducts_CurrencyBoard\",\"DataApi_DataProducts_CurrencyCell\",\"DataApi_DataProducts_DeliveryReport\",\"DataApi_DataProducts_DeliveryReportResponse\",\"DataApi_DataProducts_DmaFormatIndex\",\"DataApi_DataProducts_DmaFormatIndexResponse\",\"DataApi_DataProducts_DmaFormatIndexRow\",\"DataApi_DataProducts_FacingVerdict\",\"DataApi_DataProducts_FeedPublication\",\"DataApi_DataProducts_GeohashTileCollection\",\"DataApi_DataProducts_GeohashTileMeta\",\"DataApi_DataProducts_GeohashTileProperties\",\"DataApi_DataProducts_Geometry\",\"DataApi_DataProducts_LookedShareRow\",\"DataApi_DataProducts_MeasurementError\",\"DataApi_DataProducts_Method\",\"DataApi_DataProducts_MetricAnswer\",\"DataApi_DataProducts_MetricAnswerResponse\",\"DataApi_DataProducts_MetricBoardMeasuredImpressionsPerSpotResponse\",\"DataApi_DataProducts_MetricBoardPassAudienceResponse\",\"DataApi_DataProducts_MetricCameraDwellCappedMsResponse\",\"DataApi_DataProducts_MetricCameraGazePctResponse\",\"DataApi_DataProducts_MetricCameraHeadPoseIndexResponse\",\"DataApi_DataProducts_MetricCameraPeoplePerScreenHourResponse\",\"DataApi_DataProducts_MetricCatalog\",\"DataApi_DataProducts_MetricCatalogEntry\",\"DataApi_DataProducts_MetricCatalogResponse\",\"DataApi_DataProducts_MetricCreativeBrandHistoryResponse\",\"DataApi_DataProducts_MetricCreativeShareOfVoiceResponse\",\"DataApi_DataProducts_MetricCreativeSightingsResponse\",\"DataApi_DataProducts_MetricCreativeStreetPresenceResponse\",\"DataApi_DataProducts_MetricCreativeVacancyRateResponse\",\"DataApi_DataProducts_MetricDemographicShareResponse\",\"DataApi_DataProducts_MetricMeasure\",\"DataApi_DataProducts_MetricRadioIdentifiersPerPersonResponse\",\"DataApi_DataProducts_MetricSamePanelIndexResponse\",\"DataApi_DataProducts_MetricSeatbeltComplianceResponse\",\"DataApi_DataProducts_MetricSeatbeltUnbuckledRideRateResponse\",\"DataApi_DataProducts_MetricSensingCensusResponse\",\"DataApi_DataProducts_MultiplierFeed\",\"DataApi_DataProducts_MultiplierFeedResponse\",\"DataApi_DataProducts_OccluderCollection\",\"DataApi_DataProducts_OccluderMeta\",\"DataApi_DataProducts_OccluderProperties\",\"DataApi_DataProducts_OwnerFace\",\"DataApi_DataProducts_OwnerFaceDetail\",\"DataApi_DataProducts_OwnerFaceResponse\",\"DataApi_DataProducts_OwnerFaces\",\"DataApi_DataProducts_OwnerFacesResponse\",\"DataApi_DataProducts_OwnerUploadResponse\",\"DataApi_DataProducts_PassReplay\",\"DataApi_DataProducts_PassReplayResponse\",\"DataApi_DataProducts_Release\",\"DataApi_DataProducts_ReleaseRegistry\",\"DataApi_DataProducts_ReleaseRegistryResponse\",\"DataApi_DataProducts_ReplayPass\",\"DataApi_DataProducts_RoadCollection\",\"DataApi_DataProducts_RoadProperties\",\"DataApi_DataProducts_SetCoverage\",\"DataApi_DataProducts_SetCoverageEnvelope\",\"DataApi_DataProducts_SetCoverageResponse\",\"DataApi_DataProducts_SightedBrand\",\"DataApi_DataProducts_TileSum\",\"DataApi_DataProducts_ViewshedCollection\",\"DataApi_DataProducts_ViewshedMeta\",\"DataApi_DataProducts_ViewshedProperties\",\"DataApi_DataProducts_Watermark\",\"DataApi_DataProducts_Window\",\"DataApi_DataProducts_YieldReport\",\"DataApi_DataProducts_YieldReportResponse\",\"DataApi_Error\",\"DataApi_ErrorCode\",\"DataApi_FeedbackRewardQuery\",\"DataApi_LookalikeResponse\",\"DataApi_QueryDslBody\",\"DataApi_QueryDslResponse\",\"DataApi_QueryFilter\",\"DataApi_QueryOrderBy\",\"DataApi_ScreenAudienceResponse\",\"DataApi_ScreenHistoryResponse\",\"DataApi_ScreensListResponse\",\"DataApi_SemanticSearchResponse\",\"DataApi_StatsResponse\",\"DataApi_StreamResponse\",\"DataApi_UsageResponse\",\"DataExportSummaryResponse\",\"DemandPartners\",\"DemographicsResponse\",\"Device\",\"DeviceAuthRefusal\",\"DeviceCapabilityPayload\",\"DeviceSummary\",\"DisplaySettingsInput\",\"DisplaySettingsResponse\",\"EarnerScreens\",\"EarningsBreakdownResponse\",\"EarningsData\",\"EarningsResponse\",\"EarningsSources\",\"Error\",\"ErrorCode\",\"ErrorCodeResponse\",\"ErrorEntry\",\"ErrorEnvelope\",\"ErrorListItem\",\"ErrorListResponse\",\"ErrorType\",\"ExtendedIdentity\",\"FeedbackBrand\",\"FeedbackBrandRequest\",\"FeedbackBrandResponse\",\"FeedbackCreateRequest\",\"FeedbackCreativeReview\",\"FeedbackExperiment\",\"FeedbackExperimentDetail\",\"FeedbackExperimentDetailResponse\",\"FeedbackExperimentResponse\",\"FeedbackGenerateRequest\",\"FeedbackGenerateResponse\",\"FeedbackGeneratedCreative\",\"FeedbackImportRequest\",\"FeedbackPolicyRequest\",\"FeedbackRecoveredCreative\",\"FeedbackRegisterVariantsRequest\",\"FeedbackReviewRequest\",\"FeedbackReviewResponse\",\"FeedbackRewardQuery\",\"FeedbackRewardRow\",\"FeedbackRewards\",\"FeedbackRewardsResponse\",\"FeedbackStopRequest\",\"FeedbackVariant\",\"FleetCommand\",\"FleetCommandEvent\",\"HeaderBiddingSettings\",\"HttpProbeResult\",\"HybridError\",\"Impression\",\"LegacyCodedError\",\"LegacyError\",\"Mcp_create_media_buy_Args\",\"Mcp_discover_inventory_Args\",\"Mcp_get_media_buy_delivery_Args\",\"Mcp_get_media_buys_Args\",\"Mcp_get_products_Args\",\"Mcp_list_accounts_Args\",\"Mcp_sync_accounts_Args\",\"Mcp_sync_creatives_Args\",\"Mcp_update_media_buy_Args\",\"MdnsNetworkDevice\",\"MeasurementMethodology\",\"OpenrtbRevenueScreenHourly\",\"Pagination\",\"Partner\",\"PartnerAdDeliveryProfile\",\"PartnerCreativeWarnings\",\"PartnerDefaultStream\",\"PartnerDefaultStreamCreate\",\"PartnerDefaultStreamUpdate\",\"PartnerDeviceBatchRegistrationInput\",\"PartnerDeviceHeartbeatBody\",\"PartnerDevicePlay\",\"PartnerDeviceRegistrationInput\",\"PartnerHeartbeatCommand\",\"PartnerHeartbeatData\",\"PartnerHeartbeatMeasurementMetadata\",\"PartnerHeartbeatQueryData\",\"PartnerHeartbeatQueryResponse\",\"PartnerHeartbeatRequest\",\"PartnerHeartbeatResponse\",\"PartnerHeartbeatTelemetry\",\"PartnerInteraction\",\"PartnerLBarContent\",\"PartnerLBarDisplayPreferences\",\"PartnerLBarSettings\",\"PartnerLocationCapability\",\"PartnerLocationRail\",\"PartnerMonetizationRequirements\",\"PartnerNetworkConfig\",\"PartnerNetworkConfigUpdate\",\"PartnerPlay\",\"PartnerReconciliationReports\",\"PartnerRegistrationDisplaySettings\",\"PartnerRequirement\",\"PartnerSafeHeartbeatTelemetry\",\"PartnerSelfPromoAd\",\"PartnerSelfPromoCreate\",\"PartnerSelfPromoPlacement\",\"PartnerStats\",\"PartnerTripState\",\"PartnerVariants\",\"PartnerZoneCpmDaily\",\"PayoutResponse\",\"PlaygroundResult\",\"PlaygroundValidationError\",\"ProgrammaticSettingsInput\",\"ProgrammaticSettingsResponse\",\"RequestMetadataResponse\",\"ResolvedContentPolicy\",\"ResolvedSensingConfig\",\"RolePermissions\",\"SDKConfig\",\"Screen\",\"ScreenAnalyticsResponse\",\"ScreenGroup\",\"ScreenGroupContentPolicy\",\"ScreenGroupContentPolicyInput\",\"ScreenGroupEvent\",\"ScreenGroupSensingConfig\",\"ScreenGroupSensingConfigInput\",\"SensingPerformanceMode\",\"SensingRoute\",\"SensingRouteAction\",\"SensingRouteCondition\",\"SensingRouteReviewTimingMode\",\"SensingRouteReviewWaitSeconds\",\"SensingRouteScreenFocusRegion\",\"SensingSettingsResponse\",\"SensingThresholdCrossedEvent\",\"SsdpDeviceInfo\",\"TeamInviteResponse\",\"TeamMember\",\"Transaction\",\"TrillboardsError\",\"UpdatePartnerSensingRouteRequest\",\"VastWaterfall\",\"VastWaterfallSource\",\"Webhook\",\"WebhookDelivery\",\"WebhookEvent\",\"WifiEnvironmentSnapshot\",\"WifiScanResult\"] as const,\n operations: [\"getAdSightingFrame\",\"getAdSightingPhoto\",\"listAdSightingsInPortal\",\"listAdSightingHistoryInPortal\",\"listMeasuredBoards\",\"getMeasuredBoardAudience\",\"getMeasuredBoardCurrency\",\"getMeasuredBoardLookedShare\",\"getMeasuredBoardOccluders\",\"getMeasuredBoardPassReplay\",\"getMeasuredBoardTiles\",\"getMeasuredBoardViewshed\",\"searchSightedBrands\",\"getMeasurementCalibration\",\"listMeasurementCalibrationVersions\",\"listCurationSets\",\"getCurationSetCoverage\",\"getCurationSetRoads\",\"getCurationSetViewsheds\",\"getMeasuredMultiplierFeed\",\"getMeasuredDmaFormatIndex\",\"listApprovedMetrics\",\"getMetricBoardMeasuredImpressionsPerSpot\",\"getMetricBoardPassAudience\",\"getMetricCameraDwellCappedMs\",\"getMetricCameraGazePct\",\"getMetricCameraHeadPoseIndex\",\"getMetricCameraPeoplePerScreenHour\",\"getMetricCreativeBrandHistory\",\"getMetricCreativeShareOfVoice\",\"getMetricCreativeSightings\",\"getMetricCreativeStreetPresence\",\"getMetricCreativeVacancyRate\",\"getMetricDemographicShare\",\"getMetricRadioIdentifiersPerPerson\",\"getMetricSamePanelIndex\",\"getMetricSeatbeltCompliance\",\"getMetricSeatbeltUnbuckledRideRate\",\"getMetricSensingCensus\",\"getApprovedMetric\",\"listMeasurementReleases\",\"listMeasuredRoads\",\"listMeasuredGeohashTiles\",\"queryChangelog\",\"dataApiAdSightings\",\"dataApiAdSightingsHistory\",\"dataApiAggregate\",\"dataApiLookalikeScreens\",\"dataApiQueryDsl\",\"dataApiListScreens\",\"dataApiScreenAudienceLive\",\"dataApiScreenAudienceHistory\",\"dataApiSemanticSearch\",\"dataApiStats\",\"dataApiStream\",\"dataApiUsage\",\"listErrorCodes\",\"getErrorCode\",\"getOwnerBoardAudience\",\"getOwnerBoardCurrency\",\"getOwnerDeliveryReport\",\"getOwnerBoardLookedShare\",\"getOwnerBoardTiles\",\"getOwnerBoardViewshed\",\"listOwnerFaces\",\"getOwnerFace\",\"getOwnerMultiplierFeed\",\"uploadOwnerPlayLogs\",\"getOwnerPublisherYieldByQuery\",\"getOwnerPublisherYield\",\"listOwnerMeasurementReleases\",\"uploadOwnerFaceSpecs\",\"listPartnerSelfPromoAds\",\"createPartnerSelfPromoAd\",\"listPartnerSelfPromoPlacements\",\"schedulePartnerSelfPromo\",\"createPartnerSelfPromoUpload\",\"disableSelfPromoAd\",\"registerAgent\",\"getAnalytics\",\"getAudienceContinuity\",\"getAudienceProfile\",\"getBleSummary\",\"getContentPerformance\",\"searchCreativeCatalog\",\"getCreativeObservations\",\"getCreativeScenes\",\"getCrossScreenFlow\",\"getPartnerAnalyticsDashboard\",\"getDeviceSuiteSignature\",\"exportPartnerAnalytics\",\"exportPartnerAdsByDay\",\"getFleetHourly\",\"getHaloFunnel\",\"getLoyaltyClock\",\"getNetworkSummary\",\"getNetworkTrend\",\"getProximitySummary\",\"getRevenueAttentionCorrelation\",\"getSceneFeed\",\"getSceneIntelligence\",\"rotateApiKey\",\"getAudienceAnalytics\",\"exportAudienceData\",\"getAudienceHeatmap\",\"getLiveAudience\",\"getLookalikeScreens\",\"predictScreenAudience\",\"getResolvedHouseholdReach\",\"listAudienceSegments\",\"createAudienceSegment\",\"deleteAudienceSegment\",\"getAudienceSegment\",\"updateAudienceSegment\",\"matchAudienceSegment\",\"estimateSegmentReach\",\"generateSegmentVastTag\",\"getAudienceStats\",\"cancelBillingSubscription\",\"purchaseCredits\",\"createCreditCheckout\",\"listBillingPlans\",\"setupBilling\",\"createBillingSubscription\",\"getBillingSubscription\",\"getBillingUsage\",\"getBillingUsageSummary\",\"stripeWebhookCallback\",\"getConnectDashboard\",\"getConnectEarningsChart\",\"getConnectScreenHealth\",\"listContentPresets\",\"getContentPreset\",\"createCreativeFeedbackExperiment\",\"getCreativeFeedbackExperiment\",\"configureCreativeFeedbackBrand\",\"generateCreativeFeedbackCreative\",\"importCreativeFeedbackCreative\",\"reviewCreativeFeedbackCreative\",\"updateCreativeFeedbackPolicy\",\"getCreativeFeedbackRewards\",\"stopCreativeFeedbackExperiment\",\"registerCreativeFeedbackVariants\",\"submitPartnerCreative\",\"getPartnerCreative\",\"getDashboard\",\"exportProximityGraphEdges\",\"getDataExportSummary\",\"exportDataset\",\"getGeohashAudiencePanel\",\"getOutcomeAttribution\",\"registerDevice\",\"deleteDevice\",\"getDevice\",\"updateDevice\",\"getAdsForDevice\",\"ackDeviceCommand\",\"getDeviceHeartbeat\",\"heartbeat\",\"updateDeviceImpressionMultiplier\",\"recordPartnerDeviceInteraction\",\"recordPartnerDevicePlay\",\"recordProgrammaticEvent\",\"recordPartnerDeviceTripState\",\"getVastForDevice\",\"listDevices\",\"registerDeviceV2\",\"registerDevicesBatch\",\"batchUpdateDeviceOrientation\",\"reconcileDevices\",\"partnerDocsBrowser\",\"getEarnings\",\"getEarningsBreakdown\",\"requestPayout\",\"getTransactions\",\"getActiveSSEConnections\",\"subscribeToEvents\",\"getFleetCommand\",\"getFleetAnalytics\",\"pushFleetCommand\",\"getFleetOverview\",\"updateFleetSettings\",\"recordImpressionGet\",\"recordImpressionPost\",\"recordImpressionsBatch\",\"getPartnerInfo\",\"listIntentCategories\",\"getIntentCategory\",\"getIntentPricing\",\"getMeasurementMethodology\",\"getMeasurementMethodologyJson\",\"getNetworkConfig\",\"patchNetworkConfig\",\"updateNetworkConfig\",\"getNetworkTrends\",\"partnerPing\",\"partnerPingAuth\",\"recordPartnerPlay\",\"recordPartnerPlaysBatch\",\"getPricing\",\"recordProgrammaticEventLegacyAlias\",\"quickStart\",\"registerPartner\",\"generateSandboxEvent\",\"resetSandbox\",\"createSandboxScreen\",\"getSandboxStatus\",\"listScreenGroups\",\"createScreenGroup\",\"deleteScreenGroup\",\"getScreenGroup\",\"updateScreenGroup\",\"getScreenGroupAnalytics\",\"createScreenGroupCommand\",\"getScreenGroupContentPolicy\",\"updateScreenGroupContentPolicy\",\"removeScreenGroupMembers\",\"listScreenGroupMembers\",\"addScreenGroupMembers\",\"getScreenGroupSensingConfig\",\"updateScreenGroupSensingConfig\",\"getScreenAudienceSegments\",\"batchUpdateContentPreferences\",\"batchUpdateDisplaySettings\",\"batchUpdateProgrammaticSettings\",\"resolvePartnerScreen\",\"getScreenAnalytics\",\"getPartnerScreenAtmosphere\",\"getPartnerScreenIntelligence\",\"getPartnerScreenTasteProfile\",\"getPartnerScreenTraffic\",\"getPartnerScreenVAS\",\"applyContentPreset\",\"getAudienceMetrics\",\"getContentPreferences\",\"patchContentPreferences\",\"updateContentPreferences\",\"listPartnerDefaultStreams\",\"createPartnerDefaultStream\",\"createPartnerDefaultStreamImages\",\"reorderPartnerDefaultStreams\",\"createPartnerDefaultStreamUpload\",\"deletePartnerDefaultStream\",\"updatePartnerDefaultStream\",\"getScreenDemographics\",\"getDisplaySettings\",\"patchDisplaySettings\",\"updateDisplaySettings\",\"getPartnerLBarSettings\",\"updatePartnerLBarSettings\",\"updatePartnerLBarLiveUpdates\",\"getProgrammaticSettings\",\"patchProgrammaticSettings\",\"updateProgrammaticSettings\",\"getResolvedContentPolicy\",\"getResolvedSensingConfig\",\"getScreenSensingChips\",\"interpretScreenSensingIntent\",\"deployScreenSensingProfile\",\"getScreenSensingSettings\",\"updateScreenSensingSettings\",\"listPartnerSensingRoutes\",\"createPartnerSensingRoute\",\"deletePartnerSensingRoute\",\"getPartnerSensingRoute\",\"updatePartnerSensingRoute\",\"createStripeConnectAccount\",\"getStripeLoginLink\",\"getStripeOnboardingLink\",\"requestStripePayout\",\"getStripePayoutHistory\",\"getStripeAccountStatus\",\"handleStripeWebhook\",\"listTeamMembers\",\"acceptInvitation\",\"inviteTeamMember\",\"getInvitationByToken\",\"resendInvitation\",\"removeTeamMember\",\"changeTeamMemberRole\",\"getTrackingPublicKey\",\"recordTrackingBatch\",\"getUsageSummary\",\"getUsageDashboard\",\"getRateLimitStatus\",\"getVastConfig\",\"getVenuesNearby\",\"getVenueAtmosphere\",\"getVenueTraffic\",\"getVenueIntelligence\",\"listWebhooks\",\"createWebhook\",\"deleteWebhook\",\"updateWebhook\",\"getWebhookDeliveries\",\"testWebhook\",\"playgroundDryRun\",\"getRequestMetadata\"] as const,\n} as const;\n\nexport type GeneratedSchemaName = (typeof generatedTypes.schemas)[number];\nexport type GeneratedOperationName = (typeof generatedTypes.operations)[number];\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/generated/index.ts"],"names":[],"mappings":";;;;;;;;AAqgiBO,IAAM,cAAA,GAAiB;AAAA,EAC5B,WAAA,EAAa,GAAA;AAAA,EACb,cAAA,EAAgB,GAAA;AAAA,EAChB,SAAS,CAAC,IAAA,EAAK,YAAA,EAAa,qBAAA,EAAsB,iBAAgB,2BAAA,EAA4B,6BAAA,EAA8B,cAAA,EAAe,wBAAA,EAAyB,8BAA6B,yBAAA,EAA0B,iBAAA,EAAkB,yBAAA,EAA0B,aAAA,EAAc,eAAc,mBAAA,EAAoB,gBAAA,EAAiB,gBAAA,EAAiB,mBAAA,EAAoB,wBAAuB,oBAAA,EAAqB,yBAAA,EAA0B,4BAAA,EAA6B,eAAA,EAAgB,oCAAmC,wBAAA,EAAyB,2BAAA,EAA4B,mBAAA,EAAoB,0BAAA,EAA2B,sCAAqC,6BAAA,EAA8B,2BAAA,EAA4B,mCAAkC,yCAAA,EAA0C,uCAAA,EAAwC,wCAAuC,kDAAA,EAAmD,uCAAA,EAAwC,8CAAA,EAA+C,+CAAA,EAAgD,0CAAyC,uCAAA,EAAwC,0CAAA,EAA2C,0CAAA,EAA2C,4CAAA,EAA6C,yCAAwC,+CAAA,EAAgD,iDAAA,EAAkD,6CAAA,EAA8C,8CAAA,EAA+C,mCAAkC,qCAAA,EAAsC,8CAAA,EAA+C,0CAAyC,yCAAA,EAA0C,0CAAA,EAA2C,6CAA4C,+CAAA,EAAgD,qCAAA,EAAsC,0CAAA,EAA2C,4CAAA,EAA6C,sCAAqC,2CAAA,EAA4C,2CAAA,EAA4C,mDAAA,EAAoD,yDAAA,EAA0D,oCAAmC,6CAAA,EAA8C,2CAAA,EAA4C,wCAAA,EAAyC,oCAAA,EAAqC,oCAAmC,gCAAA,EAAiC,gCAAA,EAAiC,sCAAqC,4CAAA,EAA6C,oCAAA,EAAqC,8CAA6C,uCAAA,EAAwC,+CAAA,EAAgD,2CAAA,EAA4C,qCAAA,EAAsC,6CAA4C,iCAAA,EAAkC,yCAAA,EAA0C,kCAAA,EAAmC,kCAAA,EAAmC,4CAA2C,kCAAA,EAAmC,sCAAA,EAAuC,0CAAA,EAA2C,yCAAA,EAA0C,4CAA2C,kDAAA,EAAmD,kCAAA,EAAmC,wCAAuC,8CAAA,EAA+C,qCAAA,EAAsC,sCAAqC,mCAAA,EAAoC,qCAAA,EAAsC,6CAAA,EAA8C,qCAAA,EAAsC,+CAA8C,wCAAA,EAAyC,oCAAA,EAAqC,sCAAA,EAAuC,4CAAA,EAA6C,wCAAuC,4CAAA,EAA6C,+BAAA,EAAgC,qCAAA,EAAsC,uCAAA,EAAwC,+BAA8B,mCAAA,EAAoC,2CAAA,EAA4C,sEAAqE,sDAAA,EAAuD,wDAAA,EAAyD,oDAAmD,wDAAA,EAAyD,8DAAA,EAA+D,oCAAA,EAAqC,yCAAA,EAA0C,8CAA6C,yDAAA,EAA0D,yDAAA,EAA0D,sDAAA,EAAuD,2DAAA,EAA4D,0DAAyD,qDAAA,EAAsD,oCAAA,EAAqC,8DAAA,EAA+D,mDAAA,EAAoD,yDAAwD,8DAAA,EAA+D,kDAAA,EAAmD,uCAAsC,6CAAA,EAA8C,yCAAA,EAA0C,qCAAoC,yCAAA,EAA0C,gCAAA,EAAiC,sCAAA,EAAuC,wCAAA,EAAyC,mCAAkC,yCAAA,EAA0C,0CAAA,EAA2C,iCAAA,EAAkC,yCAAA,EAA0C,gCAA+B,sCAAA,EAAuC,8CAAA,EAA+C,iCAAA,EAAkC,qCAAA,EAAsC,uCAAsC,kCAAA,EAAmC,0CAAA,EAA2C,4CAA2C,mCAAA,EAAoC,8BAAA,EAA+B,2CAA0C,mCAAA,EAAoC,yCAAA,EAA0C,gCAAA,EAAiC,6BAAA,EAA8B,oCAAmC,0CAAA,EAA2C,eAAA,EAAgB,mBAAA,EAAoB,6BAAA,EAA8B,6BAA4B,sBAAA,EAAuB,0BAAA,EAA2B,qBAAA,EAAsB,sBAAA,EAAuB,kCAAiC,+BAAA,EAAgC,6BAAA,EAA8B,gCAAA,EAAiC,uBAAA,EAAwB,0BAAyB,uBAAA,EAAwB,2BAAA,EAA4B,gBAAA,EAAiB,sBAAA,EAAuB,UAAS,mBAAA,EAAoB,yBAAA,EAA0B,eAAA,EAAgB,sBAAA,EAAuB,2BAA0B,eAAA,EAAgB,2BAAA,EAA4B,cAAA,EAAe,kBAAA,EAAmB,mBAAkB,OAAA,EAAQ,WAAA,EAAY,qBAAoB,YAAA,EAAa,eAAA,EAAgB,iBAAgB,mBAAA,EAAoB,WAAA,EAAY,kBAAA,EAAmB,eAAA,EAAgB,wBAAuB,uBAAA,EAAwB,uBAAA,EAAwB,wBAAA,EAAyB,oBAAA,EAAqB,4BAA2B,kCAAA,EAAmC,4BAAA,EAA6B,yBAAA,EAA0B,0BAAA,EAA2B,6BAA4B,uBAAA,EAAwB,uBAAA,EAAwB,6BAA4B,iCAAA,EAAkC,uBAAA,EAAwB,0BAAyB,qBAAA,EAAsB,mBAAA,EAAoB,iBAAA,EAAkB,yBAAA,EAA0B,uBAAsB,iBAAA,EAAkB,cAAA,EAAe,mBAAA,EAAoB,uBAAA,EAAwB,mBAAkB,aAAA,EAAc,YAAA,EAAa,kBAAA,EAAmB,aAAA,EAAc,6BAA4B,6BAAA,EAA8B,iCAAA,EAAkC,2BAA0B,uBAAA,EAAwB,wBAAA,EAAyB,0BAAyB,yBAAA,EAA0B,2BAAA,EAA4B,mBAAA,EAAoB,wBAAA,EAAyB,8BAA6B,YAAA,EAAa,SAAA,EAAU,0BAAA,EAA2B,yBAAA,EAA0B,wBAAuB,4BAAA,EAA6B,4BAAA,EAA6B,qCAAA,EAAsC,4BAAA,EAA6B,qBAAoB,gCAAA,EAAiC,yBAAA,EAA0B,wBAAuB,qCAAA,EAAsC,2BAAA,EAA4B,iCAAgC,yBAAA,EAA0B,0BAAA,EAA2B,2BAAA,EAA4B,oBAAA,EAAqB,sBAAqB,+BAAA,EAAgC,qBAAA,EAAsB,2BAAA,EAA4B,qBAAA,EAAsB,mCAAkC,sBAAA,EAAuB,4BAAA,EAA6B,aAAA,EAAc,8BAAA,EAA+B,sCAAqC,oBAAA,EAAqB,+BAAA,EAAgC,sBAAqB,wBAAA,EAAyB,2BAAA,EAA4B,gBAAe,kBAAA,EAAmB,iBAAA,EAAkB,qBAAA,EAAsB,gBAAA,EAAiB,oBAAmB,2BAAA,EAA4B,2BAAA,EAA4B,8BAAA,EAA+B,yBAAA,EAA0B,yBAAwB,uBAAA,EAAwB,iBAAA,EAAkB,WAAA,EAAY,QAAA,EAAS,2BAA0B,aAAA,EAAc,0BAAA,EAA2B,iCAAgC,kBAAA,EAAmB,0BAAA,EAA2B,iCAAgC,wBAAA,EAAyB,cAAA,EAAe,oBAAA,EAAqB,uBAAA,EAAwB,gCAA+B,+BAAA,EAAgC,+BAAA,EAAgC,yBAAA,EAA0B,8BAAA,EAA+B,kBAAiB,oBAAA,EAAqB,YAAA,EAAa,aAAA,EAAc,kBAAA,EAAmB,oCAAmC,eAAA,EAAgB,qBAAA,EAAsB,WAAU,iBAAA,EAAkB,cAAA,EAAe,2BAA0B,gBAAgB,CAAA;AAAA,EACviU,UAAA,EAAY,CAAC,oBAAA,EAAqB,oBAAA,EAAqB,2BAA0B,+BAAA,EAAgC,oBAAA,EAAqB,0BAAA,EAA2B,0BAAA,EAA2B,6BAAA,EAA8B,2BAAA,EAA4B,4BAAA,EAA6B,uBAAA,EAAwB,4BAA2B,qBAAA,EAAsB,2BAAA,EAA4B,oCAAA,EAAqC,kBAAA,EAAmB,wBAAA,EAAyB,qBAAA,EAAsB,yBAAA,EAA0B,2BAAA,EAA4B,6BAA4B,qBAAA,EAAsB,0CAAA,EAA2C,4BAAA,EAA6B,8BAAA,EAA+B,0BAAyB,8BAAA,EAA+B,oCAAA,EAAqC,+BAAA,EAAgC,+BAAA,EAAgC,8BAA6B,iCAAA,EAAkC,8BAAA,EAA+B,2BAAA,EAA4B,oCAAA,EAAqC,yBAAA,EAA0B,6BAAA,EAA8B,oCAAA,EAAqC,wBAAA,EAAyB,qBAAoB,yBAAA,EAA0B,mBAAA,EAAoB,0BAAA,EAA2B,gBAAA,EAAiB,sBAAqB,2BAAA,EAA4B,kBAAA,EAAmB,yBAAA,EAA0B,iBAAA,EAAkB,sBAAqB,2BAAA,EAA4B,8BAAA,EAA+B,uBAAA,EAAwB,cAAA,EAAe,eAAA,EAAgB,cAAA,EAAe,gBAAA,EAAiB,cAAA,EAAe,yBAAwB,uBAAA,EAAwB,wBAAA,EAAyB,0BAAA,EAA2B,oBAAA,EAAqB,yBAAwB,gBAAA,EAAiB,cAAA,EAAe,wBAAA,EAAyB,qBAAA,EAAsB,iCAAgC,wBAAA,EAAyB,8BAAA,EAA+B,sBAAA,EAAuB,yBAAA,EAA0B,0BAAA,EAA2B,gCAAA,EAAiC,0BAAA,EAA2B,8BAAA,EAA+B,sBAAqB,eAAA,EAAgB,cAAA,EAAe,uBAAA,EAAwB,oBAAA,EAAqB,iBAAgB,uBAAA,EAAwB,uBAAA,EAAwB,yBAAA,EAA0B,mBAAA,EAAoB,sBAAqB,8BAAA,EAA+B,yBAAA,EAA0B,wBAAA,EAAyB,uBAAA,EAAwB,gBAAA,EAAiB,eAAA,EAAgB,iBAAA,EAAkB,mBAAA,EAAoB,mBAAkB,qBAAA,EAAsB,gCAAA,EAAiC,cAAA,EAAe,sBAAA,EAAuB,gBAAe,sBAAA,EAAuB,oBAAA,EAAqB,oBAAA,EAAqB,iBAAA,EAAkB,uBAAsB,uBAAA,EAAwB,2BAAA,EAA4B,sBAAA,EAAuB,uBAAA,EAAwB,uBAAA,EAAwB,oBAAA,EAAqB,uBAAA,EAAwB,sBAAA,EAAuB,wBAAuB,wBAAA,EAAyB,kBAAA,EAAmB,2BAAA,EAA4B,iBAAA,EAAkB,wBAAuB,kBAAA,EAAmB,cAAA,EAAe,2BAAA,EAA4B,wBAAA,EAAyB,mBAAkB,wBAAA,EAAyB,uBAAA,EAAwB,qBAAA,EAAsB,yBAAA,EAA0B,wBAAA,EAAyB,oBAAA,EAAqB,kBAAA,EAAmB,kCAAA,EAAmC,iCAAgC,gCAAA,EAAiC,kCAAA,EAAmC,gCAAA,EAAiC,gCAAA,EAAiC,gCAA+B,4BAAA,EAA6B,gCAAA,EAAiC,kCAAA,EAAmC,uBAAA,EAAwB,sBAAqB,cAAA,EAAe,2BAAA,EAA4B,sBAAA,EAAuB,eAAA,EAAgB,yBAAA,EAA0B,uBAAA,EAAwB,gBAAA,EAAiB,cAAA,EAAe,aAAY,cAAA,EAAe,iBAAA,EAAkB,kBAAA,EAAmB,oBAAA,EAAqB,aAAY,kCAAA,EAAmC,gCAAA,EAAiC,yBAAA,EAA0B,yBAAA,EAA0B,gCAA+B,kBAAA,EAAmB,aAAA,EAAc,kBAAA,EAAmB,sBAAA,EAAuB,8BAAA,EAA+B,kBAAA,EAAmB,oBAAA,EAAqB,aAAA,EAAc,wBAAuB,eAAA,EAAgB,iBAAA,EAAkB,yBAAA,EAA0B,mBAAA,EAAoB,mBAAkB,mBAAA,EAAoB,kBAAA,EAAmB,kBAAA,EAAmB,qBAAA,EAAsB,uBAAsB,sBAAA,EAAuB,wBAAA,EAAyB,gBAAA,EAAiB,sBAAA,EAAuB,mBAAA,EAAoB,kBAAA,EAAmB,2BAAA,EAA4B,+BAAA,EAAgC,oBAAmB,oBAAA,EAAqB,qBAAA,EAAsB,kBAAA,EAAmB,aAAA,EAAc,mBAAkB,mBAAA,EAAoB,yBAAA,EAA0B,YAAA,EAAa,oCAAA,EAAqC,cAAa,iBAAA,EAAkB,sBAAA,EAAuB,cAAA,EAAe,qBAAA,EAAsB,kBAAA,EAAmB,kBAAA,EAAmB,mBAAA,EAAoB,mBAAA,EAAoB,kBAAiB,mBAAA,EAAoB,yBAAA,EAA0B,0BAAA,EAA2B,6BAAA,EAA8B,kCAAiC,0BAAA,EAA2B,wBAAA,EAAyB,uBAAA,EAAwB,6BAAA,EAA8B,kCAAiC,2BAAA,EAA4B,+BAAA,EAAgC,4BAAA,EAA6B,iCAAA,EAAkC,sBAAA,EAAuB,oBAAA,EAAqB,4BAAA,EAA6B,8BAAA,EAA+B,gCAA+B,yBAAA,EAA0B,qBAAA,EAAsB,oBAAA,EAAqB,oBAAA,EAAqB,yBAAwB,yBAAA,EAA0B,0BAAA,EAA2B,2BAAA,EAA4B,4BAAA,EAA6B,oCAAmC,8BAAA,EAA+B,kCAAA,EAAmC,4BAAA,EAA6B,4BAAA,EAA6B,uBAAA,EAAwB,oBAAA,EAAqB,sBAAA,EAAuB,uBAAA,EAAwB,0BAAyB,2BAAA,EAA4B,8BAAA,EAA+B,yBAAA,EAA0B,2BAAA,EAA4B,8BAA6B,0BAAA,EAA2B,0BAAA,EAA2B,uBAAA,EAAwB,8BAAA,EAA+B,8BAA6B,0BAAA,EAA2B,6BAAA,EAA8B,0BAAA,EAA2B,2BAAA,EAA4B,2BAAA,EAA4B,wBAAA,EAAyB,2BAAA,EAA4B,4BAAA,EAA6B,sBAAqB,yBAAA,EAA0B,qBAAA,EAAsB,wBAAA,EAAyB,wBAAA,EAAyB,uBAAsB,iBAAA,EAAkB,kBAAA,EAAmB,kBAAA,EAAmB,sBAAA,EAAuB,oBAAmB,kBAAA,EAAmB,sBAAA,EAAuB,sBAAA,EAAuB,qBAAA,EAAsB,iBAAA,EAAkB,mBAAA,EAAoB,oBAAA,EAAqB,eAAA,EAAgB,mBAAkB,oBAAA,EAAqB,iBAAA,EAAkB,sBAAA,EAAuB,cAAA,EAAe,iBAAgB,eAAA,EAAgB,eAAA,EAAgB,sBAAA,EAAuB,aAAA,EAAc,oBAAmB,oBAAoB;AACr+N","file":"chunk-DI7NS7B6.mjs","sourcesContent":["/* eslint-disable */\n/**\n * AUTO-GENERATED. DO NOT EDIT.\n *\n * Generated from: merged partner API, bundled Data API and mounted MCP Zod schemas\n * Generator: trillboards-api-client/scripts/generate.js\n *\n * Re-emit via `npm run generate`.\n */\n\n// OpenAPI version: 3.0.3\n// API title: Trillboards Partner API\n// API version: 1.2.0\n// Schema count: 329\n// Operation count: 298\n\n// ─── Component schemas ───────────────────────────────────────────────────\n\nexport type Ad = {\n /** Placement/allocation ID used for delivery accounting, make-goods, and pacing. */\n allocation_id?: string;\n /** Duration in seconds */\n duration?: number;\n /** Advertisement ID */\n id?: string;\n /** Server-generated impression ID that must be echoed when reporting proof-of-play. */\n impression_id?: string;\n /** **Deprecated alias of `tracking.impression_url`.** These two fields are the same string, byte for byte, produced from one value server-side — they are not two different hooks and firing both records the same call twice. Read `tracking.impression_url`; this flat field is retained only for clients that predate the `tracking` object and will be removed once they are off it. */\n impression_url?: string;\n /** The advertiser's own creative label from the booking record (its `title`, falling back to its `name`), carried through for your logs and QA. Omitted when the booking has neither. It is an internal label, not reviewed display copy, so do not surface it to viewers. */\n title?: string;\n /** Structured proof-of-play URLs for clients that prefer named tracking hooks over legacy flat fields. **Fire exactly one of `impression_url` / `complete_url` per play.** They resolve to the same endpoint and differ only by the `completed` query parameter, which that endpoint does not act on (see `GET /impression`) — calling both records the play twice. */\n tracking?: {\n /** Call when the ad completes playback/display dwell. This is `impression_url` plus `&completed=true`; the flag is inert server-side, so this is a delivery-accounting call, not proof of play. */\n complete_url?: string;\n /** Call when the ad is presented. Identical to the top-level `impression_url`. */\n impression_url?: string;\n /** **Server-signed proof of play. Present only on owner-billable direct bookings; absent on self-promo, house/QR, demo and fully-delivered placements.** When present, fire it VERBATIM — including the `sig`, `request_id` and `impid` parameters — once the ad has finished playing. Do not rewrite, re-sign, re-order, or drop any query parameter: the signature covers the values and any edit invalidates it. This is the only completion signal on the `data.ads` rail that settles; `complete_url` above is delivery accounting and is not billing-grade. Replays of the same play are collapsed on the SIGNED `request_id`, which carries this serve's `impression_id`. Because it is covered by `sig`, a replay that alters it to claim a fresh dedup key fails verification and records nothing — one served play can settle at most once. Firing it in addition to `complete_url` is correct and does not double-count — they land in different stores. */\n owned_direct_complete_url?: string;\n };\n /** `video` or `image`. On the partner/IMA rail an image instant-ad creative is substituted with its pre-rendered MP4 and reports `video`; seeing `image` here means that MP4 was not ready on this poll, so a video-only player should skip the entry and pick it up on a later poll rather than treat it as a still. */\n type?: \"video\" | \"image\";\n /** Media URL (CDN) */\n url?: string;\n};\n\nexport type AdSettings = {\n /** Partner-configured ad rotation cadence in seconds, served from the screen display setting `ad_interval_seconds` when present and legacy display preferences only as fallback. */\n ad_interval?: number;\n content_fit?: ContentFitSettings;\n /** Seconds to display image ads; independent from ad rotation cadence. */\n image_duration?: number;\n /** An ADVISORY delivery cap the client SDK is expected to honour — the server reports it and never enforces it anywhere. Sourced from the partner's `network_config.ad_delivery.max_ads_per_hour` (an integer 1-120), falling back to `sdk_config.max_ads_per_hour`; when neither is set the key is ABSENT from the response rather than null or defaulted. */\n max_ads_per_hour?: number;\n /** Label for the tap-to-continue overlay the partner Lite SDK draws over an ad. Read from `sdk_config.overlay_button_text` only — there is no runtime-config path for it — and the key is ABSENT when unset, in which case the SDK falls back to `TAP TO CONTINUE` client-side. */\n overlay_button_text?: string;\n /** Whether ad audio plays. It reads the typed `sound_enabled` column when that is non-null, otherwise `display_preferences.sound_enabled !== false` — so an unconfigured screen reports `true` and only an explicit `false` mutes. */\n sound_enabled?: boolean;\n};\n\n/**\n * Stateful resettable operating-system advertising identity. Send\n * `available` only with the current OS ID; send `limited`,\n * `consent_denied`, `unavailable`, `unsupported`, or `error` to clear a\n * previously observed identifier. UID2 and hashed email are audience\n * tokens, not OS advertising IDs, and do not belong in this envelope.\n *\n */\nexport type AdvertisingIdentity = {\n /** DISCARDED whenever `status` is `available` — the server stores `null` in that case, deliberately, because a resettable OS advertising ID stays valid until the OS rotates it and a collector's refresh or cache cadence is not identity expiry. It is only persisted for the non-`available` states. */\n expires_at?: string | null;\n /** Present only when status is `available`. */\n id?: string | null;\n /** Resettable OS identifier type. GAID maps to OpenRTB `aaid`. */\n id_type?: \"gaid\" | \"aaid\" | \"afai\" | \"rida\" | \"tifa\" | \"idfa\" | null;\n /** Must be false for `available` and true for `limited`. */\n limit_ad_tracking: boolean | null;\n /** When the device read the identifier from the OS. It is REQUIRED and strictly parsed — an unparseable or missing timestamp causes the entire identity envelope to be dropped without an error response, which is the most common silent rejection on this endpoint. */\n observed_at: string;\n /** Which platform API produced the identifier. `host_supplied` is the value the SERVER itself stamps when it synthesises an envelope from the legacy flat `advertisingId`/`limitAdTracking` fields or from a registration hardware tuple, so seeing it in a read does not mean the device claimed it. An unrecognised source rejects the whole envelope. */\n source: \"google_play_services\" | \"amazon_fire_os\" | \"roku_os\" | \"samsung_tizen\" | \"lg_webos\" | \"apple_platform\" | \"host_supplied\";\n /** Version of the platform component or SDK that read the identifier (e.g. the Play Services version), up to 128 characters, kept for provenance only. Trimmed, with a whitespace-only value stored as `null`. */\n source_version?: string | null;\n /** The state machine, not a label. `available` is accepted only with a valid `id`, an `id_type` and `limit_ad_tracking: false` — any other combination makes the server DISCARD the whole envelope behind a 200 and keep the previously stored identity. Every other value CLEARS a stored identifier, and `limited` additionally forces `limit_ad_tracking` to true. */\n status: \"available\" | \"limited\" | \"consent_denied\" | \"unavailable\" | \"unsupported\" | \"error\";\n};\n\n/**\n * Partner analytics summary (`@trillboards/api-client` `AnalyticsData`).\n *\n */\nexport type AnalyticsData = {\n /** **Never emitted** by the analytics endpoint, which returns impression counts and cached revenue only. */\n average_cpm: number;\n /** Optional per-screen breakdown. */\n by_screen?: Array<{\n earnings: number;\n impressions: number;\n name: string;\n screen_id: string;\n }>;\n /** Fraction of ad opportunities filled, 0..1. */\n fill_rate: number;\n /** The window this summary covers (e.g. day, week, month). */\n period: string;\n /** **Not emitted under this name.** The analytics endpoint returns `data.partner.active_devices`, derived from the screen's `online_status` via the partner device-status mapping, plus a `devices_by_status` breakdown. */\n screens_active: number;\n /** **Not emitted under this name.** The analytics endpoint returns `data.partner.total_devices`, a count of registered DEVICES rather than of screens — a device with no screen row still counts. */\n screens_total: number;\n /** **Not emitted.** `GET /v1/partner/analytics` returns `data.partner.total_revenue_cents` (integer US cents, read from the `partners.stats` cache) instead; that endpoint has no dollar-denominated earnings field. */\n total_earnings: number;\n /** Declared for the SDK type; `GET /v1/partner/analytics` does not return this shape. It returns `data.partner.total_impressions` — an ALL-TIME deduped `completed_impressions` count that ignores the `start_date`/`end_date` query parameters (those bound only `impressions_by_day`). */\n total_impressions: number;\n};\n\nexport type AudienceAnalyticsResponse = {\n /** `overview.total_impressions` counts `event_tracking` `start`/`impression` events — NOT the billable `completed_impressions` the dashboard and earnings endpoints use — and `active_screens` counts screens with ANY event in the window rather than screens that are online. **`trends.impressions_trend` and `trends.audience_trend` are hardcoded to the literal `stable`**, so the `increasing`/`decreasing` values are unreachable. `period` echoes `?period=` (`24h`/`7d`/`30d`; anything else silently means 7 days). */\n data?: {\n audience?: {\n avg_attention?: number;\n avg_face_count?: number;\n screens_with_data?: number;\n };\n overview?: {\n active_screens?: number;\n avg_impressions_per_screen?: number;\n total_impressions?: number;\n total_screens?: number;\n };\n period?: string;\n timestamp?: string;\n trends?: {\n audience_trend?: \"increasing\" | \"stable\" | \"decreasing\";\n impressions_trend?: \"increasing\" | \"stable\" | \"decreasing\";\n };\n };\n /** Per-request identifier (`req_` plus 32 hex), also returned on the `X-Request-Id` response header. */\n request_id?: string;\n /** Always `true` on a 2xx; failures return the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status. */\n success?: boolean;\n};\n\n/**\n * Backend-derived predictive attention signal + buyer-grade attentive-seconds. 1:1 with audience_metrics. Never null by contract; placeholder on row 1.\n */\nexport type AudienceAttentionPrediction = {\n /** attentive_face_count SMALLINT: distinct viewers meeting the >=1s threshold; the buyer-side CPMA denominator. NEVER NULL. */\n attentive_face_count: number;\n /** attentive_seconds_observed = SUM(per_face[].gaze_seconds >= 1.0), OpenOOH 2024 4.2. NEVER NULL by DDL, so 0.000 means 'no viewer met threshold' ONLY when per_face_observations[] was present. NUMERIC(6,3). */\n attentive_seconds_observed: number;\n /** attentive_seconds_predicted_15s: expected next-15s attentive seconds from per-screen history x attention-weight; bootstrap = linear extrapolation. No global tau. NUMERIC(6,3). */\n attentive_seconds_predicted_15s: number;\n next_state_abs_error?: number | null;\n next_state_attention_forecast?: number | null;\n next_state_attention_realized?: number | null;\n next_state_confidence?: number | null;\n next_state_forecast_at?: string | null;\n next_state_graded_at?: string | null;\n next_state_horizon_minutes?: number | null;\n next_state_method?: string | null;\n next_state_persist_abs_error?: number | null;\n next_state_sample_size?: number | null;\n next_state_xscreen_abs_error?: number | null;\n next_state_xscreen_method?: string | null;\n next_state_xscreen_sample_size?: number | null;\n next_state_xsv_abs_error?: number | null;\n next_state_xsv_sample_size?: number | null;\n /** predicted_attention_next_30s enum {high,medium,low,none}. 'none' is below 'low'; fires when rolling history converges to zero or on a trend down from 'low'. */\n predicted_attention_next_30s: \"high\" | \"medium\" | \"low\" | \"none\";\n /** predicted_disengagement_imminent needs elevated dwell AND a falling trend, so it is unreachable whenever the history vector is empty. A 0% fire rate is a HISTORY-PLUMBING alarm, not a quiet fleet. */\n predicted_disengagement_imminent: boolean;\n prediction_evidence: string;\n};\n\n/**\n * Live/aggregate audience data for a screen\n * (`@trillboards/api-client` `AudienceData`).\n *\n */\nexport type AudienceData = {\n /** Count of attentive viewers in the sample. */\n attention_count: number;\n /** Optional demographic breakdown. */\n demographics?: Record<string, unknown>;\n /** Average dwell time for the sample. */\n dwell_time_avg: number;\n /** Declared for the SDK type. `GET /v1/partner/audience/live/{screenId}` puts `screen_id` at the TOP level of an `object: audience_live` envelope alongside `status` and `audience`, not inside this shape. */\n screen_id: string;\n /** **Not emitted under this name.** The live audience endpoint returns `last_updated` — the time of the newest underlying observation, nullable — and returns `audience: null` with `status: offline` when the screen has no live data at all. */\n timestamp: string;\n};\n\nexport type AudienceExportResponse = {\n /** One entry per RESOLVED screen (max 50 ids per call), emitted even for screens with no audience data — those get a zeroed `audience` block rather than being omitted. `impressions` counts `event_tracking` `start`/`impression` events, which are NOT the billable `completed_impressions` the dashboard and earnings endpoints use, and every row repeats the same request-level `period`. */\n data?: Array<{\n audience?: {\n avg_attention?: number;\n avg_face_count?: number;\n demographics?: Record<string, unknown>;\n income_profile?: Record<string, unknown>;\n lifestyle_segments?: Array<string>;\n };\n country?: string;\n impressions?: number;\n location?: string;\n period?: {\n end?: string;\n start?: string;\n };\n screen_id?: string;\n screen_name?: string;\n }>;\n /** Per-request identifier (`req_` plus 32 hex), also on the `X-Request-Id` header. Absent from the `format=csv` variant, which returns a bare five-column body and no envelope. */\n request_id?: string;\n /** Always `true` — a failure returns the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status, so this field carries nothing the status code does not. */\n success?: boolean;\n /** `total_screens` counts the screens that RESOLVED, so it can be smaller than the id list you sent. `total_impressions` sums the same non-billable `start`/`impression` event counts. `aggregation` echoes the query parameter unvalidated (default `daily`) and does not change the shape of the response. */\n summary?: {\n aggregation?: string;\n period?: Record<string, unknown>;\n total_impressions?: number;\n total_screens?: number;\n };\n};\n\n/**\n * Per-device cross-day loyalty feature row emitted by the\n * `audience_loyalty_features` dataset. Keyed by a partner-scoped\n * pseudonymous ID — the same physical device yields a different ID\n * for each partner because the HMAC salt is partner-specific: one salt\n * per partner, whichever API key calls, so the ID is the same ref the\n * partner's device-level files carry.\n *\n */\nexport type AudienceLoyaltyFeaturesRow = {\n /** How the cross-day device key was formed. `primary_signal_source` is picked by a fixed precedence (`fixed_mac` > `mdns_vendor_model` > `wifi_bssid` > `ble_continuity` > `ble_mac_stable`) and `match_confidence` is a direct relabelling of it (first three `high`, `ble_continuity` `medium`, `ble_mac_stable` `low`) — not a computed probability. `wifi_bssid` marks a device observed over WiFi, whose key is its BSSID. */\n _match_disclosure?: {\n match_confidence?: \"high\" | \"medium\" | \"low\";\n primary_signal_source?: \"ble_continuity\" | \"ble_mac_stable\" | \"mdns_vendor_model\" | \"fixed_mac\" | \"wifi_bssid\";\n };\n /** NOT a per-device inference: it is the aggregate audience profile of the first screen in the device's visited screen set that has one, copied onto every device that touched that screen. All six sub-fields are `null` when no visited screen carries a profile. */\n demographic_inference?: {\n age_bracket?: string;\n attention_score_avg?: number;\n audience_attire_archetype?: string;\n audience_group_composition?: string;\n audience_intent_stage?: string;\n gender_distribution?: Record<string, unknown>;\n };\n /** Partner-scoped HMAC of cross-day device key (16 hex chars + tb_ prefix). Different partners get different IDs for the same physical device — preventing collusion. */\n device_id_pseudonymous: string;\n /** Distinct calendar days (ClickHouse server timezone) on which this device key was observed. This is the quantity behind the published `returning_visitor` qualification of two or more days. */\n distinct_days_in_window: number;\n /** Distinct SCREENS, not venues — a site with several screens contributes more than one, so this over-counts locations for any multi-screen venue. */\n distinct_venues_in_window?: number;\n /** Days since this device was first observed at any of the partner-scoped screens. */\n first_seen_relative_days: number;\n /** Whole days between now and the newest observation in the window, floored at 0 — `0` means seen today. An unparseable source timestamp also yields `0`, so it cannot be told apart from a same-day sighting. */\n last_seen_relative_days: number;\n /** Tier derived from the Bluetooth-SIG company identifier in the device's advertisement, not from any model string. Only five vendors carry an explicit tier (Apple / Samsung / Google `premium`, Microsoft `mainstream`, Sonos `audio_iot`); every other registered vendor, and every unresolvable id, falls to `other`. */\n manufacturer_class: \"premium\" | \"mainstream\" | \"audio_iot\" | \"other\";\n /** Vendor name resolved from the same Bluetooth-SIG company id. An id that resolves to no vendor returns the literal `Other tracked devices` rather than `null`, so an unknown device is not distinguishable by a null check. */\n manufacturer_label?: string;\n /** Raw cross-day-stable identifiers when available (NULL for randomized phone MACs without Continuity). */\n raw_identifiers?: {\n ble_mac?: string | null;\n /** First 3 bytes of BLE MAC (IEEE OUI vendor lookup). */\n ble_mac_oui?: string | null;\n ble_mac_oui_vendor?: string | null;\n manufacturer_company_id?: number | null;\n mdns_hostname?: string | null;\n wifi_bssid?: string | null;\n };\n /** Same arbitrary-row behaviour as `top_hour_of_day`, and the value comes from ClickHouse `toDayOfWeek` — **1 = Monday through 7 = Sunday**, which does not fit the declared 0..6 range. */\n top_day_of_week?: number;\n /** Produced by `argMax(toHour(observed_at), 1)`; because the ordering expression is the constant `1` every row ties, so this is the hour of an ARBITRARY observation in the window, not the modal hour. Do not read a peak out of it. */\n top_hour_of_day?: number;\n /** List of venue_category labels (Bar, Restaurant, etc.) the device was observed at. */\n venue_archetypes?: Array<string>;\n /** Count of raw radio OBSERVATIONS, not of visits — one dwelling device emits many rows per minute. */\n visit_count_in_window: number;\n};\n\nexport type AudienceMetricsResponse = {\n /** **Currently always the zero/`unknown` fallback.** The handler reads `metrics.live`, `metrics.aggregated` and `metrics.history`, but the underlying `getScreenMetrics` takes a time-range STRING and returns a FLAT object carrying none of those keys — so all three are undefined on every call and the hardcoded zeros are served. `period` echoes `?period=` (default `1h`) and is likewise not honoured downstream; `timestamp` is the response time, not a measurement time. */\n data?: {\n aggregated?: {\n avgAttention?: number;\n avgDwellMs?: number;\n avgFaceCount?: number;\n groupComposition?: Record<string, unknown>;\n incomeProfile?: {\n high?: number;\n low?: number;\n medium?: number;\n premium?: number;\n };\n };\n history?: Array<Record<string, unknown>>;\n live?: {\n /** Average attention score (0-1) */\n avgAttention?: number;\n /** Average faces detected */\n avgFaceCount?: number;\n incomeLevel?: \"unknown\" | \"low\" | \"medium\" | \"high\" | \"premium\";\n /** Maximum faces detected in period */\n maxFaces?: number;\n mood?: string;\n screenEngagement?: string;\n };\n period?: string;\n screen_id?: string;\n screen_name?: string;\n timestamp?: string;\n };\n /** Per-request identifier (`req_` plus 32 hex), also returned on the `X-Request-Id` response header. */\n request_id?: string;\n /** Always `true` on a 2xx; failures return the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status. */\n success?: boolean;\n};\n\nexport type AudienceSegment = {\n /** Creation time of the authoritative PG row; the 201 create response falls back to the server clock only if the insert returned no row. */\n created_at?: string;\n /** Free text, trimmed on write. Defaults to the empty string, never `null`, when omitted at create. */\n description?: string;\n /** 24-character hex ObjectId minted by the API at create time and stored as the PG row's `mongo_id` — not the table's integer primary key. This is the value the get / patch / delete / match routes take as `:segmentId`. */\n id?: string;\n /** Stored and echoed but **nothing reads it** — `POST /segments/{id}/match` runs a segment regardless, and the list endpoint does not filter on it. Treat it as a caller-owned label, not a gate. */\n is_active?: boolean;\n /** When `POST /segments/{id}/match` last ran. The update is fire-and-forget after the response is sent, so a failed write leaves this stale or `null` with no error surfaced to the caller. */\n last_matched_at?: string | null;\n /** Number of SCREENS returned by the most recent `POST /segments/{id}/match`, capped by that call's `limit` (default 50, max 100) — so it is the size of the last result page, not the segment's reach. `null` until the first match call. */\n last_matched_count?: number;\n /** Trimmed on write, max 100 characters, and unique per partner — a repeat name is rejected `409 duplicate_segment_name` rather than upserting the existing segment. */\n name?: string;\n /** Always the literal `audience_segment`. `GET /audience/segments` wraps these in an `object: list` envelope, so the discriminator appears on both the envelope and each element. */\n object?: string;\n /** Per-request identifier, `req_` plus 32 hex characters, minted server-side and also returned on the `X-Request-Id` response header. A client-supplied `X-Request-Id` is NOT adopted — it is echoed back on `X-Client-Request-Id` instead. */\n request_id?: string;\n /** Predicates combined with AND, at most 20 per segment. `field` is restricted to a 17-name allowlist (`income_level`, `lifestyle_segment`, `attention_score`, `face_count`, `dwell_time_ms`, `crowd_density`, `ad_receptivity`, `emotional_engagement`, `purchase_intent`, `occupancy`, `noise_level`, `venue_type`, `country`, `state`, `city`, `hour_of_day`, `day_of_week`) and `operator` to `eq`/`neq`/`gt`/`gte`/`lt`/`lte`/`in`/`nin`/`contains`; any other key on a rule object is stripped on write. */\n rules?: Array<{\n field?: string;\n operator?: string;\n value?: unknown;\n }>;\n /** Last write to the segment, INCLUDING the fire-and-forget match-stats update — so running a match bumps this even though name, rules and `is_active` did not change. Omitted entirely from the 201 create response. */\n updated_at?: string;\n};\n\n/**\n * Buyer-grade social amplification signal (5 typed columns). Cloud Vertex Gemini producer. 1 row per audience observation when cascade is observable.\n */\nexport type AudienceSocialAttention = {\n amplification_evidence: string;\n cascade_depth: number;\n data_projection_version: number;\n data_projection_xid: string;\n /** All 5 columns NOT NULL except primary_attention_anchor_face_index (only legit NULL: no anchor or solo scene). */\n primary_attention_anchor_face_index?: number | null;\n /** NUMERIC(4,3). */\n social_amplification_factor: number;\n /** viral_attention_score is the headline number Viant/T-Vision license. Composite of social_amplification_factor × cascade_depth × emotional engagement. NUMERIC(4,3). */\n viral_attention_score: number;\n};\n\nexport type BatchResult = {\n /** Number that failed */\n failed_count?: number;\n /** Not emitted. The live response names this array `errors`, and each entry carries `screen_id`, a human `error` string, and an additional machine `code`: `screen_not_found` for an id that is not 24-hex or that your partner account does not own, `write_failed` for a database failure. Read `errors`. */\n failed_screens?: Array<{\n error?: string;\n screen_id?: string;\n }>;\n /** Constant discriminator `batch_result`, shared verbatim by every partner batch endpoint (content preferences, display settings, programmatic settings) — it does not identify which one you called. */\n object?: string;\n /** Server-minted per HTTP request in the form `req_<32 hex>`, also returned in the `X-Request-Id` response header; omitted if no request id was assigned to the call. Quote it when reporting a partial batch failure — it is the only handle that ties your call to the per-screen error rows. */\n request_id?: string;\n /** Number of screens requested to update */\n total_requested?: number;\n /** Number successfully updated */\n updated_count?: number;\n /** IDs of successfully updated screens */\n updated_screens?: Array<string>;\n};\n\n/**\n * Partner billing snapshot — plan, credits, and month-to-date usage\n * (`@trillboards/api-client` `BillingInfo`).\n *\n */\nexport type BillingInfo = {\n /** **Never emitted**, so its unit is undefined. The credits that do exist are bought through `POST /billing/credits`, which reports `credits_added_cents` — integer US cents, not an abstract credit count. */\n credits_remaining: number;\n /** **Never emitted.** Consumption is reported by `GET /billing/usage` (`object: billing_usage`), which returns the billing service's usage summary rather than a credit counter. */\n credits_used: number;\n /** **No producer.** There is no `GET /v1/partner/billing` route; the live billing surface is `/billing/plans`, `/billing/subscribe`, `/billing/cancel`, `/billing/usage` and `/billing/subscription`, each returning a Stripe-style envelope tagged with an `object` marker plus `request_id`. */\n plan: string;\n /** Whether the partner has a connected Stripe account. */\n stripe_connected: boolean;\n /** Usage counters for the current billing month, keyed by metric. */\n usage_this_month: Record<string, number>;\n};\n\nexport type BleScanResultData = {\n /** Despite the name this is a GENERALISED advert-subtype code, and the server stores it as `manufacturer_subtype`. Values 0x00-0x1F are genuine Apple Continuity subtypes; 0x80 and above are SYNTHETIC markers this parser assigns to non-Apple formats — 0x80 iBeacon, 0x81 Eddystone-UID, 0x82 Fast Pair, 0x83 Tile, 0x85 Eddystone-URL, 0x86 AltBeacon. Note an Apple iBeacon reports 0x80, not its literal Apple subtype 0x02. */\n appleContinuitySubtype?: number | null;\n /** The Android `BluetoothDevice.getType()` constant: 0 UNKNOWN, 1 CLASSIC, 2 LE, 3 DUAL. Treat `0` as \"unknown OR the read threw\" — the producer catches any exception and substitutes 0 rather than omitting the field. */\n deviceType?: number | null;\n /** iBeacon major value, an unsigned 16-bit integer (0-65535) parsed BIG-endian from the advert. `null` unless a valid iBeacon frame was found, and meaningless without the accompanying `ibeaconUuid`. */\n ibeaconMajor?: number | null;\n /** iBeacon minor value, unsigned 16-bit big-endian (0-65535). `null` outside a valid iBeacon frame; major and minor are only comparable within one `ibeaconUuid` namespace. */\n ibeaconMinor?: number | null;\n /** The 16-byte iBeacon proximity UUID as canonical dashed lowercase, parsed BIG-endian. Present only for a well-formed Apple iBeacon frame — an Apple subtype 0x02 whose inner length is not 0x15 is explicitly rejected rather than partially parsed. */\n ibeaconUuid?: string | null;\n /** The Bluetooth SIG assigned company identifier from the advert's Manufacturer Specific Data structure (AD type 0xFF), read little-endian — e.g. 76 (0x004c) Apple, 6 Microsoft, 224 (0x00e0) Google. `null` when the record carries no such structure. One synthetic exception: a Google Fast Pair service-data advert is forced to the Google id even though it has no 0xFF structure. */\n manufacturerCompanyId?: number | null;\n /** The BLE advertiser address exactly as Android reports it, unhashed on the device. It is sent over TLS, and Trillboards stores it as received and as a keyed HMAC-SHA256 hash. On most modern phones this is a resolvable private address that ROTATES roughly every 15 minutes, so it is not a stable device identity; the sibling `addr_type` (`public`/`random`/`anonymous`) is what tells the two apart. */\n rawAddress: string;\n /** Received signal strength in dBm (negative, bounded -120..0). It is the MAXIMUM RSSI across every advertisement from this address inside the scan window — the closest observed reading, not a mean — because the scanner groups repeated adverts per address and keeps the strongest as the representative. */\n rssi: number;\n /** Advertised GATT service UUIDs, de-duplicated. 16-bit UUIDs are rendered as FOUR lowercase hex characters (e.g. `feaa`), not expanded to the full `0000feaa-0000-1000-8000-00805f9b34fb` base form; 128-bit UUIDs are canonical dashed lowercase. `null` rather than `[]` when the advert carries none. */\n serviceUuids?: Array<string> | null;\n /** Lowercase hex, no separators, of ONLY the advert sub-bytes that survive address rotation (an iBeacon UUID+major+minor, an Eddystone namespace+instance, a Fast Pair model id…), prefixed with the synthetic subtype byte. Calibration bytes such as TX power are deliberately excluded. It is `null` far more often than it is present: 13 rotating Apple subtypes are dropped outright and unknown Apple subtypes fail closed, so a populated `appleContinuitySubtype` with a null payload here is normal. */\n stableManufacturerPayloadHex?: string | null;\n /** Advertised transmit power in dBm (bounded -127..20) taken from the advert itself, NOT from `ScanResult.getTxPower()`. For iBeacon and Eddystone frames it is the format's calibrated 1-metre reference power, which overwrites the generic AD-type-0x0A value; `null` when the advert carries neither. */\n txPowerDbm?: number | null;\n [key: string]: unknown;\n};\n\nexport type CanonicalError = {\n error: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code: string;\n /** Per-field violations (populated from Zod errors). */\n details?: Array<{\n code?: string;\n message?: string;\n param?: string;\n }>;\n /** Link to the documentation for this error code (https://api.trillboards.com/docs/errors#<code>). */\n doc_url?: string;\n /** Agent-facing hints and suggestions. */\n help?: {\n portal_url?: string;\n suggestions?: Array<string>;\n summary?: string;\n try_next?: string;\n };\n /** Human-readable error message. Safe to surface to end-users. */\n message: string;\n /** Offending parameter name (when applicable). */\n param?: string;\n /** Echoed X-Request-Id for correlation. */\n request_id: string;\n /** Stripe-style error taxonomy (derived from utils/errorCatalog). */\n type: \"api_error\" | \"authentication_error\" | \"idempotency_error\" | \"invalid_request_error\" | \"permission_error\" | \"rate_limit_error\";\n };\n};\n\nexport type ChangelogEntry = {\n /** ISO date string or null for unreleased */\n date: string | null;\n /** Human-readable change description */\n description: string;\n /** API surface: data, sdk, device, sensing, openrtb, partner, all */\n surface: string;\n /** Keepachangelog type: added, changed, deprecated, removed, fixed, security */\n type: string;\n /** \"unreleased\" or a date like \"2026-04-16\" */\n version: string;\n};\n\nexport type ChangelogResponse = {\n /** Matching changelog entries */\n data: Array<ChangelogEntry>;\n /** Always \"list\" */\n object: \"list\";\n /** Number of entries returned */\n total: number;\n};\n\n/**\n * Completed-play observations from VAST complete and proof-of-play paths. Deduped by issued request/impression key for live revenue and daily earnings.\n */\nexport type CompletedImpressions = {\n /** NUMERIC(18,6). */\n actual_cpm?: number | null;\n /** NUMERIC(18,6). */\n actual_gross_revenue?: number | null;\n ad_id: string;\n advertiser_domain?: string | null;\n bid_request_id?: string | null;\n billable_key?: string | null;\n buyer_seat?: string | null;\n completed_at: string;\n /** Creative identity is NOT content_sha256 (35 of 430,165 ClickHouse rows since 2026-10-20): join creative_identity on the row's keys (identityKeys.identityJoinSql); its sidecar has the current and ti... */\n content_sha256?: string | null;\n /** chEventParityCron: exact-key repair; created_at/oldest authorized floor; original completed_at CH key; same writer/DLQ before ACK; no delivery debit. All leaf pending indexes must be valid; failed/... */\n created_at: string;\n creative_id?: string | null;\n currency: string;\n demand_partner_id?: number | null;\n device_id?: string | null;\n /** NUMERIC(5,4). */\n display_area_ratio?: number | null;\n display_mode?: string | null;\n /** NUMERIC(10,2). */\n duration_seconds?: number | null;\n earnings_deal_id?: string | null;\n earnings_deal_type?: string | null;\n earnings_source?: string | null;\n event_clock_skew_seconds?: number | null;\n event_timestamp_clamped?: boolean | null;\n givt_passed?: boolean | null;\n /** JustBaat dedupes issued request keys; Adipolo/VidVerto/others use rendered impression_id with request fallback. Readers/rollups dedupe overlapping vast_event, proof_of_play and approved partner_sdk. */\n id?: number | null;\n impression_id?: string | null;\n /** NUMERIC(12,6). */\n impression_multiplier: number;\n ingestion_path: string;\n /** SDK missing-price is server-pending until signed native pricing; directbillable_ is not authority. Client debit/mirror/pending claims are stripped. Legacy finalization: recorded/native nonnull zero... */\n metadata: Record<string, unknown>;\n normalized_event_timestamp?: string | null;\n play_id?: string | null;\n /** PG is the canonical completion write; completed_impressions_dist is its CH reporting mirror. pricing_source: 'placement_purchase'=ad_price/goal per play; '*_overdelivered'/'*_zero'=$0; 'config_defa... */\n pricing_source: string;\n quantity_measured_at?: string | null;\n quantity_source?: string | null;\n quantity_source_type?: number | null;\n quantity_vendor?: string | null;\n raw_client_timestamp?: string | null;\n /** owned_direct = signed src or verified SDK. VAST impid, request_id and SDK suffix share one nonce/PG row; completion, exact debit and eligible billing commit together. First authorized write owns CH... */\n request_id?: string | null;\n screen_id?: number | null;\n screen_mongo_id: string;\n serving_tenant_id?: number | null;\n signature?: string | null;\n /** ImpressionController drops rows with unknown source_provider (PR #2924); earnings use partner billing policy, not raw counts. Exclude pi_e2e_*, admin-allocation and is_demo_data from revenue. */\n source_provider: string;\n variant_id?: number | null;\n variant_name?: string | null;\n zone_id?: string | null;\n};\n\n/**\n * Per-content-type sizing returned and accepted by the Partner API.\n * `fit` preserves the entire creative and may letterbox; `fill` covers\n * the screen and may crop edges. Omitting this object from a write leaves\n * the screen's current behavior unchanged.\n *\n */\nexport type ContentFitSettings = {\n /** Sizing for direct and programmatic advertisements. */\n advertisements?: \"fit\" | \"fill\";\n /** Sizing for default/background streams. */\n default_streams?: \"fit\" | \"fill\";\n /** Sizing for self-promotion and QR-code house ads. */\n self_promo?: \"fit\" | \"fill\";\n};\n\nexport type ContentPreferencesInput = {\n /** Specific advertiser IDs to block */\n blocked_advertisers?: Array<string>;\n /** Ad categories to block (e.g., \"alcohol\", \"gambling\", \"adult\") */\n blocked_categories?: Array<string>;\n /** Max times same ad can show per hour */\n max_ad_frequency?: number;\n /** Minimum ad content rating */\n min_ad_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\";\n /** Preferred ad categories (prioritized in auctions) */\n preferred_categories?: Array<string>;\n};\n\nexport type ContentPreferencesResponse = {\n /** NOT EMITTED. No handler on this endpoint produces this key — neither `formatContentPreferences` nor the service feeding it has such a field. Advertiser blocking lives on the programmatic-settings resource instead, as `blocked_advertisers` on `GET/PUT /v1/partner/screens/{screenId}/programmatic-settings`. */\n blocked_advertisers?: Array<string>;\n /** The screen's own blocked list, `[]` when unset. Matched at approval time against the ad's typed `iab_categories` with `categoriesMatch`, so IAB codes and human-readable names both work. It is the only one of this schema's five list/rating fields the server actually emits. */\n blocked_categories?: Array<string>;\n /** NOT EMITTED, and the identifier does not occur anywhere in the API source. The only delivery cap this platform exposes to partners is the advisory `max_ads_per_hour` in the `/ads` response settings. */\n max_ad_frequency?: number;\n /** NOT EMITTED, and the identifier `min_ad_rating` does not occur anywhere in the API source. The response carries `max_age_rating` instead — an UPPER bound on the ad classification (`G`..`NC-17`), defaulting to `PG-13`, not a minimum. */\n min_ad_rating?: string;\n /** Always the literal `content_preferences`. This response is FLAT — there is no `success`/`data` envelope, unlike the L-bar and default-stream routes — and `POST .../content-preferences/apply-preset` returns this same object with an extra `preset_applied` field appended. */\n object?: string;\n /** NOT EMITTED, and the identifier does not occur anywhere in the API source. The nearest real control is `allowed_categories`, which the formatter does return and which acts as a scoring boost (+10 per match) rather than a hard preference. */\n preferred_categories?: Array<string>;\n /** Echo of the server-assigned `req.requestId`. The formatter attaches it only when one exists, so the key is ABSENT rather than null on a request that carried none. */\n request_id?: string;\n /** Echoed straight back from the `{screenId}` path parameter — the formatter is handed the path value, not a column — so it always equals what you asked for. */\n screen_id?: string;\n /** ISO-8601, but it is the SCREEN row's `updatedAt`, not a preferences-specific timestamp, so unrelated screen edits move it. When the screen has none the formatter substitutes the current time, so this field is never null and never proves a write landed. */\n updated_at?: string;\n};\n\nexport type ContentPreset = {\n /** Advertiser IDs blocked */\n blocked_advertisers?: Array<string>;\n /** Categories blocked by this preset */\n blocked_categories?: Array<string>;\n /** Preset description */\n description?: string;\n /** Unique preset identifier */\n id?: string;\n /** Minimum ad rating allowed */\n min_ad_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\";\n /** Human-readable preset name */\n name?: string;\n /** Full preference object applied by this preset */\n preferences?: Record<string, unknown>;\n};\n\nexport type CreatePartnerSensingRouteRequest = {\n /** The channel actions fired on a match; at least 1 and at most 10, each carrying exactly the destination its channel requires. A route with zero actions cannot exist, so use a `webhook` action for anything you do not want delivered to a person. */\n actions: Array<SensingRouteAction>;\n /** Seven-bit weekday mask evaluated in `activeTz`: bit 0 Monday through bit 6 Sunday, so the default 127 is every day and 0 means the route never fires. Requires `activeTz`. */\n activeDaysMask?: number;\n /** Inclusive end of the daily active window, minutes past local midnight in `activeTz` (0..1439). Set it BELOW `activeStartMinute` for an overnight window — 1200 to 360 is 20:00 through 06:00. */\n activeEndMinute?: number;\n /** Inclusive start of the daily active window, minutes past local midnight in `activeTz` (0..1439; 1200 = 20:00). Has no effect without `activeTz`, and omitting either end makes the window whole-day. */\n activeStartMinute?: number;\n /** IANA zone name (e.g. `America/New_York`) the active window is evaluated in, trimmed to 64 characters. Omitting it makes `activeStartMinute`, `activeEndMinute` and `activeDaysMask` inert — the route is then always active — and an unparseable zone fails open. */\n activeTz?: string;\n condition?: SensingRouteCondition;\n /** Minimum gap in seconds between alerts for the same (route, screen) episode; clamped to 0..86400, default 300. It also bounds the falling-edge clear window at 60 s, so a value below that re-arms the route faster too. */\n debounceSeconds?: number;\n /** Required when mode=digest. `field` is required for avg/max. */\n digest?: {\n field?: string;\n intervalMinutes?: number;\n metric?: \"count\" | \"avg\" | \"max\";\n windowMinutes?: number;\n };\n /** Only the JSON literal `false` creates the route disabled — any other value, including `0` and the string `\"false\"`, creates it enabled. Note the update endpoint inverts this test, so send a real boolean on both. */\n enabled?: boolean;\n /** `threshold` (the default) needs a `condition` and evaluates every incoming observation. `digest` needs a `digest` block instead, sends on a schedule, and rejects `screenFocusRegions` and explicit review timing. Only the exact string `digest` selects digest mode; anything else falls back to `threshold`. */\n mode?: \"threshold\" | \"digest\";\n /** Operator-supplied label, required, trimmed and capped at 200 characters. It is delivered as `route_name` on every fire and shown in operator surfaces; it is not the alert text. */\n name: string;\n /** Bind to a named Sense Anything profile (stable across redeploys). */\n profileName?: string;\n reviewTimingMode?: SensingRouteReviewTimingMode;\n reviewWaitSeconds?: SensingRouteReviewWaitSeconds;\n /** Optional per-camera rectangles or polygon lassos. Every entry must reference screenMongoIds. Supported only for visual threshold alerts using once_per_episode, on_escalation, or nag_until_resolved cadence; not digest, group-targeted, non-visual, or per_new_entity routes. */\n screenFocusRegions?: Array<SensingRouteScreenFocusRegion>;\n /** Screens to watch — all owned by this partner (foreign → 403). Provide EITHER screenMongoIds OR targetGroupId, not both. */\n screenMongoIds?: Array<string>;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainMinSamples?: number;\n /** How long the condition must hold before the FIRST alert, in seconds (600 = ten minutes). Omit to alert on the first true reading. Cadence-independent, because the evaluator compares timestamps - correct however often the screen reports, including when that rate changes while the condition holds. */\n sustainSeconds?: number;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainWindowSeconds?: number;\n /** A sg_ Screen Group id (owned by this partner) to target instead of an explicit screen set. The route fires on the group's live members. Requires SENSING_ROUTES_GROUP_TARGET_ENABLED. */\n targetGroupId?: string;\n};\n\n/**\n * Structured creative classification — the same shape the Trillboards venue portal renders for a served ad.\n */\nexport type CreativeClassification = {\n /** The name whoever FIRST submitted these bytes passed on `POST /creatives`, carried through the moderation queue. It is unverified free text, and because the review row is keyed on the content hash a later submitter of the same bytes reads the first submitter's value. `null` when none was supplied. */\n advertiser_name?: string | null;\n /** One of G, PG, PG-13, R, NC-17 (null until classified). */\n age_rating?: string | null;\n /** Descriptive output of the same classifier pass — visible subjects, keywords, scene setting, mood, a quality grade, and `text_content` recovered by OCR. Every field is `null`/empty until classification finishes. This is scene description, not the moderation verdict; that is `status` plus `moderation.flags`. */\n analysis?: {\n keywords?: Array<string>;\n mood?: string | null;\n quality?: string | null;\n setting?: string | null;\n subjects?: Array<string>;\n /** On-screen text (OCR). */\n text_content?: string | null;\n };\n /** Classifier output: `brand`, `category` and IAB category codes. All three are `null`/empty while `status` is `pending`, so an empty `iab_categories` means not yet classified rather than 'no categories apply'. */\n categorization?: {\n brand?: string | null;\n category?: string | null;\n iab_categories?: Array<string>;\n };\n /** Classification confidence, 0..1. */\n confidence?: number | null;\n /** SHA-256 of the bytes the SERVER fetched from your `media_url` — lowercase 64-hex, never a hash you declare — and `id` is this same value prefixed `sha256:`. Classification is content-addressed and global, so two partners submitting identical bytes share one record, and this is the byte-identity join key into `completed_impressions` and `vast_requests`. */\n content_sha256?: string;\n /** Canonical reference — `sha256:<hex>` of the creative bytes. Use as `creative_ref` when posting plays. */\n id?: string;\n /** `approved` is not an independent verdict — it is derived as `status === 'approved'`, so it is false for both `pending` and `blocked` and adds no information beyond `status`. `flags` is the classifier's reason list and is empty until classification finishes. */\n moderation?: {\n approved?: boolean;\n flags?: Array<string>;\n };\n /** Constant discriminator `creative_classification`. It is returned identically on the 202 (queued) and 200 (already classified) forms of this response, so it tells you nothing about whether classification has finished — read `status` for that. */\n object?: string;\n /** `pending` means queued and not yet classified. `approved`, `flagged` and `blocked` are terminal: re-submitting the same bytes then returns 200 immediately without re-running the classifier or consuming your daily classification quota, whereas a still-pending submit returns 202. The value is passed through from the shared review row unmapped, so a state outside this enum (e.g. `metadata_only`) can surface. */\n status?: \"pending\" | \"approved\" | \"flagged\" | \"blocked\";\n /** Always `null` in practice: the only writer of the underlying `creative_reviews.thumbnail_url` column has no remaining callers, so nothing populates it. When it did carry a value it was constrained to a Trillboards CDN host, so an off-host thumbnail was dropped rather than passed through. */\n thumbnail_url?: string | null;\n};\n\n/**\n * Native readiness hint delivered through existing partner SSE and the audited webhook queue. The hint is free; only the canonical reward page uses native paid admission.\n */\nexport type CreativeRewardsReadyEvent = {\n data: {\n advertisement_id: string;\n /** Lossless native build stamp. */\n build_stamp: string;\n builder_version: string;\n experiment_id: string;\n from: string;\n notification_id: string;\n object: \"creative_reward_ready\";\n recovery: \"rewind_and_dedupe\";\n request_idempotency_key_required: true;\n /** Canonical native reward path plus date scope; never contains credentials or a paid request key. */\n reward_reader_url: string;\n to: string;\n view: \"latest_state\";\n };\n event: \"creative.rewards_ready\";\n /** Audited webhook notification ID; SSE data carries the same ID inside data.notification_id. */\n id?: string;\n timestamp: string;\n};\n\nexport type DashboardResponse = {\n /** All amounts are integer US cents. `total_earned_cents` is lifetime earner revenue across every status (estimated + confirmed + paid); `available_payout_cents` is only the Net-60-matured payable balance minus anything already reserved, floored at 0; `next_payout_date` is simply the 1st of next month, computed in the handler with no reference to a scheduled transfer. `revenue_share_percent` is 0-100 and reads `60` when no `publisher_payout_rates` rule applies. */\n earnings?: {\n available_payout_cents?: number;\n next_payout_date?: string;\n pending_payout_cents?: number;\n revenue_share_percent?: number;\n total_earned_cents?: number;\n };\n /** Identity block copied off the partner row, where `created_at` is the registration timestamp. The row is read through a 10-minute Redis cache, so a just-changed name or status can lag by that much. */\n partner?: {\n created_at?: string;\n name?: string;\n slug?: string;\n status?: \"pending\" | \"active\" | \"suspended\" | \"terminated\";\n };\n /** The ten newest `impression_ledger` rows for the partner, newest first. `type` is always the literal `impression` — no other activity kind is ever emitted. */\n recent_activity?: Array<{\n ad_id?: string;\n screen_id?: string;\n timestamp?: string;\n type?: string;\n }>;\n /** `active_screens`/`offline_screens` count `online_status` `online`/`offline` from the live heartbeat mirror — a screen that has never heartbeated reads `unknown` and lands in NEITHER bucket, so the two need not sum to `total_screens`. `pending_screens` is the separate approval status and overlaps both. The three impression totals are deduped, GIVT-passed `completed_impressions` over midnight-today / the last 7 days / month-to-date, all cut in the API server's local timezone rather than the screen's. */\n stats?: {\n active_screens?: number;\n offline_screens?: number;\n pending_screens?: number;\n total_impressions_month?: number;\n total_impressions_today?: number;\n total_impressions_week?: number;\n total_screens?: number;\n };\n /** `connect_account_id` is **redacted**: it is the literal string `***` when an account is connected and `null` when it is not, so it can never be used as an identifier. `account_status` defaults to `pending` and must be `active` before a payout request is accepted. */\n stripe_status?: {\n account_status?: string;\n connect_account_id?: string;\n };\n /** The five screens with the most completed impressions since midnight today (server timezone). `name` falls back to the literal `Unknown Screen`, and `location` is a `City, State` string or `null` when either part is missing. */\n top_screens?: Array<{\n impressions_today?: number;\n location?: string;\n name?: string;\n screen_id?: string;\n }>;\n};\n\nexport type DataApi_AdSightingRecord = {\n /** The words read on the ad. */\n ad_text: string | null;\n advertiser_as_read: string | null;\n board_id: string | null;\n brand_as_read: string | null;\n brand_id: string | null;\n brand_name: string | null;\n cab_heading_deg: number | null;\n cab_lat: number | null;\n cab_lon: number | null;\n capture_mode: string | null;\n /** The resolved brand's IAB tier-1 category (brand_knowledge_graph.iab_category: its vote over the brand's reads), the code the history's category slice keys by (IAB8 is Food & Drink). Null where the brand has no vote or the record names no resolved brand. */\n category: string | null;\n confidence: number | null;\n face_lat: number | null;\n face_lon: number | null;\n flight_end: string | null;\n flight_label_kind: string | null;\n flight_open: boolean | null;\n flight_passes: number | null;\n flight_reads: number | null;\n flight_start: string | null;\n /** The ad box in the frame, fractions of the frame. */\n frame_box_x0: number | null;\n frame_box_x1: number | null;\n frame_box_y0: number | null;\n frame_box_y1: number | null;\n frame_expires_at: string | null;\n /** A short-lived capability link to the whole still the ad was read off, face-blurred: the still's blurred rendition, never the original. Null until the still is blurred, and for a still the face-blur engine excluded. */\n frame_url: string | null;\n /** ssr-v2 or ssr-v1 (the still reader), vlmtext-v1 or edge_ocr_v1. */\n instrument_version: string | null;\n /** The face carried no advertiser. */\n is_vacancy: boolean;\n legibility: string | null;\n /** Legible, Partial or Illegible. */\n legibility_label: string | null;\n market_code: string | null;\n market_country: string | null;\n market_key: string | null;\n market_name: string | null;\n match_basis: string | null;\n match_distance_m: number | null;\n /** matched | unmatched | no_candidate. */\n match_status: string | null;\n orientation_idx: number | null;\n parent_name: string | null;\n /** The ad (on a close-up, its words) inside the photo, fractions of the photo. */\n photo_box_x0: number | null;\n photo_box_x1: number | null;\n photo_box_y0: number | null;\n photo_box_y1: number | null;\n photo_expires_at: string | null;\n /** The ad itself, face-blurred: closeup = the capture-resolution close-up a tablet uploaded, its blurred rendition whole; crop = the ad cut at request time from the blurred frame (its box padded 50% per side), never stored. Null when no picture of the ad can be shared. */\n photo_kind: \"closeup\" | \"crop\" | null | null;\n /** A short-lived capability link to the photo on our endpoint. It serves the face-blurred rendition only (faces are always blurred in any in-vehicle picture), never the original; null until the still is blurred, and for a still the face-blur engine excluded. */\n photo_url: string | null;\n /** What kind of placement the reader judged the ad to be (still reader ssr-v2): paid_ad = a third party's ad on space a media owner sells; own_premises = the business's own sign at or by its own place, or its own vehicle livery; other = neither. Null where the reading classified none (ssr-v1, vlmtext-v1, edge_ocr_v1). */\n placement: \"paid_ad\" | \"own_premises\" | \"other\" | null | null;\n product_as_read: string | null;\n publisher_name: string | null;\n /** The still instant, UTC. */\n seen_at: string;\n sighted_creative_id: string | null;\n /** Stable id of the sighting (32 hex). */\n sighting_id: string;\n source: string | null;\n surface: string | null;\n /** The surface as a buyer reads it (Billboard, Digital board, Storefront, ...). */\n surface_label: string | null;\n ticker: string | null;\n vehicle_side: string | null;\n};\n\nexport type DataApi_AdSightingsHistoryResponse = {\n data: {\n next_cursor: string | null;\n /** One row per month (or week, or the window), market and brand (creative_brand_history), and per slice when the request names dimensions: flights active and started, creatives launched and confirmed, board faces and points, share of voice over every ad flight in the market or slice (by flights, by faces and by face-days, with its standard error), the market vacancy, face-days, the floor-priced media value and the attention on the brand's registered flights, each with the count it is taken over. A row carries the keys of the slices asked for. */\n rows: Array<DataApi_CreativeBrandHistoryRow>;\n };\n meta: {\n /** The markets, brand ids, dimensions and slice filters applied (null: not narrowed). */\n filters: Record<string, unknown> | null;\n /** market_month, fleet_month, market_week, fleet_week, market_window or fleet_window. */\n grain: string | null;\n metric: \"creative_brand_history\";\n product: \"ad_sightings\";\n records: number;\n request: Record<string, unknown>;\n view: \"history\";\n /** The window answered: from, to, days. */\n window: Record<string, unknown> | null;\n };\n success: true;\n};\n\nexport type DataApi_AdSightingsResponse = {\n data: {\n next_cursor: string | null;\n rows: Array<DataApi_AdSightingRecord>;\n };\n meta: {\n /** The markets (market_key, or rest for every market outside the top ones) whose pictures have no passing by-eye check at the current definition: their records are left out of this page until one passes. Absent when every market is sold. */\n held_markets?: Array<string>;\n product: \"ad_sightings\";\n records: number;\n request: Record<string, unknown>;\n };\n success: true;\n};\n\nexport type DataApi_AggregateResponse = {\n aggregations: Array<Record<string, unknown>>;\n group_by: string;\n metric: string;\n time_window: string;\n};\n\nexport type DataApi_CreativeBrandHistoryRow = {\n /** Each measure on the row with no value, and why (no_flight, no_ad_flight, no_sighting_held, ...). */\n absent?: Array<{\n measure: string;\n reason: string;\n }>;\n /** One of the brand's agencies of record as Winmo carries them, on an agency slice: a brand with several is on a row per agency. Null where none links (absent: no_agency_linked). */\n agency?: string | null;\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights: number;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Null when attention_flights is 0. */\n attention_passes: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces: number;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points: number;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Null when flights_active is 0. */\n brand_face_days: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Null when flights_active is 0. */\n brand_face_share: number | null;\n /** The brand's IAB tier-1 category. */\n brand_iab_tier1: string | null;\n /** Resolved brand id (brand graph). */\n brand_id: string | null;\n /** Brand name. */\n brand_label: string | null;\n /** The brand's IAB tier-1 category on a category slice (its vote, stamped on the ledger). Null without one (absent: no_category). */\n category?: string | null;\n /** The Census CBSA (Metropolitan or Micropolitan Statistical Area, OMB's July 2023 delineation) of the faces the row counts, on a cbsa slice. Null outside every CBSA and outside the US (absent: no_cbsa). */\n cbsa_code?: string | null;\n /** The CBSA's title (Las Vegas-Henderson-North Las Vegas, NV). */\n cbsa_name?: string | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched: number;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed: number;\n /** The face on a board slice: f:<board id>:<face index> (a registered face) or p:<point id> (an unregistered board point). */\n face_key?: string | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active: number;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started: number;\n /** static or digital on a format slice. Null where no read typed the face (absent: face_type_unknown). */\n format?: string | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Null when attention_flights is 0. */\n gaze_legible_s: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Null when attention_flights is 0. */\n gaze_looked_s: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Null when attention_flights is 0. */\n head_legible_s: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Null when attention_flights is 0. */\n head_looked_s: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Null when market_ad_flights is 0. */\n market_ad_face_days: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights: number;\n /** US DMA or CA CMA code. Null on a fleet row. */\n market_code: string | null;\n /** Country of the market: US or CA. Null on a fleet row. */\n market_country: string | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. Null when market_sightings is 0. */\n market_drawn_sightings: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Null when market_ad_flights is 0. */\n market_face_days: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Null when market_ad_flights is 0. */\n market_face_share: number | null;\n /** Market name. Null on a fleet row. */\n market_name: string | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights: number;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. Null when market_sightings is 0. */\n market_sightings: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. market_vacant_face_days / market_face_days; null when market_face_days is 0. */\n market_vacancy_face_day_share: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. market_vacancy_sightings / market_sightings; null when market_sightings is 0. */\n market_vacancy_share: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. market_vacancy_weighted_sightings / market_weighted_sightings; null when market_weighted_sightings is 0. */\n market_vacancy_share_drawn_weighted: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. Null when market_sightings is 0. */\n market_vacancy_sightings: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Null when market_drawn_sightings is 0. */\n market_vacancy_weighted_sightings: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. Null when market_sightings is 0. */\n market_vacant_board_faces: number | null;\n /** Their face-days in the period. Unit: face_days. Null when market_ad_flights is 0. */\n market_vacant_face_days: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights: number;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Null when market_drawn_sightings is 0. */\n market_weighted_sightings: number | null;\n /** The faces' registry owner on a media_owner slice: a programmatic face's publisher, a permit layer's owner of record. Null on an unregistered board point (absent: no_registered_owner). */\n media_owner?: string | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Null when media_value_priced_faces is 0. */\n media_value_floor_usd: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces: number;\n /** The month (its first day, YYYY-MM-DD). */\n month: string | null;\n /** The brand's parent company on a parent slice: the brand graph id of the parent's Wikidata family. Null where the graph names none (absent: no_parent_named). */\n parent_id?: string | null;\n /** The parent company's name. */\n parent_label?: string | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. named_flights_active / market_named_flights; null when market_named_flights is 0. */\n share_of_named_voice: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. flights_active / market_ad_flights; null when market_ad_flights is 0. */\n share_of_voice: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. brand_face_days / market_ad_face_days; null when market_ad_face_days is 0. */\n share_of_voice_face_days: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Null when market_ad_flights is 0. */\n share_of_voice_face_days_se: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. brand_face_share / market_face_share; null when market_face_share is 0. */\n share_of_voice_face_weighted: number | null;\n /** The reader surface the face's held reads named most, on a surface slice: billboard, digital_board, bus_shelter or kiosk. Null where none named one (absent: no_reader_surface). */\n surface?: string | null;\n /** The ISO week on a week grain: its Monday, YYYY-MM-DD. */\n week?: string | null;\n};\n\n/**\n * Ad delivery per screen-hour: completed plays as our billing policy counts them, distinct creatives and ads, played seconds (each play's longest reported duration) with the plays that carried one, GIVT-passed plays, average CPM, gross revenue and the most frequent source provider. Join place_activity_hourly for the audience of the same screen-hour, and play_audience for the audience of each play.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `screen_id`. Definition version 4. 11 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_ad_delivery_hourly = {\n /** Mean CPM of the plays, USD. Unit: usd_per_1000_plays. NULL: No play of the hour carried a price. */\n avg_cpm?: number | null;\n /** Completed plays as our billing policy identifies them: the play key on one screen, each play once, on its first day. Unit: plays. */\n completed_plays?: number;\n /** Distinct ad ids among the plays (the pod placeholder is not an ad). Unit: ads. */\n distinct_ads?: number;\n /** Distinct creative ids among the plays (the IMA house creative placeholder is not a creative). Unit: creatives. */\n distinct_creatives?: number;\n /** Plays that passed general invalid-traffic checks. Unit: plays. */\n givt_passed_plays?: number;\n /** Sum of the plays' gross revenue, USD. Unit: usd. NULL: No play of the hour carried a price. */\n gross_revenue?: number | null;\n /** Start of the UTC hour. A play counts in the hour its kept report completed. */\n hour_start: string;\n /** Most frequent demand source of the plays by exact count, ties to the alphabetically first. NULL: No play carried a real provider. */\n modal_source_provider?: string | null;\n /** Plays that carried a positive duration: the denominator of a mean play length (played_seconds / played_duration_plays). Unit: plays. */\n played_duration_plays?: number;\n /** Sum over the plays of each play's longest positive duration over every report of the play that day. Unit: seconds. NULL: No play of the hour carried a positive duration on any of its reports. */\n played_seconds?: number | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n};\n\n/**\n * Verified attention per sensing window per screen: one row per audienceSignals window a device sends with vas_weighted > 0 (vasEngine.recordVAS), stamped measured_at by the database clock at write.\n * \n * **Delivery:** Parquet day files, one row per `id`. Definition version 2. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_attention_ledger = {\n /** Ad id the attention was measured against. NULL: The entry named no ad (set on 71,140 of ~72M rows 2026-02..09). */\n ad_id?: string | null;\n /** Mean body engagement 0-1 of those faces. Unit: index. NULL: Not measured. */\n avg_body_engagement?: number | null;\n /** Mean emotional engagement 0-1 of those faces. Unit: index. NULL: Not measured. */\n avg_emotion_engagement?: number | null;\n /** Faces in the measurement. Unit: faces. NULL: Not measured. */\n face_count?: number | null;\n /** The ledger entry's id. */\n id: string;\n /** Impression id the attention was measured against. NULL: The entry named no impression. */\n impression_id?: string | null;\n /** When the attention was measured, UTC. */\n measured_at?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** Verified attention seconds before weighting. Unit: seconds. NULL: Not measured. */\n vas_raw?: number | null;\n /** Verified attention seconds, weighted: the canonical attention value. Unit: seconds. NULL: Not measured. */\n vas_weighted?: number | null;\n};\n\n/**\n * Auction outcomes and outbound OpenRTB proxy attempts keyed by bidder-facing request ID.\n * \n * **Delivery:** Parquet day files keyed by `timestamp`, one row per `auction_id`. Definition version 2. 15 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_auction_results = {\n /** The auction's id: one auction per bid request we ran. */\n auction_id: string;\n /** Auction mechanics: first_price, or outbound_openrtb_proxy for an auction we forwarded to a demand partner. */\n auction_type?: string;\n /** OpenRTB bid request id the auction answered. NULL: Not recorded on the auction. */\n bid_request_id?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** Floor price of the auction, USD CPM. Unit: usd_per_1000_plays. NULL: No floor was set. */\n floor_price_cpm?: number | null;\n /** Auction duration in milliseconds. Unit: ms. NULL: Not recorded. */\n latency_ms?: number | null;\n /** Outcome: bid_received, no_bid, timeout or error. */\n result?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** When the auction ran, UTC. */\n timestamp?: string;\n /** Bids the auction received. Unit: bids. */\n total_bids_received?: number;\n /** Id of the winning bid. NULL: No bid won. */\n winning_bid_id?: string | null;\n /** Price the winning bid offered, USD CPM. Unit: usd_per_1000_plays. NULL: No bid won. */\n winning_bid_price_cpm?: number | null;\n /** Price the winning bid cleared at, USD CPM. Unit: usd_per_1000_plays. NULL: No bid won, or no clearing price was recorded. */\n winning_clearing_price_cpm?: number | null;\n /** Creative id of the winning bid. NULL: No bid won, or the bid named no creative. */\n winning_creative_id?: string | null;\n /** Demand platform of the winning bid. NULL: No bid won. */\n winning_dsp_name?: string | null;\n};\n\n/**\n * Audience attribute mix at venue-type x DMA x week, from AI-vision readings. Starts 2026-07-16, which is when observation_demographics begins — it is not a retention cut. Every row carries observation_count and screens as its support; no cell is dropped for being small, so a buyer sets their own threshold. week_days_in_window counts the days of the week inside the delivery window, so the first and last weeks can be partial. In the key, dma_code '' means no DMA (outside the US), country '' an unresolved country, and openooh_venue_type_id 0 an unclassified venue. lifestyle values are numeric IAB Audience Taxonomy 1.1 segment ids (segtax=4); all other dimensions are our own vocabulary.\n * \n * **Delivery:** A snapshot, one row per `week_start` x `openooh_venue_type_id` x `dma_code` x `country` x `dimension` x `attribute_value`. Definition version 2. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_audience_composition_weekly = {\n /** observation_count over every reading of the dimension in the same week, venue type, DMA and country. Unit: share. */\n attribute_share?: number;\n /** The attribute's value. lifestyle values are numeric IAB Audience Taxonomy 1.1 segment ids (segtax=4); the other dimensions use our own vocabulary. */\n attribute_value: string;\n /** Country ('' = unresolved; a key column). */\n country: string;\n /** The audience attribute. head_turn and occupant_position are image-frame values: head_turn is turned_image_left, turned_image_right, not_turned or not_assessable (where the nose points relative to the edges of the picture), occupant_position is image_left_third, image_center_third, image_right_third or driving (the third of the picture the person occupies). Neither is a side of the vehicle or the street: a rearward cabin camera mirrors the vehicle's left and right. */\n dimension: string;\n /** Nielsen DMA code ('' = no DMA, outside the US; a key column). */\n dma_code: string;\n /** Readings of the value in the week and cell. Unit: readings. */\n observation_count?: number;\n /** OpenOOH venue type of the screens (0 = unclassified; a key column, so never NULL). */\n openooh_venue_type_id: number;\n /** Distinct screens carrying the value. Unit: screens. */\n screens?: number;\n /** Days of the week inside the delivery window (7 except at its two ends). Unit: days. */\n week_days_in_window?: number;\n /** Monday of the week. */\n week_start: string;\n};\n\n/**\n * FEIN 10-second window audience observations — face count, dwell, demographic signals per screen per interval.\n * \n * **Delivery:** Parquet day files, one row per `metric_id`. Definition version 3. 28 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_audience_metrics = {\n /** Ad receptivity score 0-1 of the window: how receptive the audience in view is to an ad. Unit: index. NULL: No receptivity reading. */\n ad_receptivity_score?: number | null;\n /** Attention level the camera read for the window: high, medium or low. NULL: No attention reading. */\n attention_level?: string | null;\n /** Head-pose index 0-1 of the window: the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. NULL: No head-pose reading. */\n avg_attention?: number | null;\n /** Mean dwell of the faces in view, in milliseconds, as the device reported it, not capped at the window's length (place_activity_hourly's avg_dwell_ms caps each window at its own length). Unit: ms. NULL: Not measured. */\n avg_dwell_time_ms?: number | null;\n /** Mean face count over the window's analysed frames, as the device wrote it (place_activity_hourly's avg_face_count prefers the newer per-window face_count and falls back to this). Unit: faces. NULL: Not measured. */\n avg_face_count?: number | null;\n /** Estimated ambient noise level of the window, in decibels, from the device's audio classification. Unit: decibels. NULL: No noise reading: the device sent none (stored as -1). */\n avg_noise_level?: number | null;\n /** Crowd density of the scene. NULL: No crowd reading. */\n crowd_density?: string | null;\n /** Daypart label in the screen's local time. NULL: Not recorded. */\n daypart?: string | null;\n /** Dominant ambience of the scene (quiet, ambient, crowded ...). NULL: No ambience reading. */\n dominant_ambience?: string | null;\n /** Emotional engagement score 0-1 of the faces in view. Unit: index. NULL: No emotional engagement reading. */\n emotional_engagement_score?: number | null;\n /** Device id (fingerprint) of the screen's sensing device that recorded the window; the Data API serves the same id as device_id. */\n fingerprint?: string;\n /** Venue type the vision model inferred from the scene. NULL: Not inferred. */\n inferred_venue_type?: string | null;\n /** True when the window fell on a weekend day. */\n is_weekend?: boolean;\n /** Largest face count of any one analysed frame in the window, as the device wrote it. Unit: faces. NULL: Not measured. */\n max_face_count?: number | null;\n /** The camera observation window's id (the key; joins play_audience_window.window_metric_id). */\n metric_id: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n mongo_screen_id?: string;\n /** Movement pace of the people in view. NULL: No pace reading. */\n movement_pace?: string | null;\n /** Dominant mood of the people in view. NULL: No mood reading. */\n primary_mood?: string | null;\n /** City of the screen's stored location. NULL: The screen has no stored city. */\n screen_city?: string | null;\n /** Country of the screen's stored location (for a vehicle, where it last synced). NULL: The screen has no stored country. */\n screen_country?: string | null;\n /** DMA of the screen's stored location. NULL: No DMA (outside the US, or not geocoded). */\n screen_dma_name?: string | null;\n /** Engagement with the screen: engaged, glancing or ignoring. NULL: No engagement reading. */\n screen_engagement?: string | null;\n /** Latitude of the screen's stored location (for a vehicle, where it last synced; geohash_activity_hourly places windows on the GPS trail). Unit: degrees. NULL: The screen has no stored coordinate. */\n screen_latitude?: number | null;\n /** Longitude of the same point. Unit: degrees. NULL: The screen has no stored coordinate. */\n screen_longitude?: number | null;\n /** The screen's registered venue category. NULL: The screen has no registered category. */\n screen_venue_category?: string | null;\n /** How the window was sensed (on-device model, cloud vision analysis ...). NULL: Not recorded. */\n sensing_mode?: string | null;\n /** End of the observation window, UTC. */\n window_end?: string;\n /** Start of the observation window (about 10 s long), UTC. NULL: Not recorded: a vision-analysis window carries no start (window_end is its time). */\n window_start?: string | null;\n};\n\n/**\n * One row per outdoor ad a still reading saw: the creative as read, the board face it was attributed to (or the cab position, heading and side when unmatched), brand, company, exact creative where known, and the reading inclusion probability.\n * \n * **Delivery:** Parquet day files keyed by `seen_at`, one row per `sighting_id`. Definition version 5. 56 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_creative_sighting = {\n /** Position of the ad among the ads the reading listed, from 0. */\n ad_ordinal?: number;\n /** The words read on the ad, verbatim, parts separated by \" | \". NULL: Nothing readable. */\n ad_text?: string | null;\n /** The glass the ad was seen through, judged against the edges of the picture: rear, left or right. NULL: The reading did not say. */\n ad_window?: string | null;\n /** The creative of that line item. NULL: No exact creative. */\n advertisement_id?: string | null;\n /** The advertiser as read off the ad. NULL: Not read. */\n advertiser?: string | null;\n /** The matched board: our board id, the key every board dataset and the measurement API use. NULL: Unmatched. */\n board_id?: string | null;\n /** Left edge of the ad in the still, a fraction of the picture width. NULL: A vlm_text sighting. */\n box_x0?: number | null;\n /** Right edge of the ad in the still. NULL: A vlm_text sighting. */\n box_x1?: number | null;\n /** Top edge of the ad in the still, a fraction of the picture height. NULL: A vlm_text sighting. */\n box_y0?: number | null;\n /** Bottom edge of the ad in the still. NULL: A vlm_text sighting. */\n box_y1?: number | null;\n /** The brand as read off the ad. NULL: Not read. */\n brand?: string | null;\n /** The resolved brand (our brand knowledge graph id). NULL: Not resolved. */\n brand_id?: string | null;\n /** How the advertiser was resolved to the brand: exact, domain, grounded_verified, minted or unresolved. NULL: Not resolved. */\n brand_match_method?: string | null;\n /** The resolved brand's name. NULL: Not resolved. */\n brand_name?: string | null;\n /** Cab heading at seen_at, degrees clockwise from north. Unit: degrees. NULL: No matched path covers the instant. */\n cab_heading_deg?: number | null;\n /** Cab latitude at seen_at on its matched path. Unit: degrees. NULL: No matched path covers the instant. */\n cab_lat?: number | null;\n /** Cab longitude at seen_at on its matched path. Unit: degrees. NULL: No matched path covers the instant. */\n cab_lon?: number | null;\n /** Board faces the cab was passing at seen_at. Unit: faces. */\n candidate_count?: number;\n /** Why the tablet took the still: board_burst, face_triggered, periodic_scene, signal_mismatch_probe, vehicle_triggered. */\n capture_mode?: string;\n /** The reader's own 0-1 confidence in the entry. NULL: A vlm_text sighting. */\n confidence?: number | null;\n /** line_item_flight = the face was one we bought for this advertiser and the sighting fell inside the flight. NULL: No exact creative. */\n creative_match_method?: string | null;\n /** IAB Content Taxonomy top-level codes of what the ad advertises (IAB1..IAB25). */\n iab_categories?: Array<unknown>;\n /** Probability the still was drawn for reading; weight a sighting by 1/inclusion_probability. Unit: probability. NULL: A vlm_text sighting: no draw chose the still. */\n inclusion_probability?: number | null;\n /** The reader generation that produced the reading (ssr-v1, ssr-v2, vlmtext-v1, edge_ocr_v1). From ssr-v2 the still reader also classifies the placement. */\n instrument_version?: string;\n /** 1 when the face carried no advertiser: blank, or the media owner's own available or advertise-here message. */\n is_vacancy?: number;\n /** legible = the advertiser named with certainty; partial = a best guess from partial words or a logo; illegible = an ad with nothing readable. NULL: A vlm_text sighting. */\n legibility?: string | null;\n /** Cabin light on the pass: bright, dim or dark. NULL: No light reading for the pass. */\n light_band?: string | null;\n /** Our purchased line item the sighting matched. NULL: No exact creative. */\n line_item_id?: string | null;\n /** The market: a DMA code in the US, a CMA code in Canada. A market is the pair (market_country, market_code). NULL: No board, reading or cab position placed the sighting. */\n market_code?: string | null;\n /** Country of the market: US or CA. NULL: No board, reading or cab position placed the sighting. */\n market_country?: string | null;\n /** Metro name of the market. NULL: Unplaced. */\n market_name?: string | null;\n /** How the face was chosen: burst_board (the face the cab's board burst was taken for), only_candidate, or nearest; '' (empty, not NULL, since v4) when unmatched. on_premise rows (the ad is the brand's own sign: a storefront read, a reading classified own_premises, or one of the brand's own places within 300 m of the cab or nearer than the face) are not ad data and are not delivered. */\n match_basis?: string;\n /** Bearing of the matched face relative to the cab's travel at seen_at; positive = the cab's right. Unit: degrees. NULL: Unmatched. */\n match_beta_deg?: number | null;\n /** Distance from the cab to the matched face at seen_at; on an on_premise row, to the face the ad was moved off. Unit: meters. NULL: Unmatched. */\n match_distance_m?: number | null;\n /** 1 when seen_at fell inside the pass's legible interval. NULL: Unmatched. */\n match_legible?: number | null;\n /** matched = attributed to a board face the cab was passing; unmatched = faces were near but none is the match (none on the sighting's side, none within 300 m, or the ad is the brand's own sign: match_basis on_premise); no_candidate = the cab was passing no known face. */\n match_status?: string;\n /** Where the cab's camera pointed that day (its dated cabin map): rearward, forward, side, upward or unclear. NULL: No dated cabin map covered the cab that day. */\n mount_class?: string | null;\n /** The matched face of the board, from 0. NULL: Unmatched. */\n orientation_idx?: number | null;\n /** Parent company of the brand. NULL: No parent known. */\n parent_name?: string | null;\n /** The cab's pass of the matched face (board_pass pass_id, a 64-bit id shipped as text). NULL: Unmatched. */\n pass_id?: string | null;\n /** paid_ad: the still reader (ssr-v2 and later) judged the ad a third-party placement on a billboard, digital board, transit shelter, kiosk or wrap; '' (empty): the reading did not classify it (ssr-v1, vlm_text and edge reads, delivered by the surface and on-premise rules). Of a classified reading only paid_ad is delivered: own_premises and other are not ads. */\n placement?: string;\n /** paid_ad: the second look (since v5) confirmed the reader's paid_ad on the ad itself, the still with the ad boxed and the ad enlarged (services/sensing/stillScan/adPlacementCheckMethod.js); '' (empty): a reading the reader did not classify (delivered by the surface and on-premise rules). A reader paid_ad ships only with placement_check paid_ad. */\n placement_check?: string;\n /** The product or offer as read. NULL: Not read. */\n product?: string | null;\n /** Media owner of the matched face. NULL: Unmatched. */\n publisher_name?: string | null;\n /** The cab that took the still. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** When the still was taken, UTC: the device shutter where plausible, else when the still reached us (seen_clock says which). */\n seen_at?: string;\n /** device_shutter or called_at: which clock seen_at is. */\n seen_clock?: string;\n /** Of those, the faces on the sighting's side. Unit: faces. */\n side_candidate_count?: number;\n /** The sighted creative the read belongs to (sighted_creatives.creative_id): one artwork recognised across faces and cabs; its flights are creative_flights. NULL: The read is not yet in a sighted creative. */\n sighted_creative_id?: string | null;\n /** The sighting: one outdoor ad in one reading of one cab still. Stable across rebuilds. */\n sighting_id: string;\n /** Sun on the pass: bright (10 degrees or more up), dim (0-10) or dark (below the horizon). NULL: No pass. */\n solar_band?: string | null;\n /** still_reader = the still reader read the ad off the stored still; vlm_text = the audience prompt's existing description of the same still named it (no box, no legibility); edge_ocr = the tablet read the ad's words on the device. */\n source?: string;\n /** The read: for still_reader and vlm_text the stored still it was read off (its call id, the key of camera_frame_corpus and of the proof archive copy); for edge_ocr the tablet's reading id. */\n still_call_id?: string;\n /** billboard, digital_board, bus_shelter or kiosk; wall_or_wrap or vehicle only when the reader classified the ad paid_ad; '' (empty, not NULL, since v4) when not stated, delivered only for a read matched to a registered board face (an edge read). A storefront read is a business's own sign, and an unclassified vehicle or wall read most often a business's own livery or wall sign: neither is delivered. */\n surface?: string;\n /** Listed ticker of the brand's company. NULL: No listed company. */\n ticker?: string | null;\n /** Side of the vehicle the ad was on: left, right or behind (the picture side converted through the cab's mount). NULL: The picture side does not convert for this mount. */\n vehicle_side?: string | null;\n};\n\n/**\n * Measured delivery per roadside face (board_id is the venue id of the board face), daypart and one-dimensional condition (all, light, weather, speed) over one 28-day window: measured impressions per spot (ips) with its interval and the passes and vehicles behind it, its terms (traffic flow, legible window and share, people per vehicle in position to see), our count under the owner's definition, the owner's modelled impressions per spot with the yield comparison, its annual value and the floor CPM it supports, expected unique ads per pass, and the light, glare and rain mix of the passes. The window is the newest one the builder verified that ends inside the delivery window (window_end, the same on every row). ips is NULL only where nothing was measured, with absent_reason saying what. The 2026-10-11 window: 962,168 cells over 141,704 faces, 775,993 of them with a measured ips, 192,810 with the yield comparison drawn.\n * \n * **Delivery:** A snapshot, one row per `window_end` x `board_id` x `daypart` x `cond_scope` x `cond_value`. Definition version 2. 68 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_currency_multiweek = {\n /** Annual average daily traffic facing the face, after the two-way split. Unit: vehicles_per_day. NULL: As flow_vph. */\n aadt_facing?: number | null;\n /** Weakest traffic-count basis among the face's ways: hpms (FHWA HPMS), mtq (Quebec), mtl (Montreal), nyc (New York City), modeled or imputed; empty when the face has no flow. */\n aadt_source?: string;\n /** Empty when ips is published. Otherwise what was not measured: no_viewshed, no_passes, no_window (passes with no legible window measured), no_persons or no_flow, where ips is NULL; owner_model_missing or incremental_basis withhold the yield only, and ips publishes. */\n absent_reason?: string;\n /** Mean expected complete ads per pass. Unit: ads_per_pass. NULL: As ads_seen_mean. */\n ads_complete_mean?: number | null;\n /** Mean expected unique ads seen per pass under the modelled rotation. Unit: ads_per_pass. NULL: No passes in the cell. */\n ads_seen_mean?: number | null;\n /** Mean expected unique ads touched per pass. Unit: ads_per_pass. NULL: As ads_seen_mean. */\n ads_touched_mean?: number | null;\n /** Annual value of the measured difference at the face's floor: spots_per_day_owner x (ips - ips_owner) x floor CPM / 1000 x 365. Unit: usd_per_year. NULL: As yield_ratio. */\n annual_opportunity_usd?: number | null;\n /** Average vehicle occupancy the window uses. Unit: persons_per_vehicle. */\n avo?: number;\n /** The roadside face: the venue id of the board face. */\n board_id: string;\n /** Version of the code that built the window. */\n builder_version?: number;\n /** When the window was built, UTC. */\n built_at?: string;\n /** The board_pass rows with camera evidence. Unit: passes. */\n camera_pass_rows?: number;\n /** Face passes with camera evidence. Unit: passes. NULL: As passes. */\n camera_passes?: number | null;\n /** The one-dimensional condition marginal the row is: all, light, weather or speed. Each scope partitions the passes on its own, so rows of two scopes are two cuts of the same passes. */\n cond_scope: string;\n /** The band within cond_scope (light: day, twilight, night; weather: clear, rain, snow_ice, low_visibility; speed: free_flow, slowed, congested; unknown where the band was not read), __all__ when cond_scope is all. */\n cond_value: string;\n /** Contacts per day: the sum over the day's hours of the flow times the people per vehicle in position to see. Unit: contacts_per_day. NULL: As ips. */\n daily_contacts?: number | null;\n /** Daypart of the cell (early_morning, morning, midday, afternoon, evening, night, late_night), or __all__ for the whole day. */\n daypart: string;\n /** Coefficient of variation of flow_vph. Unit: ratio. NULL: As flow_vph. */\n flow_cv?: number | null;\n /** Vehicles per hour past the face in the cell. Unit: vehicles_per_hour. NULL: The face has no traffic flow (absent_reason no_flow), or no passes. */\n flow_vph?: number | null;\n /** Share of the passes with glare. Unit: share. NULL: No passes in the cell. */\n glare_share?: number | null;\n /** Measured impressions per dollar of floor CPM: 1000 x yield_ratio / floor. Unit: impressions_per_usd. NULL: As yield_ratio. */\n imps_per_floor_usd?: number | null;\n /** How the ips interval is computed (lognormal_delta_vehicle_clustered). */\n interval_method?: string;\n /** Measured impressions per spot: (flow_vph / 3600) x (legible_share x slot_s + window_s_mean) x persons_per_vehicle over the face's road and direction streams. Unit: impressions_per_spot. NULL: Nothing measured for the cell: absent_reason says what (no_viewshed, no_passes, no_window, no_persons or no_flow). */\n ips?: number | null;\n /** High end of ips's interval. Unit: impressions_per_spot. NULL: As ips_low. */\n ips_high?: number | null;\n /** Low end of ips's interval (log-normal delta method, clustered on vehicles). Unit: impressions_per_spot. NULL: As ips, or one vehicle behind the cell. */\n ips_low?: number | null;\n /** The owner's modelled impressions per spot: the figure the measurement is compared with. Unit: impressions_per_spot. NULL: The face has no owner model. */\n ips_owner?: number | null;\n /** Our count per spot under the owner's definition: every vehicle occupant in view over the visible window, the slot charged to every vehicle ((flow_vph / 3600) x (slot_s + owner_def_window_s) x avo over every stream in the visibility zone). Beside ips, for the comparison with ips_owner. Unit: impressions_per_spot. NULL: As ips. */\n ips_owner_def?: number | null;\n /** High end of ips_owner_def's interval. Unit: impressions_per_spot. NULL: As ips_owner_def_low. */\n ips_owner_def_high?: number | null;\n /** Low end of ips_owner_def's interval. Unit: impressions_per_spot. NULL: As ips_owner_def, or one vehicle behind the cell. */\n ips_owner_def_low?: number | null;\n /** Flow-weighted share of the vehicles the face is legible to (a legible window above 0), each road direction's share shrunk toward the face's pooled share by its passes. Unit: share. NULL: No passes in the cell. */\n legible_share?: number | null;\n /** Length of the face's ad loop, seconds. Unit: seconds. NULL: The loop length is unknown. */\n loop_s?: number | null;\n /** Mean cabin light, lux. Unit: lux. NULL: No pass of the cell read cabin light. */\n lux_mean?: number | null;\n /** exposure_currency method version of the window. */\n method_version?: number;\n /** Moving speed past the face: the face-share-weighted median of path / (visible - stationary seconds) over the cell's passes that moved, metres per second. Unit: metres_per_second. NULL: No pass of the cell moved past the face, or the window was built before exposure_currency v6. */\n moving_speed_mps?: number | null;\n /** Ad slots in the loop. Unit: slots. NULL: The slot count is unknown. */\n n_slots?: number | null;\n /** Share of the passes in the night light band. Unit: share. NULL: No passes in the cell. */\n night_share?: number | null;\n /** Flow-weighted mean visible seconds per vehicle behind ips_owner_def, each stream shrunk toward the cell's pooled mean. Unit: seconds. NULL: As ips_owner_def. */\n owner_def_window_s?: number | null;\n /** Highest pass_audience method version among the pass audience partitions the window read. */\n pass_audience_mv_max?: number;\n /** Lowest pass_audience method version among the pass audience partitions the window read. */\n pass_audience_mv_min?: number;\n /** The board_pass rows behind the cell, one per candidate facing of a traversal: a reconciliation count, never a pass count. Unit: passes. */\n pass_rows?: number;\n /** Face passes of our map-matched vehicles past the face in the cell over the window, each traversal once (the sum of board_pass.face_share): the support. Unit: passes. NULL: The window was built before face passes (exposure_currency v6). */\n passes?: number | null;\n /** Passenger camera windows behind v_pax. Unit: windows. */\n pax_windows?: number;\n /** People per vehicle in position to see the face: v_driver + (avo - 1) x v_pax. Unit: persons_per_vehicle. NULL: No passes in the cell. */\n persons_per_vehicle?: number | null;\n /** Why yield_ratio is drawn at this face: vehicle_dominated (our count under the owner's definition reaches the vehicle share of ips_owner) or owner_vehicle_component; empty when it is not drawn. */\n population_basis?: string;\n /** Why yield_ratio is not drawn at this face: population_mismatch, audience_at_venue (a point-of-sale face), owner_derivation_unknown or owner_model_missing; empty when it is drawn. ips publishes either way. */\n population_reason?: string;\n /** Basis of the hourly traffic shape: fleet_blend (our fleet's observed traversal profile blended with the TMAS prior) or tmas_prior; empty when the face has no flow. */\n profile_basis?: string;\n /** Share of the passes in the rain band. Unit: share. NULL: No passes in the cell. */\n rain_share?: number | null;\n /** Floor CPM the measurement supports: the floor CPM x min(yield_low, the yield cap). Unit: usd_per_1000_impressions. NULL: As yield_ratio. */\n recommended_floor_cpm?: number | null;\n /** Length of one ad slot on the face, seconds. Unit: seconds. */\n slot_s?: number;\n /** Where slot_s comes from: declared, declared_range, publisher_type_median or format_default. */\n slot_source?: string;\n /** Harmonic mean speed of the passes, metres per second: one stopped pass dominates it, so the moving speed is beside it. Unit: metres_per_second. NULL: No passes in the cell. */\n speed_hmean_mps?: number | null;\n /** The owner's spots per day: its average daily impressions over its impressions per spot. Unit: spots. NULL: The face has no owner model. */\n spots_per_day_owner?: number | null;\n /** Share of the in-view seconds the passing vehicles stood still: stationary over visible seconds, face-share weighted. Unit: share. NULL: As moving_speed_mps (no visible seconds). */\n stopped_share?: number | null;\n /** Share of drivers in position to see the face. Unit: share. */\n v_driver?: number;\n /** In-cab camera instrument behind v_pax (head_yaw). */\n v_instrument?: string;\n /** Ladder level v_pax comes from: board, market or fleet; empty when v_pax is NULL. */\n v_level?: string;\n /** Passenger attention term: the share of passengers in position to see the face, from the in-cab camera (v_instrument) at the ladder level v_level. Unit: share. NULL: No ladder level (board, market, fleet) carries a passenger attention reading for the cell. */\n v_pax?: number | null;\n /** High end of v_pax's interval. Unit: share. NULL: As v_pax. */\n v_pax_high?: number | null;\n /** Low end of v_pax's interval. Unit: share. NULL: As v_pax. */\n v_pax_low?: number | null;\n /** Distinct vehicles behind those passes: the cluster the intervals are computed over. Unit: vehicles. */\n vehicles?: number;\n /** Window length in days (28). Unit: days. */\n window_days?: number;\n /** Last local date of the 28-day window. */\n window_end: string;\n /** Legible seconds per vehicle: the flow-weighted mean over the face's road and direction streams of each stream's mean legible window, each shrunk toward the cell's pooled mean by its passes. Unit: seconds. NULL: No passes in the cell. */\n window_s_mean?: number | null;\n /** Vehicle-clustered standard error of window_s_mean. Unit: seconds. NULL: No passes in the cell, or one vehicle behind it. */\n window_s_se?: number | null;\n /** ratio (the face's format carries owner impressions per spot to compare: yield_ratio is drawn) or incremental (drive-past contacts reported as incremental). */\n yield_basis?: string;\n /** High end of yield_ratio's interval. Unit: ratio. NULL: As yield_ratio. */\n yield_high?: number | null;\n /** Low end of yield_ratio's interval. Unit: ratio. NULL: As yield_ratio. */\n yield_low?: number | null;\n /** Measured over owner impressions per spot: ips / ips_owner. Unit: ratio. NULL: yield_basis is incremental, the face has no owner model, or population_reason names why the comparison is not drawn. */\n yield_ratio?: number | null;\n};\n\n/**\n * Modelled vehicles per hour past each roadside face (board_id is the venue id of the board face), by day type (weekday, saturday, sunday; holidays count as sunday) and board-local hour: directional AADT facing the face (aadt_facing, after the two-way split) x TMAS month and day factors x an hourly shape that blends our fleet's observed traversal profile with the TMAS prior (profile_basis, kappa). flow_cv is its coefficient of variation. aadt_source names the weakest basis among the ways (hpms: FHWA HPMS, whose US vintage is 2020; mtq: Quebec; imputed); aadt_year is the oldest AADT year and NULL where imputed. One snapshot, rebuilt whole; fit_window_end dates the fleet profile; the exposure_currency method version is on every row.\n * \n * **Delivery:** A snapshot, one row per `board_id` x `dow_type` x `local_hour`. Definition version 1. 13 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_flow_hourly = {\n /** Annual average daily traffic facing the face, after the two-way split. Unit: vehicles_per_day. */\n aadt_facing?: number;\n /** Weakest AADT basis among the ways: hpms (FHWA HPMS), mtq (Quebec) or imputed. */\n aadt_source?: string;\n /** Oldest AADT year among the ways. NULL: The AADT is imputed. */\n aadt_year?: number | null;\n /** The roadside face: the venue id of the board face. */\n board_id: string;\n /** Day type: weekday, saturday or sunday (holidays count as sunday). */\n dow_type: string;\n /** exposure_currency method version of the flow. */\n exposure_currency_method_version?: number;\n /** Last day of the fleet profile's fit window. */\n fit_window_end?: string;\n /** Coefficient of variation of flow_vph. Unit: ratio. */\n flow_cv?: number;\n /** Modelled vehicles per hour past the face. Unit: vehicles_per_hour. */\n flow_vph?: number;\n /** Strength of the prior against the fleet profile in the blend. NULL: The build used the TMAS prior alone. */\n kappa?: number | null;\n /** Board-local hour of the day, 0-23. */\n local_hour: number;\n /** Basis of the hourly shape: fleet_blend (our fleet's observed traversal profile blended with the TMAS prior) or tmas_prior (the prior alone). */\n profile_basis?: string;\n /** Road ways contributing to the face. Unit: ways. */\n ways?: number;\n};\n\n/**\n * One row per roadside face (board_id is the venue id of the board face) per board-local day: passes of our map-matched vehicles with the face in view, distinct vehicles, visible and legible seconds (legible = available to be read), cab occupancy, and the camera attention windows, summed over the dayparts of the measurement API's currency rollups, so a board-day here equals the API's. From local date 2026-05-12. occupied_share = occupied_passes / occupancy_known_passes, over the passes whose occupancy is known. pax_count_mean = pax_count_sum / pax_count_n: passengers per occupied pass over the occupied passes that carry a passenger count (pax_count_n), NULL on a board-day with none. Heads-up and eyes-out windows are per instrument: hy_* is head yaw, sh_* is shoulders. expected_passes is the face_share-weighted pass count for a face whose orientation is unresolved. The rollups rebuild recent local dates as later trip dates land, and a later delivery carries the rebuilt days.\n * \n * **Delivery:** Parquet day files keyed by `local_date`, one row per `local_date` x `board_id`. Definition version 2. 27 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_board_pass_daily = {\n /** The roadside face: the venue id of the board face. */\n board_id: string;\n /** Cabin camera windows during the passes. Unit: windows. */\n camera_windows?: number;\n /** Nielsen DMA of the face. NULL: The face is outside a DMA. */\n dma_code?: string | null;\n /** Face-share-weighted passes, for a face whose orientation is unresolved. Unit: passes. NULL: The currency rollup holds no row for the board-day. */\n expected_passes?: number | null;\n /** exposure_currency method version of the currency rollup. NULL: More than one method version, or no currency row. */\n exposure_currency_method_version?: number | null;\n /** Head-yaw instrument: windows with the eyes out of the vehicle. Unit: windows. */\n hy_eyes_out_windows?: number;\n /** Head-yaw instrument: windows with the head up. Unit: windows. */\n hy_heads_up_windows?: number;\n /** Head-yaw instrument: windows with a valid pose. Unit: windows. */\n hy_pose_valid_windows?: number;\n /** Seconds the face was legible (available to be read) over the passes. Unit: seconds. NULL: The currency rollup holds no row for the board-day. */\n legible_s?: number | null;\n /** The board's local calendar day. */\n local_date: string;\n /** Passes whose cab occupancy is known. Unit: passes. */\n occupancy_known_passes?: number;\n /** Of those, the passes with a passenger in the cab. Unit: passes. */\n occupied_passes?: number;\n /** occupied_passes / occupancy_known_passes. Unit: share. NULL: No pass with a known occupancy (occupancy_known_passes = 0). */\n occupied_share?: number | null;\n /** pass_audience method version of the audience rollup. NULL: The board-day was built under more than one method version. */\n pass_audience_method_version?: number | null;\n /** The board_pass rows behind the board-day, one per candidate facing of a traversal: a reconciliation count, never a pass count. Unit: passes. */\n pass_rows?: number;\n /** Face passes of our map-matched vehicles with the face in view: each traversal once (the sum of board_pass.face_share; a face whose facing is unresolved has one row per candidate facing at 1/k each). Unit: passes. NULL: The board-day was built before face passes (pass_audience v8). */\n passes?: number | null;\n /** Passengers per occupied pass: pax_count_sum / pax_count_n. Unit: passengers_per_pass. NULL: No occupied pass carries a passenger count (pax_count_n = 0). */\n pax_count_mean?: number | null;\n /** Occupied passes that carry a passenger count. Unit: passes. */\n pax_count_n?: number;\n /** Passengers summed over the occupied passes that carry a count. Unit: passengers. */\n pax_count_sum?: number;\n /** Media owner of the face (empty when none is recorded). */\n publisher_name?: string;\n /** Shoulder instrument: windows with the eyes out of the vehicle. Unit: windows. */\n sh_eyes_out_windows?: number;\n /** Shoulder instrument: windows with the head up. Unit: windows. */\n sh_heads_up_windows?: number;\n /** Shoulder (MoveNet) instrument: windows with a valid pose. Unit: windows. */\n sh_pose_valid_windows?: number;\n /** Passes on which this face was the site's primary face. Unit: passes. NULL: The currency rollup holds no row for the board-day. */\n site_primary_passes?: number | null;\n /** Distinct vehicles behind the passes. Unit: vehicles. */\n vehicles?: number;\n /** OpenOOH venue type id of the face (0 = unclassified). */\n venue_type_id?: number;\n /** Seconds the face was in view over the passes. Unit: seconds. NULL: The currency rollup holds no row for the board-day. */\n visible_s?: number | null;\n};\n\n/**\n * Camera frames: one JPEG per stored frame (19,622 bytes on average over the 1,000 frames of the v4 sample), from the fleet's cameras in the venues and vehicle cabins the screens are in, people in frame: the frame of every cloud vision call and, from definition 4, every frame the device uploaded while the call was capped, throttled or answered from memory (stored with no caption, response or model), and from definition 5 the rear-view board stills of the road behind the cab (capture modes board_rear*, stored the same way). Delivered as one JPEG object per call_id plus an index parquet keyed call_id (screen_id, called_at, captured_at, image_sha256, object path, the model's caption of the scene and its whole structured response, the model, the capture trigger, and the screen's registered region and venue). The v4 index holds 4,177,893 frames from 5,420 screens, 2026-05-05..10-11 (282,838 of them legacy frames before 06-21), 3,779,384 of them with a caption (measured 2026-10-13); 37,485 frames on 2026-10-10 alone. Video is the camera video corpus (camera_video_corpus).\n * \n * **Delivery:** An imagery corpus: the files plus `<corpus>-index.parquet`, one row per item, with these columns. Definition version 6. 19 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_camera_frame_corpus = {\n /** The frame's identity: the cloud vision call it was captured for. The delivered JPEG is named by it. */\n call_id: string;\n /** When the frame was sent for analysis, UTC. */\n called_at?: string;\n /** The model's description of the scene in the frame (its scene_description). NULL: The call carried no scene description: a failed or truncated cloud call, a frame an edge model analysed on the device (model local-vlm), a frame stored without a cloud call (worker frame_store), or a legacy frame. */\n caption?: string | null;\n /** The model's whole response for the frame, as JSON text: its scene description with the audience classes, extra observations, social attention, ad-fit verdict and every other key it returned (2,853 characters on average over the 1,833 whole responses of 2026-10-10 12:00-13:00 UTC; the scene description alone averages 80). NULL: The call's response is not whole JSON (a failed or truncated cloud call), the frame was stored without a cloud call (worker frame_store: no response exists), or a legacy frame. */\n caption_response?: string | null;\n /** What triggered the capture (e.g. periodic_scene, face_triggered). NULL: Not recorded (before 2026-09-24, or captured off-device). */\n capture_mode?: string | null;\n /** Why the device captured it (e.g. periodic_scene_baseline, face_detected). NULL: Not recorded (as capture_mode). */\n capture_reason?: string | null;\n /** When the camera captured the frame, UTC. NULL: Not recorded: the device shutter time is recorded from 2026-08-13; called_at is the nearest time. */\n captured_at?: string | null;\n /** Country of the screen's registered location. NULL: The screen has no registered country. */\n country?: string | null;\n /** Nielsen DMA code of the screen's registered location. NULL: Outside the US, or not geocoded. */\n dma_code?: string | null;\n /** DMA name. NULL: As dma_code. */\n dma_name?: string | null;\n /** SHA-256 (hex) of the stored JPEG, recorded when the frame was written. NULL: Not recorded: the stored hash is written from 2026-08-20; the delivered file's own hash is in the index the rail writes. */\n image_sha256?: string | null;\n /** Vision model that analysed the frame and wrote its caption. NULL: A legacy frame, or a frame stored without a cloud call (worker frame_store: the call was capped, throttled or answered from memory, or the capture mode is a rear-view board still stored by contract, so no model analysed this frame). */\n model?: string | null;\n /** That model's version. NULL: Not recorded, a legacy frame, or a frame stored without a cloud call (as model). */\n model_version?: string | null;\n /** Path of the stored JPEG in our private media store (vision-frames-private/YYYY/MM/DD/<call_id>.jpg; vision-evals/ for the legacy frames). */\n object_key?: string;\n /** Sensing profile the call ran under (e.g. transit_hub_v1). NULL: A legacy frame (the eval prefix records none). */\n profile_id?: string | null;\n /** Trillboards screen id of the camera that captured the frame. NULL: The call carried no screen id. */\n screen_id?: string | null;\n /** State or province of the screen's registered location. NULL: The screen has no registered state. */\n state?: string | null;\n /** The screen's registered venue category (transit = a vehicle cabin). NULL: Not classified. */\n venue_category?: string | null;\n /** The screen's registered venue type. NULL: Not classified. */\n venue_type?: string | null;\n};\n\n/**\n * Camera video: MP4 segments recorded by the fleet's cameras in the venues and vehicle cabins the screens are in, people in frame, delivered as one file per segment (segments/<YYYY-MM>/<segment_id>.mp4) plus an index parquet keyed segment_id, the SHA-256 of the file. Tablet cameras record H.264 segments (60 seconds, 1280x720 at 15 fps, 1,000,000 bps video with 96,000 bps AAC audio by default: 8,220,000 bytes a segment, 493,200,000 bytes a camera-hour) for as long as people are in front of the camera: back to back from the first window with a face until 20 seconds pass with none; CCTV cameras record continuously as a stream copy of the camera's own encoding. Duration, encoding, size and MD5 are measured per segment from the stored file. Labels join by time: the camera windows (faces, attention, head pose, gaze, emotion, demographics), face tracks, the cabin ride, board passes and stills that overlap each segment.\n * \n * **Delivery:** An imagery corpus: the files plus `<corpus>-index.parquet`, one row per item, with these columns. Definition version 1. 40 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_camera_video_corpus = {\n /** Build of the software that recorded the segment: the tablet agent's, or the edge connector's. */\n agent_version?: string;\n /** Audio bitrate, measured from the file. Unit: bits per second. NULL: The file carries no audio track (has_audio false), or the recorder could not measure its track. */\n audio_bitrate_bps?: number | null;\n /** Audio codec of the file (aac). NULL: The file carries no audio track (has_audio false), or its track is in a codec other than AAC (has_audio true). */\n audio_codec?: string | null;\n /** Size of the stored file. Unit: bytes. */\n bytes?: number;\n /** Hash (16 lowercase hex) of the camera calibration the device applied: segments with one hash share one camera geometry. NULL: The camera reported no calibration: every CCTV camera, and a tablet before a calibration reached it. */\n calibration_hash?: string | null;\n /** Which clock the capture times are on: device (the camera's wall clock, accepted by the server's plausibility check) or server (the time the server received the upload request, used when the device clock failed that check). */\n capture_clock?: string;\n /** When its last frame was captured, UTC, on the same clock. */\n capture_end?: string;\n /** When the segment's first frame was captured, UTC, on the clock capture_clock names. */\n capture_start?: string;\n /** Video codec of the file: h264 or hevc. */\n codec?: string;\n /** MD5 (lowercase hex) of the stored file, re-verified by the server from the stored bytes. */\n content_md5?: string;\n /** Country of the screen's registered location. NULL: The screen has no registered country (a CCTV feed is registered as a camera, not a screen). */\n country?: string | null;\n /** Nielsen DMA code of the screen's registered location. NULL: Outside the US, or not geocoded. */\n dma_code?: string | null;\n /** Nielsen DMA name of the screen's registered location. NULL: As dma_code. */\n dma_name?: string | null;\n /** Length of the segment, measured from the file. Unit: milliseconds. */\n duration_ms?: number;\n /** Frame rate, measured from the file. Unit: frames per second. */\n fps?: number;\n /** Horizontal accuracy the device reported for its fix. Unit: meters. NULL: Not a device fix: gps_source registered or none. */\n gps_accuracy_m?: number | null;\n /** When the device took that fix, UTC (at or before capture_start). NULL: Not a device fix: gps_source registered or none. */\n gps_fix_at?: string | null;\n /** Latitude (WGS84) of the position gps_source names. Unit: degrees. NULL: No position: gps_source none. */\n gps_lat?: number | null;\n /** Longitude (WGS84) of the same position. Unit: degrees. NULL: No position: gps_source none. */\n gps_lon?: number | null;\n /** Where gps_lat and gps_lon come from: device_fix (the device's last GNSS fix at or before capture_start), registered (the CCTV camera's registered location) or none. */\n gps_source?: string;\n /** Whether the file carries an audio track. */\n has_audio?: boolean;\n /** Frame height, measured from the file. Unit: pixels. */\n height?: number;\n /** Camera windows of the screen that overlap the segment: their per-window readings (faces, attention, head pose, gaze, emotion, demographics) join by time. Unit: camera windows. */\n n_audience_windows?: number;\n /** Distinct face tracks the screen's camera followed during the segment. Unit: face tracks. */\n n_face_tracks?: number;\n /** Billboard passes the vehicle made during the segment. Unit: board passes. */\n n_passes?: number;\n /** Path of the stored MP4 in our private media store (<folder>/vision-video-private/YYYY/MM/DD/<screen_id>/<segment_id>.mp4, screen_id the recording camera). */\n object_key?: string;\n /** The most faces any one camera window overlapping the segment counted: each window's instant face count (audience_metrics.face_count), the largest over the windows. Unit: faces. NULL: No camera window of the screen overlaps the segment, or none of the overlapping windows read a face count. */\n peak_face_count?: number | null;\n /** The cabin ride the segment overlaps most, for a vehicle-cabin screen. NULL: No cabin ride overlaps the segment: every CCTV segment, and a tablet segment recorded between rides. */\n ride_id?: string | null;\n /** Trillboards screen id of the camera that recorded the segment: the tablet's screen, or the CCTV feed the edge connector records. */\n screen_id?: string;\n /** The segment's identity: the SHA-256 (lowercase hex) of the MP4 file exactly as the camera uploaded it, re-verified by the server from the stored bytes. The delivered MP4 is named by it. */\n segment_id: string;\n /** Which camera recorded it: tablet (the camera of a screen in a venue or a vehicle cabin) or cctv (a venue's CCTV camera, recorded by the edge connector as a stream copy of the camera's own encoding). */\n source?: string;\n /** State or province of the screen's registered location. NULL: The screen has no registered state. */\n state?: string | null;\n /** call_id of every stored still the same camera captured during the segment (rows of the camera frame corpus); empty when none. */\n still_call_ids?: Array<unknown>;\n /** The event that started the recording: faces (people in front of the camera), or the sensing profile's own trigger id. NULL: No trigger id: a duty_cycle or continuous segment. */\n trigger_id?: string | null;\n /** Why the camera recorded: event (people in front of the camera, or another event the device detected, named in trigger_id), duty_cycle (a periodic recording, off by default) or continuous (every minute the camera is on: the CCTV recordings). */\n trigger_kind?: string;\n /** The network the file was uploaded over: wifi, cellular, ethernet or unknown. */\n upload_network?: string;\n /** When the server verified the uploaded file (SHA-256, MD5 and size read back from the stored bytes) and indexed it, UTC. */\n uploaded_at?: string;\n /** The screen's registered venue category (transit = a vehicle cabin). NULL: Not classified. */\n venue_category?: string | null;\n /** Video bitrate, measured from the file. Unit: bits per second. */\n video_bitrate_bps?: number;\n /** Frame width, measured from the file. Unit: pixels. */\n width?: number;\n};\n\n/**\n * Completed-play observations from VAST complete and proof-of-play paths.\n * \n * **Delivery:** Parquet day files keyed by `completed_at`, one row per `play_key` x `screen_mongo_id`. Definition version 4. 24 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_completed_impressions = {\n /** CPM the play was priced at, USD; pricing_source says how the price was set. Unit: usd_per_1000_plays. NULL: No price was recorded. */\n actual_cpm?: number | null;\n /** Gross revenue of the play in USD; pricing_source says how it was set. Unit: usd. NULL: No price was recorded. */\n actual_gross_revenue?: number | null;\n /** Ad id of the play. NULL: No ad id, or the pod-build placeholder ('ima_pending') of an ad whose id arrives later. */\n ad_id?: string | null;\n /** OpenRTB bid request id (joins auction_results.bid_request_id). NULL: The report carried no bid request id. */\n bid_request_id?: string | null;\n /** When the kept report says the play completed, UTC. */\n completed_at?: string;\n /** SHA-256 of the bytes of the media file that played: the creative's content identity. NULL: The report carried no content hash. */\n content_sha256?: string | null;\n /** When we stored the report, UTC. */\n created_at?: string;\n /** Creative id the demand source supplied for the ad. NULL: No creative id, or the IMA house/fallback creative ('-1' or ''). */\n creative_id?: string | null;\n /** Currency of the price. */\n currency?: string;\n /** Share of the screen the ad occupied, 0-1. Unit: share. */\n display_area_ratio?: number;\n /** How the ad was displayed (fullscreen on every row of 2026-08..10). */\n display_mode?: string;\n /** Play length the kept report carried. ad_delivery_hourly.played_seconds uses the longest positive duration over every report of the play. Unit: seconds. NULL: The kept report carried no duration (a vast_event report never does). */\n duration_seconds?: number | null;\n /** True when the play passed general invalid-traffic checks. */\n givt_passed?: boolean;\n /** Impression id the report carried. NULL: The report carried no impression id. */\n impression_id?: string | null;\n /** OpenRTB 2.6 impression multiplier applied to the play's revenue (1 on every row to date). */\n impression_multiplier?: number;\n /** Which report of the play this is: vast_event, proof_of_play, partner_sdk or owned_direct. The kept report is the one billing keeps. */\n ingestion_path?: string;\n /** The player's own id for the play. NULL: The report carried no play id. */\n play_id?: string | null;\n /** The play's identity as our billing policy keys it: the impression id, else the bid request, else the request; the request for a request-level provider and for an SDK callback without a real impression id. With screen_mongo_id it is the key. */\n play_key: string;\n /** How the price was set: openrtb_clearing_cpm, vast_pricing, a *_reporting_api value (the price a partner's reporting API reported), placement_purchase and its variants (a direct booking), cpm_estimate or config_default (a configured estimate, not a settled price), or a *_zero value for a play that earns nothing. */\n pricing_source?: string;\n /** Our ad request id (joins vast_requests.request_id). NULL: The report carried no request id. */\n request_id?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** Proof-of-play signature over the play's impression, ad, screen, device, time and event (Ed25519, or HMAC on the older version), verifiable against our published key. NULL: The report carried no signature. */\n signature?: string | null;\n /** Demand source that served the ad. */\n source_provider?: string;\n /** Serving variant (the ad-serving configuration arm) of the request or play. NULL: Not recorded. */\n variant_name?: string | null;\n};\n\n/**\n * One row per flight: one sighted creative on one face (a registered board face, or a board our cabs pass that no registry holds) from its first read to its last before a 14-day gap. Every live flight that overlaps the delivery window ships. The ledger has no retention: a flight stays after the reads and stills behind it expire. A static face runs one creative per flight, a digital face a set (set_size, the loop). From 2026-10-13, the first still read.\n * \n * **Delivery:** A snapshot, one row per `face_key` x `creative_id` x `flight_start`. Definition version 1. 29 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_creative_flights = {\n /** The registered board (the key every board dataset and the measurement API use). NULL: A point face. */\n board_id?: string | null;\n /** The creative's brand (our brand knowledge graph id), at build time. NULL: Unlabelled. */\n brand_id?: string | null;\n /** The brand's name, at build time. NULL: Unlabelled. */\n brand_name?: string | null;\n /** The identity build that wrote the row. */\n builder_version?: string;\n /** When the row was written, UTC. */\n built_at?: string;\n /** The sighted creative (sighted_creatives.creative_id): one artwork, recognised across faces and cabs. */\n creative_id: string;\n /** The face the flight ran on: f:<board_id>:<orientation_idx> for a registered board face, p:<point_id> for a board the cabs pass that no registry holds. */\n face_key: string;\n /** registered or point. */\n face_kind?: string;\n /** static or digital. */\n face_type?: string;\n /** How face_type was decided: board_dim (a registered face) or reader_surface (the surface the point's reads named most). */\n face_type_basis?: string;\n /** The last read of the creative on the face in the flight, UTC; it moves while the flight is open. */\n flight_end?: string;\n /** The first read of the creative on the face in the flight, UTC. */\n flight_start: string;\n /** A point's circular mean cab heading at its reads, degrees clockwise from north. Unit: degrees. NULL: A registered face. */\n heading_deg?: number | null;\n /** How the creative's brand was decided, at build time. NULL: Unlabelled. */\n label_kind?: string | null;\n /** A registered face's position; for a point, the mean cab position of its reads. Unit: degrees. */\n lat?: number;\n /** Longitude, as lat. Unit: degrees. */\n lon?: number;\n /** The market: a DMA code in the US, a CMA code in Canada. NULL: Unplaced. */\n market_code?: string | null;\n /** Country of the market: US or CA. NULL: Unplaced. */\n market_country?: string | null;\n /** Metro name of the market. NULL: Unplaced. */\n market_name?: string | null;\n /** 1 = no evidence the flight has ended yet. */\n open?: number;\n /** The face of the registered board, from 0. NULL: A point face. */\n orientation_idx?: number | null;\n /** Distinct cab passes among them: (cab, board pass) on a registered face, (cab, 10-minute bucket) at a point. Unit: passes. */\n passes?: number;\n /** The unregistered board point: pt- + 16 hex, stable across builds. NULL: A registered face. */\n point_id?: string | null;\n /** Reads of the creative on the face in the flight. Unit: reads. */\n reads?: number;\n /** The cabs whose reads support the flight, sorted. */\n screen_mongo_ids?: Array<unknown>;\n /** Distinct cabs among them. Unit: screens. */\n screens?: number;\n /** Creatives with 2+ passes live on the face during the flight, this one included: the loop size on a digital face, 1 on a static one. Unit: creatives. */\n set_size?: number;\n /** The creative's reads over every read of the face in the flight: about 1 on a static face, about 1/loop on a digital one. Unit: ratio. */\n share?: number;\n /** The side of the cab the point was read on: left, right or behind. NULL: Undecided. */\n vehicle_side?: string | null;\n};\n\n/**\n * L2 cross-screen transitions (cross-screen flow): ASOF JOIN over the RSSI-INDEPENDENT stable_device_id_hash emits a row when a device appears at a different screen within 1-60 minutes.\n * \n * **Delivery:** Parquet day files keyed by `dt`, one row per `dt` x `source_screen_id` x `destination_screen_id`. Definition version 3. 7 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_cross_screen_edges_daily = {\n /** Screen the device was seen at next, 1-60 minutes later. */\n destination_screen_id: string;\n /** UTC day of the transitions. */\n dt: string;\n /** Distinct transitions (device key, screens, time, lag) from the source to the destination that day. Unit: transitions. */\n edge_count?: number;\n /** Exact median minutes between the two sightings. Unit: minutes. */\n lag_p50_minutes?: number;\n /** Screen the device was seen at first. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n source_screen_id: string;\n /** Exact median great-circle distance between the two screens' stored coordinates. The transition writer stores 0 where either screen has no coordinate, so 0 means co-located or not located. Unit: meters. */\n transition_distance_p50_m?: number;\n /** Distinct device keys behind the transitions (the RSSI-independent stable key). Unit: identifiers. */\n unique_devices?: number;\n};\n\n/**\n * The sellable curated-package catalogue: one row per behavioural segment x geography, with its inventory selector, its footprint across owned screens and partner venues, its buyer copy, the panel fit that priced it WITH its Wilson interval, and which legs evidence the areas sold.\n * \n * **Delivery:** Parquet day files, one row per `package_key`. Definition version 1. 35 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_curated_inventory_packages = {\n /** Buyer-facing audience description. NULL: No audience line written. */\n audience_line?: string | null;\n /** When the package was computed, UTC (rebuilt whole each run). */\n computed_at?: string;\n /** Countries the package selects. NULL: Not restricted by country. */\n countries?: Array<unknown> | null;\n /** Buyer-facing delivery description. NULL: No delivery line written. */\n delivery_line?: string | null;\n /** Buyer-facing package name. */\n display_name?: string;\n /** Nielsen DMA code of a DMA package. NULL: A national package. */\n dma_code?: string | null;\n /** DMAs the package selects. NULL: Not restricted by DMA. */\n dma_codes?: Array<unknown> | null;\n /** DMA name. NULL: A national package. */\n dma_name?: string | null;\n /** Device keys behind the residence evidence. Unit: identifiers. NULL: Not measured. */\n evidence_device_equivalents?: number | null;\n /** Census block groups with a home-location leg behind the areas sold. Unit: block_groups. NULL: Not measured. */\n evidence_home_block_groups?: number | null;\n /** Block groups with all three legs (camera, device, MAID). Unit: block_groups. NULL: Not measured. */\n evidence_three_leg_block_groups?: number | null;\n /** Share of the block groups with all three legs. Unit: share. NULL: Not measured. */\n evidence_three_leg_share?: number | null;\n /** Strength of the residence evidence for the areas sold. NULL: Not measured. */\n evidence_tier?: string | null;\n /** Last day of the evidence window. NULL: Not measured. */\n evidence_window_end?: string | null;\n /** First day of the evidence window. NULL: Not measured. */\n evidence_window_start?: string | null;\n /** Derived floor price of the package, USD CPM. Unit: usd_per_1000_plays. NULL: No floor derived. */\n floor_cpm?: number | null;\n /** Geography of the package: national or a DMA. */\n geo_scope?: string;\n /** Buyer-facing headline. NULL: No headline written. */\n headline?: string | null;\n /** The share over the national share (1.0 = national). Unit: index. NULL: No share. */\n index_vs_national?: number | null;\n /** Our screens in the package's footprint. Unit: screens. */\n owned_screens?: number;\n /** The package's id: one behavioural segment in one geography. */\n package_key: string;\n /** Of those, the observations in the segment. Unit: observations. NULL: No share. */\n panel_match_n?: number | null;\n /** Panel screens behind the share. Unit: screens. NULL: No share. */\n panel_screens?: number | null;\n /** Panel observations the share is computed over. Unit: observations. NULL: No share. */\n panel_support_n?: number | null;\n /** Partner venues in the footprint (supply we buy). Unit: venues. */\n partner_venues?: number;\n /** Daypart where the segment concentrates most. NULL: The package does not lead on a daypart. */\n peak_daypart?: string | null;\n /** The peak daypart's share over the package's share. Unit: index. NULL: No peak daypart. */\n peak_daypart_index?: number | null;\n /** Which panel rung the share was projected from. NULL: No share. */\n projection_tier?: string | null;\n /** The merchandised segment the package sells. */\n segment_key?: string;\n /** Fitted share of the audience in the segment, 0-1. Unit: share. NULL: The segment was not observed in the package's cells (a venue-led package). */\n share?: number | null;\n /** Upper bound of the share's Wilson interval. Unit: share. NULL: No share. */\n share_ci_high?: number | null;\n /** Lower bound of the share's Wilson interval. Unit: share. NULL: No share. */\n share_ci_low?: number | null;\n /** Venue types the package selects. NULL: Not restricted by venue type. */\n venue_types?: Array<unknown> | null;\n /** Last day of that window. */\n window_end?: string;\n /** First day of the panel window the share was fitted on. */\n window_start?: string;\n};\n\n/**\n * Hourly aggregate of device_exposure_events per (screen, hour, source: ble, wifi, mdns, ssdp, http_probe): unique devices, returning and cross-screen devices, dwell + attention sums, dwell quantiles.\n * \n * **Delivery:** Parquet day files keyed by `hour`, one row per `hour` x `screen_mongo_id` x `source`. Definition version 3. 13 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_device_exposure_hourly = {\n /** Windows whose slot carried a camera attention value. Through 2026-09-23 a slot no camera window covered carried none; from 2026-09-24 the windower writes 0 for such a slot, so every window counts. Unit: exposure_windows. */\n attention_windows?: number;\n /** Of those, the keys that also appear at another screen (cross_screen_transitions). Unit: identifiers. */\n cross_screen_devices?: number;\n /** UTC hour the 6-minute exposure slots of the row started. */\n hour: string;\n /** Exposure windows: one per device key, screen, source and 6-minute slot. Unit: exposure_windows. */\n n_windows?: number;\n /** Exact median dwell of the windows. Unit: seconds. */\n p50_dwell_seconds?: number;\n /** Exact 90th-percentile dwell of the windows. Unit: seconds. */\n p90_dwell_seconds?: number;\n /** Of those, the keys seen at this screen on an earlier day (30-day look-back). Unit: identifiers. */\n returning_devices?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** Radio signal source: ble, wifi, mdns, ssdp or http_probe. */\n source: string;\n /** Sum over those windows of the slot's camera attention seconds (the slot's high or medium attention camera windows times their length); every window of a slot carries the slot's value. From 2026-09-24 a slot no camera covered counts 0. Unit: seconds. NULL: No window of the row carried a camera attention value (through 2026-09-23: no camera window covered its slots). */\n total_attention_seconds?: number | null;\n /** Sum over the windows of each window's dwell (first to last sighting in the slot). Unit: seconds. */\n total_dwell_seconds?: number;\n /** Distinct device keys (the canonical visitor id) seen at the screen in the hour on the source. Unit: identifiers. */\n unique_devices?: number;\n /** 1 when the source is one the canonical visitor count uses (ble, mdns, ssdp, http_probe), 0 for wifi. Visitor headline counts sum the rows with 1. */\n visitor_source?: number;\n};\n\n/**\n * Every device seen at every screen: one row per (screen, 6-minute slot, device, radio source) on every radio source (BLE, WiFi, mDNS, SSDP, HTTP probe; visitor_source is 1 on the sources a visitor count uses, 0 on WiFi), with the device's pings, dwell and strongest signal in the slot, the slot's camera attention, and whether the device returns to the screen or appears at another. The device is this partner's tb_<16 hex> pseudonym, the same ref every device-level file to this partner carries. From 2026-05-24 (2026-08-08 is absent from the source); the radio camera-less screens are here too.\n * \n * **Delivery:** Parquet day files keyed by `window_start`, one row per `window_start` x `screen_id` x `source` x `device_ref`. Definition version 1. 12 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_device_exposure_windows = {\n /** Camera attention seconds of the slot: its high or medium attention camera windows times their length. From 2026-09-24 a slot no camera window covered carries 0. Unit: seconds. NULL: No camera window covered the slot (stored so through 2026-09-23). */\n attention_seconds?: number | null;\n /** The device as this partner's pseudonym: tb_ + the first 16 hex of HMAC-SHA256(partner salt, the canonical visitor id). Stable across days and across every file this partner receives (and the Data API's refs under the same salt); unrelated to another partner's refs. Unit: identifiers. */\n device_ref: string;\n /** Seconds from the first to the last ping in the slot. Unit: seconds. */\n dwell_seconds?: number;\n /** 1 when the device also appears at another screen. */\n is_cross_screen?: number;\n /** 1 when the device was seen at this screen on an earlier day (30-day look-back). */\n is_returning?: number;\n /** Strongest signal of the device in the slot (closer is higher). Unit: dBm. NULL: The source reports no signal strength. */\n max_rssi?: number | null;\n /** Radio pings of the device in the slot. Unit: pings. */\n n_observations?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Radio signal source: ble, wifi, mdns, ssdp or http_probe. */\n source: string;\n /** 1 when the source is one the canonical visitor count uses (ble, mdns, ssdp, http_probe), 0 for wifi. Visitor counts take the rows with 1. */\n visitor_source?: number;\n /** Last sighting of the device in the slot, UTC. */\n window_end?: string;\n /** Start of the 6-minute exposure slot, UTC. */\n window_start: string;\n};\n\n/**\n * One row per screen id that the delivery's ClickHouse-held datasets carry in the window (audience windows, plays and per-play audience, camera inference, demographics, IP observations, radio exposure and movement, and ad serving), with its activity in the window: the first and last day and the number of days any of them holds a row of the screen, and whether its camera, its radio and its plays were among them. Screens that appear only in the lake-archived months of the raw datasets (2026-02..06) and never in those tables inside the window have no row. Deduplicated with argMax(_version), not FINAL. in_screen_registry = 0 means the screen id is one of ours but our screen registry no longer holds it, so every attribute is NULL. The ad-serving datasets also carry ids that are not screens (partner-exchange placements such as web and mobile players); those have no row here. dma_code is NULL outside the US; city is not shipped because it is 1.88% populated fleet-wide and 0% on partner screens -- use geohash6 or postal_code to place a fixed screen. publisher_name is not shipped: measured 0% on this population. The coordinate is ONE stored point: for a fixed screen its site, for a mobile screen (is_mobile, location_basis = mobile_last_known) wherever the device last synced or was enrolled. geohash_activity_hourly places a mobile screen's activity on its GPS trail, window by window. The venue_brand_* columns say which business the screen's venue is: a partner venue is tied by place agreement (a branded place in the Overture Maps catalogue within 50 m whose brand name is a whole-word part of the venue's name) or by the brand its name carries, an owned fixed screen by place agreement; a vehicle screen has no venue brand. With the brand ship its parent, the ticker and exchange of the listed company it belongs to, the link's method and confidence, and venue_brand_as_of, when the link was decided; venue_brand_id NULL with venue_brand_as_of set means the venue was examined and is no brand the graph holds. venue_brand_id is the key ride_places' pickup and drop-off brands carry.\n * \n * **Delivery:** A snapshot, one row per `screen_id`. Definition version 4. 34 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_dim_screen = {\n /** Distinct UTC days in the window with such a row. Unit: days. */\n active_days?: number;\n /** Country of the screen's registered location. NULL: Unresolved, or not in the registry. */\n country?: string | null;\n /** Nielsen DMA code. NULL: Outside the US, unresolved, or not in the registry. */\n dma_code?: string | null;\n /** DMA name. NULL: As dma_code. */\n dma_name?: string | null;\n /** Registered environment type of the screen (e.g. indoor, outdoor). NULL: Not classified, or not in the registry. */\n environment_type?: string | null;\n /** First UTC day in the delivery window on which any of the delivery's ClickHouse-held datasets holds a row of the screen. */\n first_seen?: string;\n /** Geohash-6 cell of the stored point. NULL: No stored coordinate, or not in the registry. */\n geohash6?: string | null;\n /** 1 when the window holds a camera row of the screen: a face- or person-backed audience window, a device inference row or a demographic reading. */\n has_camera?: number;\n /** 1 when the window holds a play of the screen (a report carrying the billing key, or a per-play audience row). */\n has_plays_in_window?: number;\n /** 1 when the window holds a radio row of the screen: a radio exposure window (any source), a cross-screen transition or a movement edge. */\n has_radio?: number;\n /** 1 when our screen registry holds the screen; 0 = one of our screen ids the registry no longer holds, so every registry attribute is NULL. */\n in_screen_registry?: number;\n /** 1 for a vehicle-mounted screen (venue_category transit). NULL: Not in the registry. */\n is_mobile?: number | null;\n /** The device's last heartbeat our registry holds, UTC, as of the delivery. NULL: Not in the registry. */\n last_heartbeat_at?: string | null;\n /** Last such UTC day. */\n last_seen?: string;\n /** Latitude of the screen's one stored point: its site for a fixed screen, where it last synced for a vehicle (location_basis). Unit: degrees. NULL: No stored coordinate (a (0, 0) placeholder is NULL too), or not in the registry. */\n latitude?: number | null;\n /** What the coordinate is: fixed_site, or mobile_last_known for a vehicle. NULL: No coordinate. */\n location_basis?: string | null;\n /** Longitude of the same point. Unit: degrees. NULL: As latitude. */\n longitude?: number | null;\n /** OpenOOH venue taxonomy id. NULL: Unclassified (the 0 placeholder), or not in the registry. */\n openooh_venue_type_id?: number | null;\n /** Name of the place the screen is in. NULL: No place name, or not in the registry. */\n place_name?: string | null;\n /** How the screen is placed in the venue. NULL: Not classified, or not in the registry. */\n placement_type?: string | null;\n /** Postal code of the registered location. NULL: Unresolved, or not in the registry. */\n postal_code?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** State or province of the registered location. NULL: Unresolved, or not in the registry. */\n state?: string | null;\n /** IANA timezone of the screen. NULL: No registered timezone, or not in the registry. */\n timezone?: string | null;\n /** Mapping as-of, UTC: when the venue was tied to this brand, or examined and found to be none (venue_brand_id NULL with this set). The brand's name, parent, ticker and exchange are the brand graph's at the screen's last registry sync. NULL: The screen's venue has not been examined: a vehicle screen (only fixed screens are tied to a venue brand), a screen no daily pass has reached yet, or not in the registry. */\n venue_brand_as_of?: string | null;\n /** The confidence the link's source states, 0-1: the agreeing Overture place's confidence for place_agreement, the brand extraction's for venue_brand_key. Unit: share. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. Or the link's source states no confidence. */\n venue_brand_confidence?: number | null;\n /** ISO 10383 market identifier code (MIC) of the exchange the ticker trades on, e.g. XNYS, XNAS. NULL: As venue_brand_ticker, or the listing records no exchange. */\n venue_brand_exchange?: string | null;\n /** The brand the screen's venue is, as the brand graph's id (the key ride_places' brand columns carry): a partner venue tied by place agreement or its brand key, an owned fixed screen by place agreement (venue_brand_method). NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. */\n venue_brand_id?: string | null;\n /** How the venue was tied to the brand: place_agreement (a branded place in the Overture Maps catalogue within 50 m whose brand name is a whole-word part of the venue's own name) or venue_brand_key (the brand stem read from the partner venue's name, decided once in the brand resolution store). NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. */\n venue_brand_method?: string | null;\n /** The brand's name. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. */\n venue_brand_name?: string | null;\n /** The brand's immediate parent company, as the brand graph's id. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. Or the brand graph records no parent of the brand. */\n venue_brand_parent_id?: string | null;\n /** The parent company's name. NULL: As venue_brand_parent_id. */\n venue_brand_parent_name?: string | null;\n /** Ticker of the listed company the brand belongs to: the listing of the brand's Wikidata family (the brand and the brand rows sharing its Wikidata id: one business), else of its nearest listed parent up the parent chain (a brand of a listed parent reads the parent's); a listing only our curated seed states yields to a parent's that SEC or Wikidata states. A listing is SEC EDGAR's by CIK first, then Wikidata's stock-exchange statements, then the seed's. NULL: The screen's venue is tied to no brand (venue_brand_as_of set: examined, none), has not been examined, or the screen is not in the registry. Or no listing is recorded for the brand, its family or its parents. */\n venue_brand_ticker?: string | null;\n /** Registered venue category (transit = a vehicle). NULL: Not classified, or not in the registry. */\n venue_category?: string | null;\n};\n\n/**\n * VAST playback event funnel from IMA SDK (start, firstQuartile, midpoint, thirdQuartile, complete) plus heartbeat mirrors.\n * \n * **Delivery:** Parquet day files keyed by `occurred_at`, one row per `event_id`. Definition version 1. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_event_tracking = {\n /** Ad id the event belongs to. NULL: The event named no ad. */\n ad_mongo_id?: string | null;\n /** When we stored the event, UTC. */\n created_at?: string;\n /** Creative id the demand source supplied for the ad. '-1' is the IMA house/fallback creative. NULL: The event named no creative. */\n creative_id?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** The event's id. */\n event_id: string;\n /** Player event: impression, start, firstQuartile, midpoint, thirdQuartile, complete, heartbeat or error. */\n event_type?: string;\n /** Impression id the event belongs to. NULL: The event named no impression. */\n impression_id?: string | null;\n /** When the event happened, UTC. */\n occurred_at?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. NULL: The event named no screen. */\n screen_mongo_id?: string | null;\n /** Serving variant (the ad-serving configuration arm) of the request or play. */\n variant_name?: string;\n};\n\n/**\n * Camera and radio activity per geohash-6 cell, UTC hour and registered venue category, each unit placed where its screen WAS: on the map-matched vehicle path at the instant where one covers it, else at the screen's last GPS trail fix at or before it (looking back to UTC midnight 7 days before the day; fix_age_p50_s and fix_age_p90_s give the fixes' age), else, for a fixed screen, at its registered site. A vehicle's registered coordinate is never used. Camera: the face- and person-backed windows at their close, with faces, people in view, dwell and the head-pose index per window. Radio: the 6-minute slots of each screen at their midpoint, with the visitor-source identifiers (BLE, mDNS, SSDP, HTTP probe) concurrent in each, near and far field, and the distinct identifiers of the cell-hour; a row no radio slot fell in carries its radio readings NULL. The approved metric radio_identifiers_per_person (the in-cab panel's passenger near-field Bluetooth identifiers per person the camera read) converts identifiers of that population to people. Radio from 2026-05-24, camera from 2026-06-24 02:39 UTC.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `geohash6` x `venue_category`. Definition version 2. 33 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_geohash_activity_hourly = {\n /** Head-pose index, 0-1: the mean over every window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. NULL: No camera window in the row. */\n avg_attention?: number | null;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). Unit: ms. NULL: No window of the row carries a start time (dwell_capped_windows = 0). */\n avg_dwell_ms?: number | null;\n /** Mean faces per window: the device's face_count where it wrote one, else the window's mean face count. Unit: faces_per_window. NULL: No camera window in the row (observation_windows = 0). */\n avg_face_count?: number | null;\n /** The windows avg_dwell_ms averages: camera windows that carry a start time. Unit: windows. */\n dwell_capped_windows?: number;\n /** Of those, the face-backed windows. Unit: windows. */\n face_backed_windows?: number;\n /** Of those, the identifiers whose strongest signal was below it: the devices around the screen. Sources that report no signal strength (mDNS, SSDP, HTTP probe) are in neither split. Unit: identifier_slots. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_key_slots?: number | null;\n /** far_key_slots / radio_slots. Unit: identifiers_per_slot. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_keys_per_slot?: number | null;\n /** Median age of those fixes at the window's instant. Unit: seconds. NULL: No camera window of the row was placed by a trail fix. */\n fix_age_p50_s?: number | null;\n /** 90th-percentile age of those fixes. Unit: seconds. NULL: No camera window of the row was placed by a trail fix. */\n fix_age_p90_s?: number | null;\n /** Camera windows of a fixed screen with no trail fix in the lookback, placed at its registered site. Unit: windows. */\n fixed_site_positioned_windows?: number;\n /** Geohash-6 cell (about 1.2 x 0.6 km) where the screen was at the unit's instant: on its map-matched path, else at its last GPS trail fix, else (a fixed screen) at its registered site. */\n geohash6: string;\n /** Start of the UTC hour. A camera window counts in the hour it closed, a radio slot in the hour of its midpoint. */\n hour_start: string;\n /** Camera windows placed at the screen's last GPS fix at or before their instant. Unit: windows. */\n last_fix_positioned_windows?: number;\n /** The near-field boundary of the row's day: the active pass_audience method register's rf_near_rssi_dbm, the boundary the in-cab radio uses. Unit: dbm. */\n near_field_rssi_dbm?: number;\n /** Of those, the identifiers whose strongest signal in the slot was at or above near_field_rssi_dbm: in the vehicle or against the screen. Unit: identifier_slots. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_key_slots?: number | null;\n /** near_key_slots / radio_slots: near-field identifiers concurrent in one slot. The approved metric radio_identifiers_per_person converts near-field passenger Bluetooth identifiers to people: it is measured in the cab, where the driver's phone and the vehicle's own devices are removed by role. Unit: identifiers_per_slot. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_keys_per_slot?: number | null;\n /** Camera-graded windows (face- or person-backed, ~10 s each) placed in the cell. Unit: windows. */\n observation_windows?: number;\n /** Exact 95th percentile of the per-window face reading over the row's windows. Unit: faces_per_window. NULL: No camera window in the row. */\n p95_face_count?: number | null;\n /** Camera windows placed on the map-matched vehicle path at their instant. Unit: windows. */\n path_positioned_windows?: number;\n /** Of those, the person-backed windows. Unit: windows. */\n person_backed_windows?: number;\n /** The windows persons_per_window averages. Unit: windows. */\n person_reading_windows?: number;\n /** Mean people in view per camera window, faced or not: per window the larger of its mean person count and its mean face count (the in-cab panel's persons reading), over the windows that carry one. Unit: persons_per_window. NULL: No camera window of the row carries a persons reading (person_reading_windows = 0). */\n persons_per_window?: number | null;\n /** Radio slots of a fixed screen with no trail fix in the lookback, placed at its registered site. Unit: slots. */\n radio_fixed_site_positioned_slots?: number;\n /** Radio slots placed at the screen's last GPS fix at or before their midpoint. Unit: slots. */\n radio_last_fix_positioned_slots?: number;\n /** Radio slots placed on the map-matched path at their midpoint. Unit: slots. */\n radio_path_positioned_slots?: number;\n /** Radio observations of the visitor identifiers in the row's slots. Unit: pings. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_pings?: number | null;\n /** Distinct screens whose radio slots the row holds. Unit: screens. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_screens?: number | null;\n /** 6-minute radio slots of screens placed in the cell: a slot in which the screen's visitor radio read an identifier (a slot in which the scanner reported only the screen's own Wi-Fi access point does not show the visitor radio ran, and is no slot here). 0 when only camera windows fell in the row. Unit: slots. */\n radio_slots?: number;\n /** Distinct screens whose camera windows the row holds. Unit: screens. */\n screens?: number;\n /** Distinct visitor-source identifiers over the row's slots, exact. A distinct count: rows do not add. Unit: identifiers. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n unique_devices?: number | null;\n /** The screen's registered venue category (transit for a vehicle screen); empty when the registry holds none. */\n venue_category: string;\n /** Visitor-source radio identifiers (BLE, mDNS, SSDP, HTTP probe) distinct within each slot, summed over the slots. Unit: identifier_slots. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_key_slots?: number | null;\n /** visitor_key_slots / radio_slots: identifiers concurrent in one 6-minute slot, every visitor source and both fields. Unit: identifiers_per_slot. NULL: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_keys_per_slot?: number | null;\n};\n\n/**\n * OpenRTB bid-chain diagnostic records with contract validation.\n * \n * **Delivery:** Parquet day files keyed by `timestamp`, one row per `impression_event_id`. Definition version 2. 11 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_impression_events = {\n /** Ad id of the impression. NULL: No ad id, or the pod-build placeholder ('ima_pending') of an ad whose id arrives later. */\n ad_id?: string | null;\n /** OpenRTB bid request id of the impression. NULL: Not recorded. */\n bid_request_id?: string | null;\n /** Creative id the demand source supplied for the ad. NULL: No creative id, or the IMA house/fallback creative ('-1' or ''). */\n creative_id?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** Id of the player event that opened the impression. */\n event_id?: string;\n /** The impression event's id. */\n impression_event_id: string;\n /** Impression id. */\n impression_id?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** When the ad started, UTC. */\n start_time?: string;\n /** Impression status (started on every row of 2026-09-01..07). NULL: Not recorded. */\n status?: string | null;\n /** When the impression was recorded, UTC. */\n timestamp?: string;\n};\n\n/**\n * ML model inference results per video frame.\n * \n * **Delivery:** Parquet day files, one row per `inference_snapshot_id`. Definition version 3. 14 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_inference_outcomes = {\n /** Device attention composite 0-1 of the frame. Unit: index. NULL: Not measured. */\n attention_score?: number | null;\n /** Device body-engagement score 0-1 of the frame. Unit: index. NULL: Not measured. */\n body_engagement?: number | null;\n /** Daypart label in the screen's local time. NULL: Not recorded. */\n daypart?: string | null;\n /** Device emotion score 0-1 of the frame. Unit: index. NULL: Not measured. */\n emotion_score?: number | null;\n /** Faces the device model detected in the frame. Unit: faces. NULL: Not measured. */\n face_count?: number | null;\n /** Device id (fingerprint) of the screen's sensing device that ran the inference; the Data API serves the same id as device_id. */\n fingerprint?: string;\n /** Region of the image frame where attention concentrated (a position in the camera's frame, not on the street). NULL: Not measured. */\n focus_region?: string | null;\n /** When the inference ran, UTC. Every row is a camera (device) row. */\n inference_at?: string;\n /** The inference's id: one on-device model inference over one captured frame. */\n inference_snapshot_id: string;\n /** Ambient noise tier from the device microphone. NULL: No audio reading (the device writes -1). */\n noise_tier?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** Verified attention seconds the inference contributed, weighted. Unit: seconds. NULL: Not measured. */\n vas_weighted?: number | null;\n /** Venue type the device reported. NULL: Not recorded. */\n venue_type?: string | null;\n /** Weather code at the screen when the frame was taken. NULL: Not recorded. */\n weather_code?: string | null;\n};\n\n/**\n * Hashed public IP a screen egressed from, per UTC day, with ISP/ASN/geo enrichment: one row per (ip_hash, screen, observed_date).\n * \n * **Delivery:** Parquet day files keyed by `observed_at`, one row per `ip_hash` x `screen_mongo_id` x `observed_date`. Definition version 2. 12 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_ip_geo_observations = {\n /** City of the address's IP geolocation. NULL: The IP lookup returned no city. */\n city?: string | null;\n /** Line type from the IP lookup: residential, commercial, mobile or unknown. NULL: The IP lookup did not classify the line. */\n connection_type?: string | null;\n /** Country of the address's IP geolocation. NULL: The IP lookup returned no country. */\n country?: string | null;\n /** Geohash-6 cell (about 1.2 x 0.6 km) of the address's IP geolocation. NULL: The IP lookup returned no location. */\n geohash_6?: string | null;\n /** Hash of the public IP address the screen egressed from (the screen's network, never a visitor's); the address itself is not shipped. */\n ip_hash: string;\n /** 1 when the IP lookup classifies the address as residential, else 0. */\n is_residential?: number;\n /** Internet service provider of the address. NULL: The IP lookup named no provider. */\n isp?: string | null;\n /** Latest time that day the screen was seen on the address, UTC. */\n observed_at?: string;\n /** UTC day the screen's traffic left from the address. */\n observed_date: string;\n /** Organization the address is registered to. NULL: The IP lookup named no organization. */\n org?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** State or region of the address's IP geolocation. NULL: The IP lookup returned no state. */\n state?: string | null;\n};\n\n/**\n * Screen-to-screen movement per day and signal source, anchored on ad plays: identifiers seen at the source screen during a play and at the destination screen within 24 hours. Each row carries the day's distinct identifiers as a range, from unique_identifiers_floor (the largest hour-by-ad-window cell) to identifier_cell_sum (the sum of the cells); repeated_signal_count, ad_window_cells and median_lag_minutes describe the same cells.\n * \n * **Delivery:** Parquet day files keyed by `flow_date`, one row per `flow_date` x `source_screen_id` x `destination_screen_id` x `source`. Definition version 2. 9 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_mobility_flows_daily = {\n /** The hour-by-ad-window cells the row aggregates. Unit: cells. */\n ad_window_cells?: number;\n /** Screen where the same identifiers were seen within the next 24 hours. */\n destination_screen_id: string;\n /** UTC day of the source sightings. */\n flow_date: string;\n /** Sum of the cells' distinct identifiers: the most the day's distinct count can be. Unit: identifiers. */\n identifier_cell_sum?: number;\n /** Mean over the cells of each cell's median minutes from the source to the destination sighting. Unit: minutes. */\n median_lag_minutes?: number;\n /** Pairs of (source sighting, destination sighting) behind the row. Unit: signal_pairs. */\n repeated_signal_count?: number;\n /** Radio signal source of the identifiers: ble, mdns, ssdp or http_probe. */\n source: string;\n /** Screen where identifiers were seen during an ad play. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n source_screen_id: string;\n /** Distinct identifiers in the day's largest single hour-by-ad-window cell: the least the day's distinct count can be. Unit: identifiers. */\n unique_identifiers_floor?: number;\n};\n\n/**\n * Per-(observation, dimension, value) demographics at OBSERVATION grain in CH: age, gender, mood, activity state, device engagement (phone use), attire, carried items, intent, lifestyle.\n * \n * **Delivery:** Parquet day files keyed by `observed_date`, one row per `observation_id` x `dimension` x `value`. Definition version 2. 7 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_observation_demographics = {\n /** Readings of the value in the observation: 1 on every row (one row is one reading). Unit: readings. */\n count?: number;\n /** The audience attribute read (config/observationDemographicsDimensions.js): age, gender, mood, device_engagement, activity_state, intent, attire, lifestyle, carried_items and the others declared. head_turn and occupant_position are image-frame values: head_turn is turned_image_left, turned_image_right, not_turned or not_assessable (where the nose points relative to the edges of the picture), occupant_position is image_left_third, image_center_third, image_right_third or driving (the third of the picture the person occupies). Neither is a side of the vehicle or the street: a rearward cabin camera mirrors the vehicle's left and right. */\n dimension: string;\n /** The camera observation (one analysed frame window) the reading belongs to. */\n observation_id: string;\n /** When the camera observation the reading comes from was made, UTC. */\n observed_at?: string;\n /** UTC day of the reading. */\n observed_date?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id?: string;\n /** The value read for the dimension. lifestyle values are numeric IAB Audience Taxonomy 1.1 segment ids (segtax=4); the other dimensions use our own vocabulary. */\n value: string;\n};\n\n/**\n * Open Measurement SDK viewability sessions tracking MRC-compliant viewable percentage and duration per ad play.\n * \n * **Delivery:** Parquet day files keyed by `created_at`, one row per `session_id` x `created_at`. Definition version 1. 11 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_omsdk_sessions = {\n /** Ad id the session opened for. */\n ad_id?: string;\n /** OM ad session type: video on every row to date. */\n ad_session_type?: string;\n /** When the session opened, UTC. With session_id it is the key. */\n created_at: string;\n /** OM SDK events the session recorded: 1 on every row to date, the open. Unit: events. */\n event_count?: number;\n /** Impression id the session opened for. NULL: The session named no impression (1 row). */\n impression_id?: string | null;\n /** OMID API version of the session (1.4). */\n omid_api_version?: string;\n /** OM integration partner that opened the session: Trillboards, our own integration. */\n partner_name?: string;\n /** Version of that integration (1.0.0). */\n partner_version?: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. NULL: The session named no screen (16 of 291.7M rows). */\n screen_id?: string | null;\n /** The Open Measurement SDK session's id. */\n session_id: string;\n /** Session status: active on every row to date (no session has recorded a close). */\n status?: string;\n};\n\n/**\n * Fitted share of a merchandised segment within (venue context x daypart x market), with a Wilson interval, from TWO panels: the Ember sensing fleet (behavioural) and the Intuizi store-visit panel (brand affinity).\n * \n * **Delivery:** Parquet day files, one row per `segment_key` x `venue_type` x `daypart` x `market`. Definition version 1. 13 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_panel_segment_cells = {\n /** Upper bound of the share's Wilson interval. Unit: share. */\n ci_high?: number;\n /** Lower bound of the share's Wilson interval. Unit: share. */\n ci_low?: number;\n /** When the cell was computed, UTC. */\n computed_at?: string;\n /** Daypart of the cell (__all__ = every daypart). */\n daypart: string;\n /** Market of the cell (__all__ = every market). */\n market: string;\n /** Evaluable observations in the segment. Unit: observations. */\n match_n?: number;\n /** Panel screens behind the cell. Unit: screens. */\n panel_screens?: number;\n /** The merchandised segment (visits-* segments come from the store-visit panel, the rest from the camera panel). */\n segment_key: string;\n /** Fitted share of the cell in the segment, 0-1. Segments overlap, so shares do not sum to 1. A segment never observed in a cell has no row. Unit: share. */\n share?: number;\n /** Evaluable observations of the cell: camera observations carrying a dimension the segment reads, or store-visit exposure edges by resolvable devices on the visits leg. Unit: observations. */\n support_n?: number;\n /** Venue context of the cell (__all__ = every venue). */\n venue_type: string;\n /** Last day of the panel window. */\n window_end?: string;\n /** First day of the panel window. */\n window_start?: string;\n};\n\n/**\n * Camera-graded activity per screen-hour, one row per (hour, screen, evidence grade): the face- and person-backed camera windows of each screen, in the UTC hour each window closed, from the governed camera screen-hour (method camera_screen_hour v3). Covers 2026-06-01 onward; MANIFEST.json classifies every day of a delivery window, with a day whose governed source holds fewer camera windows than ClickHouse's raw copy for any screen-hour marked partial. evidence_grade: face_backed or person_backed: the grade of the camera windows the row counts. observation_windows: Camera windows (about 10 s each) of the row's grade that closed in the hour. avg_face_count: Mean faces per window: the device's face_count where it wrote one, else the window's mean face count. p95_face_count: Exact 95th percentile of that per-window face reading over the hour. avg_dwell_ms: Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). dwell_capped_windows: The windows avg_dwell_ms averages: camera windows that carry a start time. dwell_over_window_windows: camera windows whose reported dwell exceeded their own length. avg_attention: Head-pose index, 0-1: the mean over every window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. head_pose_index_windows: Camera windows whose head-pose index is above 0 (a pose was read); avg_attention averages over every camera window (observation_windows). avg_gaze_pct_on_screen: the gaze instrument's on-screen share, over the windows it read. gaze_pct_windows: The windows avg_gaze_pct_on_screen averages: camera windows that carry a gaze reading. modal_crowd_density and modal_attention_level: the most frequent real reading by exact count, ties to the alphabetically first, NULL when there was none. daypart_local: Daypart label in the screen's local time. Since v3 each row also carries receptivity, the passer-by ratio and the crowded share, the modal pace, screen engagement and mood, and the 10-minute buckets of the hour with a window and with a face; since v4 the screen-hour's online and camera-on minutes. DICTIONARY.json describes every column. On 2026-09-25 the camera began closing windows more often: on the same 3,555 screens, the weeks either side, camera windows per screen-hour rose from a median of 45 to 77 (mean 57 to 108) while faces per window held (1.0585, 1.0603), so compare periods on per-window and per-minute rates, never on window counts.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `screen_id` x `evidence_grade`. Definition version 4. 35 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_place_activity_hourly = {\n /** Head-pose index, 0-1: the mean over every window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. */\n avg_attention?: number;\n /** Mean body-engagement score 0-1 over every camera window of the row (a window without the score counts 0). Unit: index. */\n avg_body_engagement?: number;\n /** Mean over every camera window of the window's crowded share 0-1: the share of its audio snapshots the device's microphone classified as crowded (a window without audio counts 0). Unit: share. */\n avg_crowded_share?: number;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). Unit: ms. NULL: No window of the row carries a start time (dwell_capped_windows = 0). */\n avg_dwell_ms?: number | null;\n /** Mean emotional engagement score 0-1 over the windows that carry one (emotional_engagement_windows). Unit: index. NULL: No window carries an emotional engagement score (emotional_engagement_windows = 0). */\n avg_emotional_engagement?: number | null;\n /** Mean faces per window: the device's face_count where it wrote one, else the window's mean face count. Unit: faces_per_window. */\n avg_face_count?: number;\n /** Mean on-screen gaze share 0-1 of the gaze instrument (FaceLandmarker) over the windows it read. Unit: share. NULL: No window of the row carries a gaze reading (gaze_pct_windows = 0). */\n avg_gaze_pct_on_screen?: number | null;\n /** Mean of the device's passer-by ratio (its estimated foot traffic over the peak face count of the window; above 1 when people pass without facing the screen) over the windows that carry one. Unit: ratio. NULL: No window carries a passer-by ratio (passerby_ratio_windows = 0). */\n avg_passerby_ratio?: number | null;\n /** Mean of the device's queue estimate per window (people waiting near the screen, from the trend of its face counts and dwell), over the windows that carry one. Unit: people_per_window. NULL: No camera window of the row carried the reading. */\n avg_pedestrian_count?: number | null;\n /** Mean ad-receptivity score 0-1 (the window's reading of how receptive the audience in view is to an ad), over the windows that carry one. Unit: index. NULL: No window carries a receptivity score (receptivity_windows = 0). */\n avg_receptivity?: number | null;\n /** Mean vehicles in view per window (the device's vehicle detector), over the windows that carry a count. Unit: vehicles_per_window. NULL: No camera window of the row carried the reading. */\n avg_vehicle_count?: number | null;\n /** Mean of the device's viewability score 0-1 (dwell, full at 1 s, times attention times the ambient-light factor, on a window with a face) over the windows that carry one. Unit: index. NULL: No window of the row saw a face (the device writes no score without one). */\n avg_viewability_score?: number | null;\n /** Minutes of the hour the sensing SDK reported it was sensing: the uptime a per-minute rate divides by. Per screen-hour, like online_minutes. Unit: minutes. NULL: The heartbeat measured none of the hour, or reported no sensing status. */\n camera_on_minutes?: number | null;\n /** Daypart label in the screen's local time. NULL: The device kept no daypart label for the hour. */\n daypart_local?: string | null;\n /** The windows avg_dwell_ms averages: camera windows that carry a start time. Unit: windows. */\n dwell_capped_windows?: number;\n /** Camera windows whose reported dwell exceeded their own length, and were capped at it in avg_dwell_ms. Unit: windows. */\n dwell_over_window_windows?: number;\n /** The windows avg_emotional_engagement averages: camera windows carrying an emotional engagement score. Unit: windows. */\n emotional_engagement_windows?: number;\n /** face_backed or person_backed: the grade of the camera windows the row counts. */\n evidence_grade: string;\n /** The windows avg_gaze_pct_on_screen averages: camera windows that carry a gaze reading. Unit: windows. */\n gaze_pct_windows?: number;\n /** Camera windows whose head-pose index is above 0 (a pose was read); avg_attention averages over every camera window (observation_windows). Unit: windows. */\n head_pose_index_windows?: number;\n /** Start of the UTC hour. A camera window counts in the hour it closed. */\n hour_start: string;\n /** True when the hour fell on a weekend day in the screen's local time (the device's label). */\n is_weekend?: boolean;\n /** The 10-minute buckets of the hour (0-6) in which a camera window of the row's grade closed: how much of the hour the camera covered. Unit: 10_minute_buckets. */\n look_buckets?: number;\n /** Most frequent attention-level reading (high, medium, low) of the hour by exact count, ties to the alphabetically first. NULL: The hour carried no real attention-level reading. */\n modal_attention_level?: string | null;\n /** Most frequent crowd-density reading of the hour by exact count, ties to the alphabetically first. NULL: The hour carried no real crowd reading (only 'unknown' or none). */\n modal_crowd_density?: string | null;\n /** Most frequent screen-engagement reading (engaged, glancing, ignoring) by exact count, ties to the alphabetically first. NULL: The hour carried no real engagement reading. */\n modal_engagement?: string | null;\n /** Most frequent mood reading of the people in view (e.g. happy, neutral, focused, bored) by exact count, ties to the alphabetically first. NULL: The hour carried no real mood reading. */\n modal_mood?: string | null;\n /** Most frequent movement-pace reading of the people in view (e.g. idle, standing, slow, strolling, moderate, hurrying) by exact count, ties to the alphabetically first. NULL: The hour carried no real pace reading. */\n modal_pace?: string | null;\n /** Camera windows (about 10 s each) of the row's grade that closed in the hour. Unit: windows. */\n observation_windows?: number;\n /** Minutes of the hour the screen was online (5 x the 5-minute buckets with a heartbeat). A property of the screen-hour: both grade rows of a screen-hour carry the same value, so take it once per (hour_start, screen_id). Unit: minutes. NULL: The heartbeat measured none of the hour. */\n online_minutes?: number | null;\n /** Exact 95th percentile of that per-window face reading over the hour. Unit: faces_per_window. */\n p95_face_count?: number;\n /** The windows avg_passerby_ratio averages. Unit: windows. */\n passerby_ratio_windows?: number;\n /** The 10-minute buckets of the hour (0-6) in which such a window saw at least one face (its peak face count above 0). Unit: 10_minute_buckets. */\n present_buckets?: number;\n /** The windows avg_receptivity averages. Unit: windows. */\n receptivity_windows?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. Only ids of that shape ship. */\n screen_id: string;\n};\n\n/**\n * The audience of each ad play: one row per logged play (our billing policy's play key on one screen per UTC day, or a partner's play), including the plays no audience window overlapped (windows_n = 0). Each camera measure is the overlap-weighted mean over the camera windows inside the play (window [window_end - 10 s, window_end), attributed when it overlaps the play widened 5 s each side), with the window count and overlap behind it, so plays re-aggregate exactly: a mean times its overlap_ms, summed, over the summed overlap_ms. Faces, head pose, gaze, facing angle per instrument (head yaw and shoulders, never pooled), dwell, receptivity, emotional engagement and emotion, audio level, ambient light and face tracks. NULL means nothing measured it, never 0. From 2026-06-24; play_audience_window lists each play's windows (audience_metrics.metric_id).\n * \n * **Delivery:** Parquet day files keyed by `play_date`, one row per `play_date` x `screen_id` x `play_source` x `play_key`. Definition version 2. 58 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_play_audience = {\n /** Ad id of the kept report. NULL: No ad id, or the pod placeholder. */\n ad_id?: string | null;\n /** Overlap-weighted mean ambient light. Unit: lux. NULL: No light reading. */\n ambient_lux_mean?: number | null;\n /** Loudest audio level over those windows. Unit: dB. NULL: No audio reading. */\n audio_db_max?: number | null;\n /** Overlapping windows carrying an audio level. Unit: windows. */\n audio_windows_n?: number;\n /** Digest of the builder SQL that built the row (pa-<12 hex>). */\n builder_version?: string;\n /** Overlap of those windows: the weight of face_count_mean and head_pose_index_mean. Unit: ms. */\n camera_overlap_ms?: number;\n /** Overlapping windows that are camera-graded: the base of every camera measure. Unit: windows. */\n camera_windows_n?: number;\n /** SHA-256 of the media file's bytes that played. NULL: The report carried none. */\n content_sha256?: string | null;\n /** Lossless issued creative-feedback v1 JSON snapshot of the kept play report; empty where none was issued. Never reconstructed from current campaign or variant state. */\n creative_feedback?: string;\n /** Creative id of the kept report. NULL: No creative id, or the IMA house/fallback creative. */\n creative_id?: string | null;\n /** The emotion with the most overlap, ties to the alphabetically first. NULL: No emotion reading. */\n dominant_emotion?: string | null;\n /** Overlap milliseconds per dominant-emotion value: the play's emotion distribution. Unit: ms. */\n dominant_emotion_overlap_ms?: Record<string, unknown>;\n /** 1 when no report carried a positive duration, so the play's interval is the 30 s default. */\n duration_imputed?: number;\n /** Overlap-weighted mean dwell, each window capped at its own length. Unit: ms. NULL: No such window. */\n dwell_capped_ms_mean?: number | null;\n /** Overlap of those windows. Unit: ms. */\n dwell_overlap_ms?: number;\n /** Camera windows with a capped dwell (a start time to cap at). Unit: windows. */\n dwell_windows_n?: number;\n /** Camera windows with a real dominant-emotion reading. Unit: windows. */\n emotion_windows_n?: number;\n /** Overlap-weighted mean emotional engagement score 0-1. Unit: index. NULL: None carried one. */\n emotional_engagement_mean?: number | null;\n /** Overlap of those windows. Unit: ms. */\n emotional_engagement_overlap_ms?: number;\n /** Camera windows carrying an emotional engagement score. Unit: windows. */\n emotional_engagement_windows_n?: number;\n /** Attributed windows by evidence grade ('' = none recorded); sums to windows_n. Unit: windows. */\n evidence_grade_windows?: Record<string, unknown>;\n /** Largest per-window face reading over the camera windows. Unit: faces. NULL: No camera window. */\n face_count_max?: number | null;\n /** Overlap-weighted mean face reading over the camera windows. Unit: faces_per_window. NULL: No camera window. */\n face_count_mean?: number | null;\n /** Per-face observation rows whose span overlaps the logged play. Unit: face_rows. */\n face_rows_n?: number;\n /** Distinct face tracks over those rows (the edge's pre-merge track id where it sent one); distinct counts do not add across plays. Unit: face_tracks. NULL: No face row. */\n face_tracks_n?: number | null;\n /** Camera windows whose face reading is above 0. Unit: windows. */\n face_windows_n?: number;\n /** Face rows carrying gaze seconds. Unit: face_rows. */\n gaze_face_rows_n?: number;\n /** Overlap of those windows: gaze_pct_on_screen's weight. Unit: ms. */\n gaze_overlap_ms?: number;\n /** Overlap-weighted mean on-screen gaze share 0-1. Unit: share. NULL: No gaze window. */\n gaze_pct_on_screen?: number | null;\n /** Gaze seconds of those rows inside the logged play. Unit: seconds. NULL: No such row. */\n gaze_seconds?: number | null;\n /** Camera windows carrying a gaze reading. Unit: windows. */\n gaze_windows_n?: number;\n /** Overlap-weighted mean head-pose index (0.4 yaw + 0.3 pitch + 0.3 eye-open) over every camera window; gaze is gaze_pct_on_screen. Unit: index. NULL: No camera window. */\n head_pose_index_mean?: number | null;\n /** Camera windows whose head-pose index is above 0 (its coverage, not its denominator). Unit: windows. */\n head_pose_windows_n?: number;\n /** Overlap-weighted share of those windows facing the screen within 30 degrees. Never pooled with the shoulder instrument. Unit: share. NULL: No such window. */\n head_yaw_heads_up_share?: number | null;\n /** Overlap of those windows. Unit: ms. */\n head_yaw_overlap_ms?: number;\n /** Camera windows whose facing angle came from the head-yaw instrument and is above 0. Unit: windows. */\n head_yaw_windows_n?: number;\n /** Impression id of the kept report. NULL: The report carried none. */\n impression_id?: string | null;\n /** The kept report's path (vast_event, proof_of_play, partner_sdk, owned_direct; partner_measurement for a partner play). */\n ingestion_path?: string;\n /** Overlap of those windows. Unit: ms. */\n lux_overlap_ms?: number;\n /** Overlapping windows with an ambient light reading. Unit: windows. */\n lux_windows_n?: number;\n /** Milliseconds of window inside the logged play, summed. Unit: ms. */\n overlap_ms_sum?: number;\n /** Of those, the windows inside the logged play itself. Unit: windows. */\n overlap_windows_n?: number;\n /** When the kept report says the play completed, UTC. */\n play_completed_at?: string;\n /** UTC day of the play (of its kept report's completion). */\n play_date: string;\n /** With play_date, screen_id and play_source it is the play: billing's partner-aware key (completed_impressions.play_key) per UTC day, or partner_id:play_id for a partner play. */\n play_key: string;\n /** Where the play is logged: completed_impressions, or partner_measurement_plays for a play a partner served. */\n play_source: string;\n /** play_completed_at minus the play's length (its longest positive reported duration, else 30 s), UTC. */\n play_started_at?: string;\n /** Overlap-weighted mean ad-receptivity score 0-1. Unit: index. NULL: None carried one. */\n receptivity_mean?: number | null;\n /** Overlap of those windows. Unit: ms. */\n receptivity_overlap_ms?: number;\n /** Camera windows carrying an ad-receptivity score. Unit: windows. */\n receptivity_windows_n?: number;\n /** Our ad request id (joins vast_requests). NULL: The report carried none. */\n request_id?: string | null;\n /** Attributed windows carrying a vision-model scene description. Unit: windows. */\n scene_frames_n?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Overlap-weighted share of those windows within 30 degrees. Unit: share. NULL: No such window. */\n shoulder_heads_up_share?: number | null;\n /** Overlap of those windows. Unit: ms. */\n shoulder_overlap_ms?: number;\n /** Camera windows whose facing angle came from the shoulder (MoveNet) instrument and is above 0. Unit: windows. */\n shoulder_windows_n?: number;\n /** Demand source of the play. */\n source_provider?: string;\n /** Audience windows attributed to the play: every window overlapping it widened by 5 s each side, any sensing mode and grade. Unit: windows. */\n windows_n?: number;\n};\n\n/**\n * Which audience windows each logged play overlapped: one row per (play, window), keys and overlap only. Join play_audience on the play key for the play and audience_metrics on window_metric_id = metric_id for the window's readings. A play with three windows is three rows: count plays in play_audience. From 2026-06-24.\n * \n * **Delivery:** Parquet day files keyed by `play_date`, one row per `play_date` x `screen_id` x `play_source` x `play_key` x `window_metric_id`. Definition version 2. 8 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_play_audience_window = {\n /** Lossless issued creative-feedback v1 JSON snapshot of this play; empty where none was issued. Same kept report as its canonical play. */\n creative_feedback?: string;\n /** Milliseconds of the window inside the logged play; 0 = attributed by the 5 s clock tolerance alone. Unit: ms. */\n overlap_ms?: number;\n /** UTC day of the play. */\n play_date: string;\n /** With play_date, screen_id and play_source it is the play: billing's partner-aware key (completed_impressions.play_key) per UTC day, or partner_id:play_id for a partner play. */\n play_key: string;\n /** completed_impressions or partner_measurement_plays. */\n play_source: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** End of the window, UTC; the window is the 10 s before it. */\n window_end?: string;\n /** The attributed audience window (joins audience_metrics.metric_id). */\n window_metric_id: string;\n};\n\n/**\n * Which devices were in range of each ad play: one row per (screen, creative, device, 6-minute exposure slot) in which a play of the creative completed on the screen while the device was in radio range, with the device's dwell, the slot's camera attention, and whether the device returned to the screen on a later day or appears at another screen. The device is this partner's tb_<16 hex> pseudonym, the same ref every device-level file to this partner carries; person_ref is the identity crosswalk's person, where one resolved. Every radio source the spine reads (BLE, WiFi, mDNS, SSDP, HTTP probe). From 2026-06-20; the spine keeps 180 days.\n * \n * **Delivery:** Parquet day files keyed by `window_start`, one row per `window_start` x `screen_id` x `creative_id` x `device_ref`. Definition version 1. 10 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_play_device_exposure = {\n /** Ad id of the play. NULL: No ad id, or the pod placeholder. */\n ad_id?: string | null;\n /** Camera attention seconds of the slot: its high or medium attention camera windows times their length. From 2026-09-24 a slot no camera window covered carries 0. Unit: seconds. NULL: No camera window covered the slot (stored so through 2026-09-23). */\n attention_seconds?: number | null;\n /** Creative id of the play that completed inside the slot ('' = the play carried none; '-1' = the IMA house creative). */\n creative_id: string;\n /** The device as this partner's pseudonym: tb_ + the first 16 hex of HMAC-SHA256(partner salt, the canonical visitor id). Stable across days and across every file this partner receives (and the Data API's refs under the same salt); unrelated to another partner's refs. Unit: identifiers. */\n device_ref: string;\n /** Seconds from the device's first to last sighting in the slot. Unit: seconds. */\n dwell_seconds?: number;\n /** 1 when the device also appears at another screen. */\n is_cross_screen?: number;\n /** 1 when the device was seen at this screen on an earlier day (30-day look-back). */\n is_returning?: number;\n /** The person the identity crosswalk resolved the device to, as this partner's tb_ pseudonym of the crosswalk person id (the same HMAC as device_ref). NULL: No person resolved for the device. */\n person_ref?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Start of the device's 6-minute exposure slot at the screen, UTC. */\n window_start: string;\n};\n\n/**\n * Hourly screen-to-screen proximity edges: identifiable radio device keys seen at a source screen during an ad play and at another screen within 24 h.\n * \n * **Delivery:** Parquet day files keyed by `hour_bucket`, one row per `hour_bucket` x `source_screen_id` x `destination_screen_id` x `source`. Definition version 2. 9 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_proximity_graph_edges_hourly = {\n /** The (creative, ad) cells the row aggregates. Unit: cells. */\n ad_window_cells?: number;\n /** Screen where the same identifiers were seen within the next 24 hours. */\n destination_screen_id: string;\n /** UTC hour the identifiers were seen at the source screen during an ad play. */\n hour_bucket: string;\n /** Sum of the cells' distinct identifiers: the most the hour's distinct count can be (an identifier seen in two cells counts twice here). Unit: identifiers. */\n identifier_cell_sum?: number;\n /** Mean over the cells of each cell's median minutes from the source sighting to the destination sighting. Unit: minutes. */\n median_lag_minutes?: number;\n /** Pairs of (source-screen signal, destination-screen signal) behind the row, summed over its ad-window cells. Unit: signal_pairs. */\n repeated_signal_count?: number;\n /** Radio signal source of the identifiers: ble, mdns, ssdp or http_probe. */\n source: string;\n /** Screen where the identifiers were seen during the play. Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n source_screen_id: string;\n /** Distinct identifiers in the largest single (creative, ad) cell of the hour: the least the hour's distinct count can be. Unit: identifiers. */\n unique_identifiers_floor?: number;\n};\n\n/**\n * Camera-measured attention, dwell and gaze in front of Trillboards screens, one row per UTC hour, country, state, city and venue category, each with the screens and camera windows behind it. A camera window is about 10 seconds of the screen's own camera, graded face_backed or person_backed (method camera_screen_hour v3); it counts in the hour it closed. The measures carry the governed camera screen-hour's names: head_pose_index_mean (attention) over every window, dwell_capped_ms_mean over the windows with a start time, gaze_pct_mean over the windows the gaze instrument read, face_count_mean, and each mean carries its window count, so rows re-merge exactly: sum(mean x windows) / sum(windows). The place is where each screen is registered (for a vehicle screen, its market). Every row ships, whatever its count. Covers 2026-06-01 onward.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `country` x `state` x `city` x `venue_category`. Definition version 1. 14 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_public_attention_city_venue_hourly = {\n /** Camera windows (about 10 s each, face_backed or person_backed) of the row's screens that closed in the hour: face_count_mean and head_pose_index_mean average over them. Unit: windows. */\n camera_windows?: number;\n /** City, from the screen registry (the screens' newest registry version): the place each screen is registered in, which for a vehicle screen (venue_category transit) is the market it is registered to. Spellings that differ only in accents and case within one country and state are one city, named by its most frequent registry spelling. NULL: The registry holds no value for the row's screens. */\n city: string | null;\n /** ISO 3166-1 alpha-2 country, from the screen registry (the screens' newest registry version): the place each screen is registered in, which for a vehicle screen (venue_category transit) is the market it is registered to. NULL: The registry holds no value for the row's screens. */\n country: string | null;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over dwell_capped_windows. Unit: ms. NULL: No window of the row carries a start time (dwell_capped_windows = 0). */\n dwell_capped_ms_mean?: number | null;\n /** The windows dwell_capped_ms_mean averages: camera windows that carry a start time. Unit: windows. */\n dwell_capped_windows?: number;\n /** Mean faces per camera window over camera_windows: the device's face_count where it wrote one, else the window's mean face count. Unit: faces_per_window. NULL: No camera window of the row carried the reading. */\n face_count_mean?: number | null;\n /** Mean on-screen gaze share 0-1 of the gaze instrument (FaceLandmarker) over gaze_pct_windows. Unit: share. NULL: No window of the row carries a gaze reading (gaze_pct_windows = 0). */\n gaze_pct_mean?: number | null;\n /** The windows gaze_pct_mean averages: camera windows that carry a gaze reading. Unit: windows. */\n gaze_pct_windows?: number;\n /** Attention as the head-pose index, 0-1: the mean over every camera window of the device's composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (eye term 0.5 when unclassified); a window without a face reads 0. Unit: index. */\n head_pose_index_mean?: number;\n /** Camera windows whose head-pose index is above 0 (a pose was read); head_pose_index_mean averages over every camera window (camera_windows). Unit: windows. */\n head_pose_index_windows?: number;\n /** Start of the UTC hour. A camera window counts in the hour it closed. */\n hour_start: string;\n /** Distinct screens with at least one camera window in the row. Unit: screens. */\n screens?: number;\n /** State, province or region code, from the screen registry (the screens' newest registry version): the place each screen is registered in, which for a vehicle screen (venue_category transit) is the market it is registered to. NULL: The registry holds no value for the row's screens. */\n state: string | null;\n /** The screens' registered venue type (transit, retail, office, ...), the category dim_screen.venue_category carries. NULL: The registry holds no value for the row's screens. */\n venue_category: string | null;\n};\n\n/**\n * Every ride of our camera-equipped cabs (the cab's occupied camera windows, or the passenger-onboard instants its vision model read): its span, its kind (a trip, or stationary_presence: occupied windows while the cab stood still), and for the pickup and the drop-off the named place it sits in or at (Overture Maps polygons: the largest one containing the endpoint, else the nearest within 30 m, the roadside a cab stops at; an airfield is never the place, its terminals and garages are) and the brand that place is. A place is tied to its brand by a hand-checked rule naming the polygon (named_place: the Las Vegas resorts and venues, each to its operator), by its name decided once in the brand resolution store (place_name), or by a branded place in the Overture catalogue within 50 m whose brand name is part of the place's name (place_agreement). With the brand ship its parent and the ticker and exchange of the listed company it belongs to (the brand's own Wikidata family's listing, else its nearest listed parent's; SEC EDGAR by CIK first, then Wikidata, then our curated seed), as the brand graph stated them when the row was labelled (brand_mapping_as_of): a day is labelled again whenever a decision or a linked brand's company fact moves. The brand id is the key dim_screen.venue_brand_id carries. place_status says why an endpoint has no place (none, outside_coverage, no_position). From 2026-07-28; a day ships once its rides are labelled.\n * \n * **Delivery:** Parquet day files keyed by `observed_date`, one row per `observed_date` x `screen_id` x `ride_start`. Definition version 1. 43 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_ride_places = {\n /** Mapping as-of, UTC: when the row's places and brands were labelled, with the brand decisions and the brand graph's company facts (name, parent, ticker, exchange) as they stood then. A day is labelled again whenever a decision, its confidence or a linked brand's company fact moves. */\n brand_mapping_as_of?: string;\n /** camera (a run of occupied camera windows) or vlm (passenger-onboard instants the vision model read with no camera ride around them; ride_end equals ride_start). NULL: As ride_end. */\n detector?: string | null;\n /** As pickup_brand_confidence, for the drop-off. Unit: share. NULL: As pickup_brand_confidence, for the drop-off. */\n dropoff_brand_confidence?: number | null;\n /** As pickup_brand_exchange, for the drop-off. NULL: As pickup_brand_exchange, for the drop-off. */\n dropoff_brand_exchange?: string | null;\n /** As pickup_brand_id, for the drop-off. NULL: As pickup_brand_id, for the drop-off. */\n dropoff_brand_id?: string | null;\n /** As pickup_brand_m, for the drop-off. Unit: meters. NULL: As pickup_brand_m, for the drop-off. */\n dropoff_brand_m?: number | null;\n /** As pickup_brand_method, for the drop-off. NULL: As pickup_brand_method, for the drop-off. */\n dropoff_brand_method?: string | null;\n /** As pickup_brand_name, for the drop-off. NULL: As pickup_brand_name, for the drop-off. */\n dropoff_brand_name?: string | null;\n /** As pickup_brand_parent_id, for the drop-off. NULL: As pickup_brand_parent_id, for the drop-off. */\n dropoff_brand_parent_id?: string | null;\n /** As pickup_brand_parent_name, for the drop-off. NULL: As pickup_brand_parent_name, for the drop-off. */\n dropoff_brand_parent_name?: string | null;\n /** As pickup_brand_ticker, for the drop-off. NULL: As pickup_brand_ticker, for the drop-off. */\n dropoff_brand_ticker?: string | null;\n /** As pickup_place_class, for the drop-off. NULL: As pickup_place_class, for the drop-off. */\n dropoff_place_class?: string | null;\n /** As pickup_place_id, for the drop-off. NULL: As pickup_place_id, for the drop-off. */\n dropoff_place_id?: string | null;\n /** As pickup_place_m, for the drop-off. Unit: meters. NULL: As pickup_place_m, for the drop-off. */\n dropoff_place_m?: number | null;\n /** As pickup_place_name, for the drop-off. NULL: As pickup_place_name, for the drop-off. */\n dropoff_place_name?: string | null;\n /** As pickup_place_status, for the drop-off. */\n dropoff_place_status?: string;\n /** As pickup_place_subtype, for the drop-off. NULL: As pickup_place_subtype, for the drop-off. */\n dropoff_place_subtype?: string | null;\n /** As pickup_place_type, for the drop-off. NULL: As pickup_place_type, for the drop-off. */\n dropoff_place_type?: string | null;\n /** As pickup_position_source, for the drop-off. NULL: As pickup_position_source, for the drop-off. */\n dropoff_position_source?: string | null;\n /** UTC day the ride started (ride_start). */\n observed_date: string;\n /** Overture Maps release the places were read from (e.g. 2026-08-19.0). */\n overture_release?: string;\n /** The confidence the link's source states, 0-1: the brand decision's for named_place and place_name, the agreeing Overture place's for place_agreement. Unit: share. NULL: As pickup_brand_id, or the link's source states no confidence. */\n pickup_brand_confidence?: number | null;\n /** ISO 10383 market identifier code (MIC) of the exchange the ticker trades on, e.g. XNYS, XNAS. NULL: As pickup_brand_ticker, or the listing records no exchange. */\n pickup_brand_exchange?: string | null;\n /** The brand the pickup place is, as the brand graph's id (the key dim_screen.venue_brand_id carries). NULL: No brand: the pickup is at no named place, or the place is no brand the graph holds. */\n pickup_brand_id?: string | null;\n /** Metres from the pickup to the place (0 inside) for named_place and place_name; to the agreeing branded place for place_agreement. Unit: meters. NULL: As pickup_brand_id. */\n pickup_brand_m?: number | null;\n /** How the place was tied to its brand: named_place (a hand-checked rule naming that polygon), place_name (the place's name, decided once in the brand resolution store), or place_agreement (a branded place in the Overture Maps catalogue within 50 m of the pickup whose brand name is a whole-word part of the place's name). NULL: As pickup_brand_id. */\n pickup_brand_method?: string | null;\n /** The brand's name. NULL: As pickup_brand_id. */\n pickup_brand_name?: string | null;\n /** The brand's immediate parent company, as the brand graph's id. NULL: As pickup_brand_id, or the brand graph records no parent of the brand. */\n pickup_brand_parent_id?: string | null;\n /** The parent company's name. NULL: As pickup_brand_parent_id. */\n pickup_brand_parent_name?: string | null;\n /** Ticker of the listed company the brand belongs to: the listing of the brand's Wikidata family (the brand and the brand rows sharing its Wikidata id: one business), else of its nearest listed parent up the parent chain (a brand of a listed parent reads the parent's); a listing only our curated seed states yields to a parent's that SEC or Wikidata states. A listing is SEC EDGAR's by CIK first, then Wikidata's stock-exchange statements, then the seed's. NULL: As pickup_brand_id, or no listing is recorded for the brand, its family or its parents. */\n pickup_brand_ticker?: string | null;\n /** Overture class of the place (e.g. international_airport, hotel, retail). NULL: As pickup_place_id, or Overture states no class. */\n pickup_place_class?: string | null;\n /** Overture Maps GERS id of the place: the largest named polygon containing the pickup, else the nearest within 30 m (an airfield polygon is never the place; its terminals and garages are). NULL: pickup_place_status is not named. */\n pickup_place_id?: string | null;\n /** 0 when the place contains the pickup, else the metres from the pickup to it (at most 30 m: the roadside a cab stops at). Unit: meters. NULL: As pickup_place_id. */\n pickup_place_m?: number | null;\n /** Name of the place, e.g. an airport terminal, a resort, a store, a stadium. NULL: As pickup_place_id. */\n pickup_place_name?: string | null;\n /** named (the pickup sits in or at a named place), none (inside the loaded map coverage, no named place within 30 m), outside_coverage (beyond the loaded map extent) or no_position (the ride has no pickup position). */\n pickup_place_status?: string;\n /** Overture subtype of the place (e.g. airport, commercial, entertainment). NULL: As pickup_place_id, or Overture states no subtype. */\n pickup_place_subtype?: string | null;\n /** Overture theme type of the place polygon: building, land_use or infrastructure. NULL: As pickup_place_id. */\n pickup_place_type?: string | null;\n /** Where the pickup position comes from: matched_path (the map-matched vehicle path at the instant), asof_last_fix (the cab's last GPS fix before it) or none. NULL: The ride was rebuilt after its places were labelled; the next labelling of the day carries it. */\n pickup_position_source?: string | null;\n /** End of the ride, UTC: the last occupied window end, or the last onboard instant. NULL: The ride was rebuilt after its places were labelled; the next labelling of the day carries it. */\n ride_end?: string | null;\n /** Stable id of the ride (a 64-bit hash of the screen and ride_start, as text). */\n ride_id?: string;\n /** ride, or stationary_presence: occupied camera windows while the cab stood still (its path moved less than the stationary threshold), not a trip. NULL: As ride_end. */\n ride_kind?: string | null;\n /** Start of the ride, UTC: the cab's first occupied camera window, or the first passenger-onboard instant its vision model read (detector). */\n ride_start: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. The cab's screen. */\n screen_id: string;\n};\n\n/**\n * Camera x radio co-presence per screen-hour: radio devices from the visitor sources the resolved radio buckets carry (BLE and mDNS) in each 5-minute bucket, joined to the face- or person-backed camera windows that closed within 15 seconds of it. unique_devices counts the distinct canonical visitor keys of the screen-hour. evidence_grade is the grade of the latest such camera window. face_present_windows counts buckets whose camera window read at least 0.5 of a face (the face_count primitive, else the per-window mean). attention_high_windows counts buckets whose window qualifies under the published attention rule. total_radio_pings sums every visitor source. Covers 2026-06-24 02:39 UTC onward, where both sources exist.\n * \n * **Delivery:** Parquet day files keyed by `hour_start`, one row per `hour_start` x `screen_mongo_id` x `evidence_grade`. Definition version 2. 8 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_screen_hourly_presence = {\n /** Of those, the pairs whose camera window qualifies under the published attention rule. Unit: device_buckets. */\n attention_high_windows?: number;\n /** Grade (face_backed or person_backed) of the latest camera window that closed within 15 s of a bucket of the row. */\n evidence_grade: string;\n /** Of those, the pairs whose camera window read at least half a face. Unit: device_buckets. */\n face_present_windows?: number;\n /** Start of the UTC hour. The hour of the 5-minute radio bucket. */\n hour_start: string;\n /** Distinct (visitor key, 5-minute bucket) pairs. Unit: device_buckets. */\n observation_windows?: number;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_mongo_id: string;\n /** Radio pings of the visitor keys in those buckets (each key and bucket's largest cluster size, capped at 255). Unit: pings. */\n total_radio_pings?: number;\n /** Distinct canonical visitor keys (BLE, mDNS, SSDP, HTTP probe) in the screen-hour's buckets that had a camera window within 15 s. Unit: identifiers. */\n unique_devices?: number;\n};\n\n/**\n * The screen panel: one row per (month, panel, screen) of every screen whose camera (panel camera) or visitor radio (panel radio) was up on at least one UTC day of the month. Membership is by uptime, not by audience: a camera that ran and saw nobody is a member. The evidence is the activity dim_screen is built from, plus the heartbeat: camera windows, the camera pipeline's inference rows (the census predicate), vision demographic readings and heartbeat camera-on minutes; visitor-source radio windows, cross-screen transitions and movement edges. evidence_days counts the days of each. audience_rate is visitor identifiers per 6-minute slot on the radio panel (audience per unit time) and faces per occupied camera window on the camera panel (the group in view while someone is in view); the 2026-09-25 camera cadence step (median windows per screen-hour 45 to 77, faces per window flat) moves neither. in_previous_month marks the screens of the same panel the month before, NULL unless that month is built whole; the approved metric same_panel_index compares the rate month over month on those screens, on the evidence kinds both months hold. Every month that begins in the delivery window, its days inside the window (days_built, month_complete). The panel holds days from 2026-05-24, the first visitor radio windows; camera windows from 2026-06-01, vision demographic readings from 2026-07-16, heartbeat camera-on minutes from 2026-08-26. A day's camera_inference evidence is the inference rows ClickHouse held when the day was built (it keeps them 90 days), so a day first built later than that carries none.\n * \n * **Delivery:** A snapshot, one row per `month` x `panel` x `screen_id`. Definition version 1. 16 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_screen_panel_monthly = {\n /** UTC days of the month the instrument was up (any evidence in evidence_days): the membership. Unit: days. */\n active_days?: number;\n /** audience_sum / audience_units. radio: identifiers concurrent in a 6-minute slot, audience per unit time. camera: faces per occupied window, the group in view while someone is in view, not audience per unit time. A change in how often an instrument reports moves neither. NULL: No audience unit in the month (audience_units = 0). */\n audience_rate?: number | null;\n /** camera: faces summed over those windows; radio: visitor-source identifiers distinct within each slot, summed over the slots. */\n audience_sum?: number;\n /** camera: the face- and person-backed camera windows of the month (~10 s each, made only while someone is in view); radio: the 6-minute slots in which the screen's visitor radio read an identifier. */\n audience_units?: number;\n /** Heartbeat minutes the sensing SDK reported it was sensing, over the active days. Unit: minutes. NULL: The heartbeat measured none of the active days. */\n camera_on_minutes?: number | null;\n /** Days of the month inside the delivery window that the panel holds. Unit: days. */\n days_built?: number;\n /** Active days per kind of evidence. camera: camera_window, camera_inference (the camera pipeline ran, empty scenes included), camera_demographics, camera_heartbeat (the sensing SDK reported sensing); radio: radio_visitor_window, radio_transition, radio_movement_edge. Unit: days. */\n evidence_days?: Record<string, unknown>;\n /** First active day of the month. */\n first_active_day?: string;\n /** 1 when the screen was in the same panel the month before, else 0. NULL: The previous month is not built whole (the panel starts in it, or a day of it is missing): no answer is drawn from part of a month. */\n in_previous_month?: number | null;\n /** Last active day of the month. */\n last_active_day?: string;\n /** First day of the UTC calendar month. */\n month: string;\n /** 1 when every day of the month is built. */\n month_complete?: number;\n /** Heartbeat minutes the screen was online over its active days. Unit: minutes. NULL: The heartbeat measured none of the active days. */\n online_minutes?: number | null;\n /** camera or radio: the instrument whose uptime made the screen a member. */\n panel: string;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. */\n screen_id: string;\n /** Of those, the days with the panel's own audience evidence: a face- or person-backed camera window (camera); a visitor-source radio window (radio). Unit: days. */\n window_days?: number;\n};\n\n/**\n * One row per live sighted creative read in the delivery window: an artwork recognised across faces and cabs from its reads (crop embeddings, the words read and the brand evidence), with its brand, its reads, cabs, faces, points and markets, and its sharpest read, whose still is kept in the proof archive. The registry has no retention. From 2026-10-13, the first still read.\n * \n * **Delivery:** A snapshot, one row per `creative_id`. Definition version 1. 20 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_sighted_creatives = {\n /** Its brand (our brand knowledge graph id). NULL: Unlabelled. */\n brand_id?: string | null;\n /** The brand's name. NULL: Unlabelled. */\n brand_name?: string | null;\n /** The identity build that wrote the row. */\n builder_version?: string;\n /** When the row was written, UTC. */\n built_at?: string;\n /** The sighted creative: sc- + 16 hex, stable across builds. One artwork our cab cameras read, recognised across faces and cabs. */\n creative_id: string;\n /** Of reads, the ones a tablet read on the edge (edge_ocr_v1). Unit: reads. */\n edge_reads?: number;\n /** Distinct registered faces it was read on. Unit: faces. */\n faces?: number;\n /** Its first read, UTC. */\n first_seen?: string;\n /** Reads whose own evidence names another brand. Unit: reads. */\n label_conflicts?: number;\n /** How its brand was decided. NULL: Unlabelled. */\n label_kind?: string | null;\n /** Reads whose own evidence names the label. Unit: reads. */\n label_support?: number;\n /** Its last read, UTC. */\n last_seen?: string;\n /** The markets it was read in, as COUNTRY:CODE. */\n markets?: Array<unknown>;\n /** Distinct unregistered board points it was read on. Unit: points. */\n points?: number;\n /** Reads of it. Unit: reads. */\n reads?: number;\n /** The ad of that read, as in board_creative_sighting. NULL: No representative read. */\n rep_ad_ordinal?: number | null;\n /** The instrument of that read: ssr-v1, vlmtext-v1 or edge_ocr_v1. NULL: No representative read. */\n rep_instrument_version?: string | null;\n /** Its sharpest read: the still's call id for a cloud read (the camera_frame_corpus key), the reading id for an edge read. NULL: No read with a stored still and a box. */\n rep_still_call_id?: string | null;\n /** Distinct cabs that read it. Unit: screens. */\n screens?: number;\n /** Its most supported words, most supported first, at most 12. */\n words?: Array<unknown>;\n};\n\n/**\n * Raw VAST request telemetry.\n * \n * **Delivery:** Parquet day files keyed by `requested_at`, one row per `request_id` x `requested_at`. Definition version 3. 37 columns; every delivery carries this dictionary.\n */\nexport type DataApi_DataDelivery_vast_requests = {\n /** VAST AdSystem of the response (empty when none). */\n ad_system?: string;\n /** Advertiser the ad response named. NULL: The response named no advertiser. */\n advertiser_name?: string | null;\n /** Id of the auction request the ad request triggered. NULL: The request ran no auction. */\n auction_request_id?: string | null;\n /** Buyer seat of the winning bid (empty when none). */\n buyer_seat?: string;\n /** Clearing price the response carried, USD CPM. Unit: usd_per_1000_plays. NULL: No price was returned. */\n clearing_cpm?: number | null;\n /** True once the ad completed (a latch: it never reverts). */\n completed?: boolean;\n /** MIME type of the media file returned (empty when none). */\n content_type?: string;\n /** Creative id the demand source supplied for the ad. NULL: No creative id, or the IMA house/fallback creative ('-1' or ''). */\n creative_id?: string | null;\n /** Landing page (click-through) of the creative served. NULL: The response named no landing page. */\n creative_landing_url?: string | null;\n /** Currency of the price (empty when none). */\n currency?: string;\n /** Device family of the player (e.g. Amazon Fire TV, Android box, Samsung tablet). NULL: Not classified. */\n device_category?: string | null;\n /** Player environment the request declared (e.g. ctv). NULL: Not classified. */\n device_environment?: string | null;\n /** OpenRTB device type the player declared. NULL: Not sent. */\n device_type_hint?: string | null;\n /** Reseller (distributor) id the traffic is attributed to; empty for Trillboards' own. */\n distributor_id?: string;\n /** Serving experiment arms the request was assigned (JSON). NULL: The request was in no serving experiment. */\n experiment_assignments?: string | null;\n /** Google IMA SDK error code. NULL: No IMA error. */\n ima_error_code?: number | null;\n /** Time to answer the request, milliseconds. Unit: ms. NULL: Not recorded. */\n latency_ms?: number | null;\n /** URL of the creative's media file. NULL: The response named no media file. */\n media_url?: string | null;\n /** Bids the OpenRTB auction returned. Unit: bids. NULL: The request was not an OpenRTB auction. */\n openrtb_bid_count?: number | null;\n /** Seats that bid in the OpenRTB auction. Unit: seats. NULL: The request was not an OpenRTB auction. */\n openrtb_seat_count?: number | null;\n /** Latest outcome of the request: requested, bid_received, no_bid, no_fill, filled, redirect, player_served, completed, skipped, timeout or error. NULL: Not recorded. */\n outcome?: string | null;\n /** Operating system the player declared. NULL: Not sent. */\n platform_hint?: string | null;\n /** Our ad request id. With requested_at it is the key; to count requests keep the latest requested_at per request_id. */\n request_id: string;\n /** SHA-256 of the request's host, path and query parameters (correlator and request id excluded): one value per request shape. NULL: Not computed (an older server-built request). */\n request_signature_hash?: string | null;\n /** How the request was built: vast_wrap, server_constructed, proxy_auction, client_lifecycle or partner_sdk. NULL: Not recorded. */\n request_source?: string | null;\n /** When the request was made, UTC (a partner-supplied request id is re-stamped at each later update). */\n requested_at: string;\n /** OpenRTB supply chain object (JSON) of the request. NULL: The request carried no supply chain. */\n schain?: string | null;\n /** Trillboards screen id (24-character hex); joins dim_screen.screen_id. Partner-exchange placements carry a non-screen id here. */\n screen_mongo_id?: string;\n /** Ad SDK of the player (e.g. google-ima). NULL: Not sent. */\n sdk_type?: string | null;\n /** Version of that SDK. NULL: Not sent. */\n sdk_version?: string | null;\n /** Demand source the request was sent to. NULL: Not recorded. */\n source_name?: string | null;\n /** VAST extensions the upstream response carried (JSON). NULL: The upstream response carried no extensions. */\n upstream_extensions?: string | null;\n /** Serving variant (the ad-serving configuration arm) of the request or play. */\n variant_name?: string;\n /** VAST error code. NULL: No VAST error. */\n vast_error_code?: number | null;\n /** Shape of the VAST response: inline, inline_resolved, wrapper_passthrough or empty. NULL: Not classified. */\n vast_type?: string | null;\n /** Venue category of the screen at request time. NULL: Not recorded. */\n venue_type?: string | null;\n /** Position of the demand source in the screen's waterfall. NULL: Not in a waterfall. */\n waterfall_position?: number | null;\n};\n\nexport type DataApi_DataProducts_AudienceRow = {\n /** Interval upper bound. */\n ci_high: number | null;\n /** Interval lower bound. */\n ci_low: number | null;\n /** Daypart, or `__all__`. */\n daypart: string;\n /** Audience dimension (occupancy, age, gender, activity, mood, ...). */\n dimension: string;\n /** dense_measure (measured on every pass), face_blend (age, gender, cohort, intent from pass_audience v8: the face's own camera share blended with its area or market share in proportion to how many riders the face measured) or mrp_label (the area model's share, earlier versions). */\n estimand_kind: string;\n fit_window: {\n /** Last day. */\n end: string;\n /** First day. */\n start: string;\n } | null;\n /** This board's share against its DMA (1.0 = same). */\n index_vs_dma: number | null;\n /** Matched observations (owner mount), weighted. */\n match_n?: number | null;\n /** Its upper bound. */\n measured_ci_high: number | null;\n /** Its lower bound. */\n measured_ci_low: number | null;\n /** The share measured at this board alone. */\n measured_share: number | null;\n /** Observations at this board. */\n measured_support_n: number | null;\n /** Level the share resolved at (board_daypart, board, dma, geohash5, ...). */\n resolved_level: string | null;\n /** Share of the passing audience with this value. */\n share: number | null;\n /** Observations the share rests on. */\n support_n: number | null;\n /** share, or a mean per pass (approved-metric answers). */\n unit?: string;\n /** Measurement units (owner mount). */\n units?: number | null;\n /** The dimension value. */\n value: string;\n /** Distinct vehicles behind those observations. */\n vehicles: number | null;\n};\n\nexport type DataApi_DataProducts_AuthError = {\n /** NO_TOKEN, TOKEN_EXPIRED, TOKEN_REVOKED, INVALID_API_KEY, INSUFFICIENT_SCOPE, ... */\n code: string;\n /** Why the credential was refused. */\n message: string;\n /** The scopes the key must hold (INSUFFICIENT_SCOPE). */\n required_scopes?: Array<string>;\n success?: false;\n};\n\nexport type DataApi_DataProducts_Benchmark = {\n market: {\n /** Market code. */\n code: string;\n /** dma or cma. */\n kind: string;\n };\n measured_ips?: {\n deciles: Array<{\n /** Quantile. */\n q: number;\n /** Value. */\n value: number;\n }>;\n /** Highest. */\n max: number;\n /** Median. */\n median: number;\n /** Lowest. */\n min: number;\n /** First quartile. */\n q25: number;\n /** Third quartile. */\n q75: number;\n };\n /** Comparable faces in the market. */\n peers: number;\n /** Its percentile. */\n percentile?: number;\n /** This face's rank among them by measured impressions per spot. */\n rank?: number;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n};\n\nexport type DataApi_DataProducts_BoardAudience = {\n /** Board face id. */\n board_id: string;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours: Record<string, Array<number>>;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_AudienceRow>;\n window: DataApi_DataProducts_Window;\n};\n\nexport type DataApi_DataProducts_BoardAudienceResponse = {\n data: DataApi_DataProducts_BoardAudience;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BoardCurrency = {\n absent: Array<DataApi_DataProducts_CurrencyAbsent>;\n board: DataApi_DataProducts_CurrencyBoard;\n /** The condition scope the cells are split by. */\n by: string;\n cells: Array<DataApi_DataProducts_CurrencyCell>;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours: Record<string, Array<number>>;\n loop: {\n /** Loop length, seconds (owner mount). */\n loop_s?: number | null;\n /** Spots in the loop (owner mount). */\n n_slots?: number | null;\n /** Spot length, seconds. */\n slot_s: number | null;\n /** declared, owner_spec or format default. */\n slot_source: string | null;\n } | null;\n method: DataApi_DataProducts_Method;\n owner?: {\n /** The owner's average daily impressions. */\n avg_daily_impressions: number | null;\n /** The face's floor CPM, USD. */\n floor_cpm_usd: number | null;\n /** The owner's impressions per spot. */\n impressions_per_spot: number | null;\n /** The owner's spots per day. */\n spots_per_day: number | null;\n };\n /** Owner mount: the catalogue the owner figures come from. */\n source?: string;\n window: DataApi_DataProducts_Window & {\n built_at?: string;\n };\n};\n\nexport type DataApi_DataProducts_BoardCurrencyResponse = {\n data: DataApi_DataProducts_BoardCurrency;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BoardLookedShare = {\n /** Board face id. */\n board_id: string;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_LookedShareRow>;\n /** What the share is, in words. */\n what_this_measures: string;\n window: {\n /** First local date. */\n from: string;\n /** Last local date. */\n to: string;\n };\n};\n\nexport type DataApi_DataProducts_BoardLookedShareResponse = {\n data: DataApi_DataProducts_BoardLookedShare;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BoardPointCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_BoardPointProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_BoardPointMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_BoardPointMeta = {\n audience?: {\n /** The dimension asked for (audience=). */\n dimension: string;\n /** face_blend: the face rows of pass_audience v8. */\n estimand_kind: string;\n /** Its value. */\n value: string;\n };\n /** The bbox drawn. */\n bbox: Array<number>;\n /** The brand searched (brand=). */\n brand?: string | null;\n /** Points returned. */\n count: number;\n filters?: {\n /** The face types asked for (type=). */\n faceTypes: Array<string>;\n /** The formats asked for (format=). */\n formats: Array<string>;\n /** The owners asked for (owner=). */\n owners: Array<string>;\n /** The venue type ids asked for (venue=). */\n venueTypeIds: Array<number>;\n } | null;\n /** Extra layers drawn (sightings). */\n layers?: Array<string>;\n /** The curated set drawn, or null. */\n set_key: string | null;\n sighting_window?: {\n /** Days in the window. */\n days: number;\n /** First day of the sighting window. */\n since: string;\n /** Day after its last. */\n until_exclusive: string;\n };\n /** The points were capped at the overlay limit. */\n truncated: boolean;\n /** Unmatched sightings drawn (layers=sightings). */\n unmatched_sighting_count?: number;\n /** The sighting layer was capped. */\n unmatched_sightings_truncated?: boolean;\n /** Viewshed build version. */\n viewshed_version: string | null;\n watermark?: DataApi_DataProducts_Watermark;\n /** Currency window end. */\n window_end: string | null;\n};\n\nexport type DataApi_DataProducts_BoardPointProperties = {\n /** Advertiser as read (unmatched sighting). */\n advertiser?: string | null;\n /** With `audience=`: the level the blend's prior came from (geohash5, dma_daypart, national, ...). */\n audience_level?: string | null;\n /** With `audience=`: the distinct riders the face measured for that dimension (the row's n). */\n audience_n?: number | null;\n /** With `audience=`: the share of the passing riders with that value, measured at this face (pass_audience v8: its own camera share blended with its area or market share by the riders it measured). Null where the window carries no face row for the value. */\n audience_share?: number | null;\n /** Board structure id. */\n board_id?: string;\n /** Brand as read (unmatched sighting). */\n brand?: string | null;\n /** Cab heading, degrees (unmatched sighting). */\n cab_heading_deg?: number | null;\n /** With `brand=`: sightings of that brand on this board. */\n camera_brand_sightings?: number | null;\n /** Newest sighting on the board, UTC. */\n camera_last_sighted_at?: string | null;\n /** Distinct brands among those sightings. */\n camera_sighting_brands?: number | null;\n /** Ads our cab cameras read on this board in the sighting window (paid placements only). Null where no reading matched to it. */\n camera_sightings?: number | null;\n /** The most-read brands on the board, with their sightings. */\n camera_top_brands?: Array<{\n /** Brand as read. */\n brand: string;\n /** Sightings of it on this board. */\n sightings: number;\n }> | null;\n /** Sightings that saw the face carrying no advertiser. */\n camera_vacancy_sightings?: number | null;\n /** City. */\n city?: string | null;\n /** ISO-3166 alpha-2. */\n country?: string | null;\n /** Name shown on the card. */\n display_name?: string | null;\n /** What the face is: digital (a screen) or static (a printed board). The value the `type` filter reads. */\n face_type?: string | null;\n faces?: Array<{\n /** Direction the face points, degrees. */\n azimuth_deg: number | null;\n /** Face index. */\n orientation_idx: number;\n /** Share of the structure's passes the face serves. */\n orientation_share: number;\n }>;\n /** The face's format (a digital face's pixel-size class, a static face's type): the value the `format` filter reads. */\n format_label?: string | null;\n /** Billboard, Digital board, Street furniture, ... */\n inventory_type_label?: string | null;\n /** Measured impressions per spot (numbered points). */\n ips?: number | null;\n /** Why a measured face carries no impressions per spot (`no_slot`: a static face has no slot). Null where it carries one. */\n ips_absent_reason?: string | null;\n /** Interval upper bound. */\n ips_high?: number | null;\n /** Interval lower bound. */\n ips_low?: number | null;\n /** Who ips counts: `vehicle_occupants`. */\n ips_population?: string;\n /** The face carried no advertiser (unmatched sighting). */\n is_vacancy?: boolean;\n /** board, or unmatched_sighting (layers=sightings). */\n kind: string;\n /** Latitude. */\n latitude?: number | null;\n /** Longitude. */\n longitude?: number | null;\n /** Market name (unmatched sighting). */\n market_name?: string | null;\n /** unmatched or no_candidate (unmatched sighting). */\n match_status?: string | null;\n /** The face has passes in the current currency window (whatever its impressions per spot). */\n measured?: boolean;\n /** Board name. */\n name?: string | null;\n /** Face passes behind the figure (the sum of each pass's share of this face, a fraction where a facing is unresolved). Null on a window built before exposure_currency v6. */\n passes?: number | null;\n /** Place name. */\n place_name?: string | null;\n /** Media owner. */\n publisher_name?: string | null;\n /** The Find Screens card id for the board. */\n screen_id?: string | null;\n /** Still instant, UTC (unmatched sighting). */\n seen_at?: string;\n /** The face is sold: false for a static registry board, which is measured and never sold. */\n sellable?: boolean;\n /** Sighting id (unmatched sighting). */\n sighting_id?: string;\n /** still_reader or vlm_text (unmatched sighting). */\n source?: string;\n /** State or province. */\n state?: string | null;\n /** Surface as read (unmatched sighting). */\n surface?: string | null;\n /** Side of the cab the ad was on (unmatched sighting). */\n vehicle_side?: string | null;\n /** Distinct vehicles behind the figure. */\n vehicles?: number | null;\n /** OpenOOH venue type id. */\n venue_type_id?: number | null;\n /** Currency window end. */\n window_end?: string | null;\n};\n\nexport type DataApi_DataProducts_BoardTiles = {\n /** Board face id. */\n board_id: string;\n by_week: Array<DataApi_DataProducts_TileSum>;\n cells: Array<{\n /** Daypart. */\n daypart: string;\n /** Instrumented legible seconds. */\n facing_base_s: number | null;\n /** Facing seconds. */\n facing_s: number | null;\n /** Legible seconds. */\n legible_s: number;\n /** Passes (face-share weighted). */\n passes: number;\n /** Distinct vehicles behind the leaf. */\n vehicles: number;\n /** Monday the week starts on. */\n week_start: string;\n }>;\n meta: {\n bbox?: Array<number>;\n /** Boards summed. */\n boards?: number;\n /** Tiles returned. */\n count?: number;\n facing: DataApi_DataProducts_FacingVerdict;\n /** Days measured under two method versions. */\n method_mixed_days: Array<string>;\n /** Geohash precision. */\n precision?: number;\n weeks?: Array<string>;\n };\n total: DataApi_DataProducts_TileSum;\n weeks: Array<string>;\n};\n\nexport type DataApi_DataProducts_BoardTilesResponse = {\n data: DataApi_DataProducts_BoardTiles;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_BrandMarket = {\n /** The box the market's reads were taken in, [minLon, minLat, maxLon, maxLat]. */\n bbox: Array<number> | null;\n /** Of those, reads on a registered board face. */\n face_sightings: number;\n /** Distinct registered faces it was read on. */\n faces: number;\n /** Every read held for the market, any window. */\n held_sightings: number;\n /** Market as COUNTRY:CODE (US DMA, CA CMA). */\n market_key: string;\n /** Market name. */\n market_name: string | null;\n /** Reads of the brand in the market in the window. */\n sightings: number;\n /** Reads on no registered face (street, storefront, vehicle). */\n street_sightings: number;\n};\n\nexport type DataApi_DataProducts_BrandSearch = {\n brands: Array<DataApi_DataProducts_SightedBrand>;\n /** Its brand key: letters and digits, lower-cased (McDonald's and mcdonalds are one key). */\n key: string;\n /** The query as sent. */\n query: string;\n /** When the brand index was last rebuilt, UTC. */\n refreshed_at: string | null;\n window: {\n /** Days in the window. */\n days: number;\n /** First day of the window. */\n since: string;\n /** Day after its last. */\n until_exclusive: string;\n };\n};\n\nexport type DataApi_DataProducts_BrandSearchResponse = {\n data: DataApi_DataProducts_BrandSearch;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_Calibration = {\n calibration: DataApi_DataProducts_CalibrationVersion;\n columns: Array<{\n /** What the column measures. */\n definition: string;\n /** CSV header. */\n header: string;\n /** Column key. */\n key: string;\n /** MRC OOH requirements the column serves. */\n mrc: Array<string>;\n /** Unit. */\n unit: string;\n }>;\n /** Hash of this file. */\n content_sha256: string;\n filter: {\n /** readable or facing. */\n calibration: string | null;\n /** Instrument. */\n instrument: string | null;\n /** second, pass, ... */\n unit: string | null;\n };\n rows: Array<DataApi_DataProducts_CalibrationCell>;\n /** Where the column-to-MRC specification lives. */\n spec: string;\n /** Rows were capped. */\n truncated: boolean;\n};\n\nexport type DataApi_DataProducts_CalibrationCell = {\n /** Format class. */\n aspect_class: string;\n /** Bearing band. */\n bearing_band: string;\n /** Band upper edge, degrees. */\n bearing_max_deg: number | null;\n /** Band lower edge, degrees. */\n bearing_min_deg: number | null;\n /** readable = P(readable | geometry, speed, time); facing = P(facing | readable, bearing, format). */\n calibration: string;\n /** Version id. */\n calibration_id: string;\n /** Currency method version. */\n currency_method_version: number;\n /** Daypart. */\n daypart: string;\n /** Local hours of the daypart. */\n daypart_local_hours: string;\n /** Denominator. */\n den: number;\n /** Instrument. */\n instrument: string | null;\n /** Interval method. */\n interval_method: string;\n /** Mean speed, m/s. */\n mean_speed_mps: number | null;\n /** Boards. */\n n_boards: number;\n /** Passes. */\n n_passes: number;\n /** Distinct vehicles. */\n n_vehicles: number;\n /** Observation windows. */\n n_windows: number | null;\n /** Numerator. */\n num: number;\n /** The probability. */\n p: number;\n /** Interval upper bound. */\n p_high: number | null;\n /** Interval lower bound. */\n p_low: number | null;\n /** Pass-audience method version. */\n pass_audience_version: number;\n /** Road class. */\n road_class: string;\n /** Standard error. */\n se: number | null;\n /** free_flow, slowed, congested. */\n speed_band: string;\n /** second or pass. */\n unit: string;\n /** Venue type. */\n venue_type: string;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n /** Last day. */\n window_end: string;\n /** First day. */\n window_start: string;\n};\n\nexport type DataApi_DataProducts_CalibrationResponse = {\n data: DataApi_DataProducts_Calibration;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_CalibrationVersion = {\n /** Attention observations. */\n attention_rows: number;\n /** Boards. */\n boards: number;\n /** When it was cut, UTC. */\n built_at: string;\n /** Version id, mcal-<window_end>-cv<N>-pa<N>-b<N>. */\n calibration_id: string;\n /** Calibration cells. */\n cells: number;\n /** Hash of the version content. */\n content_sha256: string;\n /** Currency method version. */\n currency_method_version: number;\n /** Fingerprint of the currency parameters. */\n currency_params_fingerprint: string;\n engine_versions: Array<string>;\n /** Facing tolerance, degrees. */\n facing_tol_deg: number | null;\n graph_versions: Array<string>;\n matcher_versions: Array<string>;\n /** Fingerprint of the pass-audience parameters. */\n pass_audience_params_fingerprint: string;\n /** Pass-audience method version. */\n pass_audience_version: number;\n /** Passes the version rests on. */\n passes: number;\n /** Congested speed ratio threshold. */\n speed_congested_ratio: number | null;\n /** Free-flow speed ratio threshold. */\n speed_free_flow_ratio: number | null;\n /** Speed profile version. */\n speed_profile_version: string | null;\n time_model_versions: Array<string>;\n timing_curve_versions: Array<string>;\n /** Distinct vehicles. */\n vehicles: number;\n viewshed_versions: Array<string>;\n /** Days. */\n window_days: number;\n /** Last day. */\n window_end: string;\n /** First day. */\n window_start: string;\n};\n\nexport type DataApi_DataProducts_CalibrationVersions = {\n /** The newest version. */\n latest: string | null;\n /** Where the specification lives. */\n spec: string;\n versions: Array<DataApi_DataProducts_CalibrationVersion>;\n};\n\nexport type DataApi_DataProducts_CalibrationVersionsResponse = {\n data: DataApi_DataProducts_CalibrationVersions;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_CurationSet = {\n countries: Array<string>;\n coverage: DataApi_DataProducts_SetCoverage;\n /** Set name. */\n display_name: string;\n /** DMA code. */\n dma_code: string | null;\n /** DMA name. */\n dma_name: string | null;\n /** The caller holds the set. */\n entitled?: boolean;\n /** dma, national, ... */\n geo_scope: string | null;\n /** Audience segment the set is curated for. */\n segment_key: string | null;\n /** Curated set key. */\n set_key: string;\n};\n\nexport type DataApi_DataProducts_CurationSetList = {\n /** The coverage window. */\n coverage_window_end: string | null;\n /** More sets follow. */\n has_more: boolean;\n /** Page size. */\n limit: number;\n limits: {\n /** Largest bbox span the map routes accept, degrees. */\n max_bbox_deg: number;\n /** Most boards one overlay draws. */\n max_overlay_boards: number;\n };\n /** Page offset. */\n offset: number;\n /** Sets on this page. */\n returned: number;\n sets: Array<DataApi_DataProducts_CurationSet>;\n /** Sets matching. */\n total: number;\n};\n\nexport type DataApi_DataProducts_CurationSetListResponse = {\n data: DataApi_DataProducts_CurationSetList;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_CurrencyAbsent = {\n /** Condition scope. */\n cond_scope: string;\n /** Condition value. */\n cond_value: string;\n /** Daypart. */\n daypart: string;\n /** The board-pass rows seen (owner mount): a reconciliation count, never a pass count. */\n pass_rows?: number | null;\n /** Face passes seen (owner mount): the sum of face_share, a fraction where a facing is unresolved. Null on a window built before exposure_currency v6. */\n passes?: number | null;\n /** Why the currency holds no figure for the cell (no_window, no_persons, ...). */\n reason: string;\n /** Vehicles seen (owner mount). */\n vehicles?: number | null;\n};\n\nexport type DataApi_DataProducts_CurrencyBoard = {\n /** Board face id. */\n board_id: string;\n /** ISO-3166 alpha-2. */\n country: string;\n /** Nielsen DMA code. */\n dma_code: string | null;\n /** The face is active in the catalogue (owner mount). */\n is_active?: boolean;\n /** Face latitude. */\n latitude: number;\n /** Face longitude. */\n longitude: number;\n /** The media owner selling the face. */\n publisher_name: string;\n /** State or province. */\n state: string | null;\n /** IANA zone the dayparts are local to. */\n timezone: string;\n /** The face as the inventory catalogue names it. */\n venue_name: string;\n /** OpenOOH venue type id (301 = billboards). */\n venue_type_id: number;\n};\n\nexport type DataApi_DataProducts_CurrencyCell = {\n /** Why a measured cell carries no impressions per spot: `no_slot` (a face with no slot, a static board: its passes, flow, daily contacts and speed are measured). Null where it carries one; absent from a body served before serving version 16. */\n absent_reason?: string | null;\n ads_per_pass: {\n /** Ads played whole during the pass (mean). */\n complete: number | null;\n /** Passes timed to the owner's play log. */\n exact_passes: number | null;\n /** Ads seen per pass (mean). */\n seen: number | null;\n /** Ads seen per pass on passes timed to the owner's play log. */\n seen_exact: number | null;\n /** Ads on screen at any point of the pass (mean). */\n touched: number | null;\n } | null;\n /** Condition the cell is split by (all, light, weather, speed). */\n cond_scope: string;\n /** The condition value, or `__all__`. */\n cond_value: string;\n conditions: {\n /** Share of passes in sun glare. */\n glare_share: number | null;\n /** Mean ambient light, lux. */\n lux_mean: number | null;\n /** Share of passes at night. */\n night_share: number | null;\n /** Share of passes in rain. */\n rain_share: number | null;\n } | null;\n /** People passing in position to see the face per day. */\n daily_contacts: number | null;\n /** Daypart of the cell, or `__all__`. */\n daypart: string;\n flow_vph: {\n /** Annual average daily traffic facing the board (owner mount). */\n aadt_facing?: number | null;\n /** Coefficient of variation of the hourly flow. */\n cv: number | null;\n /** Vehicles per hour past the face. */\n mean: number | null;\n /** What the hourly profile is built from (fleet_blend, ...). */\n profile_basis: string | null;\n /** Traffic count source (owner mount). */\n source?: string | null;\n } | null;\n impressions_per_spot: {\n /** Interval upper bound. */\n high: number | null;\n /** How the interval is computed (lognormal_delta_vehicle_clustered). */\n interval_method: string | null;\n /** Interval lower bound. */\n low: number | null;\n /** Measured impressions per spot. */\n measured: number | null;\n /** The owner's own figure for the spot (owner mount). */\n owner?: number | null;\n } | null;\n /** Who the measured impressions per spot count: `vehicle_occupants`. */\n ips_population: string;\n legible_window_s: {\n /** Mean seconds the face is legible from a passing vehicle. */\n mean: number | null;\n /** Standard error of the mean, seconds. */\n se: number | null;\n } | null;\n /** Owner mount: what the measurement is worth at the floor. */\n money?: {\n /** Annual revenue difference at the floor, USD. */\n annual_opportunity_usd: number | null;\n /** Measured impressions per floor dollar. */\n imps_per_floor_usd: number | null;\n /** Recommended floor CPM, USD. */\n recommended_floor_cpm: number | null;\n };\n persons_in_position_to_see: {\n /** Average vehicle occupancy. */\n avo: number | null;\n /** Instrument that measured it (head_yaw, ...). */\n instrument: string | null;\n /** Level the visibility was resolved at (board, format, market). */\n level: string | null;\n /** Driver visibility factor. */\n v_driver: number | null;\n /** Share of passengers in position to see it. */\n v_pax: number | null;\n /** Upper bound of v_pax. */\n v_pax_high: number | null;\n /** Lower bound of v_pax. */\n v_pax_low: number | null;\n /** People per vehicle in position to see the face. */\n value: number | null;\n } | null;\n /** The harmonic-mean speed of earlier versions, km/h: dominated by stopped passes, kept beside the moving speed. Absent from a body served before serving version 16. */\n speed_harmonic_kph?: number | null;\n /** Moving speed past the face, km/h: the face-share-weighted median of path / (visible - stationary) seconds over the passes that moved (exposure_currency v6). Null on a window built before v6. */\n speed_kph: number | null;\n /** Share of the in-view seconds the passing vehicles stood still (stationary over visible seconds, face-share weighted; exposure_currency v6). Absent from a body served before serving version 16. */\n stopped_share?: number | null;\n support: {\n /** The board-pass rows with an in-cab camera reading. */\n camera_pass_rows?: number | null;\n /** Face passes with an in-cab camera reading (a fraction where a facing is unresolved). Null on a window built before exposure_currency v6. */\n camera_passes: number | null;\n /** The board-pass rows behind the cell (one per candidate facing of a traversal): a reconciliation count, never a pass count. */\n pass_rows?: number | null;\n /** Face passes the cell is measured over: the sum of each pass's share of this face. A traversal that crosses m of the k candidate facings of a face whose facing is unresolved adds m/k, so the count can be a fraction. Null on a window built before exposure_currency v6. */\n passes: number | null;\n /** Passenger observation windows. */\n pax_windows: number | null;\n /** Distinct vehicles behind those passes. */\n vehicles: number | null;\n };\n /** Owner mount: the measured figure against the owner's. */\n yield?: {\n /** Why no ratio is served. */\n absent_reason: string | null;\n /** ratio or incremental. */\n basis: string | null;\n /** Interval upper bound. */\n high: number | null;\n /** Interval lower bound. */\n low: number | null;\n /** Measured over the owner's figure. */\n ratio: number | null;\n };\n};\n\nexport type DataApi_DataProducts_DeliveryReport = {\n /** Per creative: creative_key, advertiser, campaign_key, precision, days, plays, measured_impressions (with low/high), owner_modelled_impressions, fleet_exposure. */\n by_creative: Array<Record<string, unknown>>;\n /** Per local day: play_date, plays, measured_impressions (with low/high), owner_modelled_impressions, fleet_passes, priced_at_window_end, state. */\n by_day: Array<Record<string, unknown>>;\n columns: Array<{\n /** CSV header. */\n header?: string;\n /** Column key. */\n key: string;\n }>;\n /** board_id, name, owner, venue_type_id, timezone, country, state, dma_code, latitude, longitude, owner_ips. */\n face: Record<string, unknown>;\n flight: {\n /** Days. */\n days: number;\n /** First day. */\n from: string;\n /** Last day. */\n to: string;\n };\n /** Who the measured impressions count. */\n ips_population: string;\n /** kinds, precisions, owner_log, modelled_rotation_only. */\n plays_basis: Record<string, unknown>;\n /** windows (each currency window that priced a day: measured_ips with its interval, slot, passes, vehicles, owner_ips, versions) and spans_windows. */\n pricing: Record<string, unknown>;\n /** One row per (day, creative), the CSV rows: board_id, face, owner, play_date, creative_key, advertiser, campaign_key, plays_basis, precision, plays, measured_impressions (with low/high), owner_modelled_impressions, fleet_passes, priced_at_window_end, priced_ips (with low/high), ips_population, measured_state. */\n rows: Array<Record<string, unknown>>;\n /** plays, measured_impressions (with low/high), owner_modelled_impressions, measured_over_owner, fleet_passes, days_with_plays, days_measured, days_unmeasured, days_without_delivery_row, unmeasured_plays. */\n totals: Record<string, unknown>;\n};\n\nexport type DataApi_DataProducts_DeliveryReportResponse = {\n data: DataApi_DataProducts_DeliveryReport;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_DmaFormatIndex = {\n /** The base the indices are against (US). */\n base: string;\n meta: {\n facing: DataApi_DataProducts_FacingVerdict;\n /** What each index means. */\n indices: Record<string, string>;\n };\n rows: Array<DataApi_DataProducts_DmaFormatIndexRow>;\n weeks: Array<string>;\n};\n\nexport type DataApi_DataProducts_DmaFormatIndexResponse = {\n data: DataApi_DataProducts_DmaFormatIndex;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_DmaFormatIndexRow = {\n /** Board-weeks measured. */\n board_weeks: number;\n /** Boards measured. */\n boards: number;\n /** DMA code. */\n dma_code: string;\n /** Why no facing index is served. */\n facing_absent_reason: string | null;\n /** Instrumented legible seconds. */\n facing_base_s: number | null;\n /** Facing seconds per instrumented legible second against the US base, x100. */\n facing_share_index: number | null;\n /** Format. */\n format: string;\n /** Legible seconds per pass against the US base, x100. */\n legible_s_per_pass_index: number | null;\n /** Passes. */\n passes: number;\n /** Passes per board-week against the US base, x100. */\n passes_per_board_week_index: number | null;\n /** Distinct vehicles. */\n vehicles: number;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n};\n\nexport type DataApi_DataProducts_FacingVerdict = {\n /** Instrument the facing seconds are measured with (head_yaw). */\n instrument: string;\n /** The facing gate is open: facing seconds are served. */\n open: boolean;\n /** Why the gate is closed. */\n reason: string | null;\n};\n\nexport type DataApi_DataProducts_FeedPublication = {\n /** Boards in the feed. */\n boards: number;\n /** Cells in the feed. */\n cells: number;\n /** Hash of the feed content. */\n content_sha256: string;\n /** When the feed was due, UTC. */\n due_at: string | null;\n /** Cells due for reissue. */\n due_cells: number;\n /** Feed date. */\n feed_date: string;\n /** When it was published, UTC. */\n published_at: string | null;\n /** Release the feed carries. */\n release_id: string;\n};\n\nexport type DataApi_DataProducts_GeohashTileCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_GeohashTileProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_GeohashTileMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_GeohashTileMeta = {\n bbox?: Array<number>;\n /** Boards summed. */\n boards?: number;\n /** Tiles returned. */\n count?: number;\n facing?: DataApi_DataProducts_FacingVerdict;\n method_mixed_days?: Array<string>;\n /** Geohash precision (5, 6 or 7). */\n precision?: number;\n watermark?: DataApi_DataProducts_Watermark;\n weeks?: Array<string>;\n};\n\nexport type DataApi_DataProducts_GeohashTileProperties = {\n /** Entitled boards in the cell. */\n boards: number;\n /** Instrumented legible seconds. */\n facing_base_s: number | null;\n /** Facing seconds. */\n facing_s: number | null;\n /** Geohash cell. */\n geohash: string;\n /** Legible seconds. */\n legible_s: number;\n /** Passes (face-share weighted). */\n passes: number;\n weeks: Array<DataApi_DataProducts_TileSum>;\n};\n\nexport type DataApi_DataProducts_Geometry = {\n /** RFC 7946 coordinates, [longitude, latitude] order. */\n coordinates: Array<unknown>;\n /** GeoJSON geometry type. */\n type: \"Point\" | \"LineString\" | \"Polygon\" | \"MultiPolygon\" | \"MultiLineString\";\n} | null;\n\nexport type DataApi_DataProducts_LookedShareRow = {\n /** single (one person in the frame) or multi (several, whose direction is a mean). Never pooled. */\n face_stratum: string;\n /** The instrument the row measured with: head_mlkit (head direction on every analysed frame), gaze_fl (eye gaze), head_yaw, shoulder. Never pooled. */\n instrument: string;\n /** Judged seconds the share divides by: the seconds the instrument read a direction. */\n judged_s: number | null;\n /** Expected looked seconds behind the share. */\n looked_s: number | null;\n /** Share of the judged seconds in which an occupant was turned toward this face. Null where nothing was judged. */\n share_of_judged: number | null;\n /** Distinct vehicles behind the row. */\n vehicles: number | null;\n};\n\nexport type DataApi_DataProducts_MeasurementError = {\n /** Machine-readable reason, e.g. invalid_bbox, board_not_found, not_entitled, quota, measurement_unavailable. */\n code: string;\n /** Owner upload refusals (sheet_refused, sheet_empty, log_refused, ssp_venue_conflict, write_failed): the plan or load report the refusal is about, with rows read, refused lines and their reasons, unmatched and ambiguous faces, and for ssp_venue_conflict the `conflicts`. */\n data?: Record<string, unknown>;\n /** What was refused and how to ask again. */\n message: string;\n /** The scopes the key must hold (INSUFFICIENT_SCOPE on the owner upload routes, which need `measurement:write`). */\n required_scopes?: Array<string>;\n status: false;\n};\n\nexport type DataApi_DataProducts_Method = {\n /** Method name (exposure_currency, pass_audience, camera_screen_hour, ...). */\n name: string;\n /** Method version the figures were computed under. */\n version: number | null;\n};\n\nexport type DataApi_DataProducts_MetricAnswer = {\n absent?: Array<Record<string, unknown>>;\n /** Board metrics: the board route's own body (board_measured_impressions_per_spot = /boards/{boardId}/currency; board_pass_audience = /boards/{boardId}/audience with each row's unit and the support behind it). */\n answer?: DataApi_DataProducts_BoardCurrency | {\n /** Board face id. */\n board_id: string;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours?: Record<string, Array<number>>;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_AudienceRow>;\n /** The passes and vehicles the rows rest on, with the window. */\n support: Record<string, unknown> | null;\n window: DataApi_DataProducts_Window;\n } | null | null;\n day_summary?: Record<string, unknown>;\n /** How hours are assigned to dayparts. */\n daypart_basis?: string | null;\n days?: Array<{\n /** Day. */\n day: string;\n /** The source measured the day. */\n measured: boolean;\n /** complete, partial or not_measured. */\n status: string;\n }>;\n /** Demographics metrics: each dimension read, with its readings in the window. */\n dimensions_measured?: Array<{\n /** A demographic dimension the answer reads. */\n dimension: string;\n /** Readings of that dimension in the window. */\n readings_in_window: number;\n }>;\n /** Metric family. */\n family: string;\n /** The filters applied (screens, markets, brands, board_id, by, ...). */\n filters: Record<string, unknown>;\n /** Camera evidence grade. */\n grade?: string | null;\n /** Grain of the rows. */\n grain: string;\n headline: {\n /** Denominator. */\n denominator: string | null;\n /** Headline measure. */\n key: string;\n /** Unit. */\n unit: string;\n };\n /** Label. */\n label: string;\n limits?: Record<string, unknown>;\n measures: Array<DataApi_DataProducts_MetricMeasure>;\n method?: Record<string, unknown> | null;\n /** Approved metric name. */\n metric: \"camera_people_per_screen_hour\" | \"camera_dwell_capped_ms\" | \"camera_head_pose_index\" | \"camera_gaze_pct\" | \"demographic_share\" | \"sensing_census\" | \"board_measured_impressions_per_spot\" | \"board_pass_audience\" | \"same_panel_index\" | \"radio_identifiers_per_person\" | \"creative_sightings\" | \"creative_share_of_voice\" | \"creative_street_presence\" | \"creative_vacancy_rate\" | \"creative_brand_history\" | \"seatbelt_compliance\" | \"seatbelt_unbuckled_ride_rate\";\n /** The population the shares are over. */\n population?: string | null;\n /** The question it answers. */\n question: string;\n /** Rows in the answer. */\n row_count?: number;\n /** One row per grain cell: the grain keys, then every measure of the metric (see the table on this operation), each with the count it is taken over; `absent` lists the measures with no value and why. */\n rows?: Array<Record<string, unknown>>;\n /** The totals over the window, shaped like `rows`: one row when the answer has one key, one row per key when it has several (per brand for creative_share_of_voice, per panel for a panel metric, per dimension value for demographics); null when no day was measured. */\n totals?: Record<string, unknown> | Array<Record<string, unknown>> | null | null;\n /** The window answered: from, to, days, timezone, defaulted (or window_end, window_days for a board metric). */\n window: Record<string, unknown>;\n};\n\nexport type DataApi_DataProducts_MetricAnswerResponse = {\n data: DataApi_DataProducts_MetricAnswer;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricBoardMeasuredImpressionsPerSpotResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n answer?: DataApi_DataProducts_BoardCurrency & Record<string, unknown> | null;\n /** This metric. */\n metric?: \"board_measured_impressions_per_spot\";\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricBoardPassAudienceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** The board route's own body for the board and window asked. */\n answer?: {\n /** Board face id. */\n board_id: string;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours?: Record<string, Array<number>>;\n method: DataApi_DataProducts_Method;\n rows: Array<DataApi_DataProducts_AudienceRow>;\n /** The passes and vehicles the rows rest on, with the window. */\n support: Record<string, unknown> | null;\n window: DataApi_DataProducts_Window;\n } | null;\n /** This metric. */\n metric?: \"board_pass_audience\";\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraDwellCappedMsResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_dwell_capped_ms\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean dwell per window in ms, each window's dwell capped at its own length. Unit: ms. Taken over `dwell_capped_windows`. */\n dwell_capped_ms_mean?: number | null;\n /** Camera windows that carry a start time, the dwell mean's denominator. Unit: windows. */\n dwell_capped_windows?: number | null;\n /** Windows whose reported dwell exceeded their own length and were capped. Unit: windows. */\n dwell_over_window_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean dwell per window in ms, each window's dwell capped at its own length. Unit: ms. Taken over `dwell_capped_windows`. */\n dwell_capped_ms_mean?: number | null;\n /** Camera windows that carry a start time, the dwell mean's denominator. Unit: windows. */\n dwell_capped_windows?: number | null;\n /** Windows whose reported dwell exceeded their own length and were capped. Unit: windows. */\n dwell_over_window_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean dwell per window in ms, each window's dwell capped at its own length. Unit: ms. Taken over `dwell_capped_windows`. */\n dwell_capped_ms_mean?: number | null;\n /** Camera windows that carry a start time, the dwell mean's denominator. Unit: windows. */\n dwell_capped_windows?: number | null;\n /** Windows whose reported dwell exceeded their own length and were capped. Unit: windows. */\n dwell_over_window_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraGazePctResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_gaze_pct\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean on-screen gaze share 0-1 over the windows carrying a gaze reading. Unit: share. Taken over `gaze_pct_windows`. */\n gaze_pct_mean?: number | null;\n /** Windows carrying a gaze reading, the gaze mean's denominator. Unit: windows. */\n gaze_pct_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean on-screen gaze share 0-1 over the windows carrying a gaze reading. Unit: share. Taken over `gaze_pct_windows`. */\n gaze_pct_mean?: number | null;\n /** Windows carrying a gaze reading, the gaze mean's denominator. Unit: windows. */\n gaze_pct_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows. Unit: windows. */\n camera_windows?: number | null;\n /** Mean on-screen gaze share 0-1 over the windows carrying a gaze reading. Unit: share. Taken over `gaze_pct_windows`. */\n gaze_pct_mean?: number | null;\n /** Windows carrying a gaze reading, the gaze mean's denominator. Unit: windows. */\n gaze_pct_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraHeadPoseIndexResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_head_pose_index\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows, the index mean's denominator. Unit: windows. */\n camera_windows?: number | null;\n /** Mean over every camera window of the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (a window without a face reads 0). Unit: index. Taken over `camera_windows`. */\n head_pose_index_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_min?: number | null;\n /** Windows whose head-pose index is above 0 (a pose was read). Unit: windows. */\n head_pose_index_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows, the index mean's denominator. Unit: windows. */\n camera_windows?: number | null;\n /** Mean over every camera window of the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (a window without a face reads 0). Unit: index. Taken over `camera_windows`. */\n head_pose_index_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_min?: number | null;\n /** Windows whose head-pose index is above 0 (a pose was read). Unit: windows. */\n head_pose_index_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows, the index mean's denominator. Unit: windows. */\n camera_windows?: number | null;\n /** Mean over every camera window of the device composite 0.4 x yaw + 0.3 x pitch + 0.3 x eye-open (a window without a face reads 0). Unit: index. Taken over `camera_windows`. */\n head_pose_index_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour head-pose index in the row. Unit: index. Taken over `screen_hours`. */\n head_pose_index_mean_screen_hour_min?: number | null;\n /** Windows whose head-pose index is above 0 (a pose was read). Unit: windows. */\n head_pose_index_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCameraPeoplePerScreenHourResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"camera_people_per_screen_hour\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Camera-graded windows (face_backed or person_backed, ~10 s each). Unit: windows. */\n camera_windows?: number | null;\n /** Mean per-window face reading: the device face_count where it wrote one, else the window mean face count. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_min?: number | null;\n /** Exact 95th percentile of the per-window face reading of one screen-hour; at a coarser grain the answer carries face_count_p95_busiest_screen_hour, the largest screen-hour p95 in the row. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_p95?: number | null;\n /** stats=spread, coarser grains: the mean over the row's screen-hours of each screen-hour's exact p95. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_mean?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour p95 in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_min?: number | null;\n /** Windows whose reading is the device face_count primitive. Unit: windows. */\n face_count_primitive_windows?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Camera-graded windows (face_backed or person_backed, ~10 s each). Unit: windows. */\n camera_windows?: number | null;\n /** Mean per-window face reading: the device face_count where it wrote one, else the window mean face count. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_min?: number | null;\n /** Exact 95th percentile of the per-window face reading of one screen-hour; at a coarser grain the answer carries face_count_p95_busiest_screen_hour, the largest screen-hour p95 in the row. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_p95?: number | null;\n /** stats=spread, coarser grains: the mean over the row's screen-hours of each screen-hour's exact p95. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_mean?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour p95 in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_min?: number | null;\n /** Windows whose reading is the device face_count primitive. Unit: windows. */\n face_count_primitive_windows?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Camera-graded windows (face_backed or person_backed, ~10 s each). Unit: windows. */\n camera_windows?: number | null;\n /** Mean per-window face reading: the device face_count where it wrote one, else the window mean face count. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_mean?: number | null;\n /** stats=spread, coarser grains: the highest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_max?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour mean face reading in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_mean_screen_hour_min?: number | null;\n /** Exact 95th percentile of the per-window face reading of one screen-hour; at a coarser grain the answer carries face_count_p95_busiest_screen_hour, the largest screen-hour p95 in the row. Unit: faces_per_window. Taken over `camera_windows`. */\n face_count_p95?: number | null;\n /** stats=spread, coarser grains: the mean over the row's screen-hours of each screen-hour's exact p95. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_mean?: number | null;\n /** stats=spread, coarser grains: the lowest screen-hour p95 in the row. Unit: faces_per_window. Taken over `screen_hours`. */\n face_count_p95_screen_hour_min?: number | null;\n /** Windows whose reading is the device face_count primitive. Unit: windows. */\n face_count_primitive_windows?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCatalog = {\n metrics: Array<DataApi_DataProducts_MetricCatalogEntry>;\n};\n\nexport type DataApi_DataProducts_MetricCatalogEntry = {\n /** How hours are assigned to dayparts. */\n daypart_basis?: string | null;\n /** Default grain. */\n default_grain: string;\n /** Default fleet grain. */\n default_grain_fleet: string | null;\n dimensions?: Array<string>;\n /** camera, demographics, census, board, panel, calibration, creative or seatbelt. */\n family: string;\n grades?: Array<string> | null;\n grains: Array<string>;\n headline: {\n /** Denominator. */\n denominator: string | null;\n /** Headline measure. */\n key: string;\n /** Unit. */\n unit: string;\n };\n /** Label. */\n label: string;\n limits: {\n /** Most rows per answer. */\n max_rows: number;\n /** Most screens per request. */\n max_screens: number;\n /** Longest window per request, days. */\n max_window_days: number | null;\n };\n measures: Array<DataApi_DataProducts_MetricMeasure>;\n method?: {\n /** Method. */\n name: string;\n /** Version. */\n version: number | null;\n } | null;\n /** Approved metric name. */\n metric: \"camera_people_per_screen_hour\" | \"camera_dwell_capped_ms\" | \"camera_head_pose_index\" | \"camera_gaze_pct\" | \"demographic_share\" | \"sensing_census\" | \"board_measured_impressions_per_spot\" | \"board_pass_audience\" | \"same_panel_index\" | \"radio_identifiers_per_person\" | \"creative_sightings\" | \"creative_share_of_voice\" | \"creative_street_presence\" | \"creative_vacancy_rate\" | \"creative_brand_history\" | \"seatbelt_compliance\" | \"seatbelt_unbuckled_ride_rate\";\n params: Array<string>;\n populations?: Array<string>;\n /** The question the metric answers. */\n question: string;\n stats?: {\n allowed: Array<string>;\n default: Array<string>;\n } | null;\n};\n\nexport type DataApi_DataProducts_MetricCatalogResponse = {\n data: DataApi_DataProducts_MetricCatalog;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeBrandHistoryResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_brand_history\";\n /** One row per grain cell. */\n rows?: Array<{\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights?: number | null;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Taken over `attention_flights`. */\n attention_passes?: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points?: number | null;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Taken over `flights_active`. */\n brand_face_days?: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Taken over `flights_active`. */\n brand_face_share?: number | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched?: number | null;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed?: number | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active?: number | null;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started?: number | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_legible_s?: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_looked_s?: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Taken over `attention_flights`. */\n head_legible_s?: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Taken over `attention_flights`. */\n head_looked_s?: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_ad_face_days?: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights?: number | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_face_days?: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Taken over `market_ad_flights`. */\n market_face_share?: number | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights?: number | null;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. */\n market_sightings?: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. Taken over `market_face_days`. */\n market_vacancy_face_day_share?: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. Taken over `market_sightings`. */\n market_vacancy_share?: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. Taken over `market_weighted_sightings`. */\n market_vacancy_share_drawn_weighted?: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. */\n market_vacancy_sightings?: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. */\n market_vacant_board_faces?: number | null;\n /** Their face-days in the period. Unit: face_days. Taken over `market_vacant_flights`. */\n market_vacant_face_days?: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights?: number | null;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Taken over `media_value_priced_faces`. */\n media_value_floor_usd?: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces?: number | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. Taken over `market_named_flights`. */\n share_of_named_voice?: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. Taken over `market_ad_flights`. */\n share_of_voice?: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days?: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days_se?: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. Taken over `market_face_share`. */\n share_of_voice_face_weighted?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights?: number | null;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Taken over `attention_flights`. */\n attention_passes?: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points?: number | null;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Taken over `flights_active`. */\n brand_face_days?: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Taken over `flights_active`. */\n brand_face_share?: number | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched?: number | null;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed?: number | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active?: number | null;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started?: number | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_legible_s?: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_looked_s?: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Taken over `attention_flights`. */\n head_legible_s?: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Taken over `attention_flights`. */\n head_looked_s?: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_ad_face_days?: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights?: number | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_face_days?: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Taken over `market_ad_flights`. */\n market_face_share?: number | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights?: number | null;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. */\n market_sightings?: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. Taken over `market_face_days`. */\n market_vacancy_face_day_share?: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. Taken over `market_sightings`. */\n market_vacancy_share?: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. Taken over `market_weighted_sightings`. */\n market_vacancy_share_drawn_weighted?: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. */\n market_vacancy_sightings?: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. */\n market_vacant_board_faces?: number | null;\n /** Their face-days in the period. Unit: face_days. Taken over `market_vacant_flights`. */\n market_vacant_face_days?: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights?: number | null;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Taken over `media_value_priced_faces`. */\n media_value_floor_usd?: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces?: number | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. Taken over `market_named_flights`. */\n share_of_named_voice?: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. Taken over `market_ad_flights`. */\n share_of_voice?: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days?: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days_se?: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. Taken over `market_face_share`. */\n share_of_voice_face_weighted?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** The brand's flights on registered faces that started in the period with a completion: the flights whose passes the attention columns sum, each once. Unit: flights. */\n attention_flights?: number | null;\n /** The board passes past those flights (inside each read span, +/- 600 s). Unit: passes. Taken over `attention_flights`. */\n attention_passes?: number | null;\n /** Distinct registered board faces the brand ran on in the period. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct unregistered board points the brand ran on in the period. Unit: board_points. */\n board_points?: number | null;\n /** The days the brand's flights ran on their faces inside the period: each flight's estimated run (creative_flight_completion est_start..est_end, clipped at now; its read span without a completion), unweighted. Unit: face_days. Taken over `flights_active`. */\n brand_face_days?: number | null;\n /** The brand's flights weighted by their share of the face's reads: about 1 on a static face, 1/loop on a digital one. Unit: flights. Taken over `flights_active`. */\n brand_face_share?: number | null;\n /** The brand's creatives whose first flight in the market (the fleet, on a fleet grain) began in the period. Unit: creatives. */\n creatives_launched?: number | null;\n /** Of creatives_launched, those whose first flight's earlier looks would have caught it: the completion's miss_before <= 0.05. Unit: creatives. */\n creatives_launched_confirmed?: number | null;\n /** The brand's flights overlapping the period: one creative's run on one registered face or unregistered board point. Unit: flights. */\n flights_active?: number | null;\n /** Of those, the flights that began in the period. Unit: flights. */\n flights_started?: number | null;\n /** Eye-gaze legible seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_legible_s?: number | null;\n /** Eye-gaze looked seconds (gaze_fl) over those passes. Unit: seconds. Taken over `attention_flights`. */\n gaze_looked_s?: number | null;\n /** Head-pose legible seconds (head_mlkit) over those passes. Unit: seconds. Taken over `attention_flights`. */\n head_legible_s?: number | null;\n /** Head-pose looked seconds (head_mlkit) over those passes. Never pooled with gaze. Unit: seconds. Taken over `attention_flights`. */\n head_looked_s?: number | null;\n /** Every ad flight's face-days in the market and period: the face-day share's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_ad_face_days?: number | null;\n /** Every ad flight active in the market and period: registered faces and unregistered points, named or not. The share of voice denominator. Under slices, every ad flight of the row's slice: its period and geography cut by every slice the request names, and narrowed by every slice filter; every market_* count is the slice's. Unit: flights. */\n market_ad_flights?: number | null;\n /** Of the market's sightings, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Ad and vacant face-days together: the face-day vacancy's denominator. Unit: face_days. Taken over `market_ad_flights`. */\n market_face_days?: number | null;\n /** Every ad flight in the market and period, weighted the same way. Unit: flights. Taken over `market_ad_flights`. */\n market_face_share?: number | null;\n /** Of the market's ad flights, those of a named brand: the named share's denominator, steady as label coverage grows. Unit: flights. */\n market_named_flights?: number | null;\n /** Every still-reader sighting in the market and period: the vacancy denominator (creative_vacancy_rate's own count, rolled to the period). NULL where board_creative_sighting (400-day TTL) holds none of the period. Under slices, the vacancy is cut by where-it-ran slices only (a vacant face has no brand): each sighting placed by its read's face. Unit: sightings. */\n market_sightings?: number | null;\n /** market_vacant_face_days / market_face_days: the market's vacancy in face-days, beside the sighting vacancy, never in place of it. Unit: share. Taken over `market_face_days`. */\n market_vacancy_face_day_share?: number | null;\n /** market_vacancy_sightings / market_sightings: the market's vacancy in the period, each sighting counted once, the same on every brand row of the market (creative_vacancy_rate's vacancy_share). Unit: share. Taken over `market_sightings`. */\n market_vacancy_share?: number | null;\n /** The design-weighted vacancy: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into market_vacancy_share. Unit: share. Taken over `market_weighted_sightings`. */\n market_vacancy_share_drawn_weighted?: number | null;\n /** Of those, the sightings of a face carrying no advertiser. Unit: sightings. */\n market_vacancy_sightings?: number | null;\n /** Its vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant in the market and period. Unit: board_faces. */\n market_vacant_board_faces?: number | null;\n /** Their face-days in the period. Unit: face_days. Taken over `market_vacant_flights`. */\n market_vacant_face_days?: number | null;\n /** The vacant spells (creative_flight.vacant = 1) active in the market and period. Unit: flights. */\n market_vacant_flights?: number | null;\n /** The market's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** Floor-priced media value: floor CPM / 1000 x modelled daily impressions per face-day, each face-day split among the flights estimated on the face that day, never fewer than its interleave set nor, on a digital face, the creatives read on it in the period, over the brand's flights on faces with a floor and impressions as of the flight's first day. An asking price, never a cleared one. Unit: usd. Taken over `media_value_priced_faces`. */\n media_value_floor_usd?: number | null;\n /** The faces the floor-priced value is priced on. Unit: board_faces. */\n media_value_priced_faces?: number | null;\n /** flights_active / market_named_flights: the brand's share of the named brands' flights in the market and period (creative_share_of_voice's named denominator, over flights on faces and points). NULL on the unnamed row. Unit: share. Taken over `market_named_flights`. */\n share_of_named_voice?: number | null;\n /** flights_active / market_ad_flights: the brand's share of every ad flight in the market and period, on registered faces AND unregistered points (creative_share_of_voice counts sightings on registered faces only). Unit: share. Taken over `market_ad_flights`. */\n share_of_voice?: number | null;\n /** brand_face_days / market_ad_face_days: the brand's share of the market's ad face-days. Never mixed into share_of_voice. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days?: number | null;\n /** The face-day share's standard error: the ratio's delta-method SE clustered by face over the market's faces. NULL under two faces. Unit: share. Taken over `market_ad_face_days`. */\n share_of_voice_face_days_se?: number | null;\n /** brand_face_share / market_face_share: the share of voice with a digital loop's flights weighted by their share of its reads. Never mixed into share_of_voice. Unit: share. Taken over `market_face_share`. */\n share_of_voice_face_weighted?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeShareOfVoiceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_share_of_voice\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct board faces the brand was sighted on. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings on registered board faces. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings on registered board faces in the key: the headline denominator. Unit: sightings. */\n market_sightings?: number | null;\n /** Every named brand's drawn sightings weighted by 1 / inclusion_probability: the weighted share's denominator. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** brand_sightings / market_sightings: the brand's share of every named brand's sightings on registered board faces, each counted once. Unit: share. Taken over `market_sightings`. */\n share?: number | null;\n /** The design-weighted share: the brand's drawn sightings weighted by 1 / inclusion_probability over every named brand's. Never mixed into share. Unit: share. Taken over `market_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct board faces the brand was sighted on. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings on registered board faces. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings on registered board faces in the key: the headline denominator. Unit: sightings. */\n market_sightings?: number | null;\n /** Every named brand's drawn sightings weighted by 1 / inclusion_probability: the weighted share's denominator. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** brand_sightings / market_sightings: the brand's share of every named brand's sightings on registered board faces, each counted once. Unit: share. Taken over `market_sightings`. */\n share?: number | null;\n /** The design-weighted share: the brand's drawn sightings weighted by 1 / inclusion_probability over every named brand's. Never mixed into share. Unit: share. Taken over `market_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct board faces the brand was sighted on. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings on registered board faces. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n market_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings on registered board faces in the key: the headline denominator. Unit: sightings. */\n market_sightings?: number | null;\n /** Every named brand's drawn sightings weighted by 1 / inclusion_probability: the weighted share's denominator. Unit: sightings. Taken over `market_drawn_sightings`. */\n market_weighted_sightings?: number | null;\n /** brand_sightings / market_sightings: the brand's share of every named brand's sightings on registered board faces, each counted once. Unit: share. Taken over `market_sightings`. */\n share?: number | null;\n /** The design-weighted share: the brand's drawn sightings weighted by 1 / inclusion_probability over every named brand's. Never mixed into share. Unit: share. Taken over `market_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeSightingsResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_sightings\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct board faces with a matched sighting. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct brands sighted (the resolved brand, else the name as read). Unit: brands. */\n brands?: number | null;\n /** Distinct cabs whose stills carried a sighting. Unit: vehicles. */\n cabs?: number | null;\n /** Sightings carrying an inclusion probability (the still reader's). Unit: sightings. */\n drawn_sightings?: number | null;\n /** Sightings attributed to the board face the cab was passing. Unit: sightings. */\n matched_sightings?: number | null;\n /** Ads read off the stills in the key and source: one per ad per reading. Unit: sightings. */\n sightings?: number | null;\n /** Sightings on no face we hold, kept with the cab position, heading and side. Unit: sightings. */\n unmatched_sightings?: number | null;\n /** Sightings of a face carrying no advertiser. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** The still reader's sightings weighted by 1 / inclusion_probability: the sightings of the whole frame the draw represents. NULL on the vlm_text source. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct board faces with a matched sighting. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct brands sighted (the resolved brand, else the name as read). Unit: brands. */\n brands?: number | null;\n /** Distinct cabs whose stills carried a sighting. Unit: vehicles. */\n cabs?: number | null;\n /** Sightings carrying an inclusion probability (the still reader's). Unit: sightings. */\n drawn_sightings?: number | null;\n /** Sightings attributed to the board face the cab was passing. Unit: sightings. */\n matched_sightings?: number | null;\n /** Ads read off the stills in the key and source: one per ad per reading. Unit: sightings. */\n sightings?: number | null;\n /** Sightings on no face we hold, kept with the cab position, heading and side. Unit: sightings. */\n unmatched_sightings?: number | null;\n /** Sightings of a face carrying no advertiser. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** The still reader's sightings weighted by 1 / inclusion_probability: the sightings of the whole frame the draw represents. NULL on the vlm_text source. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct board faces with a matched sighting. Unit: board_faces. */\n board_faces?: number | null;\n /** Distinct brands sighted (the resolved brand, else the name as read). Unit: brands. */\n brands?: number | null;\n /** Distinct cabs whose stills carried a sighting. Unit: vehicles. */\n cabs?: number | null;\n /** Sightings carrying an inclusion probability (the still reader's). Unit: sightings. */\n drawn_sightings?: number | null;\n /** Sightings attributed to the board face the cab was passing. Unit: sightings. */\n matched_sightings?: number | null;\n /** Ads read off the stills in the key and source: one per ad per reading. Unit: sightings. */\n sightings?: number | null;\n /** Sightings on no face we hold, kept with the cab position, heading and side. Unit: sightings. */\n unmatched_sightings?: number | null;\n /** Sightings of a face carrying no advertiser. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** The still reader's sightings weighted by 1 / inclusion_probability: the sightings of the whole frame the draw represents. NULL on the vlm_text source. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeStreetPresenceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_street_presence\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct registered board faces the brand was sighted on in the class. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings in the surface class. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings in the class weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n class_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings in the key and surface class: the headline denominator. Unit: sightings. */\n class_sightings?: number | null;\n /** Every named brand's drawn sightings in the class, weighted: the weighted share's denominator. Unit: sightings. Taken over `class_drawn_sightings`. */\n class_weighted_sightings?: number | null;\n /** brand_sightings / class_sightings: the brand's share of every named brand's sightings in the key and surface class (street = every surface), each counted once. Unit: share. Taken over `class_sightings`. */\n share?: number | null;\n /** The design-weighted share: drawn sightings weighted by 1 / inclusion_probability. Never mixed into share. Unit: share. Taken over `class_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct registered board faces the brand was sighted on in the class. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings in the surface class. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings in the class weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n class_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings in the key and surface class: the headline denominator. Unit: sightings. */\n class_sightings?: number | null;\n /** Every named brand's drawn sightings in the class, weighted: the weighted share's denominator. Unit: sightings. Taken over `class_drawn_sightings`. */\n class_weighted_sightings?: number | null;\n /** brand_sightings / class_sightings: the brand's share of every named brand's sightings in the key and surface class (street = every surface), each counted once. Unit: share. Taken over `class_sightings`. */\n share?: number | null;\n /** The design-weighted share: drawn sightings weighted by 1 / inclusion_probability. Never mixed into share. Unit: share. Taken over `class_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct registered board faces the brand was sighted on in the class. Unit: board_faces. */\n board_faces?: number | null;\n /** Of the brand's sightings, those with an inclusion probability. Unit: sightings. */\n brand_drawn_sightings?: number | null;\n /** The brand's still-reader sightings in the surface class. Unit: sightings. */\n brand_sightings?: number | null;\n /** The brand's drawn sightings in the class weighted by 1 / inclusion_probability. Unit: sightings. Taken over `brand_drawn_sightings`. */\n brand_weighted_sightings?: number | null;\n /** Of every named brand's, those with an inclusion probability. Unit: sightings. */\n class_drawn_sightings?: number | null;\n /** Every named brand's still-reader sightings in the key and surface class: the headline denominator. Unit: sightings. */\n class_sightings?: number | null;\n /** Every named brand's drawn sightings in the class, weighted: the weighted share's denominator. Unit: sightings. Taken over `class_drawn_sightings`. */\n class_weighted_sightings?: number | null;\n /** brand_sightings / class_sightings: the brand's share of every named brand's sightings in the key and surface class (street = every surface), each counted once. Unit: share. Taken over `class_sightings`. */\n share?: number | null;\n /** The design-weighted share: drawn sightings weighted by 1 / inclusion_probability. Never mixed into share. Unit: share. Taken over `class_weighted_sightings`. */\n share_drawn_weighted?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricCreativeVacancyRateResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"creative_vacancy_rate\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Of those, the sightings with an inclusion probability. Unit: sightings. */\n drawn_sightings?: number | null;\n /** Every still-reader sighting in the key: the headline denominator. Unit: sightings. */\n sightings?: number | null;\n /** vacancy_sightings / sightings: the share of the still reader's sightings that were vacant faces, each counted once. Unit: share. Taken over `sightings`. */\n vacancy_share?: number | null;\n /** The design-weighted share: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into vacancy_share. Unit: share. Taken over `weighted_sightings`. */\n vacancy_share_drawn_weighted?: number | null;\n /** Still-reader sightings of a vacant face. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** Vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant. Unit: board_faces. */\n vacant_board_faces?: number | null;\n /** Every drawn still-reader sighting weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Of those, the sightings with an inclusion probability. Unit: sightings. */\n drawn_sightings?: number | null;\n /** Every still-reader sighting in the key: the headline denominator. Unit: sightings. */\n sightings?: number | null;\n /** vacancy_sightings / sightings: the share of the still reader's sightings that were vacant faces, each counted once. Unit: share. Taken over `sightings`. */\n vacancy_share?: number | null;\n /** The design-weighted share: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into vacancy_share. Unit: share. Taken over `weighted_sightings`. */\n vacancy_share_drawn_weighted?: number | null;\n /** Still-reader sightings of a vacant face. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** Vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant. Unit: board_faces. */\n vacant_board_faces?: number | null;\n /** Every drawn still-reader sighting weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Of those, the sightings with an inclusion probability. Unit: sightings. */\n drawn_sightings?: number | null;\n /** Every still-reader sighting in the key: the headline denominator. Unit: sightings. */\n sightings?: number | null;\n /** vacancy_sightings / sightings: the share of the still reader's sightings that were vacant faces, each counted once. Unit: share. Taken over `sightings`. */\n vacancy_share?: number | null;\n /** The design-weighted share: vacant drawn sightings over every drawn sighting, each weighted by 1 / inclusion_probability. Never mixed into vacancy_share. Unit: share. Taken over `weighted_sightings`. */\n vacancy_share_drawn_weighted?: number | null;\n /** Still-reader sightings of a vacant face. Unit: sightings. */\n vacancy_sightings?: number | null;\n /** Vacant-face drawn sightings weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n vacancy_weighted_sightings?: number | null;\n /** Distinct matched board faces sighted vacant. Unit: board_faces. */\n vacant_board_faces?: number | null;\n /** Every drawn still-reader sighting weighted by 1 / inclusion_probability. Unit: sightings. Taken over `drawn_sightings`. */\n weighted_sightings?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricDemographicShareResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"demographic_share\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Every reading of the dimension in the key, the share's denominator. Unit: readings. */\n dimension_readings?: number | null;\n /** Classifier readings of the value: sum(count) over the key. Unit: readings. */\n readings?: number | null;\n /** Distinct screens carrying the value in the key. Unit: screens. */\n screens?: number | null;\n /** The value's readings over every reading of the dimension in the same key. Unit: share. Taken over `dimension_readings`. */\n share?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Every reading of the dimension in the key, the share's denominator. Unit: readings. */\n dimension_readings?: number | null;\n /** Classifier readings of the value: sum(count) over the key. Unit: readings. */\n readings?: number | null;\n /** Distinct screens carrying the value in the key. Unit: screens. */\n screens?: number | null;\n /** The value's readings over every reading of the dimension in the same key. Unit: share. Taken over `dimension_readings`. */\n share?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Every reading of the dimension in the key, the share's denominator. Unit: readings. */\n dimension_readings?: number | null;\n /** Classifier readings of the value: sum(count) over the key. Unit: readings. */\n readings?: number | null;\n /** Distinct screens carrying the value in the key. Unit: screens. */\n screens?: number | null;\n /** The value's readings over every reading of the dimension in the same key. Unit: share. Taken over `dimension_readings`. */\n share?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricMeasure = {\n /** The count the measure is taken over. */\n denominator: string | null;\n /** What the measure counts. */\n description: string;\n /** Measure key, a column of the rows. */\n key: string;\n /** Unit (share, seconds, faces_per_window, flights, sightings, readings, vehicles, usd, ...). */\n unit: string;\n};\n\nexport type DataApi_DataProducts_MetricRadioIdentifiersPerPersonResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"radio_identifiers_per_person\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Passenger-candidate Bluetooth keys near the tablet in one radio delivery, each ride's most, summed over the panel rides (the driver's phone and the vehicle's own devices removed by their role). Unit: identifiers. */\n keys?: number | null;\n /** Trips both instruments read: the ratio's rides. Unit: rides. */\n panel_rides?: number | null;\n /** People the cabin camera read per ride (the 90th percentile over its windows of the persons reading), summed over the panel rides. Unit: persons. */\n persons?: number | null;\n /** keys / persons over the panel rides: trips (not parked presence) that both the cabin radio and the cabin camera read. Unit: identifiers_per_person. Taken over `persons`. */\n radio_identifiers_per_person?: number | null;\n /** Upper end of the 95% interval. Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_high?: number | null;\n /** Lower end of the 95% interval: ratio estimator, vehicle-clustered linearisation, normal approximation, intersected with [0, inf). Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_low?: number | null;\n /** Every ride of the key, the panel's and the rest. Unit: rides. */\n rides?: number | null;\n /** Vehicles with a panel ride: the clusters of the interval. Unit: vehicles. */\n vehicles?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Passenger-candidate Bluetooth keys near the tablet in one radio delivery, each ride's most, summed over the panel rides (the driver's phone and the vehicle's own devices removed by their role). Unit: identifiers. */\n keys?: number | null;\n /** Trips both instruments read: the ratio's rides. Unit: rides. */\n panel_rides?: number | null;\n /** People the cabin camera read per ride (the 90th percentile over its windows of the persons reading), summed over the panel rides. Unit: persons. */\n persons?: number | null;\n /** keys / persons over the panel rides: trips (not parked presence) that both the cabin radio and the cabin camera read. Unit: identifiers_per_person. Taken over `persons`. */\n radio_identifiers_per_person?: number | null;\n /** Upper end of the 95% interval. Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_high?: number | null;\n /** Lower end of the 95% interval: ratio estimator, vehicle-clustered linearisation, normal approximation, intersected with [0, inf). Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_low?: number | null;\n /** Every ride of the key, the panel's and the rest. Unit: rides. */\n rides?: number | null;\n /** Vehicles with a panel ride: the clusters of the interval. Unit: vehicles. */\n vehicles?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Passenger-candidate Bluetooth keys near the tablet in one radio delivery, each ride's most, summed over the panel rides (the driver's phone and the vehicle's own devices removed by their role). Unit: identifiers. */\n keys?: number | null;\n /** Trips both instruments read: the ratio's rides. Unit: rides. */\n panel_rides?: number | null;\n /** People the cabin camera read per ride (the 90th percentile over its windows of the persons reading), summed over the panel rides. Unit: persons. */\n persons?: number | null;\n /** keys / persons over the panel rides: trips (not parked presence) that both the cabin radio and the cabin camera read. Unit: identifiers_per_person. Taken over `persons`. */\n radio_identifiers_per_person?: number | null;\n /** Upper end of the 95% interval. Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_high?: number | null;\n /** Lower end of the 95% interval: ratio estimator, vehicle-clustered linearisation, normal approximation, intersected with [0, inf). Unit: identifiers_per_person. Taken over `vehicles`. */\n radio_identifiers_per_person_low?: number | null;\n /** Every ride of the key, the panel's and the rest. Unit: rides. */\n rides?: number | null;\n /** Vehicles with a panel ride: the clusters of the interval. Unit: vehicles. */\n vehicles?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSamePanelIndexResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"same_panel_index\";\n /** One row per grain cell. */\n rows?: Array<{\n /** The same-panel series: the product of the monthly indexes from the answer's first month, which reads 1. Unit: ratio. Taken over `same_panel_screens`. */\n chain_index?: number | null;\n /** Days of the month the panel holds (a month in progress holds fewer). Unit: days. */\n days_built?: number | null;\n /** Camera panel: faces per occupied camera window (a face- or person-backed window: the group in view while someone is in view, not audience per unit time) this month over the same-panel screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window?: number | null;\n /** Camera panel: faces per occupied camera window this month over every member. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_panel?: number | null;\n /** Camera panel: faces per occupied camera window the month before over the same screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_previous?: number | null;\n /** Radio panel: visitor identifiers concurrent in a 6-minute slot this month over the same-panel screens: audience per unit time. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot?: number | null;\n /** Radio panel: the same this month over every member. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_panel?: number | null;\n /** Radio panel: the same the month before over the same screens. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_previous?: number | null;\n /** Members of the panel the month before on the evidence kinds both months hold (evidence_compared): the retention's denominator. Unit: screens. */\n previous_comparable_screens?: number | null;\n /** Members of the panel the month before. Unit: screens. */\n previous_screens?: number | null;\n /** same_panel_screens / previous_comparable_screens, with a Wilson interval: the previous month's members still in the panel, on the evidence both months hold (heartbeat camera-on minutes start 2026-08-26, device inference rows are held 90 days). Unit: share. Taken over `previous_comparable_screens`. */\n retained_share?: number | null;\n /** The month's rate over the previous month's, both over the screens in the panel both months. 1 is no change. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index?: number | null;\n /** Upper end of the 95% interval. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_high?: number | null;\n /** Lower end of the 95% interval: two ratio estimators over the same screens, screen-clustered linearisation on the log scale. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_low?: number | null;\n /** Members both months, each month counted on the evidence kinds both months hold (evidence_compared): the screens the index compares. Unit: screens. */\n same_panel_screens?: number | null;\n /** Members of the panel this month. Unit: screens. */\n screens?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** The same-panel series: the product of the monthly indexes from the answer's first month, which reads 1. Unit: ratio. Taken over `same_panel_screens`. */\n chain_index?: number | null;\n /** Days of the month the panel holds (a month in progress holds fewer). Unit: days. */\n days_built?: number | null;\n /** Camera panel: faces per occupied camera window (a face- or person-backed window: the group in view while someone is in view, not audience per unit time) this month over the same-panel screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window?: number | null;\n /** Camera panel: faces per occupied camera window this month over every member. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_panel?: number | null;\n /** Camera panel: faces per occupied camera window the month before over the same screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_previous?: number | null;\n /** Radio panel: visitor identifiers concurrent in a 6-minute slot this month over the same-panel screens: audience per unit time. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot?: number | null;\n /** Radio panel: the same this month over every member. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_panel?: number | null;\n /** Radio panel: the same the month before over the same screens. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_previous?: number | null;\n /** Members of the panel the month before on the evidence kinds both months hold (evidence_compared): the retention's denominator. Unit: screens. */\n previous_comparable_screens?: number | null;\n /** Members of the panel the month before. Unit: screens. */\n previous_screens?: number | null;\n /** same_panel_screens / previous_comparable_screens, with a Wilson interval: the previous month's members still in the panel, on the evidence both months hold (heartbeat camera-on minutes start 2026-08-26, device inference rows are held 90 days). Unit: share. Taken over `previous_comparable_screens`. */\n retained_share?: number | null;\n /** The month's rate over the previous month's, both over the screens in the panel both months. 1 is no change. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index?: number | null;\n /** Upper end of the 95% interval. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_high?: number | null;\n /** Lower end of the 95% interval: two ratio estimators over the same screens, screen-clustered linearisation on the log scale. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_low?: number | null;\n /** Members both months, each month counted on the evidence kinds both months hold (evidence_compared): the screens the index compares. Unit: screens. */\n same_panel_screens?: number | null;\n /** Members of the panel this month. Unit: screens. */\n screens?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** The same-panel series: the product of the monthly indexes from the answer's first month, which reads 1. Unit: ratio. Taken over `same_panel_screens`. */\n chain_index?: number | null;\n /** Days of the month the panel holds (a month in progress holds fewer). Unit: days. */\n days_built?: number | null;\n /** Camera panel: faces per occupied camera window (a face- or person-backed window: the group in view while someone is in view, not audience per unit time) this month over the same-panel screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window?: number | null;\n /** Camera panel: faces per occupied camera window this month over every member. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_panel?: number | null;\n /** Camera panel: faces per occupied camera window the month before over the same screens. Unit: faces_per_window. Taken over `camera_windows`. */\n faces_per_occupied_window_previous?: number | null;\n /** Radio panel: visitor identifiers concurrent in a 6-minute slot this month over the same-panel screens: audience per unit time. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot?: number | null;\n /** Radio panel: the same this month over every member. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_panel?: number | null;\n /** Radio panel: the same the month before over the same screens. Unit: identifiers_per_slot. Taken over `radio_slots`. */\n identifiers_per_slot_previous?: number | null;\n /** Members of the panel the month before on the evidence kinds both months hold (evidence_compared): the retention's denominator. Unit: screens. */\n previous_comparable_screens?: number | null;\n /** Members of the panel the month before. Unit: screens. */\n previous_screens?: number | null;\n /** same_panel_screens / previous_comparable_screens, with a Wilson interval: the previous month's members still in the panel, on the evidence both months hold (heartbeat camera-on minutes start 2026-08-26, device inference rows are held 90 days). Unit: share. Taken over `previous_comparable_screens`. */\n retained_share?: number | null;\n /** The month's rate over the previous month's, both over the screens in the panel both months. 1 is no change. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index?: number | null;\n /** Upper end of the 95% interval. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_high?: number | null;\n /** Lower end of the 95% interval: two ratio estimators over the same screens, screen-clustered linearisation on the log scale. Unit: ratio. Taken over `same_panel_screens`. */\n same_panel_index_low?: number | null;\n /** Members both months, each month counted on the evidence kinds both months hold (evidence_compared): the screens the index compares. Unit: screens. */\n same_panel_screens?: number | null;\n /** Members of the panel this month. Unit: screens. */\n screens?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSeatbeltComplianceResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"seatbelt_compliance\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Every visible rear rider buckled. Unit: readings. */\n all_buckled_readings?: number | null;\n /** The drawn all_buckled readings weighted by 1 / inclusion_probability. Unit: readings. Taken over `drawn_determined_readings`. */\n all_buckled_weighted_readings?: number | null;\n /** Distinct cabs with a seatbelt reading. Unit: vehicles. */\n cabs?: number | null;\n /** Riders present, no strap could be judged: in no denominator. Unit: readings. */\n cannot_determine_readings?: number | null;\n /** all_buckled_readings / determined_readings: every reading that judged a strap (all_buckled, some_unbuckled, none_buckled) counted once, drawn or not. Unit: share. Taken over `determined_readings`. */\n compliance?: number | null;\n /** The design-weighted check: all_buckled over the readings the vision governor drew, each weighted by 1 / inclusion_probability. Never mixed into compliance. Unit: share. Taken over `determined_weighted_readings`. */\n compliance_drawn_weighted?: number | null;\n /** The stratum with no draw (board-burst and UTC-governor admissions): all_buckled over its readings that judged a strap. Unit: share. Taken over `not_drawn_determined_readings`. */\n compliance_not_drawn?: number | null;\n /** The readings that judged a strap: the headline denominator. Unit: readings. */\n determined_readings?: number | null;\n /** The drawn determined readings weighted by 1 / inclusion_probability: the check's denominator. Unit: readings. Taken over `drawn_determined_readings`. */\n determined_weighted_readings?: number | null;\n /** Of those, the readings the vision governor drew (an inclusion probability). Unit: readings. */\n drawn_determined_readings?: number | null;\n /** The back seat was empty: in no denominator. Unit: readings. */\n no_rider_readings?: number | null;\n /** Rear riders present, no strap on any of them. Unit: readings. */\n none_buckled_readings?: number | null;\n /** The all_buckled readings with no draw. Unit: readings. */\n not_drawn_all_buckled_readings?: number | null;\n /** Of those, the readings with no draw (NULL inclusion probability). Unit: readings. */\n not_drawn_determined_readings?: number | null;\n /** not_drawn_determined_readings / determined_readings: the share of judged readings with no draw. A capture-rate change moves it. Unit: share. Taken over `determined_readings`. */\n not_drawn_share?: number | null;\n /** At least one rear rider buckled and one not. Unit: readings. */\n some_unbuckled_readings?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Every visible rear rider buckled. Unit: readings. */\n all_buckled_readings?: number | null;\n /** The drawn all_buckled readings weighted by 1 / inclusion_probability. Unit: readings. Taken over `drawn_determined_readings`. */\n all_buckled_weighted_readings?: number | null;\n /** Distinct cabs with a seatbelt reading. Unit: vehicles. */\n cabs?: number | null;\n /** Riders present, no strap could be judged: in no denominator. Unit: readings. */\n cannot_determine_readings?: number | null;\n /** all_buckled_readings / determined_readings: every reading that judged a strap (all_buckled, some_unbuckled, none_buckled) counted once, drawn or not. Unit: share. Taken over `determined_readings`. */\n compliance?: number | null;\n /** The design-weighted check: all_buckled over the readings the vision governor drew, each weighted by 1 / inclusion_probability. Never mixed into compliance. Unit: share. Taken over `determined_weighted_readings`. */\n compliance_drawn_weighted?: number | null;\n /** The stratum with no draw (board-burst and UTC-governor admissions): all_buckled over its readings that judged a strap. Unit: share. Taken over `not_drawn_determined_readings`. */\n compliance_not_drawn?: number | null;\n /** The readings that judged a strap: the headline denominator. Unit: readings. */\n determined_readings?: number | null;\n /** The drawn determined readings weighted by 1 / inclusion_probability: the check's denominator. Unit: readings. Taken over `drawn_determined_readings`. */\n determined_weighted_readings?: number | null;\n /** Of those, the readings the vision governor drew (an inclusion probability). Unit: readings. */\n drawn_determined_readings?: number | null;\n /** The back seat was empty: in no denominator. Unit: readings. */\n no_rider_readings?: number | null;\n /** Rear riders present, no strap on any of them. Unit: readings. */\n none_buckled_readings?: number | null;\n /** The all_buckled readings with no draw. Unit: readings. */\n not_drawn_all_buckled_readings?: number | null;\n /** Of those, the readings with no draw (NULL inclusion probability). Unit: readings. */\n not_drawn_determined_readings?: number | null;\n /** not_drawn_determined_readings / determined_readings: the share of judged readings with no draw. A capture-rate change moves it. Unit: share. Taken over `determined_readings`. */\n not_drawn_share?: number | null;\n /** At least one rear rider buckled and one not. Unit: readings. */\n some_unbuckled_readings?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Every visible rear rider buckled. Unit: readings. */\n all_buckled_readings?: number | null;\n /** The drawn all_buckled readings weighted by 1 / inclusion_probability. Unit: readings. Taken over `drawn_determined_readings`. */\n all_buckled_weighted_readings?: number | null;\n /** Distinct cabs with a seatbelt reading. Unit: vehicles. */\n cabs?: number | null;\n /** Riders present, no strap could be judged: in no denominator. Unit: readings. */\n cannot_determine_readings?: number | null;\n /** all_buckled_readings / determined_readings: every reading that judged a strap (all_buckled, some_unbuckled, none_buckled) counted once, drawn or not. Unit: share. Taken over `determined_readings`. */\n compliance?: number | null;\n /** The design-weighted check: all_buckled over the readings the vision governor drew, each weighted by 1 / inclusion_probability. Never mixed into compliance. Unit: share. Taken over `determined_weighted_readings`. */\n compliance_drawn_weighted?: number | null;\n /** The stratum with no draw (board-burst and UTC-governor admissions): all_buckled over its readings that judged a strap. Unit: share. Taken over `not_drawn_determined_readings`. */\n compliance_not_drawn?: number | null;\n /** The readings that judged a strap: the headline denominator. Unit: readings. */\n determined_readings?: number | null;\n /** The drawn determined readings weighted by 1 / inclusion_probability: the check's denominator. Unit: readings. Taken over `drawn_determined_readings`. */\n determined_weighted_readings?: number | null;\n /** Of those, the readings the vision governor drew (an inclusion probability). Unit: readings. */\n drawn_determined_readings?: number | null;\n /** The back seat was empty: in no denominator. Unit: readings. */\n no_rider_readings?: number | null;\n /** Rear riders present, no strap on any of them. Unit: readings. */\n none_buckled_readings?: number | null;\n /** The all_buckled readings with no draw. Unit: readings. */\n not_drawn_all_buckled_readings?: number | null;\n /** Of those, the readings with no draw (NULL inclusion probability). Unit: readings. */\n not_drawn_determined_readings?: number | null;\n /** not_drawn_determined_readings / determined_readings: the share of judged readings with no draw. A capture-rate change moves it. Unit: share. Taken over `determined_readings`. */\n not_drawn_share?: number | null;\n /** At least one rear rider buckled and one not. Unit: readings. */\n some_unbuckled_readings?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSeatbeltUnbuckledRideRateResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"seatbelt_unbuckled_ride_rate\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Distinct cabs with such a ride. Unit: vehicles. */\n cabs?: number | null;\n /** Rides with at least one drawn judged reading: the check's rides. Unit: rides. */\n drawn_rides?: number | null;\n /** Rides whose judged readings were all outside the draw. Unit: rides. */\n not_drawn_rides?: number | null;\n /** Of those, the unbuckled rides. Unit: rides. */\n not_drawn_unbuckled_rides?: number | null;\n /** Camera rides with at least one seatbelt reading that judged a strap. Unit: rides. */\n rides?: number | null;\n /** The drawn rides weighted by 1 / their inclusion probability. Unit: rides. Taken over `drawn_rides`. */\n rides_weighted?: number | null;\n /** unbuckled_rides / rides: every camera ride with a reading that judged a strap counted once, drawn or not. Unit: share. Taken over `rides`. */\n unbuckled_ride_rate?: number | null;\n /** The design-weighted check: unbuckled_rides_weighted / rides_weighted over the rides with a drawn reading, each weighted by 1 / the largest inclusion probability among them. Never mixed into the rate. Unit: share. Taken over `rides_weighted`. */\n unbuckled_ride_rate_drawn_weighted?: number | null;\n /** The stratum with no draw: unbuckled over the rides whose judged readings were all outside the draw. Unit: share. Taken over `not_drawn_rides`. */\n unbuckled_ride_rate_not_drawn?: number | null;\n /** Of those, the rides where any such reading saw an unbuckled rider. Unit: rides. */\n unbuckled_rides?: number | null;\n /** The drawn unbuckled rides, weighted the same way. Unit: rides. Taken over `drawn_rides`. */\n unbuckled_rides_weighted?: number | null;\n /** Camera rides whose seatbelt readings were all cannot_determine: riders there, no strap judged. Counted beside the rate, in neither of its terms. Unit: rides. */\n undetermined_rides?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Distinct cabs with such a ride. Unit: vehicles. */\n cabs?: number | null;\n /** Rides with at least one drawn judged reading: the check's rides. Unit: rides. */\n drawn_rides?: number | null;\n /** Rides whose judged readings were all outside the draw. Unit: rides. */\n not_drawn_rides?: number | null;\n /** Of those, the unbuckled rides. Unit: rides. */\n not_drawn_unbuckled_rides?: number | null;\n /** Camera rides with at least one seatbelt reading that judged a strap. Unit: rides. */\n rides?: number | null;\n /** The drawn rides weighted by 1 / their inclusion probability. Unit: rides. Taken over `drawn_rides`. */\n rides_weighted?: number | null;\n /** unbuckled_rides / rides: every camera ride with a reading that judged a strap counted once, drawn or not. Unit: share. Taken over `rides`. */\n unbuckled_ride_rate?: number | null;\n /** The design-weighted check: unbuckled_rides_weighted / rides_weighted over the rides with a drawn reading, each weighted by 1 / the largest inclusion probability among them. Never mixed into the rate. Unit: share. Taken over `rides_weighted`. */\n unbuckled_ride_rate_drawn_weighted?: number | null;\n /** The stratum with no draw: unbuckled over the rides whose judged readings were all outside the draw. Unit: share. Taken over `not_drawn_rides`. */\n unbuckled_ride_rate_not_drawn?: number | null;\n /** Of those, the rides where any such reading saw an unbuckled rider. Unit: rides. */\n unbuckled_rides?: number | null;\n /** The drawn unbuckled rides, weighted the same way. Unit: rides. Taken over `drawn_rides`. */\n unbuckled_rides_weighted?: number | null;\n /** Camera rides whose seatbelt readings were all cannot_determine: riders there, no strap judged. Counted beside the rate, in neither of its terms. Unit: rides. */\n undetermined_rides?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Distinct cabs with such a ride. Unit: vehicles. */\n cabs?: number | null;\n /** Rides with at least one drawn judged reading: the check's rides. Unit: rides. */\n drawn_rides?: number | null;\n /** Rides whose judged readings were all outside the draw. Unit: rides. */\n not_drawn_rides?: number | null;\n /** Of those, the unbuckled rides. Unit: rides. */\n not_drawn_unbuckled_rides?: number | null;\n /** Camera rides with at least one seatbelt reading that judged a strap. Unit: rides. */\n rides?: number | null;\n /** The drawn rides weighted by 1 / their inclusion probability. Unit: rides. Taken over `drawn_rides`. */\n rides_weighted?: number | null;\n /** unbuckled_rides / rides: every camera ride with a reading that judged a strap counted once, drawn or not. Unit: share. Taken over `rides`. */\n unbuckled_ride_rate?: number | null;\n /** The design-weighted check: unbuckled_rides_weighted / rides_weighted over the rides with a drawn reading, each weighted by 1 / the largest inclusion probability among them. Never mixed into the rate. Unit: share. Taken over `rides_weighted`. */\n unbuckled_ride_rate_drawn_weighted?: number | null;\n /** The stratum with no draw: unbuckled over the rides whose judged readings were all outside the draw. Unit: share. Taken over `not_drawn_rides`. */\n unbuckled_ride_rate_not_drawn?: number | null;\n /** Of those, the rides where any such reading saw an unbuckled rider. Unit: rides. */\n unbuckled_rides?: number | null;\n /** The drawn unbuckled rides, weighted the same way. Unit: rides. Taken over `drawn_rides`. */\n unbuckled_rides_weighted?: number | null;\n /** Camera rides whose seatbelt readings were all cannot_determine: riders there, no strap judged. Counted beside the rate, in neither of its terms. Unit: rides. */\n undetermined_rides?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MetricSensingCensusResponse = {\n data: DataApi_DataProducts_MetricAnswer & {\n /** This metric. */\n metric?: \"sensing_census\";\n /** One row per grain cell. */\n rows?: Array<{\n /** Screens with a device-sourced inference row in the day: the camera pipeline ran. Unit: screens. */\n camera_screens?: number | null;\n /** Screens with a visitor-source radio row (BLE, mDNS, SSDP, HTTP probe) in the day. Unit: screens. */\n radio_screens?: number | null;\n /** Screens with either: the union, never the intersection. Unit: screens. */\n sensing_screens?: number | null;\n [key: string]: unknown;\n }>;\n /** The totals over the window, shaped like `rows`: one row, or one row per key when the answer has several keys. */\n totals?: {\n /** Screens with a device-sourced inference row in the day: the camera pipeline ran. Unit: screens. */\n camera_screens?: number | null;\n /** Screens with a visitor-source radio row (BLE, mDNS, SSDP, HTTP probe) in the day. Unit: screens. */\n radio_screens?: number | null;\n /** Screens with either: the union, never the intersection. Unit: screens. */\n sensing_screens?: number | null;\n [key: string]: unknown;\n } | Array<{\n /** Screens with a device-sourced inference row in the day: the camera pipeline ran. Unit: screens. */\n camera_screens?: number | null;\n /** Screens with a visitor-source radio row (BLE, mDNS, SSDP, HTTP probe) in the day. Unit: screens. */\n radio_screens?: number | null;\n /** Screens with either: the union, never the intersection. Unit: screens. */\n sensing_screens?: number | null;\n [key: string]: unknown;\n }> | null | null;\n };\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_MultiplierFeed = {\n absent_faces?: Array<{\n /** Faces with that reason. */\n faces: number;\n /** Why the faces carry no multiplier. */\n reason: string;\n }>;\n columns: Array<{\n /** CSV header. */\n header: string;\n /** Column key. */\n key: string;\n }>;\n /** Hash of this file. */\n content_sha256: string;\n /** multipliers (per-face impression multipliers), faces or demographics. */\n dataset: string;\n feed: {\n /** Feed hash. */\n content_sha256: string;\n /** Due, UTC. */\n due_at: string | null;\n /** Feed date. */\n feed_date: string;\n /** Published, UTC. */\n published_at: string | null;\n } | null;\n /** Who the multipliers count: `vehicle_occupants`. */\n ips_population?: string;\n qty?: {\n /** OpenRTB qty.sourcetype. */\n sourcetype: number;\n /** qty.vendor. */\n vendor: string;\n };\n release: {\n /** Release hash. */\n content_sha256: string;\n /** When it came into force. */\n published_at: string;\n /** Release id. */\n release_id: string;\n /** Currency window. */\n window_end: string;\n } | null;\n /** One row per face x daypart (multipliers: release_id, feed_date, ssp, ssp_venue_id, vistar_venue_id, venue_name, publisher_name, venue_type_id, dma_code, state, country, latitude, longitude, timezone, daypart, daypart_local_hours, qty_multiplier, qty_multiplier_low, qty_multiplier_high, multiplier_absent_reason, ips_population, qty_sourcetype, qty_vendor, interval_method, release_window_end, release_passes, release_vehicles, carried_from, reissue_reason, measured_ips, measured_ips_low, measured_ips_high, measured_passes, measured_vehicles, reissue_due) or per face x dimension value (demographics: window_end, window_days, dimension, value, estimand_kind, share, ci_low, ci_high, support_n, vehicles, resolved_level, measured_share). `columns` lists them in order. */\n rows: Array<Record<string, string | number | boolean | null | null>>;\n /** The SSP whose venue ids key the file (vistar default). */\n ssp: string;\n /** Rows were capped. */\n truncated: boolean;\n};\n\nexport type DataApi_DataProducts_MultiplierFeedResponse = {\n data: DataApi_DataProducts_MultiplierFeed;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OccluderCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_OccluderProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_OccluderMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_OccluderMeta = {\n /** Why no buildings are served. */\n absent_reason: string | null;\n /** Board face id. */\n board_id: string;\n /** Buildings returned. */\n count: number;\n /** Height assumed for a building with none recorded, metres. */\n floor_height_m: number;\n orientations: Array<{\n /** Face index. */\n orientation_idx: number;\n /** Visibility range, metres. */\n visibility_range_m: number | null;\n }>;\n /** Overture Maps buildings release. */\n overture_release: string;\n /** Radius searched, metres. */\n radius_m: number;\n /** The building list was capped. */\n truncated: boolean;\n /** Viewshed build version. */\n viewshed_version: string | null;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OccluderProperties = {\n /** The height is measured, not the floor default. */\n height_known: boolean;\n /** Building height, metres. */\n height_m: number | null;\n /** Height of the building's base, metres. */\n min_height_m: number | null;\n};\n\nexport type DataApi_DataProducts_OwnerFace = {\n /** Why the face carries no measured figure. */\n absent_reason: string | null;\n /** Ads seen per pass. */\n ads_seen_per_pass: number | null;\n benchmark: DataApi_DataProducts_Benchmark & Record<string, unknown> | null;\n /** Board face id. */\n board_id: string;\n /** ISO-3166 alpha-2. */\n country: string;\n /** People passing in position to see, per day. */\n daily_contacts: number | null;\n /** DMA code. */\n dma_code: string | null;\n facing: {\n /** Why facing seconds are absent. */\n absent_reason?: string;\n /** Instrumented legible seconds. */\n facing_base_s?: number | null;\n /** Facing seconds. */\n facing_s?: number | null;\n /** First day. */\n from?: string;\n /** Instrument. */\n instrument: string;\n pass_audience_versions?: Array<number>;\n /** Facing share. */\n share?: number | null;\n /** Last day. */\n to?: string;\n };\n impressions_per_spot: {\n /** Upper bound. */\n high: number | null;\n /** Interval method. */\n interval_method: string | null;\n /** Lower bound. */\n low: number | null;\n /** Measured impressions per spot. */\n measured: number | null;\n /** The owner's figure. */\n owner: number | null;\n };\n /** The face is one the headline figures are computed over (measured by 2+ vehicles). */\n in_headline: boolean;\n /** Who the measured figure counts. */\n ips_population: string;\n /** Active in the catalogue. */\n is_active: boolean;\n /** Latitude. */\n latitude: number;\n /** Longitude. */\n longitude: number;\n /** The face carries a measured cell in the window. */\n measured: boolean;\n money: {\n /** Annual revenue difference at the floor, USD. */\n annual_opportunity_usd: number | null;\n /** Current floor CPM, USD. */\n floor_cpm_usd: number | null;\n /** Recommended floor CPM, USD. */\n recommended_floor_cpm: number | null;\n /** Why none is drawn (population_mismatch, audience_at_venue). */\n revenue_available_absent_reason: string | null;\n /** Cells it is drawn from. */\n revenue_available_cells: number | null;\n /** Annual revenue the measurement makes available, USD. */\n revenue_available_usd: number | null;\n };\n /** Publisher. */\n publisher_name: string;\n release: {\n /** Upper bound. */\n high: number;\n /** Lower bound. */\n low: number;\n /** Multiplier in force. */\n multiplier: number;\n /** Release. */\n release_id: string;\n /** Window. */\n window_end: string;\n } | null;\n /** The owner's spots per day. */\n spots_per_day_owner: number | null;\n /** State or province. */\n state: string | null;\n support: {\n /** Passes. */\n passes: number | null;\n /** Distinct vehicles. */\n vehicles: number | null;\n };\n /** IANA zone. */\n timezone: string;\n /** Catalogue name. */\n venue_name: string;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n yield: {\n /** Why no ratio is served. */\n absent_reason: string | null;\n /** ratio or incremental. */\n basis: string | null;\n /** Upper bound. */\n compared_high: number | null;\n /** That count per spot. */\n compared_impressions_per_spot: number | null;\n /** Lower bound. */\n compared_low: number | null;\n /** The count the owner's figure is compared with. */\n compared_population: string | null;\n /** Upper bound. */\n high: number | null;\n /** Lower bound. */\n low: number | null;\n /** Measured over the owner's figure. */\n ratio: number | null;\n };\n};\n\nexport type DataApi_DataProducts_OwnerFaceDetail = {\n audience: DataApi_DataProducts_BoardAudience & Record<string, unknown> | null;\n benchmark: DataApi_DataProducts_Benchmark & Record<string, unknown> | null;\n currency: DataApi_DataProducts_BoardCurrency & Record<string, unknown> | null;\n /** The local hours each daypart covers (early_morning, morning, midday, afternoon, evening, night, late_night). */\n daypart_hours: Record<string, Array<number>>;\n face: DataApi_DataProducts_OwnerFace;\n release: {\n cells: Array<Record<string, unknown>>;\n /** In force since. */\n published_at: string;\n /** Release. */\n release_id: string;\n } | null;\n spec: Record<string, unknown> | null;\n ssp_venues: Array<{\n /** Where we hold it from. */\n source: string;\n /** Reference. */\n source_ref?: string | null;\n /** SSP. */\n ssp: string;\n /** Its venue id. */\n ssp_venue_id: string;\n }>;\n window: DataApi_DataProducts_Window;\n};\n\nexport type DataApi_DataProducts_OwnerFaceResponse = {\n data: DataApi_DataProducts_OwnerFaceDetail;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OwnerFaces = {\n faces: Array<DataApi_DataProducts_OwnerFace>;\n markets: Array<DataApi_DataProducts_Benchmark>;\n method: DataApi_DataProducts_Method;\n owner: {\n /** Organisation. */\n org: string;\n publishers: Array<string>;\n };\n release: {\n /** Hash. */\n content_sha256: string;\n /** In force since. */\n published_at: string;\n /** Release. */\n release_id: string;\n /** Window. */\n window_end: string;\n } | null;\n /** faces, faces_active, measured, absent, passes, headline {min_vehicles, faces, passes}, revenue_available {usd_year, faces, cells, counted_faces, absent_faces, days_per_year, ranking_bar}, measured_impressions_day, owner_impressions_day, weighted_yield, annual_difference_at_floor_usd, facing_s, facing_base_s, facing_share. */\n summary: Record<string, unknown>;\n /** Faces were capped. */\n truncated: boolean;\n window: DataApi_DataProducts_Window;\n};\n\nexport type DataApi_DataProducts_OwnerFacesResponse = {\n data: DataApi_DataProducts_OwnerFaces;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_OwnerUploadResponse = {\n /** The plan: rows read, refused lines with their reasons, unmatched and ambiguous faces, and what was written (dry_run writes nothing). */\n data: Record<string, unknown>;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_PassReplay = {\n /** Board face id. */\n board_id: string;\n /** Local day replayed. */\n date: string;\n meta: {\n /** Board face id. */\n board_id: string;\n /** Clip distance around the viewshed, metres. */\n clip_m: number;\n /** The face has a play log for the day. */\n creative_log: boolean;\n /** Days the replay trails real time. */\n delay_days: number;\n /** Face passes on the day: the traversals those rows make (the sum of face_share). */\n face_passes_total?: number | null;\n facing: DataApi_DataProducts_FacingVerdict;\n /** Offset of the next page. */\n next_offset: number | null;\n /** Page offset. */\n offset: number;\n /** Page order. */\n order: string;\n /** Pass rows on this page. */\n passes_returned: number;\n /** Pass rows on the day: the items the pages hold (one per candidate facing of a traversal). */\n passes_total: number;\n /** Seconds of path kept around each pass. */\n path_window_s: number;\n /** Passes were capped. */\n truncated: boolean;\n viewshed_versions: Array<string>;\n };\n passes: Array<DataApi_DataProducts_ReplayPass>;\n};\n\nexport type DataApi_DataProducts_PassReplayResponse = {\n data: DataApi_DataProducts_PassReplay;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_Release = {\n /** Cells new in this release. */\n added_cells: number;\n /** Boards in the release. */\n boards: number;\n /** Board x daypart cells in the release. */\n cells: number;\n /** Hash of the release content. */\n content_sha256: string;\n /** Currency method version. */\n currency_method_version: number;\n /** Smallest relative change that triggers a reissue. */\n min_rel_change: number | null;\n /** Cells that moved from the previous release. */\n moved_cells: number;\n /** Pass-audience method version. */\n pass_audience_version: number;\n /** When it came into force, UTC. */\n published_at: string;\n /** 0 for the first issue. */\n reissue_number: number;\n /** The release this one reissues. */\n reissue_of: string | null;\n /** Release id (mooh-YYYY-MM[-rN]). */\n release_id: string;\n /** Month the release is for. */\n release_month: string;\n /** When it was superseded, UTC. */\n superseded_at: string | null;\n /** Currency window the release was cut from. */\n window_end: string;\n};\n\nexport type DataApi_DataProducts_ReleaseRegistry = {\n feeds: Array<DataApi_DataProducts_FeedPublication>;\n /** The release in force. */\n in_force: string | null;\n qty: {\n /** OpenRTB qty.sourcetype (1 = measurement vendor). */\n sourcetype: number;\n /** qty.vendor (trillboards.com). */\n vendor: string;\n };\n releases: Array<DataApi_DataProducts_Release>;\n /** What a release's multipliers count: measured_impressions_per_spot. */\n unit: string;\n};\n\nexport type DataApi_DataProducts_ReleaseRegistryResponse = {\n data: DataApi_DataProducts_ReleaseRegistry;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_ReplayPass = {\n /** Angle from the face normal per second, degrees. */\n beta_1hz: Array<number | null>;\n creatives?: Array<{\n /** Advertiser. */\n advertiser: string | null;\n /** owner_play_log or modelled_rotation. */\n basis: string;\n /** Campaign. */\n campaign_key: string | null;\n /** Creative on air during the pass. */\n creative_key: string;\n /** Seconds the creative was on air while the face was legible. */\n overlap_s: number;\n /** Probability the creative was seen. */\n p_seen: number | null;\n /** exact or modelled. */\n precision: string;\n }> | null;\n /** Distance to the face per second, metres. */\n dist_1hz: Array<number | null>;\n /** Why facing seconds are absent. */\n facing_absent_reason: string | null;\n /** Seconds a rider faced the board. */\n facing_s: number | null;\n /** 1 when the face was legible that second. */\n legible_1hz: Array<number>;\n /** Legible seconds in the pass. */\n legible_s: number | null;\n /** Face passed. */\n orientation_idx: number;\n /** Pass id (vehicle pseudonym keyed to the caller and session, and pass number). */\n pass_key: string;\n /** The vehicle path, [lon, lat] at 1 Hz, clipped to the viewshed +-200 m. */\n path: Array<Array<number>>;\n /** driver or passenger side. */\n read_side: string | null;\n /** Side of the road the face is on, relative to travel. */\n side: string | null;\n /** Speed at the closest point, m/s. */\n speed_at_closest_mps: number | null;\n /** Seconds from entry to the closest point. */\n t_closest_off_s: number | null;\n /** When the vehicle entered the viewshed, UTC. */\n t_enter: string;\n /** Offset of each path point from t_enter, ms. */\n t_off_ms: Array<number>;\n /** Visible seconds in the pass. */\n visible_s: number | null;\n};\n\nexport type DataApi_DataProducts_RoadCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_RoadProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_ViewshedMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_RoadProperties = {\n /** 0 = with the way's drawing direction, 1 = against it. */\n direction?: number;\n /** Free-flow speed, km/h. */\n free_flow_kph?: number | null;\n /** OSM highway class. */\n highway: string;\n /** road. */\n kind: string;\n /** The road serves a measured board in the bbox or set. */\n measured?: boolean;\n /** The metric the feature carries. */\n metric?: string;\n /** Road name. */\n name?: string | null;\n /** The road serves a member of the set. */\n serves_set?: boolean;\n /** Measured speed, km/h. */\n speed_kph?: number | null;\n /** Measured over free-flow speed. */\n speed_ratio?: number | null;\n /** Fleet traversals scaled to the response's busiest road (1.0). */\n traversal_index?: number | null;\n /** OpenStreetMap way id. */\n way_id: string;\n};\n\nexport type DataApi_DataProducts_SetCoverage = {\n /** When the coverage was built. */\n built_at: string | null;\n /** People passing in position to see, per day, summed. */\n daily_contacts: number | null;\n /** Members with a measured currency cell. */\n measured: number | null;\n /** Measured impressions per day, summed. */\n measured_impressions_day: number | null;\n /** Boards in the set. */\n members: number | null;\n /** Currency method version. */\n method_version: number | null;\n /** The board-pass rows across the members: a reconciliation count, never a pass count. */\n pass_rows?: number | null;\n /** Face passes across the members (the sum of each pass's share of its face). Null on a window built before they existed. */\n passes: number | null;\n /** Distinct vehicles behind them. */\n vehicles: number | null;\n /** Days in the window. */\n window_days: number | null;\n /** Currency window end. */\n window_end: string | null;\n /** Members our fleet passed. */\n with_passes: number | null;\n /** Members with a built viewshed. */\n with_viewshed: number | null;\n} | null;\n\nexport type DataApi_DataProducts_SetCoverageEnvelope = {\n data: DataApi_DataProducts_SetCoverageResponse;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_DataProducts_SetCoverageResponse = {\n coverage: DataApi_DataProducts_SetCoverage;\n set: DataApi_DataProducts_CurationSet;\n};\n\nexport type DataApi_DataProducts_SightedBrand = {\n /** Brand name. */\n brand: string;\n /** Resolved brand id (brand graph), when resolved. */\n brand_id: string | null;\n /** Brand key. */\n brand_key: string;\n /** Of those, reads on a registered board face. */\n face_sightings: number;\n /** Distinct registered faces it was read on. */\n faces: number;\n /** First read, UTC. */\n first_seen_at: string | null;\n /** Every read held for the brand, any window. */\n held_sightings: number;\n /** Newest read, UTC. */\n last_seen_at: string | null;\n markets: Array<DataApi_DataProducts_BrandMarket>;\n /** exact or prefix. */\n match: string | null;\n /** The spelling the query matched. */\n matched: string | null;\n /** Reads of the brand in the window. */\n sightings: number;\n /** Reads on no registered face. */\n street_sightings: number;\n};\n\nexport type DataApi_DataProducts_TileSum = {\n /** Legible seconds on instrumented passes (the facing denominator). */\n facing_base_s: number | null;\n /** Facing seconds (head turned to the face), when the facing gate is open. */\n facing_s: number | null;\n /** Week x daypart leaves summed. */\n leaves?: number;\n /** Legible seconds. */\n legible_s: number;\n /** Passes (face-share weighted). */\n passes: number;\n /** Monday the week starts on. */\n week_start?: string;\n};\n\nexport type DataApi_DataProducts_ViewshedCollection = {\n features: Array<{\n geometry: DataApi_DataProducts_Geometry;\n properties: DataApi_DataProducts_ViewshedProperties;\n type: \"Feature\";\n }>;\n meta?: DataApi_DataProducts_ViewshedMeta;\n type: \"FeatureCollection\";\n};\n\nexport type DataApi_DataProducts_ViewshedMeta = {\n /** Why no viewshed is served. */\n absent_reason?: string | null;\n /** The bbox drawn, if one was asked. */\n bbox?: Array<number> | null;\n /** Board face id (single-board viewshed). */\n board_id?: string;\n /** Features returned. */\n count?: number;\n /** Day-of-week type. */\n dow_type?: string;\n /** Local hour, or null for every hour. */\n hour?: number | null;\n /** Set members drawn. */\n members?: number;\n /** Road metric drawn. */\n metric?: string;\n /** Faces on the structure. */\n orientations?: number;\n /** included, or omitted past the overlay cap. */\n polygons?: string;\n /** Road speed profile version. */\n profile_version?: string | null;\n /** Curated set key (set viewsheds and roads), or null when no set was drawn. */\n set_key?: string | null;\n /** The set was capped at the overlay limit. */\n truncated?: boolean;\n /** Viewshed build version. */\n viewshed_version?: string | null;\n watermark?: DataApi_DataProducts_Watermark;\n /** Currency window end. */\n window_end?: string | null;\n};\n\nexport type DataApi_DataProducts_ViewshedProperties = {\n /** Why no figure is served (no_passes, ...). */\n absent_reason: string | null;\n /** Ads seen per pass. */\n ads_seen_mean: number | null;\n /** legible or visible. */\n area?: string;\n /** Face format class (bulletin, poster, junior, ...). */\n aspect_class?: string | null;\n /** Direction the face points, degrees from north. */\n azimuth_deg?: number | null;\n /** Where the azimuth came from (owner_spec, name_token, road_snap, ...). */\n azimuth_source?: string | null;\n /** Board face id. */\n board_id: string;\n /** Face height, metres. */\n face_height_m?: number | null;\n /** The face's own name (the owner's reference, else the catalogue venue name). */\n face_name?: string | null;\n /** owner_spec or catalogue. */\n face_name_source?: string | null;\n /** Face width, metres. */\n face_width_m?: number | null;\n /** Measured impressions per spot. */\n ips: number | null;\n /** Interval upper bound. */\n ips_high: number | null;\n /** Interval lower bound. */\n ips_low: number | null;\n /** Who ips counts: `vehicle_occupants`. */\n ips_population: string;\n /** viewshed (legible or visible area polygon) or face (the face point). */\n kind: string;\n /** Distance the face is legible from, metres. */\n legibility_range_m?: number | null;\n /** The face carries a measured currency cell. */\n measured: boolean;\n /** Height of the face centre above the road, metres. */\n mount_height_m?: number | null;\n /** Source of the mount height (format, rooftop, a spec source). */\n mount_source?: string | null;\n /** Share of the viewshed blocked by buildings. */\n occluded_share?: number | null;\n /** Face index on the structure. */\n orientation_idx?: number;\n /** Share of the structure's passes this face serves. */\n orientation_share?: number;\n /** Passes behind the figure. */\n passes: number | null;\n /** Media owner. */\n publisher_name: string;\n /** Source of the served size (owner_spec, ...); null for the format default. */\n size_source?: string | null;\n /** Distinct vehicles behind the figure. */\n vehicles: number | null;\n /** OpenOOH venue type id. */\n venue_type_id: number;\n /** ok, or why the viewshed is degenerate. */\n viewshed_status?: string | null;\n /** Viewshed build version. */\n viewshed_version?: string | null;\n /** Distance the face is visible from, metres. */\n visibility_range_m?: number | null;\n};\n\n/**\n * Present on every body read on a ledger (an organisation's or an account's): it names the licensee and the UTC day.\n */\nexport type DataApi_DataProducts_Watermark = {\n /** Watermark id, also embedded in the body's validator. */\n id: string;\n /** UTC day the body was issued. */\n issued_on: string;\n /** The visible licence line: who the body was read for and the UTC day. */\n text: string;\n};\n\nexport type DataApi_DataProducts_Window = {\n /** Days in the window (28 for the currency window). */\n window_days: number;\n /** Last local day of the measurement window. */\n window_end: string;\n};\n\nexport type DataApi_DataProducts_YieldReport = {\n columns: Array<{\n /** CSV header. */\n header: string;\n /** Column key. */\n key: string;\n }>;\n /** Daypart reported. */\n daypart: string;\n filters: {\n /** DMA filter. */\n dma: string | null;\n /** Venue type filter. */\n venue_type_id: number | null;\n };\n method: DataApi_DataProducts_Method;\n /** Publisher. */\n publisher: string;\n /** Active faces. */\n publisher_boards_active: number;\n /** Faces the publisher holds. */\n publisher_boards_total: number;\n /** One row per face: the columns listed in `columns`. */\n rows: Array<Record<string, unknown>>;\n /** boards, boards_active, measured, absent, ratio_boards, share_yield_low_above_one, weighted_yield, annual_difference_at_floor_usd. */\n summary: Record<string, unknown>;\n /** Rows were capped. */\n truncated: boolean;\n /** Days. */\n window_days: number | null;\n /** Currency window. */\n window_end: string | null;\n /** published, none or unverified. */\n window_state: string;\n};\n\nexport type DataApi_DataProducts_YieldReportResponse = {\n data: DataApi_DataProducts_YieldReport;\n status: true;\n watermark?: DataApi_DataProducts_Watermark;\n};\n\nexport type DataApi_Error = {\n error: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code: string;\n /** Per-field violations (populated from Zod errors). */\n details?: Array<{\n code?: string;\n message?: string;\n param?: string;\n }>;\n /** Link to the documentation for this error code (https://api.trillboards.com/docs/errors#<code>). */\n doc_url?: string;\n /** Agent-facing hints and suggestions. */\n help?: {\n portal_url?: string;\n suggestions?: Array<string>;\n summary?: string;\n try_next?: string;\n };\n /** Human-readable error message. Safe to surface to end-users. */\n message: string;\n /** Offending parameter name (when applicable). */\n param?: string;\n /** Echoed X-Request-Id for correlation. */\n request_id: string;\n /** Stripe-style error taxonomy (derived from utils/errorCatalog). */\n type: \"api_error\" | \"authentication_error\" | \"idempotency_error\" | \"invalid_request_error\" | \"permission_error\" | \"rate_limit_error\";\n };\n};\n\n/**\n * The 143 CATALOGUED error codes, generated from utils/errorCatalog.js — the same catalog that backs https://api.trillboards.com/docs/errors. This is the documented registry, NOT the complete set of codes the API can emit: a response `code` is an open string (see `TrillboardsError`). Use this list to recognise a code, never to assume a response cannot carry another.\n */\nexport type DataApi_ErrorCode = \"AUTH_REQUIRED\" | \"BRAND_CONFIGURATION_FAILED\" | \"BRAND_PROFILE_CONFLICT\" | \"BRAND_PROFILE_NOT_FOUND\" | \"CREATIVE_ADVERTISEMENT_NOT_OWNED\" | \"CREATIVE_MODERATION_UNAVAILABLE\" | \"CREATIVE_NOT_LINKED\" | \"CREATIVE_NOT_READY\" | \"CREATIVE_POLICY_CONFLICT\" | \"CREATIVE_TOO_LARGE\" | \"EXPERIMENT_COMPLETED\" | \"EXPERIMENT_NOT_FOUND\" | \"FEEDBACK_POLICY_REQUIRED\" | \"IDEMPOTENCY_CONFLICT\" | \"INVALID_BRAND_RULES\" | \"INVALID_CREATIVE_URL\" | \"INVALID_CREATIVE_WEIGHTS\" | \"INVALID_FEEDBACK_CREATIVE\" | \"INVALID_FEEDBACK_OBJECTIVE\" | \"INVALID_FEEDBACK_REQUEST\" | \"INVALID_POLICY_VERSION\" | \"INVALID_VARIANTS\" | \"MEDIA_BUY_NOT_FOUND\" | \"OPERATION_ALREADY_COMMITTED\" | \"OPERATION_IN_PROGRESS\" | \"POLICY_NOT_AVAILABLE\" | \"SOURCE_CREATIVE_NOT_FOUND\" | \"UNSUPPORTED_CREATIVE_TYPE\" | \"VARIANT_IDENTITY_CONFLICT\" | \"ad_interval_out_of_range\" | \"allocation_out_of_range\" | \"analytics_unavailable\" | \"api_key_expired\" | \"api_key_owner_missing\" | \"api_key_revoked\" | \"array_items_must_be_strings\" | \"array_too_large\" | \"auth_error\" | \"authentication_required\" | \"batch_size_exceeded\" | \"blocked_advertisers_too_large\" | \"blocked_iab_categories_too_large\" | \"client_ip_required\" | \"concurrent_request_limit\" | \"conflict\" | \"conflicting_lists\" | \"creative_policy_conflict\" | \"creative_policy_forbidden\" | \"daily_quota_exceeded\" | \"database_error\" | \"dataset_not_scopable\" | \"device_already_registered\" | \"device_identity_missing\" | \"device_identity_underivable\" | \"device_not_found\" | \"device_offline\" | \"dsp_access_denied\" | \"error\" | \"field_must_be_array\" | \"field_must_be_boolean\" | \"field_too_long\" | \"floor_price_out_of_range\" | \"forbidden\" | \"idempotency_error\" | \"idempotency_key_in_use\" | \"idempotency_key_mismatch\" | \"insufficient_data\" | \"insufficient_permissions\" | \"insufficient_scope\" | \"internal_error\" | \"invalid_ad_surface_mode\" | \"invalid_age_rating\" | \"invalid_api_key\" | \"invalid_api_key_format\" | \"invalid_array_items\" | \"invalid_creative_policy\" | \"invalid_currency\" | \"invalid_dataset\" | \"invalid_device_id\" | \"invalid_dimensions\" | \"invalid_display_mode\" | \"invalid_field_type\" | \"invalid_field_value\" | \"invalid_fingerprint\" | \"invalid_json\" | \"invalid_lbar_position\" | \"invalid_lbar_settings\" | \"invalid_measures\" | \"invalid_media_url\" | \"invalid_order_by\" | \"invalid_orientation\" | \"invalid_pip_position\" | \"invalid_pip_settings\" | \"invalid_preference_level\" | \"invalid_preferences\" | \"invalid_provider\" | \"invalid_screen_id\" | \"invalid_segment_rules\" | \"invalid_sizing_mode\" | \"invalid_stream_type\" | \"invalid_webhook_events\" | \"invalid_webhook_url\" | \"lbar_settings_must_be_object\" | \"lbar_size_out_of_range\" | \"missing_required_field\" | \"not_found\" | \"openrtb_auth_failed\" | \"openrtb_config_missing\" | \"paired_training_insert_failed\" | \"paired_training_rate_limit_exceeded\" | \"partner_inactive\" | \"pip_margin_out_of_range\" | \"pip_settings_must_be_object\" | \"pip_size_ratio_out_of_range\" | \"preferences_must_be_object\" | \"preferences_required\" | \"preset_id_required\" | \"preset_not_found\" | \"rate_limit_exceeded\" | \"resource_locked\" | \"screen_ids_required\" | \"screen_not_found\" | \"screen_not_in_scope\" | \"sdk_enrich_rate_limit_exceeded\" | \"sdk_impression_rate_limit_exceeded\" | \"sdk_qr_beacon_rate_limit_exceeded\" | \"sdk_qr_scan_rate_limit_exceeded\" | \"segment_limit_exceeded\" | \"segment_not_found\" | \"service_unavailable\" | \"stale_data\" | \"stream_content_required\" | \"stream_not_found\" | \"tier_insufficient\" | \"timeout\" | \"timeout_out_of_range\" | \"unknown_agent_type\" | \"unsupported_media_type\" | \"validation_error\" | \"webhook_limit_exceeded\" | \"webhook_not_found\" | \"webhook_secret_expired\" | \"webhook_url_unreachable\";\n\nexport type DataApi_FeedbackRewardQuery = {\n /** Opaque next_cursor from this same date scope; rewind after scan_complete. */\n cursor?: string;\n /** Inclusive first play date, YYYY-MM-DD; date range is at most 31 days. */\n from: string;\n /** Unique caller-owned billing key for this page; committed retries return the receipt, not another read. */\n idempotency_key: string;\n /** Maximum native play states returned on this metered page. */\n limit?: number;\n /** Inclusive last play date, YYYY-MM-DD; date range is at most 31 days. */\n to: string;\n};\n\nexport type DataApi_LookalikeResponse = {\n matches: Array<Record<string, unknown>>;\n matches_count: number;\n source_screen_id: string;\n};\n\nexport type DataApi_QueryDslBody = {\n /** Dataset name. Defaults to `inference_outcomes`. */\n dataset?: string;\n dimensions?: Array<string>;\n filters?: Array<DataApi_QueryFilter>;\n limit?: number;\n measures?: Array<string>;\n order_by?: Array<DataApi_QueryOrderBy>;\n};\n\nexport type DataApi_QueryDslResponse = {\n count: number;\n /** `observation_stream` when it is served from ClickHouse: the population the answer counts and the first instant the dataset holds. */\n coverage?: {\n population: string;\n since: string;\n };\n dataset: string;\n dimensions: Array<string>;\n /** `inference_outcomes` only. The `inference_source` values the query read (`null` when a range filter makes the set unstateable), and whether the camera-only default was applied because the request did not filter on `inference_source`. */\n inference_source?: {\n defaulted: boolean;\n values: Array<string> | null;\n };\n limit: number;\n measures: Array<string>;\n /** `inference_outcomes` only. `measured` when every row read is a camera measurement, `modeled` when every row is a venue-profile estimate, `mixed` when the answer aggregates both. */\n provenance?: \"measured\" | \"modeled\" | \"mixed\";\n /** Result rows. For `inference_outcomes` every row also carries `provenance` (`measured`, `modeled` or `mixed`). */\n rows: Array<Record<string, unknown>>;\n};\n\nexport type DataApi_QueryFilter = {\n field: string;\n op?: \"eq\" | \"in\" | \"gte\" | \"lte\" | \"between\";\n value?: unknown;\n};\n\nexport type DataApi_QueryOrderBy = {\n direction?: \"asc\" | \"desc\" | \"ASC\" | \"DESC\";\n field: string;\n};\n\nexport type DataApi_ScreenAudienceResponse = {\n audience: Record<string, unknown> | null;\n message?: string;\n screen_id: string;\n source?: string;\n};\n\nexport type DataApi_ScreenHistoryResponse = {\n count: number;\n metrics: Array<Record<string, unknown>>;\n screen_id: string;\n source?: \"camera\" | \"signal_derived\";\n};\n\nexport type DataApi_ScreensListResponse = {\n count: number;\n has_more: boolean;\n limit: number;\n next_offset: number | null;\n offset: number;\n screens: Array<Record<string, unknown>>;\n total: number;\n};\n\nexport type DataApi_SemanticSearchResponse = {\n query: string;\n results: Array<Record<string, unknown>>;\n results_count: number;\n time_window?: string;\n};\n\nexport type DataApi_StatsResponse = {\n active_screens: number;\n embeddings: Record<string, unknown>;\n metrics_last_24h: number;\n partner?: string;\n};\n\n/**\n * Server-Sent Events text: `event: <name>` and `data: <json>` lines per the SSE spec. `connected` first, then one `audience` event per screen window (screen_id, timestamp, metrics).\n */\nexport type DataApi_StreamResponse = string;\n\nexport type DataApi_UsageResponse = {\n data: Array<Record<string, unknown>>;\n period_days: number;\n};\n\n/**\n * Per-dataset record counts + date ranges for the partner's screens.\n * Returned by `GET /data-export/summary`.\n *\n */\nexport type DataExportSummaryResponse = {\n /** `lookback_days` is `min(?days, 400)` and defaults to 7. `screen_count` is how many screens the export is SCOPED to, not how many hold data. Each `datasets` entry is a `total_records`/`earliest`/`latest` triple, and a dataset whose count query FAILED is reported as `0` with null bounds rather than as an error. */\n data?: {\n /** Map of dataset name to record summary */\n datasets?: Record<string, {\n earliest?: string | null;\n latest?: string | null;\n total_records?: number;\n }>;\n lookback_days?: number;\n screen_count?: number;\n };\n /** Always `true`; a failure is raised to the global error handler and returns a canonical error envelope at a 4xx/5xx status. Note this response carries **no `request_id`**, unlike the sibling audience endpoints. */\n success?: boolean;\n};\n\n/**\n * Canonical INT-PK identity table for demand-side partners (DSPs/SSPs that Trillboards routes ad requests to). Wave 2 of pristine-state refactor. Replaces partner_key TEXT joins across the billing path.\n */\nexport type DemandPartners = {\n archived: boolean;\n created_at: string;\n /** demand_partner_id INT is the canonical FK going forward; partner_key TEXT is kept as the wire-format alternate-key FOREVER (external partner-API auth + admin UI rely on it). Never propose dropping ... */\n demand_partner_id?: string | null;\n display_name: string;\n partner_key: string;\n partner_type: string;\n /** public_alias UNIQUE: this is the obfuscated external alias partner-API consumers see. partnerAlias.js will read from this table after Wave 2 cutover. */\n public_alias: string;\n updated_at: string;\n};\n\nexport type DemographicsResponse = {\n /** `demographics.age_distribution` and `gender_split` are **hardcoded zeros even on the success path** — nothing computes them. `income_profile` and `group_composition` are shares in 0-1, not percentages, and `lifestyle_segments` is emitted as `{segment, percentage}` objects rather than the plain strings declared here. `data_quality.confidence` is a step function of sample size (>=100 gives 0.9, >=50 gives 0.7, >=20 gives 0.5, >=5 gives 0.3, else 0.1), not a statistical confidence, and `sample_size` counts measurement WINDOWS, not people. `period` echoes `?period=`; an unrecognised value silently falls back to 7 days while still being echoed verbatim. */\n data?: {\n data_quality?: {\n confidence?: number;\n sample_size?: number;\n };\n demographics?: {\n age_distribution?: {\n \"18-25\"?: number;\n \"26-35\"?: number;\n \"36-50\"?: number;\n \"50+\"?: number;\n };\n gender_split?: {\n female?: number;\n male?: number;\n };\n group_composition?: {\n couples?: number;\n families?: number;\n friends?: number;\n solo?: number;\n work_groups?: number;\n };\n income_profile?: {\n high?: number;\n low?: number;\n medium?: number;\n premium?: number;\n };\n lifestyle_segments?: Array<string>;\n };\n period?: string;\n screen_id?: string;\n screen_name?: string;\n timestamp?: string;\n };\n /** Per-request identifier (`req_` plus 32 hex), also returned on the `X-Request-Id` response header. */\n request_id?: string;\n /** Always `true` on a 2xx; failures return the error envelope (`success: false` plus an `error` object) at a 4xx/5xx status. */\n success?: boolean;\n};\n\nexport type Device = {\n /** Creation time of the DEVICE row (`earner_screen_devices`), not of the linked screen, which may be created later in the same request or on a subsequent re-registration. */\n created_at?: string;\n /** Trillboards-minted 24-char Mongo ObjectId hex for the `earner_screen_devices` row (`mongo_earnerscreen_device_id`). This is NOT the `device_id` you sent at registration — that comes back as `external_device_id`; the batch endpoint calls this same value `trillboard_id`. All three of `device_id`, `fingerprint` and `external_device_id` are accepted as the `{deviceId}` path parameter, resolved in that order. */\n device_id?: string;\n /** Saved partner category, independent of advertising classification. POST with an existing device_id and PATCH accept category updates. Legacy devices without a saved declaration retain their previous numeric-derived label until explicitly updated. */\n device_type?: string;\n /** Screen display specification. `width`/`height` are pixel resolution; `width_in`/`height_in` are physical inches. Pixel-only inputs are NOT recorded as physical size — pass `width_in`/`height_in` (most accurate) or `ppi` so the server can derive inches from pixels. */\n display?: {\n /** Display resolution height in pixels */\n height?: number;\n /** Physical screen height in inches */\n height_in?: number;\n orientation?: string;\n /** Pixels per inch (required to derive physical size from width/height) */\n ppi?: number;\n /** Display resolution width in pixels */\n width?: number;\n /** Physical screen width in inches */\n width_in?: number;\n };\n /** Static player URL of the form `https://screen.trillboards.com?fp=<fingerprint>`. It is deterministic and permanent — not a signed or expiring link — so it never rotates and anyone holding it can load the player. `null` until a screen is linked. */\n embed_url?: string;\n /** Venue-enrichment state. `status` is `complete` only when a classification source exists AND `location` actually resolved (coordinates or a city), so it never reports complete over placeholder geo; a partner-supplied venue category stamps the source as `partner` at registration, which means `complete` does not imply AI classification ran. `confidence` is dead — `venue_classification_confidence` has no column and no writer anywhere in the API, so it is always undefined and omitted from the JSON. */\n enrichment?: Record<string, unknown>;\n /** Verbatim echo of the `device_id` you sent in the registration body (`earner_screen_devices.partner_external_id`). It is the idempotency key scoped to your partner account: re-POSTing the same value updates the existing device instead of creating a second one. */\n external_device_id?: string;\n /** Deterministic device key: `P_` followed by the first 24 hex chars of `md5(\"<your partner id>_<external_device_id>\")`. It never rotates — the same partner plus the same `device_id` always regenerates it — and it is both the heartbeat/player routing key and the token embedded in `embed_url`. */\n fingerprint?: string;\n /** Saved publisher-declared audience impressions per ad play; defaults to 1. Update via PATCH /v1/partner/device/{deviceId}/impression-multiplier. */\n impression_multiplier?: number;\n /** Resolved geo, read from the enriched screen row first and falling back to the raw registration-time device row, with placeholder strings (\"City\", \"Vending Machine Location\") filtered out. `lat`/`lng` coalesce as a PAIR — a half-set or null-island (0,0) screen pair is discarded whole in favour of the device's coordinates — and `venue_type` here is the OpenOOH CHILD slug, while `venue.category` carries the parent. `timezone` is the one exception to screen-first: it is read device-first. */\n location?: Record<string, unknown>;\n location_capability?: PartnerLocationCapability;\n /** Stripe-style readiness, the same contract registration returns (see https://api.trillboards.com/docs/monetization-requirements). */\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n /** The linked screen's name, falling back to the raw `external_device_id` when the screen has none. Omitting `name` at registration seeds the screen as `Partner Device: <device_id>`, so that literal string is what you get back rather than a null. */\n name?: string;\n requirements?: PartnerMonetizationRequirements;\n /** The linked screen's Mongo ObjectId hex (`earner_screens.mongo_earnerscreen_id`), minted server-side at registration. This — not `device_id` — is the id the non-device partner endpoints take (display settings, screen groups, fleet commands, analytics). Absent when no screen is linked to the device. */\n screen_id?: string;\n /** Provisioning state of the underlying screen row, not a liveness signal — a device that has stopped reporting still reads `approved`. Partner registration stamps `approved` on create (`partnerDeviceRegistrationService.js`), which is what almost every live partner device returns; `pending` is the formatter's fallback when the screen row carries no status of its own. */\n status?: \"pending\" | \"approved\" | \"active\" | \"offline\" | \"suspended\";\n /** `earner_screen_devices.updated_at`, which the device-mirror write buffer stamps `NOW()` on every flush — including heartbeat telemetry. It therefore tracks device liveness, not configuration changes; do not poll it to detect that a registration or PATCH landed. */\n updated_at?: string;\n /** OpenOOH classification of the screen, rebuilt from the typed `screen_venue_taxonomy` row. `category` is the PARENT slug and `subcategory` the child, with `openooh_venue_type_id` the unambiguous numeric child id — so a granular input like `hotel` reads back as a parent/child pair, not as what you sent. Empty until classification lands, unless your registration itself carried a resolvable `venue.category`/`subcategory`. */\n venue?: Record<string, unknown>;\n};\n\n/**\n * The device-authentication layer's refusal (missing, invalid or replayed device credential).\n */\nexport type DeviceAuthRefusal = {\n /** The HTTP status. */\n code?: number;\n /** device_token_required, invalid_device_token, device_not_found, device_identity_mismatch, device_token_subject_mismatch, device_screen_mismatch, missing_device_timestamp, missing_device_nonce, stale_device_request, replayed_device_request or replay_guard_unavailable. */\n error?: string;\n message?: string;\n status?: false;\n};\n\nexport type DeviceCapabilityPayload = {\n /** Runtime family of the agent (`fire-tv`, `android-tv`, `tablet`, `tablet-lite`, `webos`, `vidaa`, `web-browser`, `brightsign`). It is NOT read from here on the partner path — the server derives `agent_type` from `telemetry.agentType` plus hardware signals, and overrides a self-declared `web-browser` when the model/UA say otherwise, because partner SDKs running in a WebView historically reported `web-browser` for physical DOOH tablets. */\n agentType?: string | null;\n /** Agent build version. Do not use it to identify an artifact: three different Android build constants populate this one field across three unrelated numbering schemes, so the same string can mean different code. It is also not read from here on the partner path — the version the server keeps comes from the body `agent_version`/`sdk_version`, and only for heartbeats that self-identify as Trillboards SDKs. */\n agentVersion?: string | null;\n /** Camera/microphone sensing state. On the partner path ONLY the nested `cameraHealth` block is persisted (to the typed `camera_health_*` columns) — `cameraAvailable`, `cameraType`, `cameraCount`, `microphoneAvailable` and `sensingMode` reach no column on this path. The presence of `cameraHealth` is also an in-band signal that the heartbeat came from a Trillboards SDK, which is what allows `agent_version` to be stored. `cameraAvailable` self-devolves to false after a camera has been failed for over 24 h. */\n audienceSensing?: {\n cameraAvailable?: boolean | null;\n cameraCount?: number | null;\n cameraHealth?: {\n lastFailureClass?: string | null;\n lastFailureMessage?: string | null;\n lastFrameAtMs?: number | null;\n retryCount?: number | null;\n state?: string | null;\n [key: string]: unknown;\n } | null;\n cameraType?: string | null;\n microphoneAvailable?: boolean | null;\n sensingMode?: string | null;\n [key: string]: unknown;\n } | null;\n /** Declares volume and mute control. Hardcoded `true`/`true` on the Android agents — it is not probed against `AudioManager`, so it is a claim about the agent, not proof the hardware obeys. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n audioControl?: {\n mute?: boolean | null;\n volume?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Schema version of this capability block, persisted to `earner_screen_devices.capabilities_version` for drift attribution. Every shipped Android and Vega agent emits the constant `1` and nothing overrides it, so it carries no information today — but the server treats it as an arbitrary integer, not a bounded enum. Note the server only records it when an `mlCapabilities` block is present or when it is sent with no `mlCapabilities` at all. */\n capabilitiesVersion?: number | null;\n /** Declares an ambient-light and a temperature sensor. Only `ambientLight` is a real probe (`SensorManager.getDefaultSensor(TYPE_LIGHT) != null`, false on any throw); `temperature` is hardcoded `false` on the Android agents, and the actual temperature reading that does ship comes from the battery sensor via telemetry, not from here. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n environmentSensors?: {\n ambientLight?: boolean | null;\n temperature?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Declares HDMI input switching and app switching. Also hardcoded per agent build rather than probed (a tablet reports `hdmi: false`, `appSwitch: true`). Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n inputControl?: {\n appSwitch?: boolean | null;\n hdmi?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Whether the agent holds Android Device Owner (`DevicePolicyManager.isDeviceOwnerApp`) — the privilege that gates reboot, kiosk lock, APK install and wipe. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power, precisely so a partner cannot flip it and unlock those commands. */\n isDeviceOwner?: boolean | null;\n /** Declares remote restart/reboot/screenshot/cache-clear/kiosk/APK-install/wipe. On the first-party Android agents four of the seven are simply `isDeviceOwner` repeated, and the partner SDK reports the whole block `false` because \"partner hosts own their device management\". Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n managementCapabilities?: {\n clearCache?: boolean | null;\n installApk?: boolean | null;\n kioskMode?: boolean | null;\n reboot?: boolean | null;\n restart?: boolean | null;\n screenshot?: boolean | null;\n wipe?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** The hardware manifest that decides which on-device ML models a screen is offered, and one of the few capability blocks the partner path DOES persist. Two traps: every nullable integer must be sent as JSON `null`, never 0 — the server treats 0 as a probe-failure sentinel and drops it so the COALESCE upsert preserves the prior value — and `screenWidthPx`/`screenHeightPx` below 100 are rejected outright, after agents reporting inches corrupted 940+ rows. A `recommendedModelTier` of `UNKNOWN` (or NULL) excludes the device from on-device demographics entirely. */\n mlCapabilities?: {\n availableRamMb?: number | null;\n chipsetName?: string | null;\n chipsetVendor?: string | null;\n cpuAbi?: string | null;\n densityDpi?: number | null;\n gpuDelegateSupported?: boolean | null;\n gpuName?: string | null;\n hasNpu?: boolean | null;\n maxVlmSizeMb?: number | null;\n nnapiSupported?: boolean | null;\n npuName?: string | null;\n osApiLevel?: number | null;\n recommendedModelTier?: string | null;\n screenHeightPx?: number | null;\n screenWidthPx?: number | null;\n totalRamMb?: number | null;\n [key: string]: unknown;\n } | null;\n /** Declares HDMI-CEC, wake-on-LAN and soft-blackout support. On the Android agents these are HARDCODED per build, not probed (a tablet always reports `cec: false`, `wol: false`, `softBlackout: true`), so they describe the agent variant rather than the panel. Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power. */\n powerControl?: {\n cec?: boolean | null;\n softBlackout?: boolean | null;\n wol?: boolean | null;\n [key: string]: unknown;\n } | null;\n /** Counts ESP32-S3 Wi-Fi CSI sensor nodes discovered on the LAN — it is a statement about the venue's network, not about this device's own radio (`csiHardwareType` is the literal `\"esp32-s3\"` when any node is found, `\"none\"` otherwise). Parsed by the shared capability builder but then DISCARDED on the partner heartbeat path: it is not in the partner column whitelist, which is a deliberate security boundary — partner SDKs must not be able to drive device management or power; it is also the one CSI field the ingest schema deliberately keeps, since it is a startup capability counter rather than a streaming data field. */\n wifiCsiSensing?: {\n csiAvailable?: boolean | null;\n csiHardwareType?: string | null;\n csiNodeCount?: number | null;\n [key: string]: unknown;\n } | null;\n [key: string]: unknown;\n};\n\nexport type DeviceSummary = {\n /** Creation time of the DEVICE row, not of the linked screen (which can be created later). */\n created_at?: string;\n /** Trillboards-minted 24-char Mongo ObjectId hex for the `earner_screen_devices` row (`mongo_earnerscreen_device_id`). Not the `device_id` you sent at registration — that is returned as `external_device_id`. Accepted as the `{deviceId}` path parameter, as are `fingerprint` and `external_device_id`. */\n device_id?: string;\n /** Saved mutable partner category, independent of advertising classification. Legacy devices without a saved declaration retain their previous numeric-derived label until explicitly updated. */\n device_type?: string;\n /** Emits `orientation` (from the screen, defaulting to `landscape`) and `ppi` (from the device row). `width`/`height` still read `dimension_width`/`dimension_height`, columns DROPPED from `earner_screen_devices` by migration `20260527180000`, so they resolve to undefined and are omitted from the JSON entirely — registered pixels now live in `screen_width_px`/`screen_height_px`. Physical inches you send as `width_in`/`height_in` are stored but never echoed here. */\n display?: Record<string, unknown>;\n /** Static, unsigned player URL `https://screen.trillboards.com?fp=<fingerprint>`. It never expires or rotates, and is `null` until a screen is linked. */\n embed_url?: string;\n /** Venue-enrichment state. `status` reads `complete` only when a classification source exists AND `location` actually resolved, and a partner-declared venue category alone sets that source — so `complete` does not mean AI classification ran. `confidence` is dead: `venue_classification_confidence` has no column and no writer in the API, so it is always omitted. */\n enrichment?: Record<string, unknown>;\n /** Verbatim echo of the `device_id` you sent in the registration body (`partner_external_id`). It is the per-partner idempotency key: re-registering the same value updates the existing device rather than creating another. */\n external_device_id?: string;\n /** Deterministic device key: `P_` plus the first 24 hex chars of `md5(\"<your partner id>_<external_device_id>\")`. It never rotates, and it is the token embedded in `embed_url` as well as the heartbeat routing key. */\n fingerprint?: string;\n /** Resolved geo: the enriched screen row first, falling back to the registration-time device row, with placeholder strings coalesced away. `lat`/`lng` coalesce as a pair, `venue_type` is the OpenOOH child slug, and `timezone` alone is read device-first. */\n location?: Record<string, unknown>;\n location_capability?: PartnerLocationCapability;\n /** Stripe-style readiness, the same contract registration returns (see https://api.trillboards.com/docs/monetization-requirements). */\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n /** The linked screen's name, falling back to the raw `external_device_id` when the screen has none. A registration that omits `name` seeds the screen as `Partner Device: <device_id>`. */\n name?: string;\n requirements?: PartnerMonetizationRequirements;\n /** The linked screen's Mongo ObjectId hex (`earner_screens.mongo_earnerscreen_id`). This is the id every non-device partner endpoint takes — display settings, screen groups, fleet commands, analytics. Absent when no screen is linked. */\n screen_id?: string;\n /** The linked screen's `earner_screens.status` verbatim. Partner registration auto-approves, so the live value is `approved` (`deactivated` after a DELETE, `pending` only while no screen is linked) — not the `pending`/`active`/`offline`/`suspended` vocabulary the `Device` schema declares, whose mapper has no production call site. */\n status?: string;\n /** `earner_screen_devices.updated_at`, stamped `NOW()` by the device-mirror write buffer on every flush including heartbeats — a liveness signal, not a configuration-change marker. */\n updated_at?: string;\n /** OpenOOH classification rebuilt from the typed `screen_venue_taxonomy` row: `category` is the PARENT slug, `subcategory` the child, `openooh_venue_type_id` the numeric child id. Empty until classification lands, unless registration supplied a resolvable venue category. */\n venue?: Record<string, unknown>;\n};\n\nexport type DisplaySettingsInput = {\n /** Default ad duration in seconds */\n ad_duration_default?: number;\n /** Screen brightness percentage */\n brightness?: number;\n content_fit?: ContentFitSettings;\n /** Ad display mode */\n display_mode?: \"fullscreen\" | \"l-bar\" | \"split\";\n /** What to show when no ads */\n idle_content?: \"default_stream\" | \"black\" | \"logo\";\n /** Mute audio */\n mute?: boolean;\n /** Screen orientation */\n orientation?: \"landscape\" | \"portrait\" | \"auto\";\n /** QR code position on screen */\n qr_code_position?: \"bottom-left\" | \"bottom-right\" | \"top-left\" | \"top-right\" | \"none\";\n /** Transition effect between ads */\n transition_effect?: \"fade\" | \"slide\" | \"none\";\n /** Audio volume percentage */\n volume?: number;\n};\n\nexport type DisplaySettingsResponse = {\n /** NOT EMITTED and NOT WRITABLE — the identifier does not occur anywhere in the API source. The nearest real controls are `ad_interval_seconds` on this resource (rotation cadence, 30-300s) and the slot duration the playback policy derives (clamped 5-60s). */\n ad_duration_default?: number;\n /** NOT EMITTED by this endpoint. `buildAdSurfaces` is computed on a display-settings write, but only to populate the `display_settings_updated` socket event pushed to the device — the HTTP body is the formatter's output and contains no `ad_surfaces`. The declared item shape is wrong too: real surfaces carry `id`, `surface_type`, `enabled`, `display_area_ratio`, `dimensions` and `allowed_ad_types`, never `position`/`width_percent`/`height_percent`. The L-bar PUT is the one HTTP response that does return them. */\n ad_surfaces?: Array<{\n height_percent?: number;\n id?: string;\n position?: string;\n width_percent?: number;\n }>;\n /** NOT EMITTED and NOT WRITABLE. The writer's ten-key allow-list has no `brightness`, so a PUT silently drops it, and the formatter never returns one. Brightness exists in this product only as inbound device telemetry on the heartbeat, which this resource cannot set. */\n brightness?: number;\n content_fit?: ContentFitSettings;\n /** Real and emitted: `fullscreen` (default), `l-bar` or `pip`, read from the typed `display_mode` column in preference to the legacy `display_preferences` JSONB. Note the writer validates a THREE-value enum including `pip`, while the L-bar resource's own `display_mode` accepts only `fullscreen`/`l-bar`. */\n display_mode?: string;\n /** NOT EMITTED and NOT WRITABLE — the identifier does not occur anywhere in the API source. What actually plays when no ad is available is the screen's default streams, managed through the default-streams routes. */\n idle_content?: string;\n /** NOT EMITTED and NOT WRITABLE. Use `sound_enabled: false` instead — that key the formatter does return, defaulting to `true`. */\n mute?: boolean;\n /** Always `display_settings`. The response is FLAT — no `success`/`data` envelope — and it comes from exactly one formatter shared by the GET, PUT and PATCH, so all three return an identical shape. */\n object?: string;\n /** NOT EMITTED under this name — the formatter returns `screen_orientation` instead (`landscape`, `portrait`, `mixed` or `unknown`, defaulting to `landscape`). The writer's allow-list also only accepts `screen_orientation`, so an `orientation` key in a PUT body is silently dropped. */\n orientation?: string;\n /** NOT EMITTED by this endpoint, for the same reason as `ad_surfaces` — it is computed on a write only to fill the device socket event. The declared `max_duration_seconds`/`min_break_between_ads`/`allow_skip` keys do not exist in the real policy either; `buildPlaybackPolicy` produces `policy_version`, millisecond intervals, `max_paid_share`, `surface_policy`, `schedule_policy`, `pip_settings` and `lbar_settings`. */\n playback_policy?: {\n allow_skip?: boolean;\n max_duration_seconds?: number;\n min_break_between_ads?: number;\n };\n /** NOT EMITTED and NOT WRITABLE — the identifier does not occur anywhere in the API source. */\n qr_code_position?: string;\n /** Echo of the server-assigned `req.requestId`, attached only when one exists — the key is absent, not null, otherwise. */\n request_id?: string;\n /** Echoed from the `{screenId}` path parameter rather than read from a column. */\n screen_id?: string;\n /** NOT EMITTED and NOT WRITABLE — the identifier `transition_effect` does not occur anywhere in the API source. There is no transition control on this resource. */\n transition_effect?: string;\n /** ISO-8601 of the SCREEN row's `updatedAt`, not a display-settings-specific timestamp; when the screen has none the formatter substitutes the current time, so it is never null and never proves a write landed. */\n updated_at?: string;\n /** NOT EMITTED and NOT WRITABLE — the string `volume` does not appear in the display-settings service or the formatter at all. The only audio control on this resource is the boolean `sound_enabled`. */\n volume?: number;\n};\n\n/**\n * User-owned ad screens. Each row is a logical screen that can display ads. Links user to device. PG primary with Mongo legacy mirror.\n */\nexport type EarnerScreens = {\n ad_interval_seconds?: number | null;\n ads_disabled_reasons: Array<string>;\n advertisement_sizing?: string | null;\n archetype_photo_key?: string | null;\n archetype_photo_synced_at?: string | null;\n archetype_photo_url?: string | null;\n auction_cohort?: string | null;\n auction_enabled_at?: string | null;\n auction_mode?: string | null;\n auction_type?: string | null;\n avg_dwell_time_seconds?: number | null;\n back_online_alert_sent_at?: string | null;\n billing_mode: string;\n block_group_geoid?: string | null;\n blocked_advertisers?: Array<string> | null;\n blocked_iab_categories?: Array<string> | null;\n brand_substitution_consent_at?: string | null;\n brand_substitution_consent_by?: string | null;\n brand_substitution_mode: string;\n branding_overlay_enabled: boolean;\n branding_overlay_hide_on_ads: boolean;\n branding_overlay_logo_transformed_url: string;\n branding_overlay_logo_url: string;\n /** NUMERIC(5,4). */\n branding_overlay_opacity: number;\n /** NUMERIC(5,4). */\n branding_overlay_padding_ratio: number;\n branding_overlay_placement: string;\n branding_overlay_position: string;\n /** NUMERIC(5,4). */\n branding_overlay_size_ratio: number;\n cms_payment_status: string;\n commercial_value_score?: number | null;\n content_filtering_enabled?: boolean | null;\n /** deleted_at IS NULL required — soft-delete nulls earnerscreen_device_id for partial unique index */\n deleted_at?: string | null;\n delivery_mode: string;\n device_platform_override?: string | null;\n diagonal_inches?: number | null;\n display_mode?: string | null;\n distributor_id?: number | null;\n dma_code?: string | null;\n dma_name?: string | null;\n dynamic_floor_pricing?: boolean | null;\n enrichment_attempts: number;\n enrichment_failed_at?: string | null;\n environment_type?: string | null;\n /** NUMERIC(12,6). */\n floor_price_cpm?: number | null;\n foot_traffic_multiplier?: number | null;\n gam_ad_unit_code?: string | null;\n gam_ad_unit_id?: string | null;\n gam_ad_unit_path?: string | null;\n gam_sync_status?: string | null;\n gam_synced_at?: string | null;\n geocode_source?: string | null;\n geocoded_at?: string | null;\n geocoding_raw_response?: Record<string, unknown> | null;\n hb_allocation?: number | null;\n hb_enabled?: boolean | null;\n hb_force_request?: boolean | null;\n hb_last_sync_at?: string | null;\n hb_min_interval_seconds?: number | null;\n hb_provider?: string | null;\n hb_request_mode?: string | null;\n hb_timeout_ms?: number | null;\n hb_vast_tag_url?: string | null;\n height_inches?: number | null;\n hive_stack_screen_id?: string | null;\n hive_stack_site_id?: string | null;\n hive_stack_sync_status?: string | null;\n hive_stack_synced_at?: string | null;\n hive_stack_unit_id?: string | null;\n hive_stack_unit_uuid?: string | null;\n is_demo_data: boolean;\n is_standby: boolean;\n l_bar_ads_enabled?: boolean | null;\n l_bar_position?: string | null;\n last_enrichment_attempt_at?: string | null;\n last_offline_transition_at?: string | null;\n last_programmatic_sync_at?: string | null;\n latitude?: number | null;\n longitude?: number | null;\n loop_plan_id?: number | null;\n media_capability?: \"image_video\" | \"image_only\" | \"video_only\" | null;\n mediation_priority?: number | null;\n mobile_distance_threshold_m?: number | null;\n mobile_update_interval_s?: number | null;\n mobile_vehicle_type?: string | null;\n neighborhood?: string | null;\n ntp_sync_required: boolean;\n offline_alert_sent_at?: string | null;\n offline_push_alert_sent_at?: string | null;\n operating_hours?: Record<string, unknown> | null;\n partner_mongo_id?: string | null;\n peak_hours?: Array<string> | null;\n photo_flag_notes?: string | null;\n photo_flag_reason?: string | null;\n photo_flagged: boolean;\n photo_flagged_at?: string | null;\n photo_flagged_by_mongo_id?: string | null;\n photo_notification_count: number;\n photo_notification_sent_at?: string | null;\n photo_quality_sent_at?: string | null;\n photo_review_status?: string | null;\n photos?: Record<string, unknown> | null;\n physical_size_set_at?: string | null;\n physical_size_set_by?: string | null;\n place_name?: string | null;\n placement_type?: string | null;\n places_rating?: number | null;\n places_review_count?: number | null;\n pref_allow_religious?: boolean | null;\n pref_allow_tobacco?: boolean | null;\n pref_allowed_categories?: Array<string> | null;\n pref_allowed_keywords?: Array<string> | null;\n pref_allowed_subjects?: Array<string> | null;\n pref_auto_approve_known_brands?: boolean | null;\n pref_blocked_categories?: Array<string> | null;\n pref_blocked_keywords?: Array<string> | null;\n pref_blocked_subjects?: Array<string> | null;\n pref_level?: string | null;\n pref_max_age_rating?: string | null;\n preferred_deal_ids: Array<string>;\n prog_allocation_pct?: number | null;\n prog_currency: string;\n programmatic_enabled: boolean;\n region: string;\n registration_source?: string | null;\n screen_placement?: string | null;\n serving_tenant_id?: number | null;\n slot_duration_seconds?: number | null;\n sound_enabled?: boolean | null;\n ssp_enabled?: boolean | null;\n state_iso_3166_2?: string | null;\n sync_enabled?: boolean | null;\n sync_group_name?: string | null;\n sync_is_master?: boolean | null;\n sync_last_sync_at?: string | null;\n sync_master_screen_id?: string | null;\n taggify_screen_id?: string | null;\n taxonomy_migrated_at?: string | null;\n taxonomy_spec_version?: string | null;\n venue_category?: string | null;\n venue_child?: string | null;\n venue_child_id?: string | null;\n venue_city?: string | null;\n /** enrichment_status: PG GENERATED from (venue_classification_source, enrichment_failed_at); a real classification DOMINATES a stale failure stamp (success wins). Never written directly. Values: pendi... */\n venue_classification_source?: string | null;\n venue_grandchild?: string | null;\n venue_parent?: string | null;\n venue_state?: string | null;\n venue_subcategory?: string | null;\n waterfall_optimized_at?: string | null;\n /** waterfall_partners is the ONLY pin store (order + whitelist; screen_partner_settings was never built). Serving reads it only with a screen_header_bidding_config row and ignores it once waterfall_op... */\n waterfall_partners: Array<string>;\n waterfall_total_timeout_ms?: number | null;\n /** Physical width_inches/height_inches/diagonal_inches are inches. Pixels live on earner_screen_devices; the raw screen has no resolution_width/resolution_height columns. */\n width_inches?: number | null;\n};\n\nexport type EarningsBreakdownResponse = {\n /** Keyed by `date` for `group_by=day|week` and by `screen_id` (plus a `screen_name`) for `group_by=screen`; the unused key is absent rather than null. Week rows are labelled `<year>-W<ISO week>`. `earnings_cents` is allocated cumulatively so the rows sum exactly to `summary.total_cents`. */\n breakdown?: Array<{\n /** Date or screen_id depending on group_by */\n date?: string;\n earning_sources?: EarningsSources;\n earnings_cents?: number;\n impressions?: number;\n /** Screen ID (when grouped by screen) */\n screen_id?: string;\n }>;\n /** **Both fields are hardcoded** — `estimated_cents` is always `0` and `confirmation_date` always `null`. Read `EarningsResponse.pending_confirmation_cents` for the real Net-60 pending figure. */\n pending_programmatic?: {\n confirmation_date?: string | null;\n estimated_cents?: number;\n };\n /** `start`/`end` echo the request; with neither supplied the window is the last 30 days ending now. The end bound is EXCLUSIVE in the underlying query (`period_date < end`), so passing today's date omits today. */\n period?: {\n end?: string;\n group_by?: \"day\" | \"week\" | \"screen\";\n start?: string;\n };\n /** Integer US cents for the selected period. With source reporting enabled, direct_cents is verified first-party revenue and programmatic_cents is the remainder; earning_sources supplies the business classification. Disabled reporting retains the legacy split. */\n summary?: {\n direct_cents?: number;\n earning_source_version?: 1;\n earning_sources?: EarningsSources;\n programmatic_cents?: number;\n total_cents?: number;\n total_impressions?: number;\n };\n};\n\n/**\n * Partner earnings summary with optional daily series\n * (`@trillboards/api-client` `EarningsData`).\n *\n */\nexport type EarningsData = {\n /** **Never emitted.** No partner earnings endpoint computes a CPM; the earnings chart returns impressions and cents only, so a caller must divide for itself. */\n average_cpm: number;\n /** Optional per-day earnings/impressions series. */\n daily?: Array<{\n /** Day label (YYYY-MM-DD). */\n date: string;\n earnings: number;\n impressions: number;\n }>;\n /** **Never emitted**, so its unit is undefined. Every money field the partner earnings endpoints actually return is integer US cents and carries a `_cents` suffix. */\n last_payout_amount?: number;\n /** **Never emitted.** No handler populates it — read `GET /v1/partner/earnings/transactions?type=payout`, whose rows carry `created_at` and `amount_cents`. */\n last_payout_date?: string;\n /** Balance not yet paid out. */\n pending_payout: number;\n /** Declared for the SDK type but **not emitted**: `GET /v1/partner/connect/earnings` returns `{summary, chart, period}` where `period` is an OBJECT (`days`/`start`/`end`), not this string. */\n period: string;\n /** **Not emitted under this name**, so its unit is undefined. The live earnings chart returns `summary.total_earnings_cents` — integer US cents — summed over the requested window from the payout-accounting rollup of `programmatic_earnings_daily`. */\n total_earnings: number;\n /** **Not emitted under this name.** The live earnings chart returns `summary.total_impressions`, the impression count carried on the same daily earner-revenue rows the cents are summed from. */\n total_impressions: number;\n};\n\nexport type EarningsResponse = {\n /** Amount available for immediate payout */\n available_for_payout_cents?: number;\n /** Current-month integer US cents. With source reporting enabled, direct_campaigns is verified first-party revenue and programmatic_google is the remaining aggregate, not Google-specific. programmatic_floodgates remains zero. Prefer earning_sources; disabled reporting retains the legacy all-programmatic split. */\n breakdown?: {\n direct_campaigns?: number;\n programmatic_floodgates?: number;\n programmatic_google?: number;\n };\n earning_source_version?: 1;\n earning_sources?: EarningsSources;\n /** `amount_cents` is integer US cents and simply repeats `available_for_payout_cents`; `date` is the 1st of next month, computed in the handler with no reference to any scheduled transfer; `stripe_status` is the partner's Connect account status, which must be `active` before a payout request is accepted. */\n next_payout_estimate?: {\n amount_cents?: number;\n date?: string;\n stripe_status?: string;\n };\n /** Minimum amount required for payout */\n payout_threshold_cents?: number;\n /** Programmatic earnings pending Net-60 confirmation */\n pending_confirmation_cents?: number;\n /** Partner's revenue share percentage */\n revenue_share_percent?: number;\n /** Estimated earnings for current month */\n this_month_cents?: number;\n /** Total earnings since partner started */\n total_lifetime_cents?: number;\n};\n\n/**\n * Optional reporting breakdown in integer US cents. Components sum to the existing amount. Missing evidence is Unclassified; absence of this object means reporting is unavailable.\n */\nexport type EarningsSources = {\n /** Paid first-party portal and offline IO bookings. */\n direct_bookings: number;\n /** Verified open-auction delivery outside a private deal. */\n open_exchange: number;\n /** Verified delivered DSP/SSP PMP, PG and preferred deals. */\n programmatic_deals: number;\n /** Earnings lacking supported allocation evidence. */\n unclassified: number;\n};\n\n/**\n * Legacy free-text error shape. COLLAPSED onto the shared `LegacyError`\n * definition so there is exactly one declaration of this shape across the\n * specs. Kept as a distinct NAME because hand-authored operations\n * reference it by that name; the shape is unchanged.\n *\n */\nexport type Error = LegacyError;\n\n/**\n * The 143 CATALOGUED error codes, generated from utils/errorCatalog.js — the same catalog that backs https://api.trillboards.com/docs/errors. This is the documented registry, NOT the complete set of codes the API can emit: a response `code` is an open string (see `TrillboardsError`). Use this list to recognise a code, never to assume a response cannot carry another.\n */\nexport type ErrorCode = \"AUTH_REQUIRED\" | \"BRAND_CONFIGURATION_FAILED\" | \"BRAND_PROFILE_CONFLICT\" | \"BRAND_PROFILE_NOT_FOUND\" | \"CREATIVE_ADVERTISEMENT_NOT_OWNED\" | \"CREATIVE_MODERATION_UNAVAILABLE\" | \"CREATIVE_NOT_LINKED\" | \"CREATIVE_NOT_READY\" | \"CREATIVE_POLICY_CONFLICT\" | \"CREATIVE_TOO_LARGE\" | \"EXPERIMENT_COMPLETED\" | \"EXPERIMENT_NOT_FOUND\" | \"FEEDBACK_POLICY_REQUIRED\" | \"IDEMPOTENCY_CONFLICT\" | \"INVALID_BRAND_RULES\" | \"INVALID_CREATIVE_URL\" | \"INVALID_CREATIVE_WEIGHTS\" | \"INVALID_FEEDBACK_CREATIVE\" | \"INVALID_FEEDBACK_OBJECTIVE\" | \"INVALID_FEEDBACK_REQUEST\" | \"INVALID_POLICY_VERSION\" | \"INVALID_VARIANTS\" | \"MEDIA_BUY_NOT_FOUND\" | \"OPERATION_ALREADY_COMMITTED\" | \"OPERATION_IN_PROGRESS\" | \"POLICY_NOT_AVAILABLE\" | \"SOURCE_CREATIVE_NOT_FOUND\" | \"UNSUPPORTED_CREATIVE_TYPE\" | \"VARIANT_IDENTITY_CONFLICT\" | \"ad_interval_out_of_range\" | \"allocation_out_of_range\" | \"analytics_unavailable\" | \"api_key_expired\" | \"api_key_owner_missing\" | \"api_key_revoked\" | \"array_items_must_be_strings\" | \"array_too_large\" | \"auth_error\" | \"authentication_required\" | \"batch_size_exceeded\" | \"blocked_advertisers_too_large\" | \"blocked_iab_categories_too_large\" | \"client_ip_required\" | \"concurrent_request_limit\" | \"conflict\" | \"conflicting_lists\" | \"creative_policy_conflict\" | \"creative_policy_forbidden\" | \"daily_quota_exceeded\" | \"database_error\" | \"dataset_not_scopable\" | \"device_already_registered\" | \"device_identity_missing\" | \"device_identity_underivable\" | \"device_not_found\" | \"device_offline\" | \"dsp_access_denied\" | \"error\" | \"field_must_be_array\" | \"field_must_be_boolean\" | \"field_too_long\" | \"floor_price_out_of_range\" | \"forbidden\" | \"idempotency_error\" | \"idempotency_key_in_use\" | \"idempotency_key_mismatch\" | \"insufficient_data\" | \"insufficient_permissions\" | \"insufficient_scope\" | \"internal_error\" | \"invalid_ad_surface_mode\" | \"invalid_age_rating\" | \"invalid_api_key\" | \"invalid_api_key_format\" | \"invalid_array_items\" | \"invalid_creative_policy\" | \"invalid_currency\" | \"invalid_dataset\" | \"invalid_device_id\" | \"invalid_dimensions\" | \"invalid_display_mode\" | \"invalid_field_type\" | \"invalid_field_value\" | \"invalid_fingerprint\" | \"invalid_json\" | \"invalid_lbar_position\" | \"invalid_lbar_settings\" | \"invalid_measures\" | \"invalid_media_url\" | \"invalid_order_by\" | \"invalid_orientation\" | \"invalid_pip_position\" | \"invalid_pip_settings\" | \"invalid_preference_level\" | \"invalid_preferences\" | \"invalid_provider\" | \"invalid_screen_id\" | \"invalid_segment_rules\" | \"invalid_sizing_mode\" | \"invalid_stream_type\" | \"invalid_webhook_events\" | \"invalid_webhook_url\" | \"lbar_settings_must_be_object\" | \"lbar_size_out_of_range\" | \"missing_required_field\" | \"not_found\" | \"openrtb_auth_failed\" | \"openrtb_config_missing\" | \"paired_training_insert_failed\" | \"paired_training_rate_limit_exceeded\" | \"partner_inactive\" | \"pip_margin_out_of_range\" | \"pip_settings_must_be_object\" | \"pip_size_ratio_out_of_range\" | \"preferences_must_be_object\" | \"preferences_required\" | \"preset_id_required\" | \"preset_not_found\" | \"rate_limit_exceeded\" | \"resource_locked\" | \"screen_ids_required\" | \"screen_not_found\" | \"screen_not_in_scope\" | \"sdk_enrich_rate_limit_exceeded\" | \"sdk_impression_rate_limit_exceeded\" | \"sdk_qr_beacon_rate_limit_exceeded\" | \"sdk_qr_scan_rate_limit_exceeded\" | \"segment_limit_exceeded\" | \"segment_not_found\" | \"service_unavailable\" | \"stale_data\" | \"stream_content_required\" | \"stream_not_found\" | \"tier_insufficient\" | \"timeout\" | \"timeout_out_of_range\" | \"unknown_agent_type\" | \"unsupported_media_type\" | \"validation_error\" | \"webhook_limit_exceeded\" | \"webhook_not_found\" | \"webhook_secret_expired\" | \"webhook_url_unreachable\";\n\nexport type ErrorCodeResponse = {\n code: string;\n description: string;\n doc_url: string;\n /** Example canonical error envelope for this code. */\n example_response: {\n error: {\n code: string;\n doc_url: string;\n message: string;\n param?: unknown;\n type: string;\n };\n };\n http_status: number;\n /** Always \"error_code\". */\n object: \"error_code\";\n type: string;\n};\n\n/**\n * A single partner API error-log record\n * (`@trillboards/api-client` `ErrorEntry`) — one logged error occurrence\n * scoped to the partner. Distinct from the public error *catalog* entries\n * (`ErrorListItem` / `ErrorCodeResponse`), which describe error codes in\n * the abstract.\n *\n */\nexport type ErrorEntry = {\n /** Stable machine error code (e.g. not_found). */\n code: string;\n /** Derived mechanically as `https://api.trillboards.com/docs/errors#<code>`, so it is always well-formed whether or not that anchor exists. It appears on live error envelopes and catalog entries; no per-partner error-log endpoint returns it. */\n doc_url: string;\n /** The API path that produced the error. */\n endpoint: string;\n /** **No producer.** `GET /v1/errors` returns the static error CATALOG (code definitions in the abstract), not per-partner occurrences, and the per-request metadata the API does retain is keyed by `request_id` and carries no `id`. */\n id: string;\n /** **Never emitted as part of a logged occurrence.** Human-readable text appears only on a live error envelope or a catalog entry; the retained per-request record stores `error_code`/`error_type` and no message. */\n message: string;\n /** The HTTP method of the failing request. */\n method: string;\n /** The request parameter the error concerns, if any. */\n param?: string;\n /** The `req_`-prefixed identifier of the failing request, minted server-side and returned both on the `X-Request-Id` header and inside every error envelope. It is the only handle that links a caller-side failure to server-side request metadata. */\n request_id: string;\n /** **Not emitted by any error endpoint.** The per-request metadata the API retains does stamp an ISO timestamp at response time, but it lives in a bounded in-memory LRU cache, not a queryable error log. */\n timestamp: string;\n /** Stripe-style error taxonomy (matches the SDK's ApiErrorType). */\n type: \"invalid_request_error\" | \"authentication_error\" | \"permission_error\" | \"rate_limit_error\" | \"idempotency_error\" | \"api_error\";\n};\n\n/**\n * The complete set of error envelopes this API may return. Documented on operations whose surface emits more than one — see `x-superseded-by` on each member for the migration target. New endpoints return `TrillboardsError`; switch on `error.code`, never on a message string.\n */\nexport type ErrorEnvelope = TrillboardsError | HybridError | LegacyCodedError | LegacyError;\n\nexport type ErrorListItem = {\n code: string;\n description: string;\n doc_url: string;\n http_status: number;\n type: string;\n};\n\nexport type ErrorListResponse = {\n data: Array<ErrorListItem>;\n /** Always \"list\". */\n object: \"list\";\n /** Total number of error codes. */\n total: number;\n};\n\n/**\n * Stripe-style error taxonomy. Derived from the distinct `type` values in utils/errorCatalog.js (6 values).\n */\nexport type ErrorType = \"api_error\" | \"authentication_error\" | \"idempotency_error\" | \"invalid_request_error\" | \"permission_error\" | \"rate_limit_error\";\n\n/**\n * Exact DSP-matchable audience identity kept separate from the resettable\n * OS advertising ID. `hem_sha256` is an existing SHA-256 digest: send it\n * directly (the server lowercases hexadecimal once and never hashes it\n * again). `uid2_token` is an opaque, case-sensitive UID2 advertising\n * token: send it exactly as issued and include `expires_at` so it can be\n * refreshed; tokens contain no whitespace. Use `unavailable` with no\n * `id` to clear a prior value.\n *\n */\nexport type ExtendedIdentity = {\n /** OpenRTB person-based identifier type. */\n atype: 3;\n /** When the token stops being usable — for a UID2 token this is the refresh deadline, and it is stored verbatim regardless of `status` (unlike the advertising-identity envelope, which discards `expires_at` on an `available` state). `null` means no declared expiry, not \"already expired\". */\n expires_at?: string | null;\n /** The identity value itself, up to 4096 characters and containing no whitespace. Omit it (or send `null`) with `unavailable` to CLEAR a previously stored identity — that is the only way to retract one; sending the envelope with `available` and an empty id is rejected instead. */\n id?: string | null;\n /** `hem_sha256` must be exactly 64 hexadecimal characters and is lowercased ONCE server-side and never re-hashed — send the digest, not the email. `uid2_token` is an opaque case-sensitive token forwarded byte-for-byte with only a whitespace check, so do not trim, lowercase or re-encode it. Together with `source` this pair is the row key: one identity per `(id_type, source)` per device. */\n id_type: \"hem_sha256\" | \"uid2_token\";\n /** When the device observed this identity — and it is the CONFLICT-RESOLUTION CLOCK, not just provenance: the upsert applies only when this timestamp is greater than or equal to the one already stored, so a replayed or out-of-order envelope is silently discarded with no error. An unparseable value rejects the whole array. */\n observed_at: string;\n /** Canonical top-level domain for this identity system. */\n source: string;\n /** Version of the SDK or integration that produced this identity, up to 128 characters, kept for provenance only — no server logic branches on it. It is trimmed, and a whitespace-only string is stored as `null` rather than as an empty string. */\n source_version?: string | null;\n /** `available` requires `id`; `unavailable` requires `id` to be ABSENT — sending both is a validation failure, and because normalisation is all-or-nothing across the array that single bad element discards every other identity in the same request while the heartbeat still returns 200. */\n status: \"available\" | \"unavailable\";\n};\n\nexport type FeedbackBrand = {\n advertisement_id: string;\n brand_name: string;\n profile_id: string;\n reactive_enabled: true;\n stance: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackBrandRequest = {\n /** Native brand reference assets used by creative generation. */\n brand_assets?: Array<Record<string, unknown>>;\n /** Optional brand intent supplied to the native creative generator. */\n brand_intent_text?: string | null;\n /** Advertiser brand name for the experiment’s native campaign. */\n brand_name: string;\n /** Native brand colours, typography, voice, products and required or prohibited elements. */\n brand_rules: {\n /** The advertiser brand name, e.g. \"Nike\". */\n brand_name: string;\n /** Elements that MUST appear in every creative, e.g. [\"logo top-right\",\"legal disclaimer\"]; may be empty. */\n mandatory_elements: Array<string>;\n /** Brand colour palette. */\n palette: {\n /** Accent colours; may be empty. */\n accents: Array<string>;\n /** Primary brand colour (hex or named); empty string if unknown. */\n primary: string;\n /** Secondary brand colour; empty string if none. */\n secondary: string;\n };\n /** Key products to feature; may be empty. */\n products: Array<{\n /** Short product description; empty string if none. */\n description: string;\n /** Product name. */\n name: string;\n }>;\n /** Elements that must NEVER appear, e.g. [\"competitor logos\",\"alcohol\"]; may be empty. */\n prohibited_elements: Array<string>;\n /** Preferred reactive stances for this brand; may be empty. */\n stance_preferences: Array<\"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\">;\n /** Approved taglines / slogans; may be empty. */\n taglines: Array<string>;\n /** Typography guidance. */\n typography: {\n /** Body typeface / style guidance; empty string if none. */\n body: string;\n /** Headline typeface / style guidance; empty string if none. */\n headline: string;\n };\n /** Voice + tone adjectives, e.g. [\"confident\",\"playful\"]; may be empty. */\n voice_tone: Array<string>;\n };\n /** Optional existing brand profile owned by this advertiser and advertisement. */\n profile_id?: string;\n /** Native reactive relationship used to generate or stage this creative. */\n stance?: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackBrandResponse = {\n data: FeedbackBrand;\n success: true;\n};\n\nexport type FeedbackCreateRequest = {\n /** Exact decimal policy version; zero enrolls an unclaimed native policy. */\n expected_policy_version?: string;\n /** Caller-owned key for this exact operation; do not reuse for changed inputs. */\n idempotency_key: string;\n /** Your funded native AdCP media buy ID. */\n media_buy_id: string;\n /** Name for this funded creative feedback experiment. */\n name: string;\n /** Measured objective: gaze share 0–1, gaze overlap milliseconds, or capped mean dwell milliseconds. */\n objective: \"gaze_share\" | \"gaze_overlap_ms\" | \"dwell_ms\";\n /** Native package ID within that media buy. */\n package_id: string;\n};\n\nexport type FeedbackCreativeReview = {\n success: boolean;\n};\n\nexport type FeedbackExperiment = {\n advertisement_id: string;\n advertiser_id: string;\n id: string;\n media_buy_id: string;\n name: string;\n objective: \"gaze_share\" | \"gaze_overlap_ms\" | \"dwell_ms\";\n package_id: string;\n policy_mode: \"attribution\" | \"experiment\" | \"external_agent\";\n policy_version: string;\n status: string;\n variants: Array<FeedbackVariant>;\n};\n\nexport type FeedbackExperimentDetail = FeedbackExperiment & {\n creatives: Array<FeedbackRecoveredCreative>;\n creatives_truncated: boolean;\n };\n\nexport type FeedbackExperimentDetailResponse = {\n data: FeedbackExperimentDetail;\n success: true;\n};\n\nexport type FeedbackExperimentResponse = {\n data: FeedbackExperiment;\n success: true;\n};\n\nexport type FeedbackGenerateRequest = {\n /** Image aspect ratio, such as 16:9, matched to your booked screens. */\n aspectRatio?: string;\n /** Creative direction added to your configured native brand rules. */\n brief?: string;\n /** Unique caller-owned generation key; committed retries expose creativeId and renderKey in the receipt. */\n idempotency_key: string;\n /** Native reactive relationship used to generate or stage this creative. */\n stance?: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackGenerateResponse = {\n data: FeedbackGeneratedCreative;\n success: true;\n};\n\nexport type FeedbackGeneratedCreative = {\n brandReviewStatus: string;\n cdnUrl: string;\n creativeId: string;\n deduped: boolean;\n headline?: string | null;\n moderationStatus?: string;\n renderKey: string;\n status?: string;\n success: true;\n usage_receipt: Record<string, unknown>;\n};\n\n/**\n * Exactly one native image source is required. source_creative_id resolves only within the authenticated partner. Inline bytes require content_type and are validated against the actual image MIME and byte hash by native staging.\n */\nexport type FeedbackImportRequest = {\n /** Public HTTPS image URL; provide exactly one image source. */\n asset_url?: string;\n /** Actual image MIME; required for inline bytes and checked against decoded content. */\n content_type?: \"image/png\" | \"image/jpeg\" | \"image/jpg\" | \"image/webp\";\n /** Optional headline stored with the native imported creative. */\n headline?: string;\n /** Unique caller-owned import key; a committed retry returns the existing usage receipt. */\n idempotency_key: string;\n /** Base64 PNG, JPEG or WebP bytes; provide exactly one source and content_type. */\n image_base64?: string;\n /** Existing creative ID owned by the authenticated partner; provide exactly one image source. */\n source_creative_id?: string;\n /** Native reactive relationship used to generate or stage this creative. */\n stance?: \"adversarial\" | \"complementary\" | \"same_brand\" | \"intent_capture\";\n};\n\nexport type FeedbackPolicyRequest = {\n /** Exact decimal policy version from the latest experiment; stale updates return 409. */\n expected_version: string;\n /** Replacement weights for registered variants; omitted variants are inactive. */\n weights: Array<{\n /** Registered native creative ID to assign this weight. */\n creative_id: string;\n /** Weight between zero and one; zero disables selection. Eligible weights normalize at serving. */\n weight: number;\n }>;\n};\n\nexport type FeedbackRecoveredCreative = {\n advertisement_mongo_id: string | null;\n brand_profile_id: string | null;\n brand_review_status: string;\n cdn_url: string;\n content_sha256: string | null;\n created_at: string;\n creative_id: string;\n headline: string | null;\n linked_to_experiment_ad: boolean;\n moderation_status: string | null;\n render_key: string | null;\n reviewed_at: string | null;\n stance: string | null;\n};\n\nexport type FeedbackRegisterVariantsRequest = {\n /** Exact decimal policy version from the latest experiment; stale updates return 409. */\n expected_version: string;\n /** Approved native variants; identity and bytes remain immutable. */\n variants: Array<{\n /** Approved native generated or imported creative ID. */\n creative_id: string;\n /** Your model version associated with this immutable variant. */\n model_version?: string;\n /** Stable model variant identity within this experiment. */\n variant_id: string;\n }>;\n};\n\nexport type FeedbackReviewRequest = {\n /** Owned native creative ID awaiting your explicit brand review. */\n creative_id: string;\n /** Approve or reject brand use; global AI moderation remains a separate gate. */\n decision: \"approve\" | \"reject\";\n};\n\nexport type FeedbackReviewResponse = {\n data: FeedbackCreativeReview;\n success: true;\n};\n\nexport type FeedbackRewardQuery = {\n /** Opaque next_cursor from this same date scope; rewind after scan_complete. */\n cursor?: string;\n /** Inclusive first play date, YYYY-MM-DD; date range is at most 31 days. */\n from: string;\n /** Unique caller-owned billing key for this page; committed retries return the receipt, not another read. */\n idempotency_key: string;\n /** Maximum native play states returned on this metered page. */\n limit?: number;\n /** Inclusive last play date, YYYY-MM-DD; date range is at most 31 days. */\n to: string;\n};\n\nexport type FeedbackRewardRow = {\n action: \"upsert\" | \"retract\";\n ad_id: string | null;\n build_stamp: string;\n builder_version: string;\n /** Four ordered strings: play_date, screen_mongo_id, play_source, play_key. */\n canonical_key: Array<string>;\n content_sha256: string;\n /** Lossless issued v1 JSON snapshot; empty string when unissued. Contains variant_id and creative_policy_version. */\n creative_feedback: string;\n creative_id: string | null;\n dwell_capped_ms_mean: number | null;\n dwell_overlap_ms: number | null;\n dwell_windows_n: number | null;\n gaze_face_rows_n: number | null;\n gaze_overlap_ms: number | null;\n /** Measured gaze share, 0–1; NULL when not measured. */\n gaze_pct_on_screen: number | null;\n gaze_seconds: number | null;\n gaze_windows_n: number | null;\n play_completed_at: string | null;\n play_date: string;\n play_key: string;\n play_source: string;\n play_started_at: string | null;\n request_id: string | null;\n reward_revision_id: string;\n screen_mongo_id: string;\n superseded: number;\n};\n\nexport type FeedbackRewards = {\n experiment_id: string;\n next_cursor: string | null;\n objective: \"gaze_share\" | \"gaze_overlap_ms\" | \"dwell_ms\";\n rewind_next_poll: boolean;\n rows: Array<FeedbackRewardRow>;\n scan_complete: boolean;\n usage_receipt: Record<string, unknown>;\n view: \"latest_state\";\n};\n\nexport type FeedbackRewardsResponse = {\n data: FeedbackRewards;\n success: true;\n};\n\nexport type FeedbackStopRequest = {\n /** Exact decimal policy version from the latest experiment; stale updates return 409. */\n expected_version: string;\n};\n\nexport type FeedbackVariant = {\n content_sha256?: string | null;\n creative_id: string;\n model_version?: string | null;\n variant_id: string;\n};\n\n/**\n * A fleet-command job: one batch that fanned a device command across a screen group's\n * members. Poll via GET /fleet-commands/{id}.\n *\n */\nexport type FleetCommand = {\n /** The device command that was fanned out — one of `reload`, `update_settings`, `restart`, `screenshot`, `clear_cache`, `update_content`, `refresh_ads`, `update_config`, `get_state`, `show_ad`, `play_ad`. Validated in the application against `ALLOWED_COMMANDS`, with no database constraint, so the allow-list can grow without a schema migration. */\n command_type?: string;\n /** Set on BOTH terminal states — `completed` and `failed` — so it is not a success marker. `null` only while the job has not reached a terminal state. */\n completed_at?: string | null;\n /** When the job row was inserted, i.e. when the batch was accepted. Because execution is synchronous, `created_at` and `completed_at` bracket the entire fan-out. */\n created_at?: string;\n /** The raw thrown message, set only when the JOB itself failed; `null` otherwise. Per-screen dispatch failures do NOT populate it — those live in `results[].error`, and a job whose targets all failed still reports `status: \"completed\"` with `failed` > 0. */\n error?: string | null;\n /** Screens that could not be enqueued */\n failed?: number;\n /** The `sg_<uuid>` screen group this batch fanned out to. It is a plain TEXT reference, not a foreign key: groups are only ever soft-deleted, so the job outlives its group and keeps the id as an audit record. */\n group_id?: string | null;\n /** Job id: the literal prefix `fc_` followed by a v4 UUID (`pgRepo/fleetCommands.js` mints `fc_${crypto.randomUUID()}`). Opaque — do not parse the UUID half. */\n id?: string;\n /** Constant string `fleet_command` — the Stripe-style type discriminator, present both here and inside the `data` of a `fleet_command.*` webhook. */\n object?: string;\n /** Screens the command was enqueued to */\n queued?: number;\n /** One entry per screen the dispatch touched, persisted only when the fan-out actually produced rows. `results[].status` is `queued` or `failed` — the per-screen dispatch outcome, a different vocabulary from the job's own `status` — and `device_command_id` is the queued device-command's Mongo ObjectId, or `null` when nothing was queued (e.g. `error: \"No device linked\"`). On a `fleet_command.failed` webhook this is always `[]`, because the dispatch never completed. */\n results?: Array<{\n device_command_id?: string | null;\n error?: string | null;\n screen_id?: string;\n status?: \"queued\" | \"failed\";\n }>;\n /** Execution is synchronous inside the create request — the job walks `queued` to `running` to `completed` (or `failed`) before the POST returns — so a poll will in practice only ever observe a terminal value. `queued` and `running` exist for a future async worker that claims `queued` rows. */\n status?: \"queued\" | \"running\" | \"completed\" | \"failed\";\n /** Member screens resolved for this command */\n targeted?: number;\n /** Bumped on each job state transition (`queued` to `running` to terminal), so on a completed job it is effectively the moment the fan-out finished. */\n updated_at?: string;\n};\n\n/**\n * Webhook body for a group fleet-command terminal state (`fleet_command.completed` |\n * `fleet_command.failed`). Standard `{ id, event, timestamp, data }` envelope; `data` is the\n * `fleet_command` job object (status, targeted/queued/failed counts, per-screen results; on\n * failure, an `error` message). The event type is also in the `X-Trillboards-Event` header —\n * verify the compound `X-Trillboards-Signature` over the raw body first.\n *\n */\nexport type FleetCommandEvent = {\n /** The fleet_command job object. */\n data?: Record<string, unknown>;\n /** The terminal state that fired, also sent in the `X-Trillboards-Event` header and mirrored to the SSE stream. Note `fleet_command.completed` fires even when individual screens failed — check `data.failed` and `data.results[]`. Delivery is gated by the `SCREEN_GROUP_EVENTS_ENABLED` runtime flag, off by default. */\n event?: \"fleet_command.completed\" | \"fleet_command.failed\";\n /** `evt_<base36 epoch ms>_<12 hex>`, minted once per occurrence and reused across retries of that delivery — so it is the idempotency key. The same id also goes to every endpoint subscribed to the event, so dedupe per (endpoint, id). It is not the delivery audit id and is not queryable. */\n id?: string;\n /** Stamped when the server enqueued the delivery, not when it was sent; retries keep the original value. It is the emit time of the terminal-state event, which is not the same as the job's `completed_at`. */\n timestamp?: string;\n};\n\n/**\n * Programmatic header-bidding configuration and the resolved VAST waterfall for the screen. The `vast_waterfall.sources[]` array is the programmatic demand path — fetch each source's `vast_url` in priority order and hand the returned VAST to your IMA SDK. Source names are opaque public aliases. Source-health request-pressure governance does not remove SQL/Admin-enabled sources from this catalog.\n *\n */\nexport type HeaderBiddingSettings = {\n /** `null` unless the screen falls in the ad-buffering rollout bucket. `min_buffer`, `max_buffer` and `warmup_count` are COUNTS OF PREFETCHED ADS (defaults 3 / 5 / 5), not seconds or bytes; `max_cache_age_seconds` (default 300) is how long a prefetched VAST may be held before it must be discarded. */\n ad_buffering?: {\n enabled?: boolean;\n max_buffer?: number;\n max_cache_age_seconds?: number;\n min_buffer?: number;\n warmup_count?: number;\n } | null;\n /** `null` unless the screen falls in the ad-pod experiment bucket. When present it carries `enabled`, `pod_size` (how many ads to request in a single pod) and `variant_name` (the pod-size arm this screen hashed into) — the arm is assigned server-side, not chosen by the client. */\n ad_pod?: Record<string, unknown> | null;\n /** Share of ad slots the client should give to programmatic, as a decimal FRACTION 0-1 (`0.20` = 20%), defaulting to `1.0`. Same underlying value the CMS exposes as `programmatic_allocation_percent` (0-100, i.e. this times 100). Only honoured when `request_mode` is `allocation`; under `always` it is ignored. */\n allocation?: number;\n /** One id per waterfall BUILD (one `/ads` response), shared by every entry in `vast_waterfall.sources[]`; the narrower per-source key is `request_id`. This is the value that lands in `vast_requests.auction_request_id`, so it is what groups all the source attempts belonging to a single ad opportunity. Echo it, never mint your own. */\n auction_request_id?: string;\n /** Constant `true` whenever this object is present — the whole `header_bidding_settings` object is `null` for a screen that is not programmatically eligible. This is header-bidding *configuration*, not the serving master switch: that is `programmatic_enabled` (surfaced as `ProgrammaticSettingsResponse.enabled`) plus any active ads-disabled reason, and the legacy `enabled` shadow was deliberately removed from the serving decision. */\n enabled?: boolean;\n /** `+`-joined tags for the yield experiments this screen is bucketed into (e.g. `yield_buffer_treatment+ad_pod_pod_3`), covering ad buffering, fast loop and ad pods; `null` when none is active. Assignment is a consistent hash of the screen id, so it is stable for a screen across requests. Report it back for analytics — on its own it changes no client behaviour. */\n experiment_variant?: string | null;\n /** `null` unless the screen falls in the fast-loop experiment bucket. When present it carries `enabled` and `ad_to_ad_gap_ms` — the gap to leave between consecutive ads, in MILLISECONDS (default 5000), which is the experiment's shortened alternative to the normal ~30s cadence. */\n fast_loop?: Record<string, unknown> | null;\n /** No live producer — `null` on every response. The only assignment is guarded on a partner-level `fetchMode` setting, and no demand partner in the registry defines one, so this key is never populated at either the top level or per source. Do not branch on it. */\n fetch_mode?: string | null;\n /** Legacy predecessor of `request_mode`, retained only as the fallback that selects `always` (true) versus `allocation` (false) when no explicit `request_mode` is stored. An explicit `request_mode` always wins — do not read the two independently or you will disagree with the server on screens that set both. */\n force_request?: boolean;\n /** `null` except on screens in a revenue-recovery experiment arm, where it carries `name` and `reason` plus the IMA overrides to apply for that arm — some subset of `num_redirects`, `vast_load_timeout_ms`, `load_video_timeout_ms`, `source_timeout_ms`, `mime_types`, `enable_preloading`, `sdk_version_override` and `client_hints_override`. The key set is deliberately open: apply the keys you recognise and ignore the rest. */\n ima_profile?: Record<string, unknown> | null;\n /** Minimum gap the client should leave between VAST requests, in SECONDS (not milliseconds), default `30`, accepted range 0-300. Advisory: no server-side check enforces it — the `/ads` rate limiter is a separate mechanism that does not read this value. */\n min_interval_seconds?: number;\n /** Always `null`. Every stored value for this key is JSON `null`, it has no typed home on the screen record (dropped from the typed read path), and the builder emits `hbs.prebid || null` — there is no live producer. Prebid Server demand, when it participates, is spliced into `vast_waterfall.sources[]`, not surfaced here. */\n prebid?: Record<string, unknown> | null;\n /** Opaque public alias of the first waterfall source — the same string as `variant_name` and `source_name`, not the `floodgates`/`prebid`/`other` bidding-provider value the CMS accepts on `ProgrammaticSettingsInput.provider`. The key is absent entirely when the waterfall resolved no sources. */\n provider?: string;\n /** Player tuning selected purely from the screen's `country`; today only `IN` differs from the default — `timeout_ms` 25000 vs 12000, `fallback_timeout_ms` 35000 vs 18000, `vquality` 1 vs 2, `enable_network_adaptation` true vs false, and `ad_buffer_percentage` as a 0-1 fraction of network capacity (0.25 vs 1.0). Note the wire shapes: `preferred_resolution` is an object `{width, height}` and `vquality` an integer, not the strings declared here. */\n regional_config?: {\n ad_buffer_percentage?: number;\n enable_network_adaptation?: boolean;\n fallback_timeout_ms?: number;\n preferred_resolution?: string;\n timeout_ms?: number;\n vquality?: string;\n } | null;\n /** Per-request waterfall identifier; echo it back on programmatic-event reports. */\n request_id?: string;\n /** `allocation` = request only on the `allocation` share of slots; `always` = request on every slot and ignore `allocation`. These are the only two accepted values. Defaults to `always` on the static-tag path; on the waterfall path it defaults from the legacy `force_request` boolean (`always` when true, `allocation` when false). */\n request_mode?: string;\n /** Opaque alias of the source these top-level fields describe — the first waterfall source, identical to `provider`/`variant_name`. Absent when the waterfall resolved no sources. */\n source_name?: string | null;\n /** The first source's `priority` sort key, copied up to the top level. Same semantics as `VastWaterfallSource.priority`: an opaque ascending key that may start at 0 and may be non-contiguous — it is not an index, a count, or a position you can do arithmetic on. */\n source_priority?: number | null;\n /** Opaque public alias of the first waterfall source, byte-identical to `provider` and `source_name` on the same response. Format is `src_<6 hex>` (SHA-256 of the partner key) or `var_<6 hex>` (of the variant name), plus the fixed `src_test` for the sandbox test source and `inbound_dsp` for a collapsed DSP-seat source. Never a real partner name, and it may be rotated per tenant — echo it back on `programmatic-event` reports rather than persisting it as an identity. */\n variant_name?: string;\n /** Client-side VAST/creative caching directive, `null` unless the fleet-level VAST-cache switch is on (shipped default: off). `ttl_seconds` defaults to 21600 (6 hours). `priority` is a fixed rank of `1.5` — between paid ads (1) and self-promo (2) — and is emitted as a NUMBER despite the string type declared here. */\n vast_cache?: {\n enabled?: boolean;\n priority?: string;\n ttl_seconds?: number;\n } | null;\n /** Convenience copy of `vast_waterfall.sources[0].vast_url` — the server overwrites it with the first source on every build and drops the key entirely when the waterfall resolved no sources. It is not an extra tag, so fetching only this URL is exactly the `sources[0]`-and-stop defect the `VastWaterfall` contract warns about. */\n vast_tag_url?: string;\n vast_waterfall?: VastWaterfall;\n} | null;\n\nexport type HttpProbeResult = {\n /** IP address that was probed. The target list is PARASITIC on mDNS — the hosts discovered in the same cycle plus the Wi-Fi gateway, de-duplicated and capped at 10. There is no subnet scan, so a device that advertises nothing on mDNS is never probed. */\n host: string;\n /** Always `80` — the probe only ever tries plain HTTP on port 80, and the value is a literal at the call site rather than something the scanner chose. Printer ports 515 and 9100-9102 are refused before any socket opens, because an HTTP request to a JetDirect/LPD port makes the printer physically spool the bytes. */\n port?: number | null;\n /** The HTTP `Server:` response header from a `HEAD /` request (HTTP/1.0, 1.5 s timeout). Never null in an emitted row — a probe that gets no usable header produces no row, and the value is rejected outright if it is over 256 characters or contains an `@`, angle brackets, control characters, or the words `password`/`passwd`/`secret`/`phpinfo`. Failures are counted separately in `skipReasonCounts`, so absence from this array is not evidence the host is down. */\n server?: string | null;\n [key: string]: unknown;\n};\n\n/**\n * Transitional shape: the legacy `{ success, message }` wrapper with the canonical error OBJECT under `error`. Emitted by partner routes that adopted the canonical `code`/`type` vocabulary without moving to the `TrillboardsError` envelope.\n */\nexport type HybridError = {\n error?: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code?: string;\n param?: string | null;\n type?: ErrorType;\n };\n message?: string;\n success?: boolean;\n};\n\n/**\n * A recorded ad impression / play for a partner screen\n * (`@trillboards/api-client` `Impression`).\n *\n */\nexport type Impression = {\n /** Kind of ad served (e.g. direct, programmatic, self_promo). */\n ad_type?: string;\n advertiser_name?: string;\n /** Effective CPM for the impression, in the partner's currency. */\n cpm?: number;\n /** Sent on the wire as `did`. The server accepts the device's Mongo id, its fingerprint, or the `partner_external_id` you registered for it. An unrecognised value is logged and the call still returns 200 — only a SIGNED impression 404s on an unknown device. */\n device_id: string;\n /** Play duration in seconds. */\n duration_seconds?: number;\n /** Earner revenue accrued for the impression. */\n earnings?: number;\n /** The per-serve id minted by the server on `data.ads[].impression_id` (`imp_<epoch-ms>_<8 hex>`) and echoed back as the `impid` parameter on the impression call — it is the dedup key, so never generate your own. Note that no endpoint currently returns this object: it is the `@trillboards/api-client` type describing what you SEND. */\n impression_id: string;\n /** The batch endpoint reads `timestamp`, NOT `played_at` — a `played_at` you send is ignored and the impression is stamped with server receive time instead. That matters for offline sync: send `timestamp` if the real play time has to survive the upload delay. */\n played_at: string;\n /** Your earner-screen id (24-character hex Mongo ObjectId), sent on the wire as `sid`. It is only a FALLBACK for resolving the screen — the server resolves from the device (`did`) first and reads `sid` solely when no device matched. */\n screen_id: string;\n};\n\n/**\n * Legacy error shape carrying a SCREAMING_SNAKE `code` alongside the message — emitted by the auth middlewares (`middleware/auth.js`, `middleware/partnerUserAuth.js`). Its `code` is NOT drawn from `ErrorCode`; it is a separate, older vocabulary.\n */\nexport type LegacyCodedError = {\n /** Legacy SCREAMING_SNAKE code, e.g. NO_TOKEN, TOKEN_EXPIRED, NO_API_KEY. */\n code?: string;\n message: string;\n success?: boolean;\n};\n\n/**\n * Legacy error shape returned by hand-authored routes that predate the canonical envelope (they call `res.status(n).json(...)` directly rather than routing through `globalErrorHandler`). Documented because it is what these endpoints really return; new endpoints must use `TrillboardsError`.\n */\nexport type LegacyError = {\n error?: string;\n message?: string;\n success?: boolean;\n};\n\nexport type Mcp_create_media_buy_Args = {\n brand?: {\n domain?: string;\n name?: string;\n [key: string]: unknown;\n };\n buy_spec?: {\n audience_profile?: Record<string, unknown>;\n budget?: {\n bid_cpm?: number;\n daily_usd?: number;\n total_usd?: number;\n };\n geo?: {\n city?: string;\n country?: string;\n lat?: number;\n lng?: number;\n radius_km?: number;\n state?: string;\n };\n schedule?: {\n days?: Array<number>;\n end_date?: string;\n hours?: Array<number>;\n start_date?: string;\n };\n screen_ids?: Array<string>;\n venue_types?: Array<string>;\n };\n buyer_ref?: string;\n context?: Record<string, unknown>;\n creative?: {\n duration_seconds?: number;\n height?: number;\n type?: \"video\" | \"image\" | \"vast\";\n url?: string;\n width?: number;\n };\n end_time?: string;\n idempotency_key?: string;\n name?: string;\n packages?: Array<{\n bid_price?: number;\n budget?: number | {\n amount?: number;\n currency?: string;\n [key: string]: unknown;\n };\n impressions?: number;\n pricing_option_id?: string;\n product_id?: string;\n targeting_overlay?: Record<string, unknown>;\n [key: string]: unknown;\n }>;\n start_time?: string;\n total_budget?: {\n amount?: number;\n currency?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n};\n\nexport type Mcp_discover_inventory_Args = {\n audience_profile?: {\n income?: \"high\" | \"upper_mid\" | \"mid\" | \"lower_mid\" | \"low\";\n lifestyle?: string;\n min_attention?: number;\n };\n limit?: number;\n location?: {\n city?: string;\n lat?: number;\n lng?: number;\n radius_km?: number;\n state?: string;\n };\n venue_types?: Array<string>;\n};\n\nexport type Mcp_get_media_buy_delivery_Args = {\n breakdown_by?: Array<\"screen\" | \"venue\" | \"hour\" | \"audience_segment\">;\n dimensions?: Array<\"screen\" | \"venue\" | \"hour\" | \"audience_segment\" | \"creative\" | \"day\">;\n media_buy_id: string;\n [key: string]: unknown;\n};\n\nexport type Mcp_get_media_buys_Args = {\n context?: Record<string, unknown>;\n include_snapshot?: boolean;\n media_buy_ids?: Array<string>;\n pagination?: {\n cursor?: string;\n max_results?: number;\n };\n status_filter?: \"pending_creatives\" | \"pending_start\" | \"active\" | \"paused\" | \"completed\" | \"rejected\" | \"canceled\" | Array<\"pending_creatives\" | \"pending_start\" | \"active\" | \"paused\" | \"completed\" | \"rejected\" | \"canceled\">;\n [key: string]: unknown;\n};\n\nexport type Mcp_get_products_Args = {\n audience_profile?: {\n income?: string;\n lifestyle?: string;\n min_attention?: number;\n };\n brief?: string;\n buying_mode?: \"brief\" | \"wholesale\" | \"refine\";\n filters?: {\n budget_range?: {\n currency?: string;\n max?: number;\n min?: number;\n };\n channels?: Array<string>;\n countries?: Array<string>;\n delivery_type?: string;\n format_types?: Array<string>;\n venue_types?: Array<string>;\n [key: string]: unknown;\n };\n market?: string;\n pagination?: {\n cursor?: string;\n max_results?: number;\n };\n venue_types?: Array<string>;\n [key: string]: unknown;\n};\n\nexport type Mcp_list_accounts_Args = {\n account?: {\n account_id?: string;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n operator?: string;\n sandbox?: boolean;\n };\n context?: Record<string, unknown>;\n pagination?: {\n cursor?: string;\n max_results?: number;\n };\n sandbox?: boolean;\n status?: \"active\" | \"pending_approval\" | \"rejected\" | \"payment_required\" | \"suspended\" | \"closed\";\n [key: string]: unknown;\n};\n\nexport type Mcp_sync_accounts_Args = {\n accounts: Array<{\n account?: {\n account_id?: string;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n operator?: string;\n sandbox?: boolean;\n };\n billing?: \"operator\" | \"agent\" | \"advertiser\";\n billing_entity?: Record<string, unknown>;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n notification_configs?: Array<Record<string, unknown>>;\n operator?: string;\n payment_terms?: \"net_15\" | \"net_30\" | \"net_45\" | \"net_60\" | \"net_90\" | \"prepay\";\n preferred_reporting_protocol?: string;\n sandbox?: boolean;\n }>;\n context?: Record<string, unknown>;\n delete_missing?: boolean;\n dry_run?: boolean;\n idempotency_key: string;\n push_notification_config?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport type Mcp_sync_creatives_Args = {\n account?: {\n account_id?: string;\n brand?: {\n brand_id?: string;\n domain: string;\n };\n operator?: string;\n sandbox?: boolean;\n };\n assignments?: Array<{\n creative_id: string;\n media_buy_id?: string;\n package_id?: string;\n [key: string]: unknown;\n }>;\n context?: Record<string, unknown>;\n creative_ids?: Array<string>;\n creatives: Array<{\n assets?: Record<string, unknown>;\n creative_id?: string;\n duration_seconds?: number;\n file_size_mb?: number;\n format_id?: {\n agent_url: string;\n duration_ms?: number;\n height?: number;\n id: string;\n width?: number;\n } | string;\n format_kind?: string;\n height?: number;\n name?: string;\n type?: \"video\" | \"image\" | \"vast\";\n url?: string;\n width?: number;\n [key: string]: unknown;\n }>;\n delete_missing?: boolean;\n dry_run?: boolean;\n ext?: Record<string, unknown>;\n idempotency_key?: string;\n media_buy_id?: string;\n push_notification_config?: Record<string, unknown>;\n validation_mode?: string;\n [key: string]: unknown;\n};\n\nexport type Mcp_update_media_buy_Args = {\n account?: Record<string, unknown>;\n canceled?: boolean;\n cancellation_reason?: string;\n context?: Record<string, unknown>;\n end_time?: string;\n ext?: Record<string, unknown>;\n idempotency_key?: string;\n invoice_recipient?: Record<string, unknown>;\n media_buy_id: string;\n new_packages?: Array<Record<string, unknown>>;\n packages?: Array<{\n creative_assignments?: Array<{\n creative_id: string;\n [key: string]: unknown;\n }>;\n package_id: string;\n targeting_overlay?: Record<string, unknown> | null;\n [key: string]: unknown;\n }>;\n paused?: boolean;\n push_notification_config?: Record<string, unknown>;\n reporting_webhook?: Record<string, unknown>;\n revision?: number;\n start_time?: string | string;\n updates?: {\n budget?: {\n bid_cpm?: number;\n daily_usd?: number;\n total_usd?: number;\n };\n end_date?: string;\n name?: string;\n screen_ids?: Array<string>;\n start_date?: string;\n status?: \"active\" | \"paused\" | \"cancelled\";\n targeting?: Record<string, unknown>;\n };\n [key: string]: unknown;\n};\n\nexport type MdnsNetworkDevice = {\n /** The responder's IP address as a string — the first IPv4 address if it has one, otherwise any address. A record that resolves to no address is dropped rather than emitted with a null host, so in practice this is always populated. It is also what seeds the HTTP-probe target list for the same discovery cycle. */\n host?: string | null;\n /** The service instance name verbatim from the resolve event. A PII filter runs first and DROPS THE WHOLE ROW when the name looks like a personal name (an apostrophe-s possessive, an email, a MAC), so devices named after people disappear from the list entirely rather than appearing anonymised. */\n instanceName: string;\n /** Model string lifted from the TXT record using a per-service-type key table — `md` for Chromecast and HAP, `model`/`am` for AirPlay, `ty`/`product` for IPP, `dt` for Matter (a device-TYPE code used as a model surrogate, not a model name), with a broader default list for other types. `null` when no key in that list is present or all their values are blank. */\n mdnsModel?: string | null;\n /** Version string from the TXT record. Frequently this is `txtvers` — the TXT RECORD FORMAT version, not the device firmware version — because that key is in the fallback list for most service types. `null` when no candidate key is present. */\n mdnsSoftwareVersion?: string | null;\n /** Vendor string from the TXT record, by the same per-type key table. Two traps: Chromecast has an EMPTY vendor key list, so it is always `null` there; and for HAP this carries the HomeKit `ci` CATEGORY id (a numeric device class) while for Matter it carries the raw `VP` `vendorid+productid` pair — neither is a vendor name. */\n mdnsVendor?: string | null;\n /** TCP/UDP port advertised in the SRV record. A port of 0 is coerced to `null` rather than forwarded, so `null` means \"not advertised\", never \"port zero\". */\n port?: number | null;\n /** The mDNS service type the record resolved under, e.g. `_googlecast._tcp.`. Discovery is not open-ended — the scanner browses a FIXED list of 19 types (Roku, AirPlay, RAOP, Chromecast, Amazon WPlay, Android TV Remote, Spotify Connect, device-info, companion-link, IPP/IPPS/printer/PDL, HAP, Matter, Alexa, HTTP and the Trillboards CSI type), so a device advertising anything else is invisible here. */\n serviceType: string;\n [key: string]: unknown;\n};\n\n/**\n * Versioned public disclosure of how audience measurement is produced.\n * Describes WHAT is measured and HOW IT IS QUALIFIED — deliberately never\n * names infrastructure or source locations.\n *\n */\nexport type MeasurementMethodology = {\n /** Prose description of the happy-path pipeline: edge capture, buffered ingest, `signal_observations`, a 30-minute device-resolution pass into `resolved_device_observations`, then a 30-minute transition pass. Names the stores only — never infrastructure or source locations. */\n canonical_path?: string;\n /** What each screen observes and sends. */\n capture_stack?: Record<string, unknown>;\n /** Cross-day identity, including measured coverage (1.6% of identifiable BLE rows). An earlier revision said ~31%; that graded the presence of stable_payload_hash and ignored the sanitizer the identity expression applies, and it is withdrawn. */\n cross_day_matching?: Record<string, unknown>;\n /** The in-range contour: BLE RSSI at or above -75 dBm, empirically about 5 m line-of-sight for Class-2 radios at typical mounting. Calibration is static per screen-class — there is no per-screen ranging today — and devices inside the contour classified as stationary are excluded from the audience funnel by default. */\n display_exposure_zone?: Record<string, unknown>;\n /** What promotes a raw in-range observation to a qualifying event, one entry per qualification (`ble_engagement`, `face_attention`, `returning_visitor`), each carrying its definition, its rationale, and the ClickHouse field a reviewer re-derives it from. */\n dwell_qualification_thresholds?: Record<string, unknown>;\n /** Static disclosure of how observation confidence decays: `algorithm` (Bayesian posterior with temporal decay), `decay_window_days` (90) and `max_confidence` (0.95). These are published constants, not per-request measurements. */\n edge_confidence_model?: Record<string, unknown>;\n /** Evidence grades, which are decisionable, and person-grain resolution. */\n evidence_grade_ladder: Record<string, unknown>;\n /** Prose description of degraded ingest: observations buffer on a durable queue and replay on recovery, and after repeated failures land in a dead-letter store rather than being dropped. */\n fallback_path?: string;\n /** How identifiers are keyed, and what erasure means. */\n hashing?: Record<string, unknown>;\n /** The counting UNIT. Reach and unique-device counts are counts of distinct canonical BLE keys (identifiers); one device contributes several identifiers per window and the number grows with the window. Carries the measured identifiers-per-device per fleet type and the controlled comparison it was derived from. */\n identifier_inflation?: Record<string, unknown>;\n /** Alignment against MRC OOH Phase 2. `mrc_status_accredited` is the machine-readable answer and is **false until an MRC grant reference exists** — read that boolean rather than parsing the English `status` line. Also carries the monotonic qualification chain (`in_range` through `cross_screen`) and the interval method (Wilson score for proportions, 200-sample bootstrap for medians). */\n mrc_ooh_phase2_alignment: Record<string, unknown>;\n /** Version markers for the edge parsers that produced the disclosed fields — `ble_advertisement_parser`, `mdns_txt_extractor`, and the integer `heartbeat_payload_schema`. Hand-maintained constants, bumped when a parser changes. */\n parser_versions?: Record<string, unknown>;\n /** Per-store retention in days in active systems; `basis` states how each is counted and what the encrypted archive keeps. */\n retention: Record<string, unknown>;\n /** Tables a reviewer re-derives every published count from. */\n source_tables: Array<string>;\n /** Bumped on any disclosure change; drives the ETag. */\n version: string;\n};\n\n/**\n * Revenue per screen per hour. Aggregates gross revenue from completed impressions. Refreshed from CH via clickhouseRollupSource. PG only.\n */\nexport type OpenrtbRevenueScreenHourly = {\n actual_gross_revenue: number;\n estimated_gross_revenue: number;\n estimated_impressions: number;\n gross_revenue: number;\n hour_bucket: string;\n impressions: number;\n priced_impressions: number;\n screen_mongo_id: string;\n updated_at: string;\n};\n\nexport type Pagination = {\n /** Whether more items exist */\n has_more?: boolean;\n /** Items per page */\n limit?: number;\n /** Current offset */\n offset?: number;\n /** Total number of items */\n total?: number;\n};\n\nexport type Partner = {\n /** Defaults to the literal `lite_sdk` when unset, so it is never null, and is `lite_sdk` for effectively the whole fleet. It is load-bearing at serve time: `lite_sdk`/`full_sdk` mark the partner a video-only SDK consumer, so an image creative is swapped for the ad's partner video URL unless `sdk_config.allowed_ad_types` includes `image`. */\n integration_tier?: string;\n /** Registered company name. The same string is the buyer-facing media-owner label for this partner's inventory, so it is what advertisers see in the media-owner picker. */\n name?: string;\n /** The 24-character hex Mongo-era identifier (`partners.mongo_partner_id`), not the table's integer `partner_id`. This is the value the API key's owner id and every `partner_mongo_id` foreign key carry. */\n partner_id?: string;\n /** Legacy classification retained for existing integrations. New integrations should not branch on this field. */\n partner_type?: string;\n /** The partner's share as a percentage 0-100 (the stored rate is 0-1 and is multiplied by 100 here). Resolved from the active, currently-effective `publisher_payout_rates` rule; with no such rule it falls through to the system default and reports `60` — which is also why the `POST /register` response echoes `60` even when the caller asked for 70, since the partner row is read back before the rate row is written. */\n revenue_share_percent?: number;\n sdk_config?: SDKConfig;\n /** Lower-cased at registration and unique across all partners (a collision is rejected `409`). It appears in device embed URLs and portal links, so it is effectively permanent once devices are provisioned. */\n slug?: string;\n stats?: PartnerStats;\n /** In practice **always `active` here**: the API-key resolver refuses any partner whose status is not `active`, so a `pending`/`suspended`/`terminated` partner gets `401 invalid_api_key` and never reaches this response. Registration also always creates `active`. */\n status?: \"pending\" | \"active\" | \"suspended\" | \"terminated\";\n /** Defaults to the literal `pending` when unset. `POST /earnings/payout` refuses any value other than `active`. */\n stripe_account_status?: string;\n};\n\nexport type PartnerAdDeliveryProfile = {\n /** Android SDK API level as reported by the device; `null` when not reported, and then no Android rule fires at all. Below 23 forces `mode: vast_fallback` and turns `auto_recovery_enabled` off. 23-25 with desugaring reported off only appends a warning to `notes` and leaves the mode alone. */\n android_api_level?: number | null;\n /** Whether the SERVER may auto-enqueue recovery device commands for this device — the `refresh_ads` and `restart` it issues when a screen heartbeats online without recent VAST requests, or with stalled playback. It is not a client-side setting, and it goes false alongside every `vast_fallback` verdict so we do not restart a device whose player we already know is the wrong one. Even when true, a recovery command is queued only for a device that acts on commands, meaning one that acknowledged a command (`POST /device/{deviceId}/command/{commandId}/ack`) in the last 7 days, or that was handed none in that time. A device that let a delivered command expire unacknowledged, and acknowledged none, is sent no recovery command until that command is 7 days old. */\n auto_recovery_enabled?: boolean;\n /** Echoed back from the device's own heartbeat telemetry, or `unknown` when the device never reported one. It selects which compatibility rules run: `android_native` enables the Android API-level gate, `html5_webview` the Chromium-version checks; `disabled` and `unknown` skip both, so no mode change can result from those. */\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n /** The server's per-heartbeat verdict on how this device should play ads: `ima_sdk` is the normal IMA path, `vast_fallback` means bypass IMA entirely and play the VAST in your own fallback player. It is recomputed from the telemetry on every heartbeat, so treat it as a live instruction rather than one-time provisioning. */\n mode?: \"ima_sdk\" | \"vast_fallback\";\n /** Human-readable diagnostics accompanying the decision above; an empty array on a healthy device. They are free prose for logs and support tickets, not a stable enum — nothing in the contract depends on matching their text, and their presence alone does not imply degraded delivery. */\n notes?: Array<string>;\n /** Machine token for why `mode` was chosen: `default` (nothing disqualified the device), `sdk_reported_ima_unsupported` (your own telemetry reported `imaSupported: false`), or `android_api_below_23_for_current_ima_android_sdk`. `default` is always what accompanies `ima_sdk`. */\n reason?: string;\n /** Major Chromium version of the device's WebView, `null` when not reported. Advisory only — it never changes `mode`: below 87 appends a content-restoration note and below 80 an additional autoplay/media note. */\n webview_chromium_major?: number | null;\n};\n\n/**\n * Non-fatal advisories about the creative that was just accepted. The ad IS created and will serve — these describe problems only the uploader can fix. Empty when there is nothing to report. The most important one is an over-length video: a spot longer than the 30 second ad slot is cut off when the next ad starts, so it never reaches its completion event and its final seconds are never seen.\n */\nexport type PartnerCreativeWarnings = Array<string>;\n\nexport type PartnerDefaultStream = {\n /** The stream's 24-hex id, minted server-side with `newObjectId()` at create and stored as `default_streams.mongo_default_stream_id`. It is the value every other default-stream route takes as `{streamId}`; the shape is Mongo's but PostgreSQL is the store of record. */\n _id?: string;\n /** Accepted with no required-field check, same as `google_slides_url`. The derived `canva_design_id` is returned alongside it although this schema does not declare it. */\n canva_url?: string | null;\n /** Mapped from `default_streams.created_at`. It is the list endpoint's secondary sort key, so two streams sharing a `playback_order` play oldest-first. */\n createdAt?: string;\n /** Falls back to `name`, then to `Background content`; the upload and image routes use `Uploaded video content` / `Image carousel content` instead. */\n description?: string;\n /** Seconds one pass of this stream occupies. It is computed as `images.length x image_duration` when you send images without it; for every other type it is only ever what you sent — nothing probes a YouTube or uploaded video to fill it in on this path. */\n duration_seconds?: number | null;\n /** The URL the player actually loads into the iframe. It defaults to `generic_iframe_url` when you do not send it, so on an iframe stream the two are usually equal. */\n embed_url?: string | null;\n /** The iframe source for the `generic_iframe` type. It also seeds `embed_url` when that is omitted, so sending only this one populates both fields. */\n generic_iframe_url?: string | null;\n /** Unlike `youtube`/`twitch`/`uploaded`/`images`, the `google_slides` type has NO required-field check — a create naming that type with no URL is accepted, stores null, and the screen then renders an empty frame. */\n google_slides_url?: string | null;\n /** Only five keys survive: `auto_advance`, `slide_delay_ms`, `refresh_interval_seconds`, `sandbox_flags`, `allow_flags` — anything else is silently discarded and a non-object is discarded whole. On update it is MERGED over the stored config rather than replacing it, so a key cannot be cleared by omitting it. */\n iframe_config?: Record<string, unknown> | null;\n /** Seconds each image is held before advancing. The multipart image route defaults it to 10 when omitted and uses it to compute `duration_seconds`; the JSON create leaves it unset unless you send it. */\n image_duration?: number | null;\n /** Ordered image URLs, each held for `image_duration` seconds. Required and non-empty when `stream_type` is `images` (400 otherwise), null for every other type; the create accepts a real array, a JSON-encoded array string, or a comma-separated string. */\n images?: Array<string>;\n /** Soft-deactivation flag. The list filters `is_active = true`, so it is always `true` on anything this API returns; the partner DELETE removes the row outright rather than clearing this flag, which is instead used by the screen-wide deactivate paths. */\n is_active?: boolean;\n /** At most one stream per screen carries this — promoting or reordering clears it on every sibling first. A create sets it on the new stream, `reorder` gives it to `order[0]`, and deleting the current stream hands it to whatever the ordering resolves next. */\n is_currently_playing?: boolean;\n /** Falls back to `description`, then to the literal `Default Stream`, so it is never empty. The multipart upload route instead falls back to the uploaded file's original name, and the multi-image route to `Image Carousel (N images)`. */\n name?: string;\n /** Present ONLY on the 201 from the three create routes, which echo the in-memory document back. `default_streams` has no partner column, so list, update and read responses omit this key entirely — tenancy is enforced at the screen, not on the stream row. */\n partner_id?: string;\n /** 1-based position in the screen's rotation; the list sorts on it and breaks ties with `createdAt`. A newly created stream is promoted to 1 and every sibling shifts down, and `POST .../reorder` rewrites it to each id's index in the `order` array you send. */\n playback_order?: number;\n /** The owning screen, mapped from `default_streams.screen_mongo_id` — the same 24-hex id you passed as `{screenId}` in the path. Note the camelCase spelling inside an otherwise snake_case object. */\n screenId?: string;\n /** Accepted with no required-field check. The derived `social_wall_provider` and `social_wall_widget_id` are returned alongside it although this schema does not declare them. */\n social_wall_url?: string;\n /** Which renderer the screen uses. When omitted at create it is DERIVED from whichever content field you sent, in this fixed order: `images`, `youtube_url`, `twitch_url`, `google_slides_url`, `canva_url`, `social_wall_url`, `generic_iframe_url`/`embed_url`, `video_url` (`uploaded`), `local_file_path` (`local`) — and the create is rejected 400 if none resolves. Only `youtube`, `uploaded`, `images` and `twitch` are ever content-analyzed; the four embed types deliberately keep `gemini_analyzed_at` NULL. */\n stream_type?: string;\n /** Required when `stream_type` is `twitch` (400 otherwise). The response also carries the undeclared `twitch_embed_url`, `twitch_content_type` and `twitch_id` companions that the PG reshape returns. */\n twitch_url?: string | null;\n /** Mapped from `default_streams.updated_at`. Playback bookkeeping writes it — marking a stream current, clearing a stale current flag, or stamping `last_played_at` — so it moves without anyone editing the stream content. */\n updatedAt?: string;\n /** Required when `stream_type` is `uploaded`. The `/default-streams/upload` route sets it for you to the stored object URL of the file you posted (`req.file.location`), so you never send it on that path. */\n video_url?: string | null;\n /** Required when `stream_type` is `youtube` — the create is rejected 400 (`youtube_url is required for youtube streams`) without it. Null on every other stream type. */\n youtube_url?: string | null;\n};\n\nexport type PartnerDefaultStreamCreate = {\n /** Accepted with no required-field check, same as `google_slides_url` — a `canva` create with this omitted succeeds and renders nothing. */\n canva_url?: string;\n /** Optional. Falls back to `name` and then to `Background content`. */\n description?: string;\n /** Optional explicit duration for iframe-based streams */\n duration_seconds?: number;\n /** The URL actually loaded into the iframe. When omitted it is filled from `generic_iframe_url`, so send it only when the embeddable URL differs from the one you want recorded. */\n embed_url?: string;\n /** The iframe source. Sending it also derives `stream_type: generic_iframe` and seeds `embed_url`, so this one field is enough to create an iframe stream. */\n generic_iframe_url?: string;\n /** The `google_slides` type has NO required-field check, so a create naming that type without this URL is accepted and stores null. Send a published-to-web slides URL. */\n google_slides_url?: string;\n /** Only these five keys are kept — every other key you send is silently dropped, a non-object is dropped whole, and `slide_delay_ms`/`refresh_interval_seconds` must be finite numbers or they are dropped individually. On a later update this object is merged over the stored one rather than replacing it. */\n iframe_config?: {\n allow_flags?: string;\n auto_advance?: boolean;\n refresh_interval_seconds?: number;\n sandbox_flags?: string;\n slide_delay_ms?: number;\n };\n /** Seconds per image */\n image_duration?: number;\n /** Required and non-empty for an `images` stream. Accepted as a real array, a JSON-encoded array string, or a comma-separated string; combined with `image_duration` it also derives `duration_seconds` when you do not send one. */\n images?: Array<string>;\n /** Optional. Falls back to `description` and then to the literal `Default Stream`, so the created stream always has one. */\n name?: string;\n /** Accepted with no required-field check — a `social_wall` create with this omitted succeeds and renders nothing. */\n social_wall_url?: string;\n /** Optional — omit it and the server DERIVES it from whichever content field you sent, checking in this order: `images`, `youtube_url`, `twitch_url`, `google_slides_url`, `canva_url`, `social_wall_url`, `generic_iframe_url`/`embed_url`, `video_url` (`uploaded`), `local_file_path` (`local`). If nothing resolves the request is rejected 400 `No supported stream content provided`. */\n stream_type?: \"local\" | \"youtube\" | \"uploaded\" | \"images\" | \"twitch\" | \"google_slides\" | \"canva\" | \"social_wall\" | \"generic_iframe\";\n /** Required when the resolved `stream_type` is `twitch`; the create is rejected 400 without it. */\n twitch_url?: string;\n /** Required when the resolved `stream_type` is `uploaded`. Use `POST .../default-streams/upload` with a multipart file instead if you want us to host the video — that route fills this in for you. */\n video_url?: string;\n /** Required when the resolved `stream_type` is `youtube`; the create is rejected 400 without it. Sending it alone is enough — the type is derived. */\n youtube_url?: string;\n};\n\nexport type PartnerDefaultStreamUpdate = PartnerDefaultStreamCreate;\n\n/**\n * Batch device-registration body (`@trillboards/api-client`\n * `PartnerDeviceBatchRegistrationInput`) — up to 100 devices with optional\n * fleet-wide `defaults`. `defaults` applies to every device in the batch\n * except the per-device identifier fields (`device_id` / `device_name`).\n *\n */\nexport type PartnerDeviceBatchRegistrationInput = {\n /** Fleet-wide defaults applied to each device except its identifier fields. */\n defaults?: PartnerDeviceRegistrationInput;\n /** 1 to 100 entries; more than 100 rejects the whole request with `Maximum 100 devices per batch request`. The batch is NOT transactional — entries are registered sequentially and independently, so the call can return 2xx with some entries reported under `errors[]` while the rest committed. An entry whose `device_id` already exists is an update, counted under `summary.updated` rather than `summary.created`. */\n devices: Array<PartnerDeviceRegistrationInput>;\n};\n\n/**\n * Heartbeat payload from agent-core / agent-core-lite Android partner\n * SDKs. Only includes fields verified populated in production\n * `signal_observations` (last 30 days). Stub fields wired in Kotlin but\n * never observed in CH are intentionally excluded; re-add only after\n * telemetry confirms >1% population over 7 days.\n *\n */\nexport type PartnerDeviceHeartbeatBody = {\n /** Legacy flat advertising identifier, superseded by the `advertising_identity` envelope. It is only honoured when no canonical envelope is present AND it passes a plausibility check; a value that fails the check is dropped without an error, and it never reaches the device record through the generic device snapshot — identity has one dedicated persistence rail. */\n advertisingId?: string | null;\n /** Type of the legacy flat `advertisingId`. It is retained only when `advertisingId` itself survives the plausibility check — otherwise it is nulled with it — and the canonical `advertising_identity.id_type` enum is wider (`gaid`, `aaid`, `afai`, `rida`, `tifa`, `idfa`) than the two values allowed here. */\n advertisingIdType?: \"gaid\" | \"idfa\" | null | null;\n advertising_identity?: AdvertisingIdentity;\n /** Number of distinct BLE devices seen in the scan window, BEFORE the 50-entry cap on `nearbyBleDevices` — so it can legitimately exceed the array length (the on-device scanner tracks up to 100 groups). Omit it and the server substitutes the array length. Both this and the snake_case `ble_device_count` are accepted. */\n bleDeviceCount?: number;\n capabilities?: DeviceCapabilityPayload;\n /** mDNS/Bonjour service instances found on the LAN, capped at 50. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`discovered_network_devices`). */\n discoveredNetworkDevices?: Array<MdnsNetworkDevice> | null;\n /** Up to 16 audience identities (hashed email / UID2) keyed by `(id_type, source)`. Rejection is all-or-nothing — one bad element or a 17th entry drops the whole array — and the row-level upsert additionally refuses any envelope whose `observed_at` is older than the stored one, so a replayed batch is a silent no-op. */\n extended_identities?: Array<ExtendedIdentity>;\n /** The agent's stable device fingerprint. On this endpoint it is inert: the path parameter `deviceId` is the sole binding boundary, and the partner heartbeat controller never reads `fingerprint` from the body — it uses the fingerprint of the device the path already resolved. */\n fingerprint?: string;\n /** Hash of the LAN default-gateway IP — the venue-network join key, and the seed the HTTP probe adds to its mDNS-derived target list. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`gateway_ip_hash`). */\n gatewayIpHash?: string | null;\n /** Results of HTTP HEAD probes against at most 10 hosts — the mDNS hosts found in the same cycle plus the Wi-Fi gateway, port 80 only. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`http_probes`). */\n httpProbes?: Array<HttpProbeResult> | null;\n /** Legacy flat LAT flag. `true` alone is enough to clear a previously stored identifier — the server synthesises a `limited` identity envelope from it even with no `advertisingId` present — so do not send `true` speculatively. */\n limitAdTracking?: boolean | null;\n /** Alternate namespace for the same telemetry keys as `telemetry`, merged UNDER it (`{...metadata, ...telemetry}`), so `telemetry` wins on a collision. This is where the Android agents actually put their telemetry — `uptimeSeconds`, `agentType`, `agentVersion`, screen geometry, `sensingMode` — and where the per-heartbeat CPU/memory/thermal gauges are merged in. */\n metadata?: Record<string, unknown>;\n /** Capped at 50 devices (RSSI-sorted, strongest first). */\n nearbyBleDevices?: Array<BleScanResultData> | null;\n /** Wi-Fi scan results, capped at 50 with the joined AP pinned first. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`nearby_wifi_networks`, whose inner keys are `raw_bssid`/`signal_dbm`/`frequency_mhz` — note `signal_dbm`, not a snake_case form of `signalStrengthDbm`). */\n nearbyWifiNetworks?: Array<WifiScanResult> | null;\n /** Count of mDNS instances discovered, before the 50-entry cap (the Rust scanner itself keeps at most 30). Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`network_device_count`). */\n networkDeviceCount?: number;\n /** Heartbeat schema version (1=baseline, 2=nativeSensorSnapshot) */\n schemaVersion?: number;\n /** The screen the agent believes it is bound to. Also inert on this endpoint — the server resolves the screen from the device record, never from this value; correct a wrong binding through registration or the socket heartbeat, which returns an authoritative screen id. */\n screenId?: string | null;\n /** Per-source skip-reason counter map. Shape `{source: {reason: count}}`. */\n skipReasonCounts?: Record<string, Record<string, number>>;\n /** UPnP/SSDP responders found by one `M-SEARCH` with `ST: ssdp:all`, deduped by LOCATION and capped at 50. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`ssdp_devices`). */\n ssdpDevices?: Array<SsdpDeviceInfo> | null;\n /** Agent lifecycle word — the Android agents hardcode `\"active\"` on every heartbeat, so it carries no information. The partner heartbeat controller does not read it; online/standby state is derived from `telemetry.powerState`, not from this field. */\n status?: string;\n /** Hash of the joined access point's BSSID. This field is accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`wifi_bssid_hash`). */\n wifiBssidHash?: string | null;\n wifiEnvironment?: WifiEnvironmentSnapshot;\n /** Count of distinct access points seen, before the 50-entry cap on `nearbyWifiNetworks`. Accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`wifi_network_count`). */\n wifiNetworkCount?: number;\n /** Hash of the joined network's SSID. Same as `wifiBssidHash`: accepted by the schema but NOT forwarded by the partner heartbeat handler — that controller contains no reference to wifi/mdns/ssdp/http-probe fields at all and passes only the BLE block to the ingest pipeline. The shipped Android agent sends these to the FIRST-PARTY heartbeat instead, in snake_case (`wifi_ssid_hash`). */\n wifiSsidHash?: string | null;\n [key: string]: unknown;\n};\n\n/**\n * A play reported by the partner SDK's reportPlay. The PartnerPlay body without screen_id (the screen is the device's binding), plus the Trillboards impression id.\n */\nexport type PartnerDevicePlay = {\n /** Optional ad/line identifier; defaults to the sha-keyed creative. */\n ad_id?: string;\n /** When the play completed (device clock), within the last 7 days and at most 5 minutes ahead of the server clock. */\n completed_at: string;\n /** The classification reference from POST /creatives — `sha256:<hex>` or the bare 64-char content hash. */\n creative_ref: string;\n /** Play duration in seconds (default 30). */\n duration_seconds?: number;\n /** The Trillboards impression id, when the host played an ad Trillboards served. The Trillboards record of that play is then kept and this report is not counted twice. */\n impression_id?: string;\n /** Your unique id for this play (idempotency key, shared with POST /v1/partner/plays). */\n play_id: string;\n /** Optional request identifier. */\n request_id?: string;\n};\n\n/**\n * Request body accepted by the single-device registration endpoints\n * (`@trillboards/api-client` `PartnerDeviceRegistrationInput`). Additional\n * vendor-specific fields are accepted and forwarded to enrichment.\n *\n */\nexport type PartnerDeviceRegistrationInput = {\n /** Stable partner-owned device identifier. */\n device_id?: string;\n /** Legacy SDK alias for the device identifier, retained for backwards compatibility. */\n device_name?: string;\n /** Mutable partner category stored independently of advertising classification. Defaults to other on a new device; omission on an existing device preserves its value. Unsupported categories return HTTP 400. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Display specification (pixel resolution and/or physical size). */\n display?: Record<string, unknown>;\n display_settings?: PartnerRegistrationDisplaySettings;\n /** Location hints (lat/lng, address, venue type). */\n location?: Record<string, unknown>;\n /** Friendly name for the device. */\n name?: string;\n /** Placement hints for the screen within the venue. */\n placement?: Record<string, unknown>;\n /** Venue taxonomy hints. */\n venue?: Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport type PartnerHeartbeatCommand = {\n /** Command normalized for partner SDK compatibility. */\n command?: string;\n /** Opaque command identifier — echo it verbatim to `POST /device/{deviceId}/command/{commandId}/ack`. The ack is ownership-checked against the device that received it, so acknowledging another device's command is refused with 403. */\n id?: string;\n /** Command arguments, shape determined by `command` (for example a brightness level or a target URL). Always an object — commands that take no arguments carry `{}`, never null. */\n payload?: Record<string, unknown>;\n /** When the command was enqueued, not when it was dispatched to you — the gap is up to one heartbeat interval, and a large gap means the device was silent, not that the server was slow. */\n queued_at?: string;\n};\n\nexport type PartnerHeartbeatData = {\n ad_delivery_profile?: PartnerAdDeliveryProfile;\n /** Pending remote commands, at most 5 per heartbeat, drained from the PG `device_commands` store. Each is marked `sent` as it is handed to you, so it appears in exactly ONE heartbeat response and is not re-delivered — acknowledge every entry via the ack endpoint, and dedupe on `id` because delivery is at-most-once, not exactly-once. */\n commands?: Array<PartnerHeartbeatCommand>;\n /** Server-clock timestamp stamped when this heartbeat was processed — the same instant used for the liveness write, not a device-supplied time and not the time of a previous heartbeat. */\n last_seen_at?: string;\n /** Liveness verdict for the screen. In practice it is `online`, or `standby` when the heartbeat reported `power_state` of `off`/`standby` — `standby` is NOT in the declared enum, and `offline` can never be returned here because receiving this response is itself proof the device reached us. It falls back to `online` when the device is not yet linked to a screen. */\n status?: \"online\" | \"offline\";\n};\n\nexport type PartnerHeartbeatMeasurementMetadata = {\n /** Whole seconds since `receivedAt`, computed when the response was built and floored at 0 — the same number as the sibling `stalenessSeconds`. It measures the age of the HEARTBEAT, not of the cache entry; use `cachedAt` for cache age. */\n ageSeconds?: number | null;\n /** When the Redis device twin that served this response was written. It is non-null ONLY when `source` is `redis_twin`, and even then only if the twin carried a `cachedAt`/`observedAt` stamp; the `pg_fallback` and `unknown` paths always report `null`. */\n cachedAt?: string | null;\n /** ISO-8601 server-clock time the underlying heartbeat was received — byte-for-byte the same value as the sibling `lastHeartbeatAt`, not an independent measurement. `null` when no heartbeat has ever been recorded. */\n receivedAt?: string | null;\n /** Which store answered: `redis_twin` (the hot pre-computed device twin — the normal path), `pg_fallback` (the twin was cold or missing, so the persisted last-heartbeat record was used), or `unknown` (no heartbeat has ever been recorded). This is the field that determines which keys `telemetry` can contain, and it is the only signal that the twin was a miss. */\n source?: \"redis_twin\" | \"pg_fallback\" | \"unknown\";\n [key: string]: unknown;\n};\n\nexport type PartnerHeartbeatQueryData = {\n adDeliveryProfile?: PartnerAdDeliveryProfile;\n /** The device's canonical identifier, which need NOT equal the value you put in the path: the server echoes the device fingerprint, falling back to your registered `external_id` and then to the internal id. Match responses on your own request, not on this field. */\n deviceId: string;\n /** Server-clock time the most recent heartbeat was RECEIVED — never a device-supplied timestamp. `null` means this device has never sent a heartbeat that the server retained; note the value can come from the Redis twin, which expires, so a cold cache falls back to the persisted record rather than reporting null. */\n lastHeartbeatAt?: string | null;\n measurementMetadata?: PartnerHeartbeatMeasurementMetadata;\n /** Whole seconds between `lastHeartbeatAt` and the moment this response was built, floored at 0 and rounded — it is computed at read time, so two calls a minute apart return different values for the same heartbeat. `null` when `lastHeartbeatAt` is null. It duplicates `measurementMetadata.ageSeconds` exactly. */\n stalenessSeconds?: number | null;\n telemetry?: PartnerSafeHeartbeatTelemetry;\n [key: string]: unknown;\n};\n\nexport type PartnerHeartbeatQueryResponse = {\n data?: PartnerHeartbeatQueryData;\n /** Always `true` on this 200 response. The 400 (missing `deviceId`), 404 (unknown device), 403 (device belongs to another partner) and 500 paths return `success: false` with a `message` and no `data`. */\n success?: boolean;\n};\n\n/**\n * Optional heartbeat payload. Nested telemetry objects are preferred; legacy flat keys\n * are still accepted for backward compatibility. The registered\n * `deviceId` is the binding boundary for both liveness and identity; no\n * separate partner API key is required.\n *\n */\nexport type PartnerHeartbeatRequest = {\n /** Highest-precedence source for `last_vast_request_at`, `last_vast_response_at` and `proof_of_play_enabled`. All three are dead on both sides — no agent or SDK in the repo emits this block, and nothing reads the values once stored. */\n ad?: {\n last_vast_request_at?: string;\n last_vast_response_at?: string;\n proof_of_play_enabled?: boolean;\n };\n advertising_identity?: AdvertisingIdentity;\n /** Flat alias of `telemetry.agentStatus`. No producer uses this spelling; live values arrive camelCase and come from two disjoint vocabularies — `sensing`/`camera_failed`/`starting`/`idle` from the Android sensing SDK, `foreground`/`background` from the browser SDK. */\n agent_status?: string;\n /** Second-precedence source (after `telemetry.agentVersion`) for the Trillboards agent/SDK version — this is the key the Android sensing SDK actually sends on the partner heartbeat. It is kept ONLY if the heartbeat self-identifies as a Trillboards SDK; otherwise the server force-nulls it so a BYO player's app version is never recorded as ours. */\n agent_version?: string;\n /** Android SDK/API level; below 23 forces `vast_fallback` for a native-Android IMA host. The shipped browser SDK derives it from the user-agent token `Android <n>`, which is the platform RELEASE number (Android 9 gives 9), not the API level (28) — so a value under ~23 is more likely a release number than a genuinely old device. */\n android_api_level?: number;\n /** Flat alias of `telemetry.brightness`, on the platform's own 0-100 scale. Only the Tizen and webOS agents emit a brightness at all, and they put it in `metadata`, not here. */\n brightness?: number;\n /** Java 8+ library desugaring in a native-Android IMA host. Nothing in the repo emits it in any casing, so it is absent fleet-wide; it is read only when `ima_integration` is `android_native` and `android_api_level` is 25 or below, where `false` adds a crash-risk note to `ad_delivery_profile.notes`. */\n desugaring_enabled?: boolean;\n /** Hardware self-description. `os`/`osv`/`make`/`model` here rank below `telemetry`/`metadata` and above the flat body keys, while `android_api_level` and `webview_chromium_major` are read from here in snake_case. It also carries the undocumented `native_bridge` object — the Android WebView bridge's ground-truth make/model/OS/advertising identity — and the DOOH taxonomy keys `dth`/`msid`/`venuetype`/`rdid`/`idtype`/`is_lat`. */\n device?: {\n android_api_level?: number;\n make?: string;\n model?: string;\n os?: string;\n osv?: string;\n webview_chromium_major?: number;\n };\n /** Up to 16 DSP-matchable audience identities (hashed email / UID2). Normalisation is ALL-OR-NOTHING across the array: one malformed element, a duplicate `(id_type, source)` pair beyond the first, or more than 16 entries causes the ENTIRE array to be dropped and the heartbeat still answers 200. Send `[]`-worth of care — a partially valid batch stores nothing. */\n extended_identities?: Array<ExtendedIdentity>;\n /** Flat alias, outranked by `ima.integration`. `html5_webview` marks the heartbeat as coming from a Trillboards SDK (which is what permits `agent_version` to be stored); `android_native` with an API level below 23 forces `vast_fallback`. Unrecognised or absent values become `unknown`, never null. */\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n /** Flat alias with no producer — the browser SDK sends `ima.sdk_version` (from `window.google.ima.VERSION`), which outranks this key and is `null` when IMA failed to load. */\n ima_sdk_version?: string;\n /** Flat alias with no producer — the browser SDK sends `ima.support_reason`, the literal `ok` on success or its IMA load-failure reason. Stored only; the ad-delivery decision never reads it. */\n ima_support_reason?: string;\n /** Flat alias, outranked by `ima.supported` and by `telemetry`/`metadata`. An explicit `false` pins `ad_delivery_profile.mode` to `vast_fallback` and turns `auto_recovery_enabled` off, so the server stops attempting to move the device back onto IMA. */\n ima_supported?: boolean;\n /** Flat alias of `telemetry.inputSource`. Dead on both sides — no producer emits either casing, and the column has no ClickHouse mirror. */\n input_source?: string;\n /** Numeric IMA `AdError` code from the last IMA failure. The browser SDK sends it inside `ima`, which outranks this flat key; it is persisted on the device record and read by nothing. */\n last_ima_error_code?: number;\n /** Numeric VAST error code from the last tag failure (e.g. 303 for an empty wrapper chain), sent inside `ima` by the browser SDK. Persisted only, with no server-side consumer. */\n last_vast_error_code?: number;\n /** Timestamp of the last outbound VAST request. No producer exists anywhere in the repo and nothing reads the stored value, so this field is dead on both ends. */\n last_vast_request_at?: string;\n /** Timestamp of the last VAST response received. Like `last_vast_request_at`, no agent or SDK emits it and nothing consumes it. */\n last_vast_response_at?: string;\n /** Current GPS fix for a moving screen. Processed only for screens whose `mobility_type` is `mobile` or `semi_mobile` (declare it at registration or via PATCH /device/{deviceId}), OR for any screen still missing coordinates (a one-time self-heal that also kicks off venue classification). Static screens with valid coordinates ignore it. Updates live geo-targeting, geofencing and analytics. Fully optional — omit it on stationary screens. */\n location?: {\n /** Horizontal accuracy radius in meters, stored as the device reports it. */\n accuracy_m?: number;\n /** Up to 200 fixes recorded while the device was offline, replayed as a historical track. Timestamps MUST be in ascending order — a non-chronological batch is rejected with HTTP 400. Only the top-level `location` updates the live serving position. */\n buffered_locations?: Array<{\n accuracy_m?: number;\n heading?: number;\n lat: number;\n lng: number;\n speed_mps?: number;\n timestamp?: number;\n }>;\n /** Bearing in degrees (0–360, 0 = true north). Omit if unavailable. */\n heading?: number;\n /** Latitude in decimal degrees (WGS 84). */\n lat?: number;\n /** Longitude in decimal degrees (WGS 84). */\n lng?: number;\n /** `gps` — a live on-device fix. `gps_buffered` — a fix recorded while offline and replayed on reconnect. */\n source?: \"gps\" | \"gps_buffered\";\n /** Ground speed in meters per second. Omit if unavailable. */\n speed_mps?: number;\n /** Unix epoch milliseconds of the on-device fix. Send the device clock value. A fix whose timestamp is more than 60 s ahead of the server's clock, or more than 6 h behind it, is kept without a fix time. A position jump implying > 320 km/h between consecutive fixes is rejected. */\n timestamp?: number;\n };\n /** Alternate namespace for telemetry keys (legacy support). */\n metadata?: Record<string, unknown>;\n /** Flat alias of `telemetry.muted`. The TV agents fall back to `false` here when power state is unreadable while falling back to `null` for `brightness`/`volume`, so a `false` cannot be read as evidence the read succeeded. */\n muted?: boolean;\n /** Connection metrics. The server reads ONLY the camelCase keys shown here; the shipped `trillboards-lite` browser SDK sends this block snake_case (`connection_type`, `effective_type`, `bandwidth_mbps`, `latency_rtt`), so not one key matches and its entire network block is silently discarded on every heartbeat. `bandwidthMbps`/`downlinkMbps` share one slot and `latencyRtt`/`rtt` share another. */\n network?: {\n bandwidthMbps?: number;\n connectionType?: string;\n downlinkMbps?: number;\n effectiveType?: string;\n latencyRtt?: number;\n rtt?: number;\n saveData?: boolean;\n };\n /** Flat alias of `telemetry.networkStrengthDbm`, in dBm (negative). No agent or SDK populates either spelling, so it is absent fleet-wide. */\n network_strength_dbm?: number;\n /** Flat alias of `telemetry.powerState`, used only when the nested value is absent. It coerces to `unknown` rather than failing, and `off`/`standby` downgrade the screen to `standby` so it stops receiving ads. No shipped producer uses this snake_case spelling — every emitter sends the camelCase form. */\n power_state?: \"on\" | \"standby\" | \"off\" | \"unknown\";\n /** Declares that the player emits proof-of-play. No producer sends it and no server logic reads it — proof-of-play eligibility is decided server-side, not from this flag. */\n proof_of_play_enabled?: boolean;\n /** Lowest-precedence source for the IMA/build fields: `ima_supported`, `ima_integration`, `ima_sdk_version`, `android_api_level` and `webview_chromium_major` are read from here only after `ima.*`, `telemetry`/`metadata` and the flat body keys have all missed. Its `version` sub-key is NOT read at all — the SDK version the server stores comes from body `agent_version`/`sdk_version`. */\n sdk?: {\n android_api_level?: number;\n desugaring_enabled?: boolean;\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n ima_sdk_version?: string;\n ima_supported?: boolean;\n version?: string;\n webview_chromium_major?: number;\n };\n /** Third-precedence alias of `agent_version` — same destination and the same BYO-nulling rule. This is what the shipped `trillboards-lite` browser SDK sends, alongside `sdk_type: \"lite\"`, which is itself one of the signals that classify the heartbeat as ours. */\n sdk_version?: string;\n telemetry?: PartnerHeartbeatTelemetry;\n /** Flat alias of `telemetry.temperatureC`, in degrees Celsius from the Android battery thermal sensor. No producer uses this snake_case spelling, and battery-less CTV hardware omits the reading altogether rather than sending 0. */\n temperature_c?: number;\n /** Flat alias of `telemetry.uptimeSeconds`. It measures seconds since DEVICE boot (`SystemClock.elapsedRealtime()/1000` on Android — it survives an agent restart and counts through deep sleep), not agent process uptime. Producers send the camelCase form inside `telemetry`/`metadata`. */\n uptime_seconds?: number;\n /** Flat alias of `telemetry.volume`, on the platform's own scale (0-100 on Tizen/webOS), not a percentage of any documented maximum. Emitted by the Tizen and webOS agents through `metadata` only. */\n volume?: number;\n /** Chromium major version behind the WebView, parsed from the `Chrome/<n>` user-agent token. Below 87 and below 80 each append an advisory note to `ad_delivery_profile.notes`; neither changes the delivery mode. */\n webview_chromium_major?: number;\n};\n\nexport type PartnerHeartbeatResponse = {\n data?: PartnerHeartbeatData;\n /** Always `true` on this 200 response. The failure paths — 404 for an unresolvable `deviceId`, 400 for an invalid BLE payload, 500 on an internal error — return `success: false` with a `message` and no `data` key at all. */\n success?: boolean;\n};\n\nexport type PartnerHeartbeatTelemetry = {\n /** A status word whose vocabulary depends on which SDK reports it: the Android sensing SDK derives it from camera health and sends exactly `sensing` (camera open), `camera_failed`, `starting` or `idle`, while the browser SDK sends `foreground`/`background` from `document.hidden`. Those four Android values are also an in-band signal that the heartbeat came from a Trillboards SDK, which is what allows `agentVersion` to be stored. */\n agentStatus?: string;\n /** Version of the TRILLBOARDS agent/SDK only. If the heartbeat does not self-identify as one of ours (`ima.integration=html5_webview`, `sdk_type=lite`, a `capabilities.audienceSensing.cameraHealth` block, or one of the four sensing `agentStatus` values), the server discards what you send and force-nulls both casings, so a BYO player's own app version is never stamped as ours. Resolution order is `telemetry.agentVersion`, then body `agent_version`, then body `sdk_version`. */\n agentVersion?: string;\n /** Android SDK/API level (23 = Marshmallow, 28 = Pie); below 23 it forces `vast_fallback` when `ima_integration` is `android_native`. Beware the unit — the shipped browser SDK derives it from the user-agent token `Android <n>`, which is the platform RELEASE number (Android 9 gives 9), not the API level (28). */\n android_api_level?: number;\n /** Downlink bandwidth in MEGABITS PER SECOND from `navigator.connection.downlink`. It shares one destination with `downlinkMbps` (`bandwidthMbps` wins), then the same two keys inside `network`, so only one value ever survives. */\n bandwidthMbps?: number;\n /** Panel backlight level on the platform's own scale — on Samsung Tizen and LG webOS the 0-100 picture-brightness value, `null` when that picture-control service is unavailable (VIDAA hardcodes `null`, the API does not exist there). Neither partner SDK sends it; the `brightness` seen in the Android agents is a command-ACK detail, not heartbeat telemetry. */\n brightness?: number;\n /** Free-text connection label (`wifi`, `ethernet`, `cellular`…) that becomes `networkMetrics.connectionType`; `networkConnectionType` outranks it and `network.connectionType` is the fallback. It does NOT set the OpenRTB `device.connectiontype` sent in bid requests — that is the separate all-lowercase `connectiontype` key, which is an INTEGER enum (0 unknown, 1 ethernet, 2 wifi, 3 cellular, 4 2G, 5 3G, 6 4G, 7 5G), is not declared in this schema, and only passes because the object allows additional properties. */\n connectionType?: string;\n /** Whether Java 8+ library desugaring is enabled in a native-Android IMA host. No agent or SDK anywhere in the repo emits it, so it is absent fleet-wide; it is consulted only when `ima_integration` is `android_native` and `android_api_level` is 25 or below, where `false` adds a known-crash-risk note to `ad_delivery_profile.notes`. */\n desugaring_enabled?: boolean;\n /** Second-precedence spelling of `bandwidthMbps` (Mbps) filling the same `networkMetrics.bandwidthMbps` slot; ignored whenever `bandwidthMbps` is also present. The npm SDK sends both from the same `connection.downlink` reading. */\n downlinkMbps?: number;\n /** How the player reaches Google IMA. `html5_webview` is hardcoded by both Trillboards browser SDKs and is itself the signal marking the heartbeat as ours (which is what allows `agentVersion` to be stored); `android_native` with `android_api_level` below 23 forces `ad_delivery_profile.mode` to `vast_fallback`. Absent or unrecognised values normalise to `unknown`, never null, and the undocumented nested `ima.integration` key — what the shipped browser SDK actually sends — outranks this flat one. */\n ima_integration?: \"android_native\" | \"html5_webview\" | \"disabled\" | \"unknown\";\n /** The IMA SDK's own version string. Nothing produces this flat spelling — the shipped browser SDK sends it as `ima.sdk_version`, read from `window.google.ima.VERSION`, which takes precedence — and it is `null` whenever IMA failed to load, so absence usually pairs with `ima_supported: false`. */\n ima_sdk_version?: string;\n /** Free-text explanation for the `ima_supported` verdict — the browser SDK sends the literal `ok` when IMA loaded and its load-failure reason otherwise, under `ima.support_reason`, which outranks this flat spelling (nothing produces the flat one). Stored only: the ad-delivery decision never reads it. */\n ima_support_reason?: string;\n /** Whether the IMA SDK is usable on this player. An explicit `false` is a hard switch, not a hint: it pins `ad_delivery_profile.mode` to `vast_fallback` AND sets `auto_recovery_enabled: false`, so the server stops trying to move the device back onto IMA. The browser SDKs compute it as `Boolean(window.google.ima)` / an IMA load-failure flag. */\n ima_supported?: boolean;\n /** Free-form active-input label (e.g. an HDMI port name), stored verbatim on the device record. It has NO producer: no agent or SDK in the repo emits either casing, the only other references are Flutter UI localisation strings, and the schema sidecar marks the column PG-only with no ClickHouse mirror. Treat it as permanently absent. */\n inputSource?: string;\n /** Numeric IMA `AdError` code from the most recent IMA failure, cached client-side between heartbeats. The shipped browser SDK sends it inside `ima`, which outranks this flat key. Persisted on the device record only — no server logic reads it. */\n last_ima_error_code?: number;\n /** Numeric VAST error code from the most recent tag failure (e.g. 303 for a wrapper chain that resolved to nothing), cached client-side and sent inside `ima` by the browser SDK. Persisted only, with no server-side consumer. */\n last_vast_error_code?: number;\n /** Timestamp of the player's last outbound VAST request. It has NO producer: a repo-wide grep finds only the server-side reader and the generated API client, so it is absent on every live device, and nothing downstream consumes the stored value. */\n last_vast_request_at?: string;\n /** Timestamp of the last VAST response the player received. Like `last_vast_request_at` it has no producer in any agent or SDK, and the persisted value has no consumer. */\n last_vast_response_at?: string;\n /** Round-trip time in MILLISECONDS from `navigator.connection.rtt`. Shares one destination with `rtt` (`latencyRtt` wins); the read-side schema bounds the stored value to 0-60000. */\n latencyRtt?: number;\n /** Device manufacturer. Written to the device column but not authoritative — every heartbeat runs a device-identity fusion pass that can replace `make`/`model`/`os` from the user agent and 51Degrees specs, and the corrected value is what is persisted and read back. */\n make?: string;\n /** Device model, subject to the same identity-fusion overwrite as `make`. The browser SDK has no real model string and sends the full user agent in this field instead. */\n model?: string;\n /** Audio mute state. Note the asymmetry with `brightness`/`volume`: when the Tizen/webOS agent cannot read power state it still sends `false` here while sending `null` for the other two, so `false` does not distinguish \"not muted\" from \"could not be read\". The `muted` the browser SDK sends elsewhere belongs to the ad request, not the heartbeat. */\n muted?: boolean;\n /** Highest-precedence spelling of the free-text connection label that becomes `networkMetrics.connectionType`. No agent or SDK emits it, so in practice the value comes from `connectionType` or `network.connectionType`. Sending any of the six network keys makes the server stamp `networkMetrics.measuredAt` and increment `networkMetrics.measurementCount`. */\n networkConnectionType?: string;\n /** Highest-precedence spelling of the Network Information API `effectiveType` bucket (`slow-2g`/`2g`/`3g`/`4g`) — a round-trip-time and downlink classification, not the physical bearer. No producer emits this spelling; live values arrive as `effectiveType` or `network.effectiveType`. */\n networkEffectiveType?: string;\n /** Wi-Fi/cellular RSSI in dBm (negative; the read-side schema bounds it to -120..0). No agent or SDK populates it — the field exists on the Kotlin model and the only value in the tree is a hardcoded test literal — so it is absent fleet-wide. Per-AP signal is instead carried by `nearbyWifiNetworks[].signalStrengthDbm` and `wifiEnvironment.connectedSignalDbm`. */\n networkStrengthDbm?: number;\n /** Operating-system family, written straight to the device column `os` — the Android agents send the full `\"Android <release>\"` string, not a bare family name. It is an input to the identity-fusion pass that runs on every heartbeat, so what the read endpoint later returns may be a corrected value rather than what you sent. */\n os?: string;\n /** Lower-precedence alias of `osv`: both resolve to the same normalized value and the same `osv` device column, with `osv` winning when both are present. */\n osVersion?: string;\n /** OS version string. `osv` and `osVersion` are two spellings of ONE value — the normalizer takes `osv` first and falls back to `osVersion`, and both land in the single device column `osv`, so sending different values in the two keys silently keeps only `osv`. */\n osv?: string;\n /** Display power as the device reports it. Never null and never rejected: any unrecognised or absent value is coerced to `unknown`, and `off`/`standby` make the server record the screen `standby` rather than `online`, which stops ad delivery. Producers use this camelCase spelling only — the browser SDK derives it from `document.hidden` (`standby` when hidden, else `on`), the Fire TV / Android TV agents send their `PowerController` state; the flat `power_state` alias has no producer at all. */\n powerState?: \"on\" | \"standby\" | \"off\" | \"unknown\";\n /** Whether the player is configured to emit proof-of-play. No agent or SDK sends it, so it is absent fleet-wide, and nothing reads the stored value — actual proof-of-play eligibility is decided server-side, never from this flag. */\n proof_of_play_enabled?: boolean;\n /** Second-precedence spelling of `latencyRtt` (milliseconds), ignored when `latencyRtt` is also present. */\n rtt?: number;\n /** The browser's Data Saver preference (`navigator.connection.saveData`). Accepted as a boolean or the strings `\"true\"`/`\"false\"`; anything else becomes `null` rather than `false`. */\n saveData?: boolean;\n /** Degrees Celsius from the BATTERY thermal sensor — the only real °C reading a non-system Android app can obtain. Battery-less CTV hardware (Fire TV sticks, TV boxes) omits the key entirely rather than sending 0, so absence means \"no battery sensor\", not \"cool\"; the derived ClickHouse `cpu_temp_c` was measured above zero on ZERO rows. */\n temperatureC?: number;\n /** Seconds since the DEVICE booted, not since the agent process started: the Android producers send `SystemClock.elapsedRealtime() / 1000`, which keeps counting through deep sleep and resets only on reboot, so an agent crash-loop leaves this climbing. It is also the sole camelCase survivor in the ClickHouse heartbeat blob — every other gauge there is snake_case. */\n uptimeSeconds?: number;\n /** Speaker volume on the platform's own scale — 0-100 on Tizen (`tizen.tvaudiocontrol.getVolume()`) and webOS, `null` when the audio-control service is unavailable or (on VIDAA) does not exist. It is not normalised to a percentage of any maximum, and neither partner SDK sends it. */\n volume?: number;\n /** Major version of the Chromium engine backing the WebView, parsed from the `Chrome/<n>` user-agent token by both browser SDKs. Below 87 adds a content-restoration warning to `ad_delivery_profile.notes` and below 80 an autoplay/media warning; neither changes the delivery mode. */\n webview_chromium_major?: number;\n [key: string]: unknown;\n};\n\n/**\n * What a rider did with the screen, reported by the partner SDK's reportInteraction. (partner, device, interaction_id) is the event's identity.\n */\nexport type PartnerInteraction = {\n /** The creative on screen, as the host names it. */\n creative_id?: string;\n /** The host app's id for this interaction (idempotency key, per device). */\n interaction_id: string;\n /** When it happened (device clock), within the last 7 days and at most 5 minutes ahead of the server clock. */\n occurred_at: string;\n /** Milliseconds into the creative's playback when it happened. */\n t_ms?: number;\n /** What happened. seatbelt_reminder_shown = the host app showed a SeatbeltReminder that agent-core 1.24 delivered to its safety-event listener; send the reminder's eventId as interaction_id. Never a programmatic ad-lifecycle event (those are POST /device/{deviceId}/programmatic-event). */\n type: \"tap\" | \"qr_shown\" | \"qr_scanned\" | \"dwell_prompt\" | \"seatbelt_reminder_shown\";\n};\n\nexport type PartnerLBarContent = {\n /** The venue name rendered in the L-bar; empty string when unset. One of only three scalar keys (`enabled`, `business_name`, `current_promotion`) the PUT copies straight across — every other key here is an object that gets shallow-merged. */\n business_name?: string;\n /** Holds `phone`, `email`, `website`, `address` and `wifi_password`, all free text and all empty-string when unset, shallow-merged on PUT. `wifi_password` is rendered on the screen, so treat it as public. */\n contact_info?: Record<string, unknown>;\n /** The promo line shown in the L-bar. It is also writable through the much lighter `PUT .../l-bar/live-updates` endpoint as its `promotion` field, which is the path to use for frequent changes. */\n current_promotion?: string;\n /** Free-text lines rotated in the L-bar. Unlike every nested object above, this is REPLACED wholesale whenever it is present in the body, so send the complete list each time. */\n custom_messages?: Array<string>;\n /** The L-bar's own cosmetics — NOT the screen display-settings resource. Holds `background_color` (`#000000`), `text_color` (`#FFFFFF`), `accent_color` (`#4A90E2`), the widget toggles `show_weather`/`show_time`/`show_date`/`show_store_hours` (default true) and `show_contact_info`/`show_social_media`/`show_sports_scores`/`show_stock_market` (default false), plus `selected_sports_leagues`. Shallow-merged on PUT. */\n display_settings?: Record<string, unknown>;\n /** Whether the L-bar content region is drawn; defaults `false`. It is COUPLED to `display_preferences.display_mode` on the PUT — sending `display_mode: \"fullscreen\"` forces this to `false`, and `\"l-bar\"` forces it to `true` unless you send an explicit boolean in the same request. */\n enabled?: boolean;\n /** Exactly three sub-objects are merged — `queue_management` (`enabled`, `current_number`, `queue_message`, default `Now Serving`), `wait_time` (`enabled`, `current_wait_minutes`, `wait_message`, default `Current Wait Time`) and `custom_status` (`enabled`, `status_message`); any other key nested here is silently dropped. The live-updates endpoint sets `enabled` for you as a side effect of writing a value, and clears `custom_status.enabled` when you send an empty message. */\n live_updates?: Record<string, unknown>;\n /** Holds `facebook`, `instagram`, `twitter` and `google_reviews`, free text and empty-string when unset, shallow-merged on PUT. */\n social_media?: Record<string, unknown>;\n /** Free-text opening hours: one string per lowercase day name (`monday`..`sunday`) plus a `timezone` defaulting to `America/New_York`. The strings are displayed verbatim — nothing parses them into open/close times — and the PUT shallow-merges them, so you can send a single day. */\n store_hours?: Record<string, unknown>;\n};\n\nexport type PartnerLBarDisplayPreferences = {\n /** Which surfaces ads may occupy; `null` by default, in which case it is derived from `display_mode` + `l_bar_ads_enabled`. Setting `lbar` also flips `display_mode` to `l-bar` when the same request does not set it, and narrows the fullscreen surface to `self_promo` only — paid and programmatic demand stops running full screen. */\n ad_surface_mode?: \"fullscreen\" | \"lbar\" | \"pip\" | \"all\" | null | null;\n /** Default `fullscreen`. Writing it has side effects: `fullscreen` also forces `l_bar_ads_enabled` and `l_bar_content.enabled` to `false`, and `l-bar` forces both to `true` unless the same request sets them explicitly. A change also emits a `refresh` control event so the kiosk reloads and swaps surfaces. */\n display_mode?: \"fullscreen\" | \"l-bar\";\n /** Seconds one L-bar ad is held; default 8, accepted range 3-30. It must be strictly LESS than `l_bar_ad_interval`, and the check falls back to the stored interval when this request does not send one. */\n l_bar_ad_duration?: number;\n /** Seconds between L-bar ad plays; default 25, accepted range 10-120. It must be strictly GREATER than `l_bar_ad_duration`, and the pair is cross-checked against the STORED values, so lowering this alone can fail on a duration set by an earlier request. */\n l_bar_ad_interval?: number;\n /** Whether ads may fill the L-bar slots. When it has never been set it is DERIVED as `display_mode === \"l-bar\"`, so it reads `true` on an L-bar screen and `false` on a fullscreen one. Accepts a boolean or the strings `\"true\"`/`\"false\"`; anything else is 400. */\n l_bar_ads_enabled?: boolean;\n /** Which edge the L-bar occupies; default `bottom`. It decides ad-slot geometry — `bottom` lays slots out horizontally and `right` vertically — and the slot COUNT is derived from it, so switching sides changes how many `lbar_slot_*` surfaces exist. This endpoint does not validate the value against any enum (the display-settings resource's `l_bar.position` does, and accepts `top`/`bottom`/`left`/`right`). */\n l_bar_position?: \"bottom\" | \"right\";\n /** Share of the screen the L-bar occupies, as a PERCENT; default 20. This endpoint accepts it with no range check at all, while the equivalent `l_bar.size_percent` on the display-settings resource clamps to 10-50. It is also not what sizes ad slots — `buildAdSurfaces` uses a fixed 25%. */\n l_bar_size?: number;\n /** Picture-in-picture ad window: `enabled` (default false), `position` (default `bottom-right`), `size_ratio` as a FRACTION of the screen 0.15-0.45 (default 0.3), `aspect_ratio` as width/height 0.5-3 (default 16/9), and `margin` in PIXELS 8-64 (default 24). A PiP surface is only produced when `ad_surface_mode` is `pip` or `all` AND `enabled` is true. */\n pip_settings?: {\n aspect_ratio?: number;\n enabled?: boolean;\n margin?: number;\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n size_ratio?: number;\n };\n};\n\nexport type PartnerLBarSettings = {\n /** The resolved renderable ad surfaces, one entry per surface (`fullscreen`, `lbar_slot_1..N`, `pip`). Present ONLY on the PUT response; the GET does not compute it. */\n ad_surfaces?: Array<{\n allowed_ad_types?: Array<string>;\n dimensions?: {\n height?: number;\n width?: number;\n };\n display_area_ratio?: number;\n display_mode?: string;\n enabled?: boolean;\n id?: string;\n surface_group?: string;\n surface_type?: string;\n }>;\n display_preferences?: PartnerLBarDisplayPreferences;\n l_bar_content?: PartnerLBarContent;\n /** The screen's resolved pacing contract, present only on the PUT response. `policy_version` is `v1` and every interval is in MILLISECONDS (`paid_interval_ms`, `self_promo_interval_ms`, `image_ad_total_ms`, `image_ad_min_ms`); it also carries `max_paid_share` (null unless a loop share cap is enabled), `surface_policy`, `schedule_policy`, `pip_settings` and `lbar_settings`. */\n playback_policy?: Record<string, unknown>;\n};\n\n/**\n * Where the screen's location comes from, and, per rail, whether that rail\n * has the location it needs. Location is a readiness capability, never a\n * registration rule: a device without one is registered, and this says\n * which rails serve it until a position arrives. `monetization_status` is\n * computed over `inventory_feed` and `geo_targeted_demand`.\n *\n */\nexport type PartnerLocationCapability = {\n /** `precise` — the screen or its device has coordinates; `fleet_market` — none of its own, your account's declared fleet market location lists it; `none`. */\n position?: \"precise\" | \"fleet_market\" | \"none\";\n rails?: {\n geo_targeted_demand?: PartnerLocationRail;\n inventory_feed?: PartnerLocationRail;\n visit_attribution?: PartnerLocationRail;\n };\n};\n\nexport type PartnerLocationRail = {\n /** Where a ready rail's location comes from; null when blocked. Only `inventory_feed` reads `fleet_market`. */\n location_source?: \"screen\" | \"device\" | \"fleet_market\" | null | null;\n /** Why a blocked rail has no location; null when ready. See https://api.trillboards.com/docs/monetization-requirements#location-capability. */\n reason?: \"awaiting_device_gps\" | \"no_location_provided\" | \"city_without_state\" | \"geocode_failed\" | \"screen_position_pending\" | \"country_unknown\" | \"country_not_supported\" | null | null;\n status?: \"ready\" | \"blocked\";\n};\n\n/**\n * Stripe-style monetization requirements (account.requirements analogue).\n * Returned on device register / update / get / batch so bulk partners can\n * detect and self-remediate missing data instead of discovering silent\n * gaps later. `currently_due` blocks or limits monetization now;\n * `eventually_due` improves serving but isn't blocking.\n *\n */\nexport type PartnerMonetizationRequirements = {\n /** Requirements blocking or limiting monetization right now. */\n currently_due?: Array<PartnerRequirement>;\n /** Non-blocking improvements (e.g. display dimensions). */\n eventually_due?: Array<PartnerRequirement>;\n};\n\nexport type PartnerNetworkConfig = {\n /** Partner-level ad pacing and identity controls applied to every screen you own; on the `/ads` path they OUTRANK the screen's own `ad_interval_seconds` and the partner's `sdk_config.max_ads_per_hour`. A PATCH merges key-by-key and rejects unknown keys with a 400, and sending `null` for `identity_mode` or `self_promo_priority_mode` DELETES the key rather than storing null, so those two come back absent rather than as `null`. */\n ad_delivery?: {\n /** `/ads` response cache lifetime. Zero requires a fresh response for every request. */\n cache_max_age_seconds?: number;\n /** Delegates resettable advertising identity to the native Google IMA SDK; the API never fabricates one. Set null to restore the platform default identity path. */\n identity_mode?: \"ima_sdk\" | null;\n /** Fleet-wide hourly ad cap returned in `settings.max_ads_per_hour`. */\n max_ads_per_hour?: number;\n /** Requests non-personalized demand when true. Never provide an advertising identifier unless the OS legitimately exposes it. */\n non_personalized_ads?: boolean;\n /** Returned as both `settings.ad_interval` and `header_bidding_settings.min_interval_seconds`; the player should request each monetizable slot at this cadence. */\n request_interval_seconds?: number;\n /** Controls whether a scheduled self-promo/house slot may lead the VAST waterfall. `scheduled_primary` preserves the bounded house cadence; `fallback_only` keeps self-promo behind paid programmatic demand; `disabled` removes the self-promo/house creative from your screens entirely — it is served on neither `ads[]` nor the VAST waterfall, and no new house creative is generated for your screens. Paid-direct guarantees always retain priority and are never affected. Set null to restore `scheduled_primary`. */\n self_promo_priority_mode?: \"scheduled_primary\" | \"fallback_only\" | \"disabled\" | null;\n };\n /** White-label presentation for your buyer-facing advertiser portal. These values are read and written directly against the branding your portal renders — a GET returns what a buyer currently sees, and a write takes effect on their next page load. Omitted entirely if no white-label portal is linked to your partner account; writing branding in that state returns `409` `white_label_distributor_not_linked` rather than accepting values that would render nowhere. Contact Trillboards to have one linked. */\n branding?: {\n /** Shown as the portal name and the browser tab title. */\n display_name?: string;\n /** Absolute HTTPS URL. */\n favicon_url?: string;\n font_body?: string;\n font_heading?: string;\n /** Absolute HTTPS URL. Rendered in the portal header. */\n logo_url?: string;\n /** CSS color. HSL triplets (\"210 90% 40%\") and hex are both accepted. */\n primary_color?: string;\n secondary_color?: string;\n tagline?: string;\n };\n /** Default content preferences inherited by newly provisioned screens. */\n default_content_preferences?: Record<string, unknown>;\n /** Partner-level (fleet-wide) demand-source ordering; there is no per-screen override for these keys. A PATCH merges key-by-key into what is stored, and any key other than `source_order`/`total_timeout_ms` is rejected with a 400 naming it. The GET omits this object entirely when nothing has been stored, so absence means \"never configured\" — it is not a rendering of the effective defaults. */\n default_waterfall?: {\n /** Preferred opaque source aliases from the `/ads` response. Sources not listed here remain enabled and are appended. Internal demand names and `sort_by: cpm` are rejected. */\n source_order?: Array<string>;\n /** Total deadline for one waterfall snapshot, in milliseconds. */\n total_timeout_ms?: number;\n };\n /** Limits your branded buyer portal to YOUR OWN screens. Off by default: a branded portal otherwise sells the whole Trillboards network, which is what most white-label partners want. The screen set is DERIVED from the media-owner identity your screens already carry — both the ones we host and the ones resold through partner exchanges — so it stays correct as you add inventory and there is no list to maintain. It cannot be set to another operator's inventory. */\n storefront?: {\n /** When true, every inventory surface in your buyers' portal — search, map, forecasts, quotes, bookings and proposals — is limited to your own screens. */\n enabled?: boolean;\n };\n};\n\n/**\n * Partner-safe partial update. Internal `partners`, `supply_chain`, seller\n * IDs, direct demand names, and CPM-sort controls are rejected.\n *\n */\nexport type PartnerNetworkConfigUpdate = PartnerNetworkConfig;\n\n/**\n * A log-level play for a partner-served ad.\n */\nexport type PartnerPlay = {\n /** Optional ad/line identifier; defaults to the sha-keyed creative when creative_ref is sent. */\n ad_id?: string;\n /** ISO 8601 timestamp when the play completed. */\n completed_at: string;\n /** Optional. The classification reference from POST /creatives — `sha256:<hex>` or the bare 64-char content hash. Omit it for a play of an ad you hold no content hash for; the play is then recorded with its `ad_id`, or with none. */\n creative_ref?: string;\n /** Play duration in seconds (default 30). */\n duration_seconds?: number;\n /** Your unique id for this play (idempotency key). */\n play_id: string;\n /** Optional partner request identifier. */\n request_id?: string;\n /** One of your registered earner-screen ids. */\n screen_id: string;\n};\n\n/**\n * Partner-reported impression and revenue counts for reconciliation against deduped completed_impressions. Ingested from VidVerto SSP API and Adipolo API / JustBaat CSV reports. PG only.\n */\nexport type PartnerReconciliationReports = {\n adjustment_id?: number | null;\n applied_at?: string | null;\n /** applied_report_hash/applied_at (mig 449) gate the hourly pricing re-apply: syncs skip the CI re-stamp + PED rebuild when the applied tuple is unchanged. Written ONLY by partnerPricingApplyGate.reco... */\n applied_report_hash?: string | null;\n created_at: string;\n /** Wave 2 B added demand_partner_id INT + variant_id INT FKs. Legacy partner_key TEXT kept as wire-format alternate-key. Backfill via follow-up Wave 2 B-backfill PR. */\n demand_partner_id?: number | null;\n /** VidVerto synced daily via vidvertoRevenueSync before programmatic earnings aggregation. */\n id?: number | null;\n imported_by?: string | null;\n /** NUMERIC(8,4). */\n impression_variance?: number | null;\n /** NUMERIC(10,4). */\n our_ecpm?: number | null;\n our_impressions?: number | null;\n our_requests?: number | null;\n /** NUMERIC(14,6). */\n our_revenue?: number | null;\n provider_name: string;\n /** Adipolo publisher revenue requires a completed vast_requests lifecycle plus latest screens_live source='owned'. ID shape/event alone is insufficient; shared, external, and unjoined bundles are excl... */\n raw_data?: Record<string, unknown> | null;\n report_date: string;\n report_type: \"partner_api\" | \"manual_upload\" | \"email_extract\" | \"dashboard_snapshot\";\n /** NUMERIC(10,4). */\n request_variance?: number | null;\n resolution_notes?: string | null;\n /** NUMERIC(8,4). */\n revenue_variance?: number | null;\n reviewed_at?: string | null;\n reviewed_by?: string | null;\n status: \"pending\" | \"matched\" | \"flagged\" | \"disputed\" | \"resolved\" | \"accepted\";\n /** NUMERIC(10,4). */\n their_ecpm?: number | null;\n /** NUMERIC(6,4). */\n their_fill_rate?: number | null;\n their_impressions?: number | null;\n their_requests?: number | null;\n /** NUMERIC(14,6). */\n their_revenue?: number | null;\n updated_at: string;\n variant_id?: number | null;\n};\n\n/**\n * Optional display behavior applied while registering or re-registering a device.\n */\nexport type PartnerRegistrationDisplaySettings = {\n content_fit?: ContentFitSettings;\n};\n\nexport type PartnerRequirement = {\n /** Stable machine code, e.g. location_unresolvable, location_awaiting_device_gps, enrichment_failed, display_size_missing. */\n code?: string;\n /** Built mechanically as `https://api.trillboards.com/docs/monetization-requirements#<code>`, so the anchor always matches `code`. A bare `docs.` subdomain is deliberately NOT used — it resolves to an unrelated portal SPA rather than documentation — and a CI guard blocks reintroducing it. */\n doc_url?: string;\n /** The request field this concerns (location, venue, display). */\n field?: string;\n /** Human-readable, actionable remediation. */\n message?: string;\n /** Specific reason variant, e.g. city_without_state, no_location_provided, geocode_failed, awaiting_device_gps. */\n reason?: string;\n};\n\n/**\n * Partner-safe subset of device telemetry. Strips MDM compliance,\n * Vertex embeddings, identity-correction internals, partner identifiers,\n * and Mongo `_id` so partners only see what they need to decide\n * whether a device is healthy enough to receive ads.\n *\n */\nexport type PartnerSafeHeartbeatTelemetry = {\n /** Agent lifecycle word, with two disjoint vocabularies depending on the reporting SDK (`sensing`/`camera_failed`/`starting`/`idle` from the Android sensing SDK, `foreground`/`background` from the browser SDK). Absent on the primary `redis_twin` path — the device twin has no such field, so it surfaces only on the `pg_fallback` path. */\n agentStatus?: string | null;\n /** Trillboards agent/SDK version. Never present here on either path: the heartbeat writes it to the device record root, not into the last-heartbeat telemetry blob, and the device twin does not carry it either. It is also nulled at write time for any heartbeat that does not self-identify as a Trillboards SDK. */\n agentVersion?: string | null;\n /** Downlink bandwidth in Mbps. Never present on either path: the write path stores it under `networkMetrics.bandwidthMbps`, a sibling of the last-heartbeat blob this endpoint reads, and the device twin has no such field. */\n bandwidthMbps?: number | null;\n /** Panel brightness on the platform's own scale (0-100 on Tizen/webOS, `null` where no picture-control API exists). Absent on the primary `redis_twin` path — the device twin has no such field, so it can only appear on the `pg_fallback` path and only for the TV agents that emit it. */\n brightness?: number | null;\n /** Free-text connection label. Not present on either path — the write path stores it as `networkMetrics.connectionType`, and while the device twin does carry a `connectiontype`, that is the all-lowercase OpenRTB INTEGER enum, a different quantity under a different key. */\n connectionType?: string | null;\n /** Running count of back-to-back ad failures the player has seen, from the heartbeat's `playback.consecutive_failures`; it is what drives the server's stalled-playback recovery. Absent on the primary `redis_twin` path — the device twin has no such field, so it appears only on the `pg_fallback` path. */\n consecutiveAdFailures?: number | null;\n /** Network Information API `effectiveType` bucket (`slow-2g`/`2g`/`3g`/`4g`) — a latency/throughput classification, not the physical bearer. Stored under `networkMetrics.effectiveType` and carried by neither source object, so it never appears here. */\n effectiveType?: string | null;\n /** Round-trip time in MILLISECONDS (bounded 0-60000 by the read-side schema). Like `bandwidthMbps` it is stored under `networkMetrics.*` and is on neither of this endpoint's two source objects. */\n latencyRtt?: number | null;\n /** Device manufacturer, after the identity-fusion correction pass — so it can differ from what the device reported. Present only on the `redis_twin` path: it is a device-record field, and the `pg_fallback` path returns just the last-heartbeat telemetry blob. */\n make?: string | null;\n /** Device model, after identity-fusion correction. Like `make`, it is a twin-only field and is absent whenever `measurementMetadata.source` is `pg_fallback`. */\n model?: string | null;\n /** Mute state. Absent on the primary `redis_twin` path — the device twin has no such field. On the agents that do report it, `false` is also the fallback used when the power state could not be read at all, so it does not prove a successful read. */\n muted?: boolean | null;\n /** RSSI in dBm, bounded -120..0. Doubly absent: no shipped agent produces it in the first place, and absent on the primary `redis_twin` path — the device twin has no such field. */\n networkStrengthDbm?: number | null;\n /** Declared but NEVER POPULATED on either source path: nothing writes an `onlineStatus` into the last-heartbeat telemetry blob and the device twin has no such field. The equivalent state lives on the screen row (`earner_screens.online_status`), which this endpoint does not read — use `stalenessSeconds` to judge liveness instead. */\n onlineStatus?: \"online\" | \"offline\" | \"standby\" | \"unknown\" | null;\n /** Operating-system family after correction — the Android agents report the full `\"Android <release>\"` string. Twin-only, so absent on the `pg_fallback` path. */\n os?: string | null;\n /** OS version string after correction; the heartbeat collapses the `osv` and `osVersion` request spellings into this one value. Twin-only, so absent on the `pg_fallback` path. */\n osv?: string | null;\n /** Last reported display power (`on`/`standby`/`off`/`unknown`). Absent on the primary `redis_twin` path — the device twin has no such field, so it appears only when `measurementMetadata.source` is `pg_fallback`, which reads the persisted last-heartbeat telemetry blob. */\n powerState?: string | null;\n /** Degrees Celsius from the Android BATTERY thermal sensor (bounded -50..150 by the read schema). Absent on the primary `redis_twin` path — the device twin has no such field, and battery-less CTV hardware never reports it at all, so absence carries no thermal information. */\n temperatureC?: number | null;\n /** User agent, resolved with a three-tier fallback — the corrected device UA, then the stored device UA, then the `User-Agent` header of the heartbeat request that built the twin — so it can reflect the HTTP client rather than the player. Twin-only. */\n ua?: string | null;\n /** Seconds since the DEVICE booted, not since the agent started — it survives an agent restart and counts through deep sleep. Absent on the primary `redis_twin` path — the device twin has no such field, so it surfaces only on the `pg_fallback` path. */\n uptimeSeconds?: number | null;\n /** The browser `document.visibilityState` of the player page (`visible`/`hidden`), sourced from the heartbeat's `content.visibility_state`. One of only two telemetry-derived fields that survive onto the Redis device twin, so it is the one health signal available on BOTH source paths. */\n visibilityState?: string | null;\n /** Speaker volume on the platform's own scale, not a normalised percentage. Absent on the primary `redis_twin` path — the device twin has no such field; only the Tizen and webOS agents ever supply it. */\n volume?: number | null;\n [key: string]: unknown;\n};\n\nexport type PartnerSelfPromoAd = {\n /** The 24-hex advertisement id, minted server-side with `newObjectId()`, and the `ad_id` the schedule and disable endpoints take. Partner self-promo rows carry no `user_mongo_id`, so this id is only resolvable through the partner's own `partner-self-promo` placements — an owner-keyed lookup structurally cannot find it. */\n _id?: string;\n /** Click-through / QR destination; empty string, not null, when it was never set — the PG read coalesces it the same way. */\n campaign_link?: string;\n /** When the advertisement row was written. It is the rotation order for a screen's self-promo pool: the placements read sorts `instant_ad_qr` first, then oldest `created_at` first. */\n createdAt?: string;\n /** Defaults to `name` at create, never null. Note the placements listing trims the embedded advertisement to `_id`, `name`, `video`, `photos`, `status` — this field is absent there. */\n description?: string;\n /** Required at create. It is also copied onto each placement as `advertisement_name`. */\n name?: string;\n /** Image creatives. A JSON create puts `image_url` here as the single element; the multipart route puts the uploaded file here when its MIME type is `image/*`. Empty array for a video-only promo. */\n photos?: Array<string>;\n /** Minted as `approved` — self-promo skips review entirely. The disable endpoint sets it to `deactivated`, and that is the ONLY thing that stops delivery: placements stay `booked` so the disable is idempotent, and every serve-path read has to gate on this field. The listings additionally hide `deleted` and `rejected`. */\n status?: string;\n /** URL of the video creative, or `null` for an image-only promo. This is the field the `trillboards_direct` VAST bridge serves from, which is why the advertisement row is written and awaited BEFORE any placement is created. */\n video?: string;\n /** Measured length of the `video` creative in whole seconds, probed when the ad is created. This is the real media length and is what the served VAST declares as `<Duration>`. `null` means the media could not be measured, in which case the VAST declares the 30 second ad-slot default instead. */\n video_duration_seconds?: number | null;\n};\n\nexport type PartnerSelfPromoCreate = {\n /** Click-through / QR destination. Stored as an empty string, not null, when omitted. */\n campaign_link?: string;\n /** Optional; defaults to `name` rather than staying null. */\n description?: string;\n /** Last day the promo may serve, in each screen's own timezone. Omitting it leaves the placement OPEN-ENDED (`preserveOpenEnd: true`) — it runs until you disable the ad — and leaves `end_time` null rather than 23:59. */\n end_date?: string;\n /** The image creative, stored as a single-element `photos` array. At least one of `image_url` or `video_url` is required (400 `Provide image_url or video_url`); sending both stores both. */\n image_url?: string;\n /** Required — the create is rejected 400 without it. It is also written onto every placement as `advertisement_name`, so it is what appears in delivery bookkeeping. */\n name: string;\n /** Which of YOUR screens the promo is placed on. Accepts a real array, a JSON-encoded array string, or a comma-separated string; the list is intersected with the partner's own non-deactivated screens so a foreign id is dropped silently, but if you send ids and NONE survive the create fails 404. Omitting it entirely creates the advertisement with no placements, so it serves nowhere until you call the schedule endpoint. */\n screen_ids?: Array<string>;\n /** First day the promo may serve, resolved PER SCREEN in that screen's own timezone. A window that is already open lands the placement `active` and fires an immediate `self_promo_active` push to the screen; a future one lands it `scheduled`. Serving times are fixed at 00:00-23:59 local and are not derived from this value. */\n start_date?: string;\n /** The video creative. Its length is PROBED at create time and returned as `video_duration_seconds`, which is what the served VAST declares as `<Duration>`; a spot longer than the 30-second slot also comes back as a non-fatal entry in the response `warnings` array. The probe never blocks the create — on failure the duration stays null and the VAST falls back to a flat 30s. */\n video_url?: string;\n};\n\nexport type PartnerSelfPromoPlacement = {\n /** One entry per `partner-self-promo` placement on that screen, each carrying `allocation_id`, `status`, `start_date`, `end_date` and a TRIMMED `advertisement` (`_id`, `name`, `video`, `photos`, `status` only — no `description`, `campaign_link` or `createdAt`). The underlying read filters out `deactivated`/`deleted`/`rejected` advertisements, so a disabled promo disappears from here even though its placement row still exists. */\n ads?: Array<{\n advertisement?: PartnerSelfPromoAd;\n allocation_id?: string;\n end_date?: string;\n start_date?: string;\n status?: string;\n }>;\n /** Trimmed to `_id` and `name` only. EVERY non-deactivated screen the partner owns appears in this listing, including ones with an empty `ads` array — the response is a full screen roster, not just the placed subset. */\n screen?: {\n _id?: string;\n name?: string;\n };\n};\n\nexport type PartnerStats = {\n /** Recomputed by the daily stats cron as the count of the partner's screens in status `approved`/`active` — an APPROVAL count, not a liveness count. The identically-named field on `GET /v1/partner/analytics` is instead derived live from `online_status`, so the two measure different things. */\n active_devices?: number;\n /** ISO timestamp stamped by the partner impression-record endpoints on each recorded impression. Only those endpoints write it, so it does not move for revenue booked through other rails. */\n last_impression_at?: string;\n /** Integer US cents already reserved by an in-flight payout request. Sourced from the typed `partners.pending_payout_cents` column (the JSONB key was dropped) and subtracted from the available balance so repeat payout requests cannot double-spend. */\n pending_payout_cents?: number;\n /** Read from the `partners.stats` JSONB cache, maintained by signed-delta counters on device register/delete. `GET /v1/partner/analytics` publishes the same field name from a LIVE device count instead, so the two can disagree. */\n total_devices?: number;\n /** Incremented per impression by the partner impression-record path, then OVERWRITTEN by the daily reconcile with `SUM(impressions_count)` over `programmatic_earnings_daily` — two different denominators writing one key, so its meaning depends on when in the cron cycle you read it. */\n total_impressions?: number;\n /** Integer US cents. Recomputed daily as `SUM(earner_revenue) * 100` across ALL of the partner's non-demo `programmatic_earnings_daily` rows, with no payable-source filter and no Net-60 maturity gate — so it can exceed `EarningsResponse.total_lifetime_cents`, which applies the payable filter. */\n total_revenue_cents?: number;\n};\n\n/**\n * One taxi-meter state change reported by the partner SDK's setTripState. (partner, device, trip_id, event_seq) is the event's identity.\n */\nexport type PartnerTripState = {\n /** The host's destination text or zone. */\n destination?: string;\n /** The event's position in the trip. Increases within a trip; a retry re-sends the same value (idempotency key with trip_id, per device). */\n event_seq: number;\n /** Fare so far, in the smallest currency unit. */\n fare_cents?: number;\n /** true while the meter runs (a hired trip). */\n meter_on: boolean;\n /** Riders the host counted. */\n passenger_count?: number;\n /** The host's payment type (stored trimmed and lowercased). */\n payment_type?: string;\n /** When the meter changed state (device clock), within the last 7 days and at most 5 minutes ahead of the server clock. */\n state_at: string;\n /** Tip, in the smallest currency unit. */\n tip_cents?: number;\n /** The host app's trip id. Unique per device, not per partner. */\n trip_id: string;\n};\n\n/**\n * Canonical INT-PK identity for partner variants (e.g. adipolo_lower_floor_tablet). Wave 2 of pristine-state refactor. variant_name TEXT remains as the wire-format alternate-key indefinitely.\n */\nexport type PartnerVariants = {\n archived: boolean;\n created_at: string;\n /** NUMERIC(10,2). */\n daily_budget_cap?: number | null;\n daily_impression_cap?: number | null;\n daily_request_cap?: number | null;\n /** Backfill is 1:N from demand_partner_config.variant_names[]. Rows with NULL demand_partner_id at apply time are silently skipped — deploy-controller previous-tick guard ensures Wave 2 A1 has populat... */\n demand_partner_id: number;\n /** vast_tag_variants JSONB on demand_partner_config still co-exists during transition. Backfill UPDATE pulls display_name from the JSONB if present (no-op today; forward-compatible). */\n display_name?: string | null;\n /** public_alias is the obfuscation alias for partner-API responses (matches partnerAlias.encodeAlias pattern: 'var_' || sha256(variant_name)[0..5]). */\n public_alias: string;\n request_pressure_base_interval_seconds?: number | null;\n /** NUMERIC(12,8). */\n request_pressure_completion_rate_floor?: number | null;\n /** NUMERIC(6,3). */\n request_pressure_confidence_level?: number | null;\n request_pressure_defer_seconds?: number | null;\n /** request_pressure_enabled=false fails open for pressure shaping only. It must not be treated as demand-source enablement. */\n request_pressure_enabled?: boolean | null;\n request_pressure_max_multiplier?: number | null;\n request_pressure_min_pair_requests?: number | null;\n request_pressure_min_source_requests?: number | null;\n request_pressure_probe_interval_seconds?: number | null;\n request_pressure_probe_modulo?: number | null;\n /** NUMERIC(10,4). */\n request_pressure_probe_target_per_minute?: number | null;\n updated_at: string;\n /** feeds_into lists tables that will gain a nullable variant_id INT FK in Wave 2 Stream B. Each is a separate PR — this PR mints the dimension only. */\n variant_id?: string | null;\n /** variant_name TEXT is the wire-format alternate-key (kept forever) — internal logs and partner integrations rely on it. Never propose dropping variant_name. */\n variant_name: string;\n};\n\n/**\n * Per-zone per-day CPM rates from partner APIs. Used for revenue estimation and settled partner-truth allocation when partner_reconciliation_reports does not provide a newer manual/API row. PG only.\n */\nexport type PartnerZoneCpmDaily = {\n created_at: string;\n /** Wave 2 B added demand_partner_id INT + variant_id INT FKs. Legacy partner_key TEXT kept as wire-format alternate-key. Backfill via follow-up Wave 2 B-backfill PR. */\n demand_partner_id?: number | null;\n /** NUMERIC(10,4). */\n ecpm: number;\n fetched_at: string;\n /** NUMERIC(6,4). */\n fill_rate?: number | null;\n /** NUMERIC(14,6). */\n gross_revenue?: number | null;\n id?: string | null;\n impressions?: number | null;\n partner_key: string;\n period_date: string;\n requests?: number | null;\n /** Daily earnings aggregation may use these rows to settle gross revenue, but completed_impressions remains the event-count source for programmatic_earnings_daily.impressions_count. */\n source: string;\n updated_at: string;\n variant_id?: number | null;\n zone_id: string;\n zone_label?: string | null;\n};\n\nexport type PayoutResponse = {\n /** Integer US cents actually reserved: `min(requested, available)`, where available is CONFIRMED earnings minus anything already pending. It must clear the partner's `payout_threshold_cents` (default 2500, i.e. $25.00) or the request is rejected `400`. */\n amount_cents?: number;\n /** Today plus 5 CALENDAR days, computed in the handler with no reference to banking days, the Stripe payout schedule, or whether any transfer exists. It is a display placeholder. */\n estimated_arrival?: string;\n /** Generated in the handler as `po_<epoch_ms>_<random>` and **not persisted anywhere** — no row, no Stripe object. It cannot be used to look the payout up afterwards. */\n payout_id?: string;\n /** Always the literal `processing` on a successful request — the other enum values are never returned by this endpoint. The only side effect is a bump to the partner's `pending_payout_cents` counter; no Stripe transfer is created here. */\n status?: \"pending\" | \"processing\" | \"completed\" | \"failed\";\n /** **Always `null`.** The handler returns a hardcoded null because it creates no transfer; a real transfer id appears only later on the corresponding `payout` row from `GET /earnings/transactions`. */\n stripe_transfer_id?: string | null;\n};\n\nexport type PlaygroundResult = {\n /** Whether the operation is safe for autonomous agents. */\n agent_safe: boolean;\n /** Billing tier: free, metered, or paid. */\n cost_tier: string;\n /** Whether the operation is idempotent. */\n idempotent: boolean;\n /** Object type identifier. */\n object: \"playground_result\";\n operation_id: string;\n /** Declared side effects of the operation. */\n side_effects: Array<string>;\n /** Whether the request body passed validation. */\n valid: boolean;\n /** The parsed/coerced body on success, null on failure. */\n validated_body?: unknown;\n /** Array of validation issues on failure, null on success. */\n validation_errors: Array<PlaygroundValidationError> | null;\n /** The HTTP method and path this operation maps to. */\n would_call: {\n method: string;\n path: string;\n };\n};\n\nexport type PlaygroundValidationError = {\n /** Zod issue code. */\n code: string;\n /** Human-readable validation message. */\n message: string;\n /** Dot-delimited path to the invalid field. */\n path: string;\n};\n\nexport type ProgrammaticSettingsInput = {\n /** Enable programmatic ads */\n enabled?: boolean;\n /** Minimum CPM in dollars */\n floor_price_cpm?: number;\n /** Accepted by this schema but silently discarded. The write path keeps only an explicit whitelist — `enabled`, `provider`, `vast_tag_url`, `timeout_ms`, `programmatic_allocation_percent`, `floor_price_cpm`, `currency`, `dynamic_floor_pricing`, `blocked_advertisers`, `blocked_iab_categories`, `preferred_deal_ids` — and `google_ima` is not in it. A body containing only this key persists nothing and still returns 200. */\n google_ima?: {\n ad_tag_url?: string;\n enabled?: boolean;\n max_duration?: number;\n };\n /** Accepted by this schema but silently discarded — not in the write whitelist, never persisted, and never read back (`header_bidding_settings.prebid` is JSON `null` on every row). A body containing only this key persists nothing and still returns 200. */\n prebid?: {\n bidders?: Array<{\n name?: string;\n params?: Record<string, unknown>;\n }>;\n enabled?: boolean;\n };\n /** Ad source priority */\n priority?: \"direct_first\" | \"programmatic_first\" | \"highest_bid\";\n};\n\nexport type ProgrammaticSettingsResponse = {\n /** The master serving gate `earner_screens.programmatic_enabled`, which is `NOT NULL DEFAULT true` — so it reads `true` for a screen nobody has ever configured — and NOT the legacy `header_bidding_settings.enabled` shadow. Setting it false stops programmatic serving for the screen; the write invalidates the serving caches, and a missed invalidation still drains within the 120s hot-cache TTL. */\n enabled?: boolean;\n /** Minimum clearing price in DOLLARS per thousand impressions (not cents), default `0.50`, accepted range 0.01-100, denominated in the screen's `currency`. It is a floor only: the auction clears at the `max()` of this, any floor rule, the dynamic floor and any matched deal floor, so a low value here does not guarantee cheap fill and can never lower a rule-derived floor. */\n floor_price_cpm?: number;\n /** Never emitted. The response formatter builds the entire body and has no `google_ima` key, and the string appears nowhere on this API's request or response surface — there is no producer. Configure the IMA tag through the screen's `vast_tag_url` / VAST waterfall instead. */\n google_ima?: {\n ad_tag_url?: string;\n enabled?: boolean;\n max_duration?: number;\n };\n /** Constant discriminator `programmatic_settings` (Stripe-style envelope). It is present on the GET, the PUT and the PATCH alike, so it identifies the resource type and tells you nothing about which verb produced the response. */\n object?: string;\n /** Never emitted. The response formatter has no `prebid` key, and the underlying `header_bidding_settings.prebid` is JSON `null` on every stored row with no typed home — nothing populates it on either side. */\n prebid?: {\n bidders?: Array<Record<string, unknown>>;\n enabled?: boolean;\n };\n /** Never emitted, and not settable. The response formatter has no `priority` key and the field is absent from the write whitelist, so `direct_first` / `programmatic_first` / `highest_bid` can neither be stored through this endpoint nor read back from it. */\n priority?: string;\n /** Server-minted per HTTP request in the form `req_<32 hex>`, and also returned in the `X-Request-Id` response header. A client-supplied `X-Request-Id` is echoed back separately as `X-Client-Request-Id` and never becomes this value. Unrelated to `HeaderBiddingSettings.request_id`, which identifies a VAST waterfall attempt. */\n request_id?: string;\n /** Echoed straight back from the path parameter — it is not re-read from the stored row. Must be a 24-character hex Mongo ObjectId; anything else is rejected before any lookup happens. */\n screen_id?: string;\n /** Never emitted — the response formatter has no `stats` key, so `impressions_today`, `fill_rate_percent` and `avg_cpm` have no producer here; use the partner analytics endpoints for delivery numbers. When you do, note that partner-rail impression counts are delivery accounting, not billing: only `completed_impressions` settles revenue. */\n stats?: {\n avg_cpm?: number;\n fill_rate_percent?: number;\n impressions_today?: number;\n };\n /** The SCREEN row's `updated_at`, so any change to the screen moves it — not just a programmatic-settings change. When the row carries no timestamp the server substitutes the current time, so this can never be relied on as 'when these settings last changed' or used as a change-detection cursor. */\n updated_at?: string;\n};\n\nexport type RequestMetadataResponse = {\n duration_ms: number;\n /** Present only when the original request resulted in an error. */\n error?: {\n code: string;\n type: string;\n };\n method: string;\n /** Object type identifier. */\n object: \"request\";\n path: string;\n request_id: string;\n status_code: number;\n timestamp: string;\n};\n\n/**\n * The EFFECTIVE content policy for a screen + its provenance. Whole-layer\n * coalescing: the effective policy comes from exactly ONE layer.\n *\n */\nexport type ResolvedContentPolicy = {\n /** All content_preferences keys + blocked_iab_categories. */\n effective?: Record<string, unknown>;\n /** Always `resolved_content_policy`. This resource is read-only introspection — a \"why is this screen serving what it serves\" preview — and unlike the content-preferences response it IS wrapped in `{ success, data }`. */\n object?: string;\n /** Which single layer supplied the whole `effective` object. `source` is `screen` when the screen's OWN policy is explicit — specifically `content_filtering_enabled === true`, or any of the six content lists non-empty, or a non-empty `programmatic_settings.blocked_iab_categories`; the `allow_*` toggles and the two scalars NEVER make it explicit because they always carry a default. Otherwise it is `group` (lowest `group_id` wins, and `group_id` is present only then), then `network` (the partner's `network_config.default_content_preferences`, used only when it has at least one populated key and merged onto the system baseline), then `default`. */\n provenance?: {\n /** Present only when source=group. */\n group_id?: string;\n source?: \"screen\" | \"group\" | \"network\" | \"default\";\n };\n /** The screen whose effective policy this is, echoed from the path parameter as a string. Ownership is checked first, so a screen you do not own returns 404 rather than an empty policy. */\n screen_id?: string;\n};\n\n/**\n * The EFFECTIVE sensing view for a screen + its provenance (screen\n * deployment ?? group sensing config ?? default).\n *\n */\nexport type ResolvedSensingConfig = {\n /** The profile scalars actually in force after resolution. When the winning layer is a group, the base profile is hydrated first and only the group's NON-null overrides are laid over it, so this is always a complete view rather than a sparse patch. */\n effective?: {\n capture_interval_ms?: number | null;\n estimated_fps_impact?: number | null;\n min_confidence?: number | null;\n profile_name?: string | null;\n report_interval_ms?: number | null;\n };\n /** Stripe-style type discriminator; always the literal `resolved_sensing_config`, so it is safe to switch on. */\n object?: string;\n /** Which layer won: `screen` (the screen's own active deployment), `group_default` (a group sensing config, with `group_id` naming it), or `default` (nothing bound). Resolution is whole-layer — `effective` never mixes values from two sources. */\n provenance?: {\n /** Present only when source=group_default. */\n group_id?: string;\n source?: \"screen\" | \"group_default\" | \"default\";\n };\n /** The screen's Mongo id — the same identifier the route surfaces call `screenMongoId`. Echoes the path parameter. */\n screen_id?: string;\n};\n\n/**\n * Permission flags for each role. Owners have all permissions,\n * admins have operational permissions, viewers have read-only access.\n *\n */\nexport type RolePermissions = {\n /** Can configure webhooks */\n configure_webhooks?: boolean;\n /** Can edit screen settings */\n edit_screens?: boolean;\n /** Can invite/remove team members */\n manage_team?: boolean;\n /** Can request payouts */\n request_payouts?: boolean;\n /** Can rotate API keys */\n rotate_api_keys?: boolean;\n /** Can view impression analytics */\n view_analytics?: boolean;\n /** Can view earnings/revenue */\n view_earnings?: boolean;\n /** Can view impression data */\n view_impressions?: boolean;\n /** Can view payout history */\n view_payouts?: boolean;\n /** Can view online/offline status */\n view_screen_status?: boolean;\n /** Can view screen list */\n view_screens?: boolean;\n};\n\nexport type SDKConfig = {\n /** Seconds between ads */\n ad_interval?: number;\n /** The only `sdk_config` key that changes what is SERVED: if it contains `image`, the server stops substituting a transcoded MP4 for an image creative on `lite_sdk`/`full_sdk` tiers, because you are declaring the client can render images itself. Frozen at the quick-start default `[\"video\", \"image\"]` — there is no partner-facing endpoint that writes `sdk_config`. */\n allowed_ad_types?: Array<string>;\n /** Maximum number of ads the `trillboards-connect` client retains for offline playback (`cacheAdsOffline`). Client-side hint only — the server never reads it — and it is frozen at the quick-start default of 10 because no partner-facing endpoint writes `sdk_config`. */\n cache_size?: number;\n /** Seconds to display image ads */\n image_duration?: number;\n /** Fleet-wide hourly ad cap echoed as `settings.max_ads_per_hour` in the `/ads` response, but only as the FALLBACK behind `network_config.ad_delivery.max_ads_per_hour` — that is the writable control, and this one is frozen at the quick-start default of 20 because no partner-facing endpoint writes `sdk_config`. */\n max_ads_per_hour?: number;\n /** Label the lite SDK paints on the tap-to-continue overlay; when absent the SDK falls back to the literal `TAP TO CONTINUE`, which is also the quick-start default stored for every partner. Frozen — there is no partner-facing endpoint that writes `sdk_config`. */\n overlay_button_text?: string;\n /** Has no reader anywhere in the server or the shipped SDKs — the `settings.sound_enabled` a player actually obeys is resolved per screen from `earner_screens.sound_enabled` / display preferences, not from this partner-level value. Frozen at the quick-start default `false`. */\n sound_enabled?: boolean;\n};\n\n/**\n * A partner screen — the client-facing projection of a registered\n * device+screen pair (`@trillboards/api-client` `Screen`). The screens\n * resource reads the partner device endpoints.\n *\n */\nexport type Screen = {\n /** City resolved at registration by reverse/forward geocoding or taken from your own `location.city`, with placeholder strings (\"City\", \"Vending Machine Location\") coalesced to null rather than stored. The screens resource reads the partner device endpoints, whose payload carries this as `location.city`. */\n city?: string;\n /** Country of the screen, taken from the enriched screen row with a fallback to the device row. The device row DEFAULTS this to `\"US\"` when registration could not resolve a country, so it is effectively never null and a `US` value can mean \"unresolved\". The screens resource reads the partner device endpoints, whose payload carries this as `location.country`. */\n country?: string;\n /** Creation time of the DEVICE row backing the screen, not of the screen record itself — the screens resource is a projection of the partner device endpoints, and the screen can be created later than its device. */\n created_at: string;\n /** The paired device identifier. */\n device_id?: string;\n /** Player embed URL for the screen. */\n embed_url?: string;\n /** Friendly screen/venue name. */\n name: string;\n /** Display resolution label (e.g. \"1920x1080\") when known. */\n resolution?: string;\n /** Stable screen identifier. */\n screen_id: string;\n /** Screen lifecycle status (e.g. pending, active, offline, suspended). */\n status: string;\n /** IANA zone, and it is ONLY ever what you supplied as `location.timezone` at registration — nothing derives it from the resolved coordinates, so a large share of screens carry null. The screens resource reads the partner device endpoints, whose payload carries this as `location.timezone`, and it is the one geo field read device-first rather than screen-first. */\n timezone?: string;\n /** `earner_screen_devices.updated_at` of the backing device, which the device-mirror write buffer stamps `NOW()` on every flush including heartbeats. It moves continuously on a live screen, so it cannot be used to detect a configuration change. */\n updated_at: string;\n /** Granular OpenOOH venue type of the screen's location. */\n venue_type?: string;\n};\n\nexport type ScreenAnalyticsResponse = {\n /** `total` is deduped, GIVT-passed `completed_impressions` over the period. `daily_average` divides by the number of days that RETURNED A ROW, not by the period length, so zero-impression days do not dilute it. `trend_percent` compares the second half of the returned rows against the first half and is `0` whenever the earlier half is zero. */\n impressions?: {\n daily_average?: number;\n total?: number;\n /** Percentage change compared to previous period */\n trend_percent?: number;\n };\n /** `days` is 7, 30 or 90; any other `?period=` value silently becomes 7. `start` is midnight (API-server local time) that many days back and `end` is the moment the request was served, so the window is not a whole number of days. */\n period?: {\n days?: number;\n end?: string;\n start?: string;\n };\n /** `location` is a `City, State` string or `null` when either part is missing. `online_status` comes from the live heartbeat mirror and is `online`/`offline`/`unknown`, where `unknown` means the screen has never heartbeated — it is not a synonym for offline. `status` is the separate approval state. */\n screen?: {\n id?: string;\n location?: string;\n name?: string;\n online_status?: string;\n status?: string;\n };\n /** One entry per day that had impressions — days with none are absent, not zero-filled, which is why `daily_average` and this array can disagree with the period length. **`avg_duration_ms` is always `0`**: it is a hardcoded literal in both the ClickHouse query and the Postgres fallback. */\n timeline?: Array<{\n avg_duration_ms?: number;\n date?: string;\n impressions?: number;\n }>;\n};\n\n/**\n * A reusable, named, partner-scoped set of screens that analytics,\n * moderation policy, sensing/model deployment, fleet commands, and\n * sensing routes can target. Members are always a subset of the\n * partner's own screens.\n *\n */\nexport type ScreenGroup = {\n created_at?: string;\n /** Free-text note. Returned as an explicit `null` rather than omitted when unset, and an empty string supplied at create is stored as `null`. A PATCH writes only the keys you actually send, so omitting it preserves the current value. */\n description?: string | null;\n /** Screen group id: the literal prefix `sg_` followed by a v4 UUID (`pgRepo/screenGroups.js` mints `sg_${crypto.randomUUID()}`). Treat it as an opaque string; do not parse the UUID half. */\n id?: string;\n /** Required, non-empty label. It is NOT unique and has no length constraint in the database, so two of your groups may share a name; `id` (`sg_<uuid>`) is the only stable handle. */\n name?: string;\n /** Constant string `screen_group` — the Stripe-style type discriminator. It is present on every group payload, including inside a webhook's `data`, so a single handler can switch on it. */\n object?: string;\n /** Distinct member screens (COUNT and member list share one junction — they cannot diverge). */\n screen_count?: number;\n /** Bumped by membership changes as well as metadata edits — `addMembers`, `removeMembers` and the soft delete all set `updated_at = NOW()` on the group row — so it is a change marker for the group INCLUDING its member set, not just its name and description. */\n updated_at?: string;\n};\n\n/**\n * The typed content/moderation policy a screen group carries (Phase 4 live\n * policy). `null` when the group has no policy of its own. Member screens\n * inherit it at read/serve time when they have no explicit own policy\n * (screen ?? group ?? partner network default ?? system default). Mirrors\n * the per-screen content_preferences keys 1:1; blocked_iab_categories is\n * first-class here (the auction bcat).\n *\n */\nexport type ScreenGroupContentPolicy = {\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_adult_content`. A `false` also adds `IAB25` plus `IAB25-2`..`IAB25-5` to the `bcat` and `sexually_suggestive`/`sexual_health`/`sensationalism` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_adult_content?: boolean;\n /** Rejects a direct ad only when set to `false` AND the ad's classification carries `contains_alcohol`. A `false` also adds `IAB8-5`/`IAB8-18` to the outgoing OpenRTB `bcat` and `alcohol` to the GAM `excl_cat`; when the key is unset that list-building step uses the platform default, which for alcohol is `true` (not blocked). */\n allow_alcohol?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_gambling`. A `false` also adds `IAB9-7` to the `bcat` and `gambling`/`online_gambling` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_gambling?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_political`. A `false` also adds `IAB11-4` to the `bcat` and `politics` to the GAM `excl_cat`; unset falls back to the platform default of `true` (allowed). */\n allow_political?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_profanity`. A `false` also adds `IAB25-2` to the `bcat` and `sensationalism` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_profanity?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_religious`. A `false` also adds `IAB23` to the `bcat` and `religion` to the GAM `excl_cat`; unset falls back to the platform default of `true` (allowed). */\n allow_religious?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_tobacco`. A `false` also adds `IAB25-6` to the `bcat` and `drugs_tobacco` to the GAM `excl_cat`; unset falls back to the platform default of `false`, so tobacco is blocked on the programmatic side even when you never configure it. */\n allow_tobacco?: boolean;\n /** Rejects a direct ad only when `false` AND the ad's classification carries `contains_violence`. A `false` also adds `IAB25-3`/`IAB25-4` to the `bcat` and `violence`/`military_conflict` to the GAM `excl_cat`; unset falls back to the platform default of `false`. */\n allow_violence?: boolean;\n /** Consulted only when non-empty, and matched against the ad's typed `iab_categories` with `categoriesMatch`, so IAB codes and human-readable names both work (categories are inferred from subjects/keywords when the ad carries none). Under `lenient` and `permissive` a non-match is allowed through anyway, which makes the list inert at those levels; it also adds +10 per match to the content match score. */\n allowed_categories?: Array<string>;\n /** A SOFT preference, not a filter: it never rejects anything. Matching keywords add +3 each to the content match score used for prioritisation, and the approval path explicitly skips this list. */\n allowed_keywords?: Array<string>;\n /** Matched by case-insensitive SUBSTRING containment against the ad's `moderation.analysis.subjects`, not equality. Consulted only when non-empty and inert under `lenient`/`permissive`, like `allowed_categories`; it also adds +5 per match to the content match score. */\n allowed_subjects?: Array<string>;\n /** When `true` and the ad's classification says `is_known_brand`, approval returns IMMEDIATELY — the `blocked_categories`, `blocked_subjects`, `blocked_keywords` and every `allowed_*` check below it never run. The `allow_*` toggles and the age-rating check sit above it and still apply. */\n auto_approve_known_brands?: boolean;\n /** Same matching as `allowed_categories` (IAB code or human-readable name, via `categoriesMatch`), but a single hit rejects the ad at every `preference_level`. The rejection reason reports the human-readable name rather than the code you stored. */\n blocked_categories?: Array<string>;\n /** The auction `bcat` sent on OpenRTB bid requests for member screens. It is NOT part of `content_preferences`: on an individual screen the same list lives on `programmatic_settings.blocked_iab_categories`, and a non-empty one there is one of the three conditions that makes the screen layer explicit and bypasses this group policy entirely. */\n blocked_iab_categories?: Array<string>;\n /** The keyword list that DOES block, unlike `allowed_keywords`. Case-insensitive substring containment against the ad's `moderation.analysis.keywords`, so a short entry matches inside longer words. */\n blocked_keywords?: Array<string>;\n /** Case-insensitive substring containment against the ad's `moderation.analysis.subjects` — `bar` therefore also blocks `barbecue`, so use whole distinctive words. A hit is a hard reject. */\n blocked_subjects?: Array<string>;\n /** When `false`, direct-ad moderation short-circuits and every ad is auto-approved for member screens. It does NOT disable brand safety on the programmatic side — the `allow_*` toggles are still translated into the OpenRTB `bcat` and GAM `excl_cat` regardless of this flag. */\n content_filtering_enabled?: boolean;\n /** The group this row belongs to. It is also the tiebreak: a screen that is a member of more than one policy-bearing group inherits from the LOWEST `group_id`, so a screen should be in at most one. */\n group_id?: string;\n /** Highest ad classification a member screen accepts. `G` is deliberately NOT the strictest setting — the matcher silently rewrites it to `PG-13` for backwards compatibility — and `preference_level` then adds its buffer on top, so `lenient` with `PG-13` actually admits `R`. */\n max_age_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\" | \"NC-17\";\n /** Always the literal `screen_group_content_policy`. The policy is returned as `data.content_policy`, and a group carrying no policy of its own returns a bare `null` there — so on that path there is no `object` to branch on at all. */\n object?: string;\n /** Selects a strictness profile, not a label. It sets the age-rating buffer (`strict`/`moderate` 0, `lenient` +1, `permissive` +2 notches above `max_age_rating`), whether an ad with no AI classification is auto-approved (`lenient`/`permissive` yes; `strict`/`moderate` reject and queue re-moderation), and how the `allowed_*` lists behave on a non-match — `strict` rejects, `moderate` lets common business categories through, `lenient`/`permissive` make them inert. */\n preference_level?: \"strict\" | \"moderate\" | \"lenient\" | \"permissive\";\n /** ISO-8601 timestamp of the last write to this policy row, or `null` when the row has none. Member screens read the resolved policy through a screen-keyed Redis cache that a policy, membership or group-delete write busts, so an edit here reaches serving immediately rather than after the 60-second TTL. */\n updated_at?: string;\n} | null;\n\n/**\n * Partial, non-clobbering — only the fields present are written. Same keys\n * the per-screen content-preferences PUT accepts, plus blocked_iab_categories.\n *\n */\nexport type ScreenGroupContentPolicyInput = {\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25` and `IAB25-2`..`IAB25-5` to the member screens' `bcat`; unset already blocks it via the platform default. */\n allow_adult_content?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` both rejects classified alcohol creatives on member screens and adds `IAB8-5`/`IAB8-18` to their outgoing `bcat`. */\n allow_alcohol?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB9-7` to the member screens' `bcat`; unset already blocks gambling programmatically via the platform default. */\n allow_gambling?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB11-4` to the member screens' `bcat`; the platform default here is `true`, so political ads run unless you set this. */\n allow_political?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25-2` to the member screens' `bcat`; unset already blocks it via the platform default. */\n allow_profanity?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB23` to the member screens' `bcat`; the platform default here is `true`, so religious ads run unless you set this. */\n allow_religious?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25-6` to the member screens' `bcat`; leaving it unset already blocks tobacco programmatically via the platform brand-safety default. */\n allow_tobacco?: boolean;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Writing `false` adds `IAB25-3`/`IAB25-4` to the member screens' `bcat`; unset already blocks it via the platform default. */\n allow_violence?: boolean;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and the allow/block pair is conflict-checked case-insensitively against this patch MERGED onto the stored row, so it can 400 with `conflicting_lists` on a term you set in an earlier request. */\n allowed_categories?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and it is conflict-checked against `blocked_keywords`, even though at serve time this list never rejects anything — it only contributes to the content match score. */\n allowed_keywords?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and the Subjects allow/block pair is conflict-checked against the stored row merged with this patch. Note these are matched by substring at serve time, not equality. */\n allowed_subjects?: Array<string>;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Setting it `true` makes a known-brand ad bypass every category, subject and keyword check on member screens, so treat it as a widening, not a convenience. */\n auto_approve_known_brands?: boolean;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and blocking a category an earlier PUT allowed fails with `conflicting_lists` even though this request names only one side of the pair. */\n blocked_categories?: Array<string>;\n /** Array of strings capped at 100 by a DIFFERENT constant from the other lists (`PROGRAMMATIC_SETTINGS_LIMITS.max_blocked_iab_categories`), reported as `blocked_iab_categories_too_large`. It is not conflict-checked, because there is no `allowed_iab_categories` counterpart. */\n blocked_iab_categories?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and unlike `allowed_keywords` this one really does reject, by case-insensitive substring match against the ad's analysed keywords. */\n blocked_keywords?: Array<string>;\n /** Array of strings, at most 100 items (`array_too_large`); a non-array is `field_must_be_array` and a non-string element is `array_items_must_be_strings`. Writing it REPLACES the stored list — there is no append — and it is a hard reject at serve time, matched by case-insensitive substring — so a short entry blocks more than you intend. */\n blocked_subjects?: Array<string>;\n /** Must be a real JSON boolean — the strings `\"true\"`/`\"false\"` are rejected with `field_must_be_boolean`, unlike the L-bar PUT which accepts them. Omitting the key leaves the stored value untouched; there is no way to reset a key back to \"inherit\". */\n content_filtering_enabled?: boolean;\n /** One of `G`, `PG`, `PG-13`, `R`, `NC-17`; anything else is `invalid_age_rating`. Writing `G` does not give you the strictest policy — the matcher later treats `G` as `PG-13`. */\n max_age_rating?: \"G\" | \"PG\" | \"PG-13\" | \"R\" | \"NC-17\";\n /** One of `strict`, `moderate`, `lenient`, `permissive`; anything else is rejected with `invalid_preference_level`. Validated against the same constant the per-screen content-preferences PUT uses, so the two surfaces cannot drift. */\n preference_level?: \"strict\" | \"moderate\" | \"lenient\" | \"permissive\";\n};\n\n/**\n * Webhook body for a Screen Group lifecycle event (`screen_group.created` | `updated` |\n * `deleted` | `member.added` | `member.removed` | `content_policy.updated` |\n * `sensing_config.updated`). Standard `{ id, event, timestamp, data }` envelope: `id` (`evt_…`)\n * is the idempotency key, and `data` is the Stripe-style `screen_group` /\n * `screen_group_content_policy` / `screen_group_sensing_config` object the REST API returns.\n * The event type is also in the `X-Trillboards-Event` header — verify the compound\n * `X-Trillboards-Signature` over the raw body first.\n *\n */\nexport type ScreenGroupEvent = {\n /** The screen_group / content-policy / sensing-config object. */\n data?: Record<string, unknown>;\n /** The event type, also sent in the `X-Trillboards-Event` header and mirrored to the SSE stream at `GET /v1/partner/events/stream`. This whole event family is gated by the `SCREEN_GROUP_EVENTS_ENABLED` runtime flag, which is OFF by default — when off, nothing is enqueued at all. */\n event?: \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\";\n /** `evt_<base36 epoch ms>_<12 hex>`, minted once per occurrence. Use it as the idempotency key: a retried delivery of the same occurrence reuses it, but the same id is also sent to EVERY endpoint you have subscribed to that event, so dedupe per (endpoint, id). It is not the server-side delivery audit id and cannot be looked up. */\n id?: string;\n /** Stamped when the server ENQUEUED the delivery, not when it was sent, so a retried delivery still carries the original value and can trail wall-clock by the retry backoff. It is not the resource's own `updated_at`. */\n timestamp?: string;\n};\n\n/**\n * A screen group's sensing profile binding (profile_name) + typed\n * performance overrides. `null` when the group has none. Member screens\n * inherit via the sensing resolver's group step when they have no\n * screen-specific deployment.\n *\n */\nexport type ScreenGroupSensingConfig = {\n /** Edge frame-capture cadence overrides pushed to member screens (SensingConfig.capture keys, milliseconds). Group wins over the profile default per-key when set. */\n capture?: {\n faceTriggeredIntervalMs?: number | null;\n minCaptureIntervalMs?: number | null;\n periodicIntervalMs?: number | null;\n vehicleTriggeredIntervalMs?: number | null;\n } | null;\n /** Group override of the profile's declared frame-capture cadence in milliseconds; `null` inherits the base profile's value. Treat it as advisory - this legacy scalar does not reach the device capture loop (the edge `FrameCaptureManager` reads the nested `capture` block), and observed cadence was measured at ~12x the declared value against a fleet floor of one analysis per 30 s. */\n capture_interval_ms?: number | null;\n /** When `false` the whole group step is a no-op and member screens fall straight through to the next layer of the resolver — the row is retained but contributes nothing, which is how you disable group sensing without losing the overrides. */\n enabled?: boolean;\n /** Advisory workload cost of the profile, normally derived server-side as the sum of the selected models' registry `fps_cost` (built-ins run 5.5-12.0). It is display metadata only — no device or pipeline code reads it, so overriding it throttles nothing. */\n estimated_fps_impact?: number | null;\n /** The `sg_`-prefixed Screen Group this config belongs to; echoes the `groupId` path parameter. */\n group_id?: string;\n /** Detection-confidence floor in 0..1, overlaid onto the resolved profile's `thresholds.min_confidence`; built-in profiles ship 0.35-0.45. `null` inherits the base profile's value. */\n min_confidence?: number | null;\n /** Stripe-style type discriminator; always the literal `screen_group_sensing_config`, so it is safe to switch on. */\n object?: string;\n /** The sensing profile members inherit, bound by NAME (a builtin or an existing custom profile) rather than by `profile_id`, because `setDeployment` clones a fresh `profile_id` per screen on every redeploy. `null` means the group binds no profile. */\n profile_name?: string | null;\n /** Group override of how often the device batches observations back to the server, in milliseconds; `null` inherits the base profile's value. Built-in profiles ship 15000-30000. */\n report_interval_ms?: number | null;\n /** When this group's sensing config row was last written. The write also busts the resolver caches for the members as they stood at that instant and emits a `screen_group.sensing_config.updated` webhook, so a screen added to the group afterwards picks the config up on its own next cache miss instead. */\n updated_at?: string;\n /** Per-screen cloud-vision budget for member screens. screen_hourly_pace wins when both are set; otherwise derived from screen_daily_calls. null = no group budget (fleet keeps platform-default caps). */\n vision_budget?: {\n screen_daily_calls?: number | null;\n screen_hourly_pace?: number | null;\n } | null;\n} | null;\n\n/**\n * Partial, non-clobbering. A null override means \"inherit that field from\n * the base profile\". profile_name must resolve to a builtin or an existing\n * custom profile (else 400).\n *\n */\nexport type ScreenGroupSensingConfigInput = {\n /** Edge frame-capture cadence block (milliseconds); null clears it. Unknown keys are rejected (400). */\n capture?: {\n faceTriggeredIntervalMs?: number | null;\n minCaptureIntervalMs?: number | null;\n periodicIntervalMs?: number | null;\n vehicleTriggeredIntervalMs?: number | null;\n } | null;\n /** Frame-capture cadence override in milliseconds (100..3600000); `null` means inherit from the base profile. Advisory in practice: this legacy scalar does not reach the device capture loop (the edge reads the nested `capture` block), the fleet floors at one analysis per 30 s, and observed cadence was measured at ~12x the declared value. */\n capture_interval_ms?: number | null;\n /** Set `false` to make the group step a no-op — members fall through to the next resolver layer while the overrides stay stored, so this is the reversible way to switch group sensing off. */\n enabled?: boolean;\n /** Advisory workload-cost number (must be >= 0); `null` inherits the profile's own value, which the server derives from the selected models' registry `fps_cost`. Purely descriptive — setting it changes what readback and operator surfaces display and throttles nothing. */\n estimated_fps_impact?: number | null;\n /** Detection-confidence floor in 0..1 written into the resolved profile's `thresholds.min_confidence`; `null` inherits the base profile's value (built-ins are 0.35-0.45). */\n min_confidence?: number | null;\n /** Bind the group to a builtin or existing custom profile BY NAME; a name that resolves to neither is a 400. `null` clears the binding. Never a `profile_id` — that is re-minted per screen on each redeploy. */\n profile_name?: string | null;\n /** Observation-reporting cadence override in milliseconds (100..3600000); `null` means inherit from the base profile. */\n report_interval_ms?: number | null;\n /** Per-screen cloud-vision budget block; null clears it. Unknown keys are rejected (400). */\n vision_budget?: {\n screen_daily_calls?: number | null;\n screen_hourly_pace?: number | null;\n } | null;\n};\n\n/**\n * High-level sensing workload intent. Hardware tier and device telemetry are read-only server facts.\n */\nexport type SensingPerformanceMode = \"auto\" | \"presence_only\" | \"demographics\" | \"advanced\";\n\n/**\n * A Sense Anything Route — a (condition → channel actions) alert/automation rule.\n */\nexport type SensingRoute = {\n /** Every channel action fired when the route matches; 1 to 10 per route, each with its own `enabled` flag so one can be muted without deleting the route. `webhook` is the only channel with no external side effect — `whatsapp`, `sms`, `email` and `slack` deliver a real message to a real person, so point a test route at `webhook`. */\n actions?: Array<SensingRouteAction>;\n /** One bit per weekday (127 = always). */\n activeDaysMask?: number;\n /** Inclusive end of the daily active window, in minutes past local midnight in `activeTz` (0..1439). When it is LESS than `activeStartMinute` the window is read as overnight — 1200 to 360 means 20:00 through 06:00 — rather than as an empty range. */\n activeEndMinute?: number | null;\n /** Inclusive start of the daily active window, in minutes past local midnight in `activeTz` (0..1439; 1200 = 20:00). Ignored unless `activeTz` is set, and a `null` on either end makes the window whole-day. */\n activeStartMinute?: number | null;\n /** IANA zone name (e.g. `America/New_York`) the active window is evaluated in, trimmed to 64 characters. `null` disables the ENTIRE active-window check — `activeStartMinute`, `activeEndMinute` and `activeDaysMask` do nothing without it — and a zone the runtime cannot parse fails OPEN (always active) rather than silently dropping alerts. */\n activeTz?: string | null;\n /** `null` on a `count`-metric digest route (there is nothing to aggregate over). On an `avg`/`max` digest it carries only `field`, with `op` and `value` absent — only a `threshold`-mode route has a complete condition. */\n condition?: SensingRouteCondition | null;\n createdAt?: string;\n /** Minimum gap in seconds between alerts for the same (route, screen) episode; clamped to 0..86400 and defaulting to 300. It also caps the falling-edge clear window (60 s maximum), so a shorter debounce re-arms the route sooner as well as spacing alerts more tightly. */\n debounceSeconds?: number;\n /** Scheduled-aggregate configuration; `null` on `threshold` routes. `nextRunAt` is a server-held cursor the digest cron advances after every send, so it moves on its own without any edit from you. */\n digest?: {\n intervalMinutes?: number;\n metric?: \"count\" | \"avg\" | \"max\";\n nextRunAt?: string;\n windowMinutes?: number;\n } | null;\n /** Whether the evaluator considers this route at all. A disabled route keeps its condition, actions and screen set and is simply skipped by every hot-path read; deleting a route also sets this `false` (rows are soft-deleted, never removed). */\n enabled?: boolean;\n /** `threshold` evaluates `condition` against each incoming observation. `digest` ignores the condition and instead sends a scheduled aggregate driven by the `digest.nextRunAt` cursor; focus regions and explicit review timing are rejected on digest routes. */\n mode?: \"threshold\" | \"digest\";\n /** Operator-supplied label, trimmed and capped at 200 characters. It is delivered verbatim as `route_name` on every fire but is not the alert text — the human-readable message is composed separately from the screen's sensing intent. */\n name?: string;\n /** The owning principal's id, compared against your credential on every read and write — a mismatch answers 404 (existence-hidden), never 403. Equal to your partner id for routes created here. */\n ownerId?: string;\n /** Which principal created the route: `partner` for anything created through this API, `earner_user` for a route the screen's own operator created in the earner portal. The Partner API only ever lists or edits `partner` routes, but an `earner_user` route on your screen still delivers webhooks to you. */\n ownerKind?: string;\n /** The partner the route was created under. Equal to `ownerId` for partner-created routes and `null` for a route an earner created in the portal, so it is not a reliable join key for the screen's partner. */\n partnerId?: string;\n /** Binds the route to a sensing profile BY NAME, never by `profile_id` — redeploying a profile mints a fresh `profile_id` per screen, which would orphan the binding. `null` means unbound; when set, the route stays dormant on any screen whose active profile has a different name. */\n profileName?: string | null;\n reviewTimingMode?: SensingRouteReviewTimingMode;\n reviewWaitSeconds?: SensingRouteReviewWaitSeconds;\n /** Server-minted immutable id: the literal prefix `rt_` followed by a UUID. Webhook consumers should key on this rather than `route_name`, which the owner can rename at any time. */\n routeId?: string;\n /** Per-camera areas, at most one entry per screen. The legacy cloud path converts geometry into prompt text and is not geometrically enforced (measured 2026-08-25 on gemini-3.1-flash-lite). The retained local connector masks actual pixels separately for each declared scope; original unmasked JPEGs remain alert evidence. Retained installation and model accuracy require separate qualification. */\n screenFocusRegions?: Array<SensingRouteScreenFocusRegion>;\n /** The screens this route watches — deduped and capped at 250. For a group-targeted route these are the group's LIVE members resolved at read time, not a stored set, so the list can change between two GETs without any edit. */\n screenMongoIds?: Array<string>;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainMinSamples?: number;\n /** How long the condition must hold before the FIRST alert, in seconds (600 = ten minutes). Omit to alert on the first true reading. Cadence-independent, because the evaluator compares timestamps - correct however often the screen reports, including when that rate changes while the condition holds. */\n sustainSeconds?: number | null;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainWindowSeconds?: number;\n /** The sg_ Screen Group this route targets. When set, the route fires on the group's LIVE members (screenMongoIds reflects the resolved members at read time) and no explicit screens are stored. */\n targetGroupId?: string | null;\n /** Last write to the route row — NOT a configuration-change stamp. The digest cron bumps it every time it advances a digest route's next-run cursor, and a soft delete bumps it too, so it moves on rows nobody edited. */\n updatedAt?: string;\n};\n\n/**\n * One channel action fired when the route matches.\n */\nexport type SensingRouteAction = {\n /** Attach the evidence frame/clip (people-facing channels). */\n attachClip?: boolean;\n /** Selects a strict per-channel shape: `webhook` requires `webhookId`, `whatsapp`/`sms` require `recipientE164`, `email` requires `recipientEmail`, `slack` requires `slackChannelId`, and `clip` needs no destination. Any other destination field on the action is rejected, and `webhook` is the only channel that does not deliver to a person — use it for test routes. */\n channel: \"webhook\" | \"whatsapp\" | \"sms\" | \"slack\" | \"email\" | \"clip\";\n /** E.164 phone number (channel=whatsapp|sms). */\n recipientE164?: string;\n /** Recipient email (channel=email). */\n recipientEmail?: string | null;\n /** Slack channel id (channel=slack). */\n slackChannelId?: string | null;\n /** Message template name (managed WhatsApp/SMS). */\n templateName?: string;\n /** Target webhook endpoint id (channel=webhook). */\n webhookId?: string | null;\n};\n\n/**\n * A threshold condition — the route fires when the sensed field crosses the value.\n */\nexport type SensingRouteCondition = {\n /** The sensed field key (snake_case) to evaluate. */\n field: string;\n /** How the observed value is compared with `value`. `gt`/`gte`/`lt`/`lte` match ONLY when both sides parse as finite numbers; `eq`/`neq` fall back to strict equality for booleans and non-numeric strings. A missing or null observation never matches — including `neq`, which does not fire on absence. */\n op: \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"eq\" | \"neq\";\n /** The threshold value (numeric, string, or boolean depending on the field). */\n value?: number | string | boolean;\n};\n\n/**\n * Threshold-alert timing. NULL preserves legacy behavior; immediate adds no check delay; wait_recheck requires distinct first/follow-up positive images at least reviewWaitSeconds apart on capture time, not uninterrupted activity or message grouping.\n */\nexport type SensingRouteReviewTimingMode = \"immediate\" | \"wait_recheck\" | null | null;\n\n/**\n * Whole seconds before a fresh follow-up check. Required only for wait_recheck; must be NULL for immediate or unspecified timing. These two settings must be updated together.\n */\nexport type SensingRouteReviewWaitSeconds = number | null;\n\n/**\n * A normalized camera area used only by this alert. The rectangle is the compatibility bounding box; optional ordered points define the exact lasso perimeter. Omitted cameras use the whole view.\n */\nexport type SensingRouteScreenFocusRegion = {\n /** Rectangle height as a fraction of frame height, at least 0.05. When `points` is supplied this is DERIVED from the lasso's bounding box. Note the region is only ever sent to the model as prompt text and is not geometrically enforced — measured 2026-08-25, both shapes leaked 100% at every anchor, so a focused alert reacts to the whole frame. */\n height: number;\n /** Ordered non-self-intersecting lasso vertices, normalized to a 0.01 coordinate grid so the saved perimeter is represented exactly in model instructions. The perimeter closes from the last point to the first. */\n points?: Array<{\n x: number;\n y: number;\n }>;\n /** Which of the route's cameras this area applies to. It must appear in the route's explicit `screenMongoIds` and may appear at most once across the array, or the write is a 400; cameras with no entry are watched whole-view. */\n screenMongoId: string;\n /** Rectangle width as a fraction of frame width, at least 0.05. When `points` is supplied this is DERIVED from the lasso's bounding box rather than read from the request, so older readers keep a safe approximation of the polygon. */\n width: number;\n /** Left edge of the bounding rectangle as a fraction of frame width, origin top-left. Stored rounded to 4 decimal places, and capped at 0.95 because `width` has a 0.05 minimum and `x + width` may not exceed 1. */\n x: number;\n /** Top edge of the bounding rectangle as a fraction of frame height, origin top-left. Stored rounded to 4 decimal places, and capped at 0.95 because `height` has a 0.05 minimum and `y + height` may not exceed 1. */\n y: number;\n};\n\nexport type SensingSettingsResponse = {\n /** Summary of the profile row currently deployed and active on this screen (id, name, cadences and derived capabilities). `null` when the screen has never had a profile deployed, in which case the response's mode fields describe the default rather than anything running. */\n active_profile?: {\n capabilities?: Array<string>;\n capture_interval_ms?: number | null;\n profile_id?: string | null;\n profile_name?: string | null;\n report_interval_ms?: number | null;\n } | null;\n desired_mode?: SensingPerformanceMode;\n /** Read-only latest device telemetry used for safety checks. */\n device_capability?: {\n agent_version?: string | null;\n gpu_delegate_supported?: boolean | null;\n gpu_name?: string | null;\n model_tier?: string | null;\n recent_failure_count?: number;\n soc_name?: string | null;\n soc_vendor?: string | null;\n telemetry_fresh?: boolean;\n };\n effective_mode?: SensingPerformanceMode;\n /** Despite the name this is not an apply OUTCOME and carries no device acknowledgement: it is `null` when the screen has no active profile and otherwise always `{ status: \"active_profile_loaded\", profile_id, updated_at }` describing the profile row that is loaded now. */\n last_apply_status?: Record<string, unknown> | null;\n /** The full selectable set with human labels (`auto` = \"Auto recommended\", `presence_only` = \"Viewer count only\", and so on). It is a static list, NOT filtered by this screen's hardware — a mode listed here can still be refused; read `safety.blocks` before offering it. */\n modes?: Array<{\n label?: string;\n value?: SensingPerformanceMode;\n }>;\n /** Hardware pre-flight for `effective_mode`. `allowed` is simply `blocks.length === 0`; `warnings` never block (stale telemetry, recent device failures), while a `block` — missing fresh telemetry for a load-increasing mode, or FLOOR-tier/CPU-only hardware for `advanced` — makes a PUT of that mode answer 409 with this object under `error.details.safety`. */\n safety?: {\n allowed?: boolean;\n blocks?: Array<{\n code?: string;\n message?: string;\n }>;\n warnings?: Array<{\n code?: string;\n message?: string;\n }>;\n };\n /** The screen's Mongo id — the same identifier the route surfaces call `screenMongoId`. Echoes the path parameter. */\n screen_id?: string;\n};\n\n/**\n * Webhook request BODY delivered when a Sense Anything Route fires. Unlike the\n * device/programmatic events, a Route fire delivers a FLAT, self-describing\n * payload (no `{event,timestamp,data}` wrapper) — the event type is in the\n * `X-Trillboards-Event` request header (`sensing.threshold_crossed` for a custom\n * sensed field, or the matching `audience.*` / `venue.*` event for a known\n * semantic; a scheduled-digest Route delivers `venue.traffic_summary`). All Route\n * events share this same body shape. Verify the `X-Trillboards-Signature` header\n * over the raw body before trusting it.\n *\n */\nexport type SensingThresholdCrossedEvent = {\n /** The sensed field key evaluated (null for count-only digests). */\n field?: string | null;\n /** Server clock when the evaluator fired — not when the camera saw it. On the cloud path it was measured 8.2 s median and 15.3 s p95 behind the frame's shutter, so use the payload's `captured_at` (the device's own shutter instant) whenever the fire carried a frame. */\n fired_at?: string;\n /** The observed value that crossed the threshold. */\n observed?: unknown;\n /** The comparison the evaluator applied. `null` for a scheduled digest, which aggregates rather than comparing. Numeric operators only ever match when both the observed value and the threshold parse as finite numbers. */\n op?: \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"eq\" | \"neq\" | null;\n /** Who owns the route that fired. Webhooks are dispatched to the SCREEN's partner regardless of who created the route, so a partner endpoint legitimately receives `earner_user` fires for routes the screen's own operator configured and which are not visible through the Partner API. */\n owner_kind?: \"earner_user\" | \"partner\";\n /** The Route that fired. */\n route_id?: string;\n /** The route's operator-supplied label at the time of the fire. It is mutable and not unique — match on `route_id` for idempotency and routing. */\n route_name?: string;\n /** The screen (mongo id) whose observation crossed the threshold. */\n screen_id?: string;\n /** The configured threshold value (number, string, or boolean). May be null. */\n threshold?: unknown;\n};\n\nexport type SsdpDeviceInfo = {\n /** The `<friendlyName>` element from the fetched description XML. If it looks like a personal name (possessive apostrophe-s, an email, a MAC) the ENTIRE row is discarded rather than the field being blanked, so consumer devices named after their owner never appear at all. */\n friendlyName?: string | null;\n /** The `LOCATION:` header from the M-SEARCH response — the URL of the device description XML, and the de-duplication key for the whole list (one row per distinct LOCATION, last response wins). A response without it produces no row at all. */\n location: string;\n /** The `<manufacturer>` element from the description XML. `null` whenever the description fetch was skipped, timed out or failed — which is common, since fetching is bounded to half the listen window with a 1.5 s per-host timeout — so absence says nothing about the device. */\n manufacturer?: string | null;\n /** The `<modelName>` element from the description XML, field-stripped (not row-dropped) if it contains an email or a MAC. Absent on every row whose description fetch did not complete. */\n modelName?: string | null;\n /** The raw `SERVER:` response header, an RFC 2616 product token such as `Linux UPnP/1.0 Sonos/72.6-31040`. It comes from the M-SEARCH response itself, so unlike the XML-derived fields below it is present even when the description fetch fails — and it is deliberately neither PII-filtered nor hashed server-side, being treated as a low-cardinality vendor hint. */\n server?: string | null;\n /** The `ST:` search-target header of the response, e.g. `urn:schemas-upnp-org:device:ZonePlayer:1`. The probe searches with `ST: ssdp:all`, so this reflects what the device chose to answer as, not what we asked for. It arrives with the M-SEARCH response, so it survives a failed description fetch; an empty string means the responder omitted the header. */\n st: string;\n /** The `<UDN>` element — the device's self-declared Unique Device Name, typically a `uuid:` URN and the most stable per-device key SSDP offers. It is hashed server-side, and it is absent whenever the description fetch did not complete. */\n udn?: string | null;\n [key: string]: unknown;\n};\n\nexport type TeamInviteResponse = {\n /** The invited address, lower-cased and trimmed. Once the invitation is accepted the listing reports the accepting user account's email instead, which may differ from this one. */\n email?: string;\n /** When the invitation expires (7 days from creation) */\n expires_at?: string;\n /** A freshly minted 24-character hex ObjectId held as the membership's legacy id — NOT the `memberships` UUID primary key. It is the value the team routes take as the member path parameter. */\n membership_id?: string;\n /** Only `admin` and `viewer` can be invited — `owner` is the membership created with the partner account and cannot be granted through this endpoint. */\n role?: \"admin\" | \"viewer\";\n /** `active` when the invited email already had a Trillboards account: the membership is auto-accepted at invite time, `accepted_at` is set immediately, no token is issued and `expires_at` is `null`. `pending` otherwise, with a 7-day invite token. Either way the team is capped at 50 active-or-pending members. */\n status?: \"pending\" | \"active\";\n};\n\nexport type TeamMember = {\n /** `null` while `status` is `pending`. Set at INVITE time rather than click time when the invitee already had a Trillboards account and the membership was auto-activated. */\n accepted_at?: string | null;\n /** The linked user account's email once the invitation is accepted; the address the invitation was SENT to while `status` is `pending`. The two differ if the invitee accepts with a different account. */\n email?: string;\n /** When the invitation row was created. Re-inviting the same address rotates the token and moves this timestamp forward. */\n invited_at?: string;\n /** Name and email of the inviting user, resolved by join. `null` for the owner membership created with the partner account, and for any invitation whose inviter row no longer resolves. */\n invited_by?: {\n email?: string;\n name?: string;\n } | null;\n /** **Always `null`.** The column has no counterpart in `memberships` after the tenant-membership cutover, so the canonical reader projects a literal `NULL::timestamptz` and nothing writes it. */\n last_portal_access?: string | null;\n /** Unique membership record ID */\n membership_id?: string;\n /** The linked user account's display name. Undefined — and so omitted from the JSON — while `status` is `pending`, because no user row is attached until the invitation is accepted. */\n name?: string;\n permissions?: RolePermissions;\n /** Profile photo URL from the linked user account, and null/absent while the invitation is pending for the same reason as `name`. */\n photo?: string | null;\n /** `owner` is the membership created with the partner account and can never be invited or granted — only `admin` and `viewer` are grantable. Role alone determines `permissions`. */\n role?: \"owner\" | \"admin\" | \"viewer\";\n /** The listing returns `active` + `pending` only; `revoked` rows appear only when `?status=revoked` is passed explicitly. An invitation to an email that already has a Trillboards account is auto-accepted and lands `active` immediately. */\n status?: \"active\" | \"pending\" | \"revoked\";\n /** User ID (null if pending invitation) */\n user_id?: string;\n};\n\nexport type Transaction = {\n /** Integer US cents. Earnings rows are allocated cumulatively so the list sums EXACTLY to the lifetime total — an individual row can therefore differ by one cent from rounding that day's dollars on its own. */\n amount_cents?: number;\n /** For a `payout`, the real creation timestamp. For an `earning` it is `new Date(period_date)` — midnight UTC of the accounting day, a value derived from the date key rather than the time anything happened. */\n created_at?: string;\n /** For an `earning` row, the `YYYY-MM-DD` accounting period the aggregate covers. For a `payout` row it is the payout record's creation timestamp, so it carries a time component despite the declared `date` format. */\n date?: string;\n earning_source_version?: 1;\n earning_sources?: EarningsSources;\n /** Synthetic and namespaced by origin, never a ledger primary key: earnings rows are `daily_<YYYY-MM-DD>` (one per accounting day, not per impression); payouts are `admin_batch:<ledger_id>`, `earner_withdrawal:<withdrawal_id>` or `legacy_transfer:<id>`. */\n id?: string;\n /** Number of impressions (for earning transactions) */\n impressions?: number;\n /** Source of the transaction (e.g., impressions, payout) */\n source?: string;\n /** Stripe transfer ID (for payout transactions) */\n stripe_transfer_id?: string;\n /** `earning` rows are daily revenue aggregates from `programmatic_earnings_daily`; `payout` rows are money leaving, unioned from three sources and deduplicated by provider transfer id. `?type=all` (the default) merges both and sorts newest-first. */\n type?: \"earning\" | \"payout\";\n};\n\n/**\n * The canonical Trillboards error envelope. Emitted by `middleware/globalErrorHandler.js` for every error that reaches it: `utils/apiErrors.ts` `toJSON()` builds the inner object and the handler wraps it in `{ error }` and stamps `request_id`.\n */\nexport type TrillboardsError = {\n error: {\n /** Stable machine-readable error code. Switch on this, never on `message`. The 143 CATALOGUED codes are published as the `ErrorCode` schema and served live by `GET /v1/errors`, which is the authority. This field is NOT limited to them: services emit further codes directly, and `ApiError.notFound(resource)` mints `<resource>_not_found` from an arbitrary resource name. Always handle an unrecognised code by falling back to `type`. */\n code: string;\n /** Per-field violations (populated from Zod errors). */\n details?: Array<{\n code?: string;\n message?: string;\n param?: string;\n }>;\n /** Documentation for this code — https://api.trillboards.com/docs/errors#<code>. */\n doc_url?: string;\n /** Agent-facing hints and suggestions. */\n help?: {\n portal_url?: string;\n suggestions?: Array<string>;\n summary?: string;\n try_next?: string;\n };\n /** Human-readable error message. Safe to surface to end-users. */\n message: string;\n /** Offending parameter name, or null when the error is not field-scoped. */\n param?: string | null;\n /** Echoed X-Request-Id. Quote this to support for log correlation. */\n request_id: string;\n type: ErrorType;\n };\n};\n\n/**\n * Partial, non-clobbering update — include only the fields to change. Update reviewTimingMode and reviewWaitSeconds together; omit both to preserve existing timing. Explicit timing cannot be added to a digest, and changing to a digest clears the prior event check timing.\n */\nexport type UpdatePartnerSensingRouteRequest = {\n /** REPLACES the entire action list (1..10 entries); the existing rows are deleted and reinserted. Omit the key to leave actions untouched — there is no way to add or remove a single action. */\n actions?: Array<SensingRouteAction>;\n /** Seven-bit weekday mask evaluated in `activeTz`: bit 0 is Monday through bit 6 is Sunday, so 127 is every day and 0 never fires. Requires `activeTz`, like the rest of the active window. */\n activeDaysMask?: number;\n /** Inclusive end of the daily active window, minutes past local midnight in `activeTz` (0..1439). A value below `activeStartMinute` is read as an overnight window, not an empty one. */\n activeEndMinute?: number;\n /** Inclusive start of the daily active window, minutes past local midnight in `activeTz` (0..1439). Requires `activeTz` to have any effect. */\n activeStartMinute?: number;\n /** IANA zone name the active window is evaluated in. Setting the minute/day fields without this leaves the window inert, and an unparseable zone fails open (always active) rather than suppressing alerts. */\n activeTz?: string;\n condition?: SensingRouteCondition;\n /** Minimum gap in seconds between alerts for the same (route, screen) episode, clamped to 0..86400. `0` means fire on every rising edge with no spacing at all. */\n debounceSeconds?: number;\n /** Replaces the digest block and, as a side effect, rewrites `condition` to `{ field }` or `null`. `field` is required for `avg` and `max`; `intervalMinutes` must be at least 5 because the digest cron only runs every 5 minutes. */\n digest?: {\n field?: string;\n intervalMinutes?: number;\n metric?: \"count\" | \"avg\" | \"max\";\n windowMinutes?: number;\n };\n /** Only the JSON literal `true` enables the route here — every other value, including the string `\"true\"` and `1`, is written as `false`. This is the mirror image of create, where only the literal `false` disables, so send a real boolean. */\n enabled?: boolean;\n /** Replaces the label. Must be a non-empty string after trimming and at most 200 characters; sending an empty or whitespace-only name is a 400 rather than a clear. */\n name?: string;\n /** Rebinds the route to a different named sensing profile; send `null` (or an empty/whitespace string) to unbind it. Always a profile NAME — a `profile_id` is re-minted on every redeploy and would orphan the binding. */\n profileName?: string | null;\n reviewTimingMode?: SensingRouteReviewTimingMode;\n reviewWaitSeconds?: SensingRouteReviewWaitSeconds;\n /** Replace all selected rectangles or polygon lassos for the route; send [] to return every camera to whole view. Entries must target the route's explicit screenMongoIds. */\n screenFocusRegions?: Array<SensingRouteScreenFocusRegion>;\n /** REPLACES the watched screen set (1..250, deduped); mutually exclusive with `targetGroupId` in one request. Focus regions for cameras that survive the swap are PRESERVED unless you also send `screenFocusRegions` (including `[]` to clear them). */\n screenMongoIds?: Array<string>;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainMinSamples?: number;\n /** How long the condition must hold before the FIRST alert, in seconds (600 = ten minutes). Omit to alert on the first true reading. Cadence-independent, because the evaluator compares timestamps - correct however often the screen reports, including when that rate changes while the condition holds. */\n sustainSeconds?: number;\n /** DEPRECATED and rejected on write with 400. A duration expressed as N readings inside a fixed window can only be satisfied by a screen reporting faster than window/(N-1) seconds, and nothing knows that rate when the route is saved - so the route saves cleanly and then never fires at all. Send sustainSeconds instead. Still honoured for rows that already carry it. */\n sustainWindowSeconds?: number;\n /** Set to a sg_ group id to (re)target the group's live members, or null to switch back to an explicit screenMongoIds set. Mutually exclusive with screenMongoIds in one request. */\n targetGroupId?: string | null;\n};\n\n/**\n * The resolved programmatic VAST waterfall. `sources` is an ORDERED ARRAY and clients MUST iterate ALL of it — by `priority` ascending, skipping `enabled: false` — advancing to the next source on no-fill, empty VAST, timeout, IMA load error AND playback error (VAST 303 / 300 / 301 / 1009 all mean \"try the next source\", never \"stop\"). Reading `sources[0]` and stopping is the most common integration defect and reads as \"no demand\" when demand exists further down. Apply each source's own `timeout_ms`, and cap the whole loop at `total_timeout_ms`. Always handle player error and never leave the screen black; always fire the VAST `<Error>` beacon with `[ERRORCODE]` substituted. Full contract: docs/integrations/partner-native-ima-sdk.md §0 and §4.1. SQL/Admin-enabled sources remain visible; request-pressure decisions are enforced, when enabled, at first-party upstream fetch seams rather than by removing sources from this catalog.\n *\n */\nexport type VastWaterfall = {\n /** Derived, not configured: it is simply `sources.length > 0`. `false` means no demand source resolved for this screen on this request, so fall back to your own content. It is not a partner-settable toggle and it does not mean programmatic serving is switched off for the screen. */\n enabled?: boolean;\n /** Every source must be attempted, by `priority` ascending, until one actually plays. Not a preference list. */\n sources?: Array<VastWaterfallSource>;\n /** Budget in ms for the ENTIRE waterfall loop, across all sources. When it is spent, stop trying sources and return to your own content. */\n total_timeout_ms?: number;\n} | null;\n\n/**\n * One demand source in the VAST waterfall. Fetch `vast_url` (already a Trillboards vast-wrap URL — use as-is) and pass the response to your IMA SDK. A failure here means \"advance to the next source\", not \"the request had no demand\".\n */\nexport type VastWaterfallSource = {\n /** Identical across every source in this response — one id per waterfall build, so it groups all of a single ad opportunity's source attempts, while `request_id` identifies this source alone. Echo it back; never mint your own. */\n auction_request_id?: string;\n /** The source's effective FLOOR CPM in dollars per thousand impressions (never cents) — the configured tag floor (`NUMERIC(8,2)`) or the partner's default, after any demand price action. It is an expectation used to order the waterfall, not a cleared price and not what the screen earns; `null` when the partner has no floor configured. */\n cpm?: number | null;\n /** High recent error rate measured server-side. Degraded sources are already pushed to the tail of the array for you — do NOT skip a source because of this flag. */\n degraded?: boolean;\n /** Whole seconds of the creative THIS source will serve, so you can schedule continuous loop playback without first fetching the VAST and probing the MP4. Present only on the first-party `trillboards_direct` source (a programmatic source's length is not known until its own VAST is fetched). It is the same number as the `<Duration>` in the VAST that `vast_url` returns, so use either — they cannot disagree. NOT a playback control: IMA still takes its real timing from the media, so treat this as scheduling metadata and keep honouring the actual quartile/complete events. A creative longer than your ad slot will still be cut off by the next poll; we warn the uploader at upload time when that is the case. */\n duration_seconds?: number;\n /** When false, skip this source entirely. Present-but-disabled sources may appear in the array. */\n enabled?: boolean;\n /** Recent non-response rate for this demand source as a PERCENT 0-100 (not a 0-1 fraction). It is fleet-wide rather than per-screen, derived from an hourly rollup that can be ~15 minutes stale, and it is present only on sources that also carry `degraded: true`. Advisory: it never means skip the source. */\n error_rate_pct?: number;\n /** No live producer — `null` on every source. The only assignment is guarded on a partner-level `fetchMode` setting that no demand partner in the registry defines. Do not branch on it. */\n fetch_mode?: string | null;\n /** Opaque public alias for the demand source. Echo it back as `variant_name` on `programmatic-event` reports. */\n name?: string;\n /** Opaque ascending sort key — lowest is tried first. Do NOT treat it as an index: it may start at 0 (a source we want to win outright — the `?test=1` source, an injected first-party bid, an auction winner — is stamped `priority: 0`), and values may be non-contiguous (some paths renumber survivors 1..N, others keep catalog values). Only the relative order is meaningful; sort ascending and do no arithmetic on it. */\n priority?: number;\n /** Per-source request identifier. Report against the source you actually used, not `sources[0]`. */\n request_id?: string;\n /** Per-source budget in ms for fetching and loading THIS source. Distinct from the waterfall-wide `total_timeout_ms`. */\n timeout_ms?: number;\n /** Fetch verbatim. The server has already appended this source's `request_id` and rewritten every partner-identifying path segment and query parameter to an opaque alias, so editing, re-ordering or re-signing the query breaks impression attribution. A `data:` URL can appear here for an inbound-DSP source that carries its VAST inline. */\n vast_url?: string;\n};\n\nexport type Webhook = {\n /** When webhook was created */\n created_at?: string;\n /** Subscribed event types */\n events?: Array<\"device.online\" | \"device.offline\" | \"impression.recorded\" | \"creative.rewards_ready\" | \"campaign.allocated\" | \"payout.processed\" | \"sensing.threshold_crossed\" | \"audience.spike\" | \"audience.venue_busy\" | \"audience.purchase_intent\" | \"audience.demographics_update\" | \"venue.traffic_summary\" | \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\" | \"fleet_command.completed\" | \"fleet_command.failed\">;\n /** Total failed deliveries */\n failure_count?: number;\n /** Last time webhook was triggered */\n last_triggered_at?: string;\n /** Webhook signing secret (whsec_…). Returned when the webhook is created so partners can verify the compound `X-Trillboards-Signature` header over the raw payload (see the SDK's Webhooks.constructEvent). Treat as a credential — store it securely and never expose it client-side. */\n secret?: string;\n /** Webhook status */\n status?: \"active\" | \"inactive\";\n /** Total successful deliveries */\n success_count?: number;\n /** Webhook endpoint URL */\n url?: string;\n /** Unique webhook identifier */\n webhook_id?: string;\n};\n\nexport type WebhookDelivery = {\n /** When delivery was first attempted */\n attempted_at?: string;\n /** When delivery succeeded */\n delivered_at?: string;\n /** Error message if failed */\n error_message?: string;\n /** Event that triggered this delivery */\n event_type?: string;\n /** HTTP status code from endpoint */\n http_status?: number;\n /** Delivery record ID */\n id?: string;\n /** Response time in milliseconds */\n response_time_ms?: number;\n /** Number of retry attempts */\n retry_count?: number;\n /** Delivery status */\n status?: \"pending\" | \"success\" | \"failed\" | \"retrying\";\n};\n\n/**\n * Standard webhook event payload sent to your endpoint.\n * All events follow this structure.\n *\n */\nexport type WebhookEvent = {\n /** Event-specific data */\n data?: Record<string, unknown>;\n /** Event type */\n event?: string;\n /** When event occurred */\n timestamp?: string;\n};\n\nexport type WifiEnvironmentSnapshot = {\n /** Dimensionless 0.0-1.0: visible APs whose centre frequency is within ±10 MHz of the joined AP, divided by ALL visible APs in the capped list. Because the joined AP is itself in the numerator it is never 0 while connected — a literal `0.0` means not connected (or an empty scan), not an empty channel. Above ~0.5 indicates a dense venue, below ~0.2 an isolated one. */\n channelCongestionRatio?: number | null;\n /** Channel width of the joined AP in MHz — but it is APPROXIMATE by construction: the producer returns the width of the FIRST entry in the scan list, which is only usually the joined AP, rather than matching on BSSID. `null` when not connected, on Android below API 23, or for an 80+80 MHz AP, which the width mapping does not cover. */\n connectedChannelWidthMhz?: number | null;\n /** Centre frequency of the joined AP's primary 20 MHz channel, in MHz. `0` means not connected / unavailable, and that zero also zeroes `channelCongestionRatio` and forces `frequencyBand` to `unknown`. */\n connectedFrequencyMhz?: number | null;\n /** Negotiated PHY link speed of the joined AP in Mbps (`WifiInfo.getLinkSpeed()`) — a link-rate ceiling, not measured throughput. `null` rather than 0 when not connected or when the platform reports a non-positive value. */\n connectedLinkSpeedMbps?: number | null;\n /** RSSI of the JOINED access point in dBm. `-100` is a SENTINEL, not a measurement: it is the literal default when `WifiInfo` is unavailable or the device is not on Wi-Fi, so a genuinely weak link and no link at all are indistinguishable here. */\n connectedSignalDbm?: number | null;\n /** Band of the JOINED AP: `2.4ghz`, `5ghz`, `6ghz` or `unknown`. It is derived from `connectedFrequencyMhz`, so a device that is not on Wi-Fi reports `unknown` rather than null — and the 5900-5924 MHz range falls into `unknown` too, because the classifier's 5 GHz and 6 GHz windows do not meet. */\n frequencyBand?: string | null;\n /** Median RSSI in dBm across ALL visible APs (not just the joined one). It is the UPPER median for an even-sized list — the two middle values are not averaged — and falls back to the `-100` sentinel on an empty list. */\n medianSignalDbm?: number | null;\n /** Distinct BSSIDs in the scan, after the 50-entry cap. It is literally the SAME value as `uniqueBssidCount` — both are assigned from one field — so the two never disagree and neither is a count of the uncapped scan. */\n networkCount?: number | null;\n /** Population VARIANCE of the joined AP's RSSI in dBm SQUARED — not a standard deviation, and the divisor is N, not N-1. The window is the last 5 HEARTBEAT cycles held in a process-lifetime buffer, not the current scan, so it reads `0.0` on the first cycle after an agent restart; the `-100` not-connected sentinel is admitted into that history and skews it. Intended as a coarse motion indicator, not occupancy. */\n rssiVariance?: number | null;\n /** UNIX EPOCH milliseconds (`System.currentTimeMillis()`) stamped when the scan COMPLETED — wall clock, not boot-relative, and not the scan start. It is a different clock from Android's own per-result `ScanResult.timestamp`, which is microseconds since boot and never reaches the wire. */\n scanTimestampMs?: number | null;\n /** Strongest minus weakest visible RSSI, in dB — a positive difference, not an absolute level. It is `0` when fewer than two APs are visible, which is indistinguishable from a genuinely uniform RF environment. Used as a venue-openness hint. */\n signalSpreadDbm?: number | null;\n /** Distinct BSSIDs after de-duplication and the 50-entry cap — the identical value to `networkCount` above, assigned from the same field, so it adds no independent information. */\n uniqueBssidCount?: number | null;\n [key: string]: unknown;\n} | null;\n\nexport type WifiScanResult = {\n /** Bonded channel width in MHz, mapped from Android's width enum to a literal 20, 40, 80 or 160. `null` on Android below API 23, on any read failure, AND for an 80+80 MHz AP — that variant has no mapping, so `null` does not mean narrow. */\n channelWidthMhz?: number | null;\n /** Centre frequency of the AP's PRIMARY 20 MHz channel in MHz (2400-7200 accepted, covering 2.4/5/6 GHz) — not the centre of a wider bonded channel. Convert to a channel number yourself; the wire carries only the frequency. */\n frequencyMhz: number;\n /** The AP's BSSID exactly as Android reports it, unhashed on the device; Trillboards stores it as received and as a keyed HMAC-SHA256 hash. Rows are de-duplicated by BSSID keeping the strongest reading, and the literal `02:00:00:00:00:00` — Android's redaction placeholder for a caller without location permission — is dropped rather than forwarded, so a permission-less device produces an empty list, not a list of placeholders. */\n rawBssid: string;\n /** AP signal level in dBm (negative, bounded -120..0), from `ScanResult.level`. Note the wire key the Android agent actually sends is `signal_dbm`, not a snake_case form of this name — a mismatch of exactly this kind left the ClickHouse `rssi` column NULL on 100% of Wi-Fi rows until 2026-08-08. */\n signalStrengthDbm: number;\n [key: string]: unknown;\n};\n\n\n// ─── Operations ──────────────────────────────────────────────────────────\n\n/**\n * The whole still a sighted ad was read off, face-blurred.\n * GET /v1/ad-sighting-frames/{token}\n */\nexport interface getAdSightingFrameOperation {\n readonly path: \"/v1/ad-sighting-frames/{token}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The signed capability in the record's photo_url / frame_url. */\n token: string;\n};\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * The photo of a sighted ad: the close-up, or the ad cut from its still at request time.\n * GET /v1/ad-sighting-photos/{token}\n */\nexport interface getAdSightingPhotoOperation {\n readonly path: \"/v1/ad-sighting-photos/{token}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The signed capability in the record's photo_url / frame_url. */\n token: string;\n};\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * Ad-sighting records for a signed-in portal buyer (the Creatives lens).\n * GET /v1/advertiser/measurement/ad-sightings\n */\nexport interface listAdSightingsInPortalOperation {\n readonly path: \"/v1/advertiser/measurement/ad-sightings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** A board the sighting was matched to, repeatable. */\n board_id?: Array<string> | null;\n /** A brand, repeatable for a brand set (competitors). Matched however it is typed: \"McDonald's\", \"mcdonalds\" and \"Mc Donalds\" find the same records. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. Combined with `brand` as either-or. */\n brand_id?: Array<string> | null;\n /** The brand's IAB tier-1 category (IAB1..IAB25), repeatable: the records whose resolved brand votes in it (brand_knowledge_graph.iab_category, the `category` field). */\n category?: Array<string> | null;\n /** A sighted creative (the campaign artwork), repeatable. */\n creative_id?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** Start (inclusive), YYYY-MM-DD or an ISO-8601 instant. Default: 30 days before `to`. */\n from?: string;\n /** true returns only records that carry a photo (photo_url set): a record without a shareable face-blurred picture is skipped, so it is never returned or billed. The page can hold fewer than limit records; keep following next_cursor until it is null. */\n has_photo?: \"true\" | \"false\";\n /** The reading instrument (ssr-v2, ssr-v1, vlmtext-v1, edge_ocr_v1), repeatable. */\n instrument?: Array<string> | null;\n /** Records per page, 1..500 (default 50). The page limit is reserved; the records returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE (US DMA or CA CMA), repeatable. */\n market?: Array<string> | null;\n /** A media owner, repeatable: the records matched to a face whose owner (`publisher_name`, the registry's) holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)). */\n media_owner?: Array<string> | null;\n /** The surface kind as read (billboard, storefront, bus_shelter, ...), repeatable. */\n surface?: Array<string> | null;\n /** End (exclusive). Default: now. The span is at most 400 days. */\n to?: string;\n};\n response: DataApi_AdSightingsResponse;\n}\n\n/**\n * Brand x market x month creative history for a signed-in portal buyer.\n * GET /v1/advertiser/measurement/ad-sightings/history\n */\nexport interface listAdSightingHistoryInPortalOperation {\n readonly path: \"/v1/advertiser/measurement/ad-sightings/history\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Narrow to brands this agency holds as agency of record (Winmo), by name in any case, repeatable. */\n agency?: Array<string> | null;\n /** Narrow to faces by face key, repeatable for a set of boards: f:<board id>:<face index> (a registered face) or p:<point id> (an unregistered board point), the `face_key` a board slice answers with. */\n board?: Array<string> | null;\n /** A brand by name, repeatable (competitors). Resolved to its brand id the way the brand search does. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. */\n brand_id?: Array<string> | null;\n /** Narrow to brands of an IAB tier-1 category (IAB1..IAB25), repeatable. A slice filter narrows the denominators with the rows: the shares are within the categories named. */\n category?: Array<string> | null;\n /** Narrow to faces in a Census CBSA (5-digit code, OMB July 2023 delineation), repeatable. */\n cbsa?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** A slice the rows are cut by, repeatable: category, parent, agency (what the brand is), media_owner, format, surface, board, cbsa (where it ran). Each row is a brand within its slice, and every share is over its slice: a slice recomputes every denominator, and every distinct count is counted within it. The market vacancy is cut by where-it-ran slices only. */\n dimension?: Array<string> | null;\n /** Narrow to static or digital faces, repeatable. */\n format?: Array<string> | null;\n /** First month (YYYY-MM) or day. Default: 12 months before `to`. */\n from?: string;\n /** market_month (default) or fleet_month; market_week or fleet_week (ISO weeks from their Monday, each counted whole, every week the from..to span touches); market_window or fleet_window (the from..to span as one period). A fleet grain drops the market: with dimension=cbsa it is the CBSA geography. */\n grain?: \"market_month\" | \"fleet_month\" | \"market_week\" | \"fleet_week\" | \"market_window\" | \"fleet_window\";\n /** Rows per page, 1..500 (default 100). The page limit is reserved; the rows returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE, repeatable. */\n market?: Array<string> | null;\n /** Narrow to faces whose registry owner holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)), repeatable. */\n media_owner?: Array<string> | null;\n /** Narrow to brands whose parent company is in this brand graph id's family (the `parent_id` a parent slice answers with), repeatable. */\n parent?: Array<string> | null;\n /** Narrow to faces of a reader surface (billboard, digital_board, bus_shelter, kiosk), repeatable. */\n surface?: Array<string> | null;\n /** Last month (YYYY-MM, inclusive) or day. Default: this month. */\n to?: string;\n};\n response: DataApi_AdSightingsHistoryResponse;\n}\n\n/**\n * Every measured board in a bbox as a map point, with the ads our cab cameras read on it.\n * GET /v1/advertiser/measurement/boards.geojson\n */\nexport interface listMeasuredBoardsOperation {\n readonly path: \"/v1/advertiser/measurement/boards.geojson\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** An audience measured at the face to carry on every numbered point, as `<dimension>:<value>` (age, gender, cohort, intent; e.g. gender:female): its share, riders and prior level, to rank faces by. */\n audience?: string;\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** A brand to count per board and to narrow the sighting layer to. */\n brand?: string;\n /** A face format, as `format_label` spells it. Repeat the parameter for several (`format=A&format=B`); a value is never split on a comma. */\n format?: string | Array<string>;\n /** Extra layers: `sightings`. */\n layers?: string;\n /** A media owner, any case. Repeat the parameter for several (`owner=A&owner=B`); a value is never split on a comma, since owner names hold commas. */\n owner?: string | Array<string>;\n /** A curated set key: draw only its members. */\n set?: string;\n /** Comma-separated face types: `digital`, `static`. */\n type?: string;\n /** Comma-separated OpenOOH venue type ids (301 billboard, 302 urban panel, 303 shelter, 201 fueling station, ...). */\n venue?: string;\n};\n response: DataApi_DataProducts_BoardPointCollection;\n}\n\n/**\n * Who passes a board: occupancy, age, gender, activity and mood shares by daypart.\n * GET /v1/advertiser/measurement/boards/{boardId}/audience\n */\nexport interface getMeasuredBoardAudienceOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/audience\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Window end. Absent: the newest. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardAudienceResponse;\n}\n\n/**\n * Measured impressions per spot for one board face, by daypart, light, weather or speed.\n * GET /v1/advertiser/measurement/boards/{boardId}/currency\n */\nexport interface getMeasuredBoardCurrencyOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/currency\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Split the cells by daypart (default), light, weather or speed. */\n by?: \"daypart\" | \"light\" | \"weather\" | \"speed\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Measurement window end (YYYY-MM-DD). Absent: the newest published window. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardCurrencyResponse;\n}\n\n/**\n * How much of the time passengers were turned toward a board, per instrument.\n * GET /v1/advertiser/measurement/boards/{boardId}/looked-share\n */\nexport interface getMeasuredBoardLookedShareOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/looked-share\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First local date. Absent: 27 days before `to`. */\n from?: string;\n /** Last local date. Absent: the current currency window end. */\n to?: string;\n};\n response: DataApi_DataProducts_BoardLookedShareResponse;\n}\n\n/**\n * The buildings around a board that shape its viewshed.\n * GET /v1/advertiser/measurement/boards/{boardId}/occluders.geojson\n */\nexport interface getMeasuredBoardOccludersOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/occluders.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_OccluderCollection;\n}\n\n/**\n * Every pass our fleet made of a board on one day, second by second.\n * GET /v1/advertiser/measurement/boards/{boardId}/passes/replay\n */\nexport interface getMeasuredBoardPassReplayOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/passes/replay\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Local day to replay. */\n date: string;\n /** Page offset. */\n offset?: number;\n};\n response: DataApi_DataProducts_PassReplayResponse;\n}\n\n/**\n * Passes, legible seconds and facing seconds per week and daypart for one board.\n * GET /v1/advertiser/measurement/boards/{boardId}/tiles\n */\nexport interface getMeasuredBoardTilesOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/tiles\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First week (snaps to its Monday). */\n from?: string;\n /** Last week (snaps to its Monday). */\n to?: string;\n};\n response: DataApi_DataProducts_BoardTilesResponse;\n}\n\n/**\n * The legible and visible viewshed of each face of a board, with its measured figures.\n * GET /v1/advertiser/measurement/boards/{boardId}/viewshed.geojson\n */\nexport interface getMeasuredBoardViewshedOperation {\n readonly path: \"/v1/advertiser/measurement/boards/{boardId}/viewshed.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_ViewshedCollection;\n}\n\n/**\n * Brand typeahead over the outdoor ads our cab cameras read, with each brand's reads and metros.\n * GET /v1/advertiser/measurement/brands\n */\nexport interface searchSightedBrandsOperation {\n readonly path: \"/v1/advertiser/measurement/brands\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Brands to return. */\n limit?: number;\n /** Brand name as typed. Empty: the most-read brands. */\n q?: string;\n};\n response: DataApi_DataProducts_BrandSearchResponse;\n}\n\n/**\n * The calibration panel: P(readable) and P(facing) per format, road class, speed, daypart and bearing.\n * GET /v1/advertiser/measurement/calibration\n */\nexport interface getMeasurementCalibrationOperation {\n readonly path: \"/v1/advertiser/measurement/calibration\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One calibration. */\n calibration?: \"readable\" | \"facing\";\n /** A version id (mcal-2026-09-26-cv3-pa6-b1). Absent: the newest. */\n calibration_id?: string;\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** One instrument. */\n instrument?: string;\n /** One unit. */\n unit?: string;\n};\n response: DataApi_DataProducts_CalibrationResponse;\n}\n\n/**\n * Every verified calibration version, to pin a calibration_id from.\n * GET /v1/advertiser/measurement/calibration/versions\n */\nexport interface listMeasurementCalibrationVersionsOperation {\n readonly path: \"/v1/advertiser/measurement/calibration/versions\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Versions to return (default 52). */\n limit?: number;\n};\n response: DataApi_DataProducts_CalibrationVersionsResponse;\n}\n\n/**\n * The curated board sets (approved packages) with their measured coverage.\n * GET /v1/advertiser/measurement/curation-sets\n */\nexport interface listCurationSetsOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Page size (default 200). */\n limit?: number;\n /** Page offset. */\n offset?: number;\n /** Search the set names. */\n q?: string;\n};\n response: DataApi_DataProducts_CurationSetListResponse;\n}\n\n/**\n * The measured coverage of one curated set.\n * GET /v1/advertiser/measurement/curation-sets/{setKey}/coverage\n */\nexport interface getCurationSetCoverageOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets/{setKey}/coverage\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A curated set key, as listed by /curation-sets. */\n setKey: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_SetCoverageEnvelope;\n}\n\n/**\n * The roads that serve a curated set, with the traffic index and speeds.\n * GET /v1/advertiser/measurement/curation-sets/{setKey}/roads.geojson\n */\nexport interface getCurationSetRoadsOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets/{setKey}/roads.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A curated set key, as listed by /curation-sets. */\n setKey: string;\n};\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** Day-of-week type (default weekday). */\n dow_type?: \"weekday\" | \"saturday\" | \"sunday\" | \"all\";\n /** Local hour 0-23. Absent: every hour. */\n hour?: number;\n /** traversal_index (default), speed or speed_ratio. */\n metric?: \"traversal_index\" | \"speed\" | \"speed_ratio\";\n /** Comma-separated OSM classes: motorway, motorway_link, trunk, trunk_link, primary, primary_link, secondary, secondary_link, tertiary, tertiary_link, unclassified, residential, living_street, service. */\n road_class?: string;\n};\n response: DataApi_DataProducts_RoadCollection;\n}\n\n/**\n * The viewsheds and face points of every member of a curated set.\n * GET /v1/advertiser/measurement/curation-sets/{setKey}/viewsheds.geojson\n */\nexport interface getCurationSetViewshedsOperation {\n readonly path: \"/v1/advertiser/measurement/curation-sets/{setKey}/viewsheds.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A curated set key, as listed by /curation-sets. */\n setKey: string;\n};\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox?: string;\n};\n response: DataApi_DataProducts_ViewshedCollection;\n}\n\n/**\n * The measured multiplier file for an SSP: per-face impression multipliers, or per-face demographics.\n * GET /v1/advertiser/measurement/feeds/multipliers\n */\nexport interface getMeasuredMultiplierFeedOperation {\n readonly path: \"/v1/advertiser/measurement/feeds/multipliers\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** multipliers (default), faces or demographics. */\n dataset?: \"multipliers\" | \"faces\" | \"demographics\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Three-digit DMA code. */\n dma?: string;\n /** Feed date. Absent: the newest. */\n feed_date?: string;\n /** json (default) or csv (text/csv attachment). */\n format?: \"json\" | \"csv\";\n /** SSP whose venue ids key the file: vistar (default), place_exchange, broadsign, hivestack, viooh, magnite, lmx. */\n ssp?: string;\n};\n response: DataApi_DataProducts_MultiplierFeedResponse;\n}\n\n/**\n * The DMA x format index: passes per board-week, legible seconds per pass and facing share against the US base.\n * GET /v1/advertiser/measurement/index\n */\nexport interface getMeasuredDmaFormatIndexOperation {\n readonly path: \"/v1/advertiser/measurement/index\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One DMA. */\n dma?: string;\n /** First week. */\n from?: string;\n /** Last week. */\n to?: string;\n};\n response: DataApi_DataProducts_DmaFormatIndexResponse;\n}\n\n/**\n * The approved metrics: every governed audience, camera, creative, seatbelt, board and panel answer you can buy.\n * GET /v1/advertiser/measurement/metrics\n */\nexport interface listApprovedMetricsOperation {\n readonly path: \"/v1/advertiser/measurement/metrics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: DataApi_DataProducts_MetricCatalogResponse;\n}\n\n/**\n * Measured impressions per spot (OOH board)\n * GET /v1/advertiser/measurement/metrics/board_measured_impressions_per_spot\n */\nexport interface getMetricBoardMeasuredImpressionsPerSpotOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/board_measured_impressions_per_spot\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Board face id (board metrics). */\n board_id?: string;\n /** Condition scope (board metrics): daypart, light, weather or speed. */\n by?: string;\n /** Daypart filter (board metrics). */\n daypart?: string;\n /** Currency window end (board metrics). */\n window_end?: string;\n};\n response: DataApi_DataProducts_MetricBoardMeasuredImpressionsPerSpotResponse;\n}\n\n/**\n * Who was in the cab during a board pass\n * GET /v1/advertiser/measurement/metrics/board_pass_audience\n */\nexport interface getMetricBoardPassAudienceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/board_pass_audience\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Board face id (board metrics). */\n board_id?: string;\n /** Daypart filter (board metrics). */\n daypart?: string;\n /** Currency window end (board metrics). */\n window_end?: string;\n};\n response: DataApi_DataProducts_MetricBoardPassAudienceResponse;\n}\n\n/**\n * Capped dwell per camera window\n * GET /v1/advertiser/measurement/metrics/camera_dwell_capped_ms\n */\nexport interface getMetricCameraDwellCappedMsOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_dwell_capped_ms\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraDwellCappedMsResponse;\n}\n\n/**\n * Gaze on screen per camera window\n * GET /v1/advertiser/measurement/metrics/camera_gaze_pct\n */\nexport interface getMetricCameraGazePctOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_gaze_pct\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraGazePctResponse;\n}\n\n/**\n * Head-pose index per camera window\n * GET /v1/advertiser/measurement/metrics/camera_head_pose_index\n */\nexport interface getMetricCameraHeadPoseIndexOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_head_pose_index\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** Comma-separated statistics (mean, p50, ...), from the metric's allowed stats. This metric's: `mean`, `spread`; default `mean`. */\n stats?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraHeadPoseIndexResponse;\n}\n\n/**\n * Camera people per screen-hour\n * GET /v1/advertiser/measurement/metrics/camera_people_per_screen_hour\n */\nexport interface getMetricCameraPeoplePerScreenHourOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/camera_people_per_screen_hour\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Camera evidence grade: face_backed or person_backed. */\n grade?: \"face_backed\" | \"person_backed\";\n /** The answer grain; default `screen_hour`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** Comma-separated statistics (mean, p50, ...), from the metric's allowed stats. This metric's: `mean`, `p95`, `spread`; default `mean`, `p95`. */\n stats?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCameraPeoplePerScreenHourResponse;\n}\n\n/**\n * Outdoor creative history by brand, metro and month (camera creative ledger)\n * GET /v1/advertiser/measurement/metrics/creative_brand_history\n */\nexport interface getMetricCreativeBrandHistoryOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_brand_history\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Agency names, |-separated (or repeated): the brands one of them holds as agency of record (Winmo), any case. */\n agencies?: string;\n /** Face keys, |-separated (or repeated): f:<board id>:<face index> or p:<point id>. */\n boards?: string;\n /** Comma-separated resolved brand ids. */\n brands?: string;\n /** Comma-separated IAB tier-1 codes (IAB1..IAB25): the brands of those categories. A slice filter narrows the denominators with the rows. */\n categories?: string;\n /** Comma-separated 5-digit Census CBSA codes (OMB July 2023 delineation). */\n cbsas?: string;\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Comma-separated dimensions (dimension= is the one-value spelling): the audience dimensions of a demographics metric (default all), or the slices creative_brand_history cuts its rows by (category, parent, agency, media_owner, format, surface, board, cbsa; default none), every share over its slice. This metric's: `category`, `parent`, `agency`, `media_owner`, `format`, `surface`, `board`, `cbsa`. */\n dimensions?: string;\n /** Comma-separated face formats: static, digital. */\n formats?: string;\n /** The answer grain; default `market_month`. */\n grain?: \"market_month\" | \"fleet_month\" | \"market_week\" | \"fleet_week\" | \"market_window\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** Media owner names, |-separated (or repeated): the faces whose registry owner holds a name's letters and digits, any case and punctuation. */\n media_owners?: string;\n /** Comma-separated brand graph ids: the brands whose parent company is in one of those Wikidata families. */\n parents?: string;\n /** Comma-separated reader surfaces: billboard, digital_board, bus_shelter, kiosk. */\n surfaces?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeBrandHistoryResponse;\n}\n\n/**\n * Outdoor share of voice by brand (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_share_of_voice\n */\nexport interface getMetricCreativeShareOfVoiceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_share_of_voice\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeShareOfVoiceResponse;\n}\n\n/**\n * Outdoor ad sightings (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_sightings\n */\nexport interface getMetricCreativeSightingsOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_sightings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_day`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeSightingsResponse;\n}\n\n/**\n * Street presence by brand and surface (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_street_presence\n */\nexport interface getMetricCreativeStreetPresenceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_street_presence\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeStreetPresenceResponse;\n}\n\n/**\n * Outdoor vacancy rate (camera creative map)\n * GET /v1/advertiser/measurement/metrics/creative_vacancy_rate\n */\nexport interface getMetricCreativeVacancyRateOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/creative_vacancy_rate\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `market_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricCreativeVacancyRateResponse;\n}\n\n/**\n * Demographic share\n * GET /v1/advertiser/measurement/metrics/demographic_share\n */\nexport interface getMetricDemographicShareOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/demographic_share\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** Comma-separated dimensions (dimension= is the one-value spelling): the audience dimensions of a demographics metric (default all), or the slices creative_brand_history cuts its rows by (category, parent, agency, media_owner, format, surface, board, cbsa; default none), every share over its slice. This metric's: `activity_state`, `age`, `apparel_tier`, `attire`, `carried_items`, `cohort`, `device_engagement`, `diet`, `exposure_quality`, `gender`, `head_turn`, `income`, `intent`, `lifestage`, `lifestyle`, `mood`, `occupant_position`, `seatbelt_state`, `tech`, `venue`. */\n dimensions?: string;\n /** The answer grain; default `screen_day`. */\n grain?: \"screen_hour\" | \"screen_day\" | \"screen_daypart_local\" | \"screen_window\" | \"fleet_hour\" | \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricDemographicShareResponse;\n}\n\n/**\n * Radio identifiers per person (in-cab calibration)\n * GET /v1/advertiser/measurement/metrics/radio_identifiers_per_person\n */\nexport interface getMetricRadioIdentifiersPerPersonOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/radio_identifiers_per_person\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `fleet_window`. */\n grain?: \"fleet_day\" | \"fleet_daypart_local\" | \"fleet_window\";\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricRadioIdentifiersPerPersonResponse;\n}\n\n/**\n * Same-panel index (screen panel, month over month)\n * GET /v1/advertiser/measurement/metrics/same_panel_index\n */\nexport interface getMetricSamePanelIndexOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/same_panel_index\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `fleet_month`. */\n grain?: \"fleet_month\";\n /** The population the shares are over. */\n population?: \"camera\" | \"radio\";\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricSamePanelIndexResponse;\n}\n\n/**\n * Rear-seat seatbelt compliance (in-cab camera)\n * GET /v1/advertiser/measurement/metrics/seatbelt_compliance\n */\nexport interface getMetricSeatbeltComplianceOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/seatbelt_compliance\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `screen_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\" | \"screen_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricSeatbeltComplianceResponse;\n}\n\n/**\n * Unbuckled-ride rate (in-cab camera, per ride)\n * GET /v1/advertiser/measurement/metrics/seatbelt_unbuckled_ride_rate\n */\nexport interface getMetricSeatbeltUnbuckledRideRateOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/seatbelt_unbuckled_ride_rate\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `screen_window`. */\n grain?: \"market_day\" | \"market_window\" | \"fleet_day\" | \"fleet_window\" | \"screen_window\";\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). */\n markets?: string;\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. */\n screens?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. */\n window?: string;\n};\n response: DataApi_DataProducts_MetricSeatbeltUnbuckledRideRateResponse;\n}\n\n/**\n * Camera and sensing screen census\n * GET /v1/advertiser/measurement/metrics/sensing_census\n */\nexport interface getMetricSensingCensusOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/sensing_census\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. */\n day?: string;\n /** The answer grain; default `fleet_day`. */\n grain?: \"fleet_day\" | \"screen\";\n /** The population the shares are over. */\n population?: \"camera\" | \"radio\" | \"sensing\";\n};\n response: DataApi_DataProducts_MetricSensingCensusResponse;\n}\n\n/**\n * One approved metric answered for a day or window, at its grain.\n * GET /v1/advertiser/measurement/metrics/{metric}\n */\nexport interface getApprovedMetricOperation {\n readonly path: \"/v1/advertiser/measurement/metrics/{metric}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** An approved metric name. */\n metric: \"camera_people_per_screen_hour\" | \"camera_dwell_capped_ms\" | \"camera_head_pose_index\" | \"camera_gaze_pct\" | \"demographic_share\" | \"sensing_census\" | \"board_measured_impressions_per_spot\" | \"board_pass_audience\" | \"same_panel_index\" | \"radio_identifiers_per_person\" | \"creative_sightings\" | \"creative_share_of_voice\" | \"creative_street_presence\" | \"creative_vacancy_rate\" | \"creative_brand_history\" | \"seatbelt_compliance\" | \"seatbelt_unbuckled_ride_rate\";\n};\n query: {\n /** Agency names, |-separated (or repeated): the brands one of them holds as agency of record (Winmo), any case. Taken by: creative_brand_history. */\n agencies?: string;\n /** Board face id (board metrics). Taken by: board_measured_impressions_per_spot, board_pass_audience. */\n board_id?: string;\n /** Face keys, |-separated (or repeated): f:<board id>:<face index> or p:<point id>. Taken by: creative_brand_history. */\n boards?: string;\n /** Comma-separated resolved brand ids. Taken by: creative_brand_history. */\n brands?: string;\n /** Condition scope (board metrics): daypart, light, weather or speed. Taken by: board_measured_impressions_per_spot. */\n by?: string;\n /** Comma-separated IAB tier-1 codes (IAB1..IAB25): the brands of those categories. A slice filter narrows the denominators with the rows. Taken by: creative_brand_history. */\n categories?: string;\n /** Comma-separated 5-digit Census CBSA codes (OMB July 2023 delineation). Taken by: creative_brand_history. */\n cbsas?: string;\n /** One day (YYYY-MM-DD). Give day or window; neither is the last settled day. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, sensing_census, same_panel_index, radio_identifiers_per_person, creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n day?: string;\n /** Daypart filter (board metrics). Taken by: board_measured_impressions_per_spot, board_pass_audience. */\n daypart?: string;\n /** Comma-separated dimensions (dimension= is the one-value spelling): the audience dimensions of a demographics metric (default all), or the slices creative_brand_history cuts its rows by (category, parent, agency, media_owner, format, surface, board, cbsa; default none), every share over its slice. Taken by: demographic_share, creative_brand_history. */\n dimensions?: string;\n /** Comma-separated face formats: static, digital. Taken by: creative_brand_history. */\n formats?: string;\n /** Camera evidence grade: face_backed or person_backed. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct. */\n grade?: string;\n /** The answer grain (screen_hour, screen_day, fleet_day, market_day, market_month, ...): one of the metric's grains. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, sensing_census, same_panel_index, radio_identifiers_per_person, creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n grain?: string;\n /** Comma-separated markets as COUNTRY:CODE (US DMA, CA CMA). Taken by: creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n markets?: string;\n /** Media owner names, |-separated (or repeated): the faces whose registry owner holds a name's letters and digits, any case and punctuation. Taken by: creative_brand_history. */\n media_owners?: string;\n /** Comma-separated brand graph ids: the brands whose parent company is in one of those Wikidata families. Taken by: creative_brand_history. */\n parents?: string;\n /** The population the shares are over. Taken by: sensing_census, same_panel_index. */\n population?: string;\n /** Comma-separated 24-hex screen ids, up to the metric's max_screens. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n screens?: string;\n /** Comma-separated statistics (mean, p50, ...), from the metric's allowed stats. Taken by: camera_people_per_screen_hour, camera_head_pose_index. */\n stats?: string;\n /** Comma-separated reader surfaces: billboard, digital_board, bus_shelter, kiosk. Taken by: creative_brand_history. */\n surfaces?: string;\n /** An inclusive span, YYYY-MM-DD..YYYY-MM-DD, up to the metric's max_window_days. Taken by: camera_people_per_screen_hour, camera_dwell_capped_ms, camera_head_pose_index, camera_gaze_pct, demographic_share, same_panel_index, radio_identifiers_per_person, creative_sightings, creative_share_of_voice, creative_street_presence, creative_vacancy_rate, creative_brand_history, seatbelt_compliance, seatbelt_unbuckled_ride_rate. */\n window?: string;\n /** Currency window end (board metrics). Taken by: board_measured_impressions_per_spot, board_pass_audience. */\n window_end?: string;\n};\n response: DataApi_DataProducts_MetricAnswerResponse;\n}\n\n/**\n * The release registry: every monthly release of measured multipliers and every feed published from it.\n * GET /v1/advertiser/measurement/releases\n */\nexport interface listMeasurementReleasesOperation {\n readonly path: \"/v1/advertiser/measurement/releases\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Releases to return (default 24). */\n limit?: number;\n};\n response: DataApi_DataProducts_ReleaseRegistryResponse;\n}\n\n/**\n * The roads our fleet drove in a bbox, with the traffic index and speeds.\n * GET /v1/advertiser/measurement/roads.geojson\n */\nexport interface listMeasuredRoadsOperation {\n readonly path: \"/v1/advertiser/measurement/roads.geojson\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** Day-of-week type (default weekday). */\n dow_type?: \"weekday\" | \"saturday\" | \"sunday\" | \"all\";\n /** Local hour 0-23. Absent: every hour. */\n hour?: number;\n /** traversal_index (default), speed or speed_ratio. */\n metric?: \"traversal_index\" | \"speed\" | \"speed_ratio\";\n /** Comma-separated OSM classes: motorway, motorway_link, trunk, trunk_link, primary, primary_link, secondary, secondary_link, tertiary, tertiary_link, unclassified, residential, living_street, service. */\n road_class?: string;\n /** A curated set key. */\n set?: string;\n};\n response: DataApi_DataProducts_RoadCollection;\n}\n\n/**\n * Passes, legible and facing seconds summed per geohash cell over the entitled boards in a bbox.\n * GET /v1/advertiser/measurement/tiles.geojson\n */\nexport interface listMeasuredGeohashTilesOperation {\n readonly path: \"/v1/advertiser/measurement/tiles.geojson\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** minLon,minLat,maxLon,maxLat (RFC 7946 order). The span is capped (`max_bbox_deg` on /curation-sets); a wider box answers 413 bbox_too_large. */\n bbox: string;\n /** First week. */\n from?: string;\n /** Geohash precision: 5 (default), 6 or 7. */\n precision?: number;\n /** Last week. */\n to?: string;\n};\n response: DataApi_DataProducts_GeohashTileCollection;\n}\n\n/**\n * Query API changelog\n * GET /v1/changelog\n */\nexport interface queryChangelogOperation {\n readonly path: \"/v1/changelog\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Only entries dated on or after this date (YYYY-MM-DD). Unreleased entries always included. */\n since?: string;\n /** Filter by change category: \"breaking\" (changed+removed), \"additive\" (added), \"deprecation\" (deprecated), \"fix\" (fixed). Comma-separated for multiple. */\n type?: string;\n};\n response: ChangelogResponse;\n}\n\n/**\n * Ad-sighting records: outdoor ads our cab cameras read, each with a signed photo link.\n * GET /v1/data/ad-sightings\n */\nexport interface dataApiAdSightingsOperation {\n readonly path: \"/v1/data/ad-sightings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** A board the sighting was matched to, repeatable. */\n board_id?: Array<string> | null;\n /** A brand, repeatable for a brand set (competitors). Matched however it is typed: \"McDonald's\", \"mcdonalds\" and \"Mc Donalds\" find the same records. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. Combined with `brand` as either-or. */\n brand_id?: Array<string> | null;\n /** The brand's IAB tier-1 category (IAB1..IAB25), repeatable: the records whose resolved brand votes in it (brand_knowledge_graph.iab_category, the `category` field). */\n category?: Array<string> | null;\n /** A sighted creative (the campaign artwork), repeatable. */\n creative_id?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** Start (inclusive), YYYY-MM-DD or an ISO-8601 instant. Default: 30 days before `to`. */\n from?: string;\n /** true returns only records that carry a photo (photo_url set): a record without a shareable face-blurred picture is skipped, so it is never returned or billed. The page can hold fewer than limit records; keep following next_cursor until it is null. */\n has_photo?: \"true\" | \"false\";\n /** The reading instrument (ssr-v2, ssr-v1, vlmtext-v1, edge_ocr_v1), repeatable. */\n instrument?: Array<string> | null;\n /** Records per page, 1..500 (default 50). The page limit is reserved; the records returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE (US DMA or CA CMA), repeatable. */\n market?: Array<string> | null;\n /** A media owner, repeatable: the records matched to a face whose owner (`publisher_name`, the registry's) holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)). */\n media_owner?: Array<string> | null;\n /** The surface kind as read (billboard, storefront, bus_shelter, ...), repeatable. */\n surface?: Array<string> | null;\n /** End (exclusive). Default: now. The span is at most 400 days. */\n to?: string;\n};\n response: DataApi_AdSightingsResponse;\n}\n\n/**\n * Outdoor creative history by brand, market and month, from the creative ledger.\n * GET /v1/data/ad-sightings/history\n */\nexport interface dataApiAdSightingsHistoryOperation {\n readonly path: \"/v1/data/ad-sightings/history\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Narrow to brands this agency holds as agency of record (Winmo), by name in any case, repeatable. */\n agency?: Array<string> | null;\n /** Narrow to faces by face key, repeatable for a set of boards: f:<board id>:<face index> (a registered face) or p:<point id> (an unregistered board point), the `face_key` a board slice answers with. */\n board?: Array<string> | null;\n /** A brand by name, repeatable (competitors). Resolved to its brand id the way the brand search does. */\n brand?: Array<string> | null;\n /** A resolved brand id, repeatable. */\n brand_id?: Array<string> | null;\n /** Narrow to brands of an IAB tier-1 category (IAB1..IAB25), repeatable. A slice filter narrows the denominators with the rows: the shares are within the categories named. */\n category?: Array<string> | null;\n /** Narrow to faces in a Census CBSA (5-digit code, OMB July 2023 delineation), repeatable. */\n cbsa?: Array<string> | null;\n /** The `next_cursor` of the previous page. */\n cursor?: string;\n /** A slice the rows are cut by, repeatable: category, parent, agency (what the brand is), media_owner, format, surface, board, cbsa (where it ran). Each row is a brand within its slice, and every share is over its slice: a slice recomputes every denominator, and every distinct count is counted within it. The market vacancy is cut by where-it-ran slices only. */\n dimension?: Array<string> | null;\n /** Narrow to static or digital faces, repeatable. */\n format?: Array<string> | null;\n /** First month (YYYY-MM) or day. Default: 12 months before `to`. */\n from?: string;\n /** market_month (default) or fleet_month; market_week or fleet_week (ISO weeks from their Monday, each counted whole, every week the from..to span touches); market_window or fleet_window (the from..to span as one period). A fleet grain drops the market: with dimension=cbsa it is the CBSA geography. */\n grain?: \"market_month\" | \"fleet_month\" | \"market_week\" | \"fleet_week\" | \"market_window\" | \"fleet_window\";\n /** Rows per page, 1..500 (default 100). The page limit is reserved; the rows returned are billed. */\n limit?: number;\n /** A market as COUNTRY:CODE, repeatable. */\n market?: Array<string> | null;\n /** Narrow to faces whose registry owner holds the name's letters and digits, any case and punctuation (Lamar finds LAMAR-PITTSBURGH and Lamar (Cincinnati)), repeatable. */\n media_owner?: Array<string> | null;\n /** Narrow to brands whose parent company is in this brand graph id's family (the `parent_id` a parent slice answers with), repeatable. */\n parent?: Array<string> | null;\n /** Narrow to faces of a reader surface (billboard, digital_board, bus_shelter, kiosk), repeatable. */\n surface?: Array<string> | null;\n /** Last month (YYYY-MM, inclusive) or day. Default: this month. */\n to?: string;\n};\n response: DataApi_AdSightingsHistoryResponse;\n}\n\n/**\n * Aggregate audience analytics for a time window.\n * GET /v1/data/aggregate\n */\nexport interface dataApiAggregateOperation {\n readonly path: \"/v1/data/aggregate\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Dimension to group aggregations by. */\n group_by?: \"venue_type\" | \"daypart\" | \"day_of_week\" | \"income_estimated_level\" | \"primary_mood\";\n /** Metric to aggregate on. */\n metric?: \"avg_face_count\" | \"avg_attention\" | \"income_confidence\" | \"max_face_count\";\n /** Relative time window (e.g. \"24h\", \"7d\"). */\n since?: string;\n};\n response: DataApi_AggregateResponse;\n}\n\n/**\n * Find screens with similar audience profiles.\n * GET /v1/data/lookalike\n */\nexport interface dataApiLookalikeScreensOperation {\n readonly path: \"/v1/data/lookalike\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Matches to return, 1-100. */\n limit?: number;\n /** The lowest similarity a match may have, 0-1 (default 0.7; 0 keeps every match that is not opposite). */\n min_similarity?: number;\n /** Internal screen identifier. */\n screen_id: string;\n};\n response: DataApi_LookalikeResponse;\n}\n\n/**\n * Composable query DSL over approved datasets.\n * POST /v1/data/query\n */\nexport interface dataApiQueryDslOperation {\n readonly path: \"/v1/data/query\";\n readonly method: \"POST\";\n request: DataApi_QueryDslBody;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: DataApi_QueryDslResponse;\n}\n\n/**\n * List screens visible to the caller.\n * GET /v1/data/screens\n */\nexport interface dataApiListScreensOperation {\n readonly path: \"/v1/data/screens\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** ISO-3166 alpha-2 country code. */\n country?: string;\n /** Screens per page, 1-200. */\n limit?: number;\n /** Screens to skip; the previous page's `next_offset`. */\n offset?: number;\n /** Filter by venue taxonomy type (e.g. bar, restaurant). */\n venue_type?: string;\n};\n response: DataApi_ScreensListResponse;\n}\n\n/**\n * Real-time audience snapshot for a screen.\n * GET /v1/data/screens/{screenId}/audience\n */\nexport interface dataApiScreenAudienceLiveOperation {\n readonly path: \"/v1/data/screens/{screenId}/audience\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Internal screen identifier. */\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_ScreenAudienceResponse;\n}\n\n/**\n * Historical audience_metrics rows for a screen.\n * GET /v1/data/screens/{screenId}/history\n */\nexport interface dataApiScreenAudienceHistoryOperation {\n readonly path: \"/v1/data/screens/{screenId}/history\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Internal screen identifier. */\n screenId: string;\n};\n query: {\n /** Windows to return, newest first, 1-1000 (default 100). */\n limit?: number;\n /** ISO-8601 start timestamp. */\n since?: string;\n /** ISO-8601 end timestamp. */\n until?: string;\n};\n response: DataApi_ScreenHistoryResponse;\n}\n\n/**\n * Similarity search over scene embeddings.\n * GET /v1/data/semantic-search\n */\nexport interface dataApiSemanticSearchOperation {\n readonly path: \"/v1/data/semantic-search\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Matches to return, 1-100. */\n limit?: number;\n /** The lowest cosine similarity a match may have, 0-1. */\n min_similarity?: number;\n /** What to find, in words (3-512 characters): \"people waiting for a train\". */\n q: string;\n /** Relative time window (e.g. \"24h\", \"7d\"). */\n since?: string;\n};\n response: DataApi_SemanticSearchResponse;\n}\n\n/**\n * Platform-wide counters.\n * GET /v1/data/stats\n */\nexport interface dataApiStatsOperation {\n readonly path: \"/v1/data/stats\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: DataApi_StatsResponse;\n}\n\n/**\n * Server-Sent Events stream of live audience/observation events.\n * GET /v1/data/stream\n */\nexport interface dataApiStreamOperation {\n readonly path: \"/v1/data/stream\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Only events of this observation family (screen_audience, ...). */\n observation_family?: string;\n /** Only events from screens of this venue type (transit, retail, ...). */\n venue_type?: string;\n};\n response: unknown;\n}\n\n/**\n * API usage for the authenticated key (billing dashboard).\n * GET /v1/data/usage\n */\nexport interface dataApiUsageOperation {\n readonly path: \"/v1/data/usage\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Days of usage to sum, 1-90. */\n days?: number;\n};\n response: DataApi_UsageResponse;\n}\n\n/**\n * List all error codes\n * GET /v1/errors\n */\nexport interface listErrorCodesOperation {\n readonly path: \"/v1/errors\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: ErrorListResponse;\n}\n\n/**\n * Look up a single error code\n * GET /v1/errors/{code}\n */\nexport interface getErrorCodeOperation {\n readonly path: \"/v1/errors/{code}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** A stable error code from the catalog. See GET /v1/errors for the full list. */\n code: string;\n};\n query: Record<string, unknown>;\n response: ErrorCodeResponse;\n}\n\n/**\n * The pass audience of an owned face.\n * GET /v1/owner/measurement/boards/{boardId}/audience\n */\nexport interface getOwnerBoardAudienceOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/audience\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardAudienceResponse;\n}\n\n/**\n * The currency of an owned face, with the owner comparison, yield and money.\n * GET /v1/owner/measurement/boards/{boardId}/currency\n */\nexport interface getOwnerBoardCurrencyOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/currency\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Split the cells by daypart (default), light, weather or speed. */\n by?: \"daypart\" | \"light\" | \"weather\" | \"speed\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Measurement window end (YYYY-MM-DD). Absent: the newest published window. */\n window_end?: string;\n};\n response: DataApi_DataProducts_BoardCurrencyResponse;\n}\n\n/**\n * The DOOH delivery report: what one face aired over a flight and the measured impressions it delivered.\n * GET /v1/owner/measurement/boards/{boardId}/delivery-report\n */\nexport interface getOwnerDeliveryReportOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/delivery-report\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** json or csv. */\n format?: \"json\" | \"csv\";\n /** First flight day. */\n from?: string;\n /** Last flight day. */\n to?: string;\n};\n response: DataApi_DataProducts_DeliveryReportResponse;\n}\n\n/**\n * How much of the time passengers were turned toward an owned face, per instrument.\n * GET /v1/owner/measurement/boards/{boardId}/looked-share\n */\nexport interface getOwnerBoardLookedShareOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/looked-share\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First local date. */\n from?: string;\n /** Last local date. */\n to?: string;\n};\n response: DataApi_DataProducts_BoardLookedShareResponse;\n}\n\n/**\n * The week x daypart tiles of an owned face.\n * GET /v1/owner/measurement/boards/{boardId}/tiles\n */\nexport interface getOwnerBoardTilesOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/tiles\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** First week (snaps to its Monday). */\n from?: string;\n /** Last week (snaps to its Monday). */\n to?: string;\n};\n response: DataApi_DataProducts_BoardTilesResponse;\n}\n\n/**\n * The viewshed of an owned face.\n * GET /v1/owner/measurement/boards/{boardId}/viewshed.geojson\n */\nexport interface getOwnerBoardViewshedOperation {\n readonly path: \"/v1/owner/measurement/boards/{boardId}/viewshed.geojson\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: Record<string, unknown>;\n response: DataApi_DataProducts_ViewshedCollection;\n}\n\n/**\n * Every face the media owner holds, measured: impressions per spot beside its own figure, yield, money, facing and rank.\n * GET /v1/owner/measurement/faces\n */\nexport interface listOwnerFacesOperation {\n readonly path: \"/v1/owner/measurement/faces\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** Window end. Absent: the newest. */\n window_end?: string;\n};\n response: DataApi_DataProducts_OwnerFacesResponse;\n}\n\n/**\n * One owned face in full: currency, audience, spec, SSP venue ids, benchmark and release cells.\n * GET /v1/owner/measurement/faces/{boardId}\n */\nexport interface getOwnerFaceOperation {\n readonly path: \"/v1/owner/measurement/faces/{boardId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** The board face id (board_dim.board_id), printable, as listed by /boards.geojson. */\n boardId: string;\n};\n query: {\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_OwnerFaceResponse;\n}\n\n/**\n * The measured multiplier file for the owner's faces.\n * GET /v1/owner/measurement/feeds/multipliers\n */\nexport interface getOwnerMultiplierFeedOperation {\n readonly path: \"/v1/owner/measurement/feeds/multipliers\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** multipliers (default), faces or demographics. */\n dataset?: \"multipliers\" | \"faces\" | \"demographics\";\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** Three-digit DMA code. */\n dma?: string;\n /** Feed date. Absent: the newest. */\n feed_date?: string;\n /** json (default) or csv (text/csv attachment). */\n format?: \"json\" | \"csv\";\n /** SSP whose venue ids key the file: vistar (default), place_exchange, broadsign, hivestack, viooh, magnite, lmx. */\n ssp?: string;\n};\n response: DataApi_DataProducts_MultiplierFeedResponse;\n}\n\n/**\n * Send a proof-of-play log or an ad server flight schedule (CSV) for your faces.\n * POST /v1/owner/measurement/logs\n */\nexport interface uploadOwnerPlayLogsOperation {\n readonly path: \"/v1/owner/measurement/logs\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** The file holds every play of each face-day it names. */\n complete?: \"true\" | \"false\";\n /** Answer the plan, write nothing. */\n dry_run?: \"true\" | \"false\";\n /** The file's name (or send X-Filename). */\n filename?: string;\n /** The reader. */\n format?: \"generic\" | \"flight\";\n};\n response: DataApi_DataProducts_OwnerUploadResponse;\n}\n\n/**\n * The publisher yield report, the publisher named in the query string.\n * GET /v1/owner/measurement/publishers/yield\n */\nexport interface getOwnerPublisherYieldByQueryOperation {\n readonly path: \"/v1/owner/measurement/publishers/yield\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** One DMA. */\n dma?: string;\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** Publisher name. */\n publisher: string;\n /** OpenOOH venue type id. */\n venue_type?: string;\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_YieldReportResponse;\n}\n\n/**\n * The publisher yield report: every face measured against the owner's own figure.\n * GET /v1/owner/measurement/publishers/{publisher}/yield\n */\nexport interface getOwnerPublisherYieldOperation {\n readonly path: \"/v1/owner/measurement/publishers/{publisher}/yield\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Publisher name. */\n publisher: string;\n};\n query: {\n /** One daypart (early_morning, morning, midday, afternoon, evening, night, late_night) or `__all__`. Absent: every daypart. */\n daypart?: string;\n /** One DMA. */\n dma?: string;\n /** json (default) or csv. */\n format?: \"json\" | \"csv\";\n /** OpenOOH venue type id. */\n venue_type?: string;\n /** Window end. */\n window_end?: string;\n};\n response: DataApi_DataProducts_YieldReportResponse;\n}\n\n/**\n * The release registry, on the owner mount.\n * GET /v1/owner/measurement/releases\n */\nexport interface listOwnerMeasurementReleasesOperation {\n readonly path: \"/v1/owner/measurement/releases\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Releases to return. */\n limit?: number;\n};\n response: DataApi_DataProducts_ReleaseRegistryResponse;\n}\n\n/**\n * Send a face specification sheet (CSV): size, mount, facing, format, illumination and SSP venue ids per face.\n * POST /v1/owner/measurement/specs\n */\nexport interface uploadOwnerFaceSpecsOperation {\n readonly path: \"/v1/owner/measurement/specs\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: {\n /** Answer the plan, write nothing. */\n dry_run?: \"true\" | \"false\";\n};\n response: DataApi_DataProducts_OwnerUploadResponse;\n}\n\n/**\n * List self-promo ads\n * GET /v1/partner/ads/self-promo\n */\nexport interface listPartnerSelfPromoAdsOperation {\n readonly path: \"/v1/partner/ads/self-promo\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<PartnerSelfPromoAd>;\n success?: boolean;\n};\n}\n\n/**\n * Create self-promo ad (URL-based)\n * POST /v1/partner/ads/self-promo\n */\nexport interface createPartnerSelfPromoAdOperation {\n readonly path: \"/v1/partner/ads/self-promo\";\n readonly method: \"POST\";\n request: PartnerSelfPromoCreate;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: PartnerSelfPromoAd;\n success?: boolean;\n warnings?: PartnerCreativeWarnings;\n};\n}\n\n/**\n * List self-promo placements by screen\n * GET /v1/partner/ads/self-promo/placements\n */\nexport interface listPartnerSelfPromoPlacementsOperation {\n readonly path: \"/v1/partner/ads/self-promo/placements\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<PartnerSelfPromoPlacement>;\n success?: boolean;\n};\n}\n\n/**\n * Schedule existing self-promo ad to screens\n * POST /v1/partner/ads/self-promo/schedule\n */\nexport interface schedulePartnerSelfPromoOperation {\n readonly path: \"/v1/partner/ads/self-promo/schedule\";\n readonly method: \"POST\";\n request: {\n ad_id: string;\n end_date?: string;\n screen_ids: Array<string>;\n start_date?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Create self-promo ad (upload)\n * POST /v1/partner/ads/self-promo/upload\n */\nexport interface createPartnerSelfPromoUploadOperation {\n readonly path: \"/v1/partner/ads/self-promo/upload\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: PartnerSelfPromoAd;\n success?: boolean;\n warnings?: PartnerCreativeWarnings;\n};\n}\n\n/**\n * Disable a self-promo ad\n * POST /v1/partner/ads/self-promo/{ad_id}/disable\n */\nexport interface disableSelfPromoAdOperation {\n readonly path: \"/v1/partner/ads/self-promo/{ad_id}/disable\";\n readonly method: \"POST\";\n request: never;\n params: {\n ad_id: string;\n};\n query: Record<string, unknown>;\n response: {\n ad_id?: string;\n status?: \"disabled\";\n};\n}\n\n/**\n * Register an AI agent\n * POST /v1/partner/agent/register\n */\nexport interface registerAgentOperation {\n readonly path: \"/v1/partner/agent/register\";\n readonly method: \"POST\";\n request: {\n /** Type of agent being registered */\n agent_type: \"dsp_agent\" | \"ssp_agent\" | \"trading_desk\" | \"analytics_platform\" | \"developer\";\n /** Company name (optional) */\n company?: string;\n /** Brief description of the agent's purpose */\n description?: string;\n /** Contact email */\n email: string;\n /** Agent or company name */\n name: string;\n /** Mint an AdCP **sandbox account** (`account.sandbox` in `get_adcp_capabilities`). Media buys made with the returned key validate end to end — screen resolution, published CPM/floor, flight parsing, derived impression goal, every error path — and return a well-formed response marked `sandbox: true`, but persist **no advertisements and no placements**. Nothing can serve, deliver, bill, or pay a venue. Use this for conformance and no-spend testing; register without it for a live account. */\n sandbox?: boolean;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** The AdCP **account** this key is bound to. Distinct from the `sandbox` block below, which describes auto-provisioned test SCREENS (supply); this is the account-level buying contract (demand) declared as `account.sandbox` in `get_adcp_capabilities`. */\n account?: {\n /** Seller-assigned account id. Same value as `partner_id`. */\n account_id?: string;\n note?: string;\n /** True when this is a sandbox account: its media buys write no advertisements and no placements, and every media-buy tool response is marked `sandbox: true`. */\n sandbox?: boolean;\n };\n agent_type?: string;\n /** API key for authentication (display once — save it!) */\n api_key?: string;\n /** MCP tools available to this agent */\n available_tools?: Array<string>;\n /** Exact same-key handoff for buyer/OpenRTB control-plane capabilities. */\n control_plane_onboarding?: {\n authorization?: string;\n endpoint?: string;\n method?: string;\n purpose?: string;\n reuses_api_key?: boolean;\n };\n docs_url?: string;\n /** Free tier limits per product */\n free_tiers?: Record<string, unknown>;\n mcp_endpoint?: string;\n mcp_transport?: string;\n /** Guidance for getting started */\n next_steps?: Array<string>;\n object?: string;\n /** Unique partner ID */\n partner_id?: string;\n pricing_url?: string;\n request_id?: string;\n /** Auto-provisioned test SCREENS (supply side). Unrelated to `account.sandbox`. */\n sandbox?: {\n note?: string;\n screens?: Array<{\n device_id?: string;\n name?: string;\n venue_type?: string;\n }>;\n };\n tools_url?: string;\n};\n}\n\n/**\n * Get partner analytics\n * GET /v1/partner/analytics\n */\nexport interface getAnalyticsOperation {\n readonly path: \"/v1/partner/analytics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n end_date?: string;\n start_date?: string;\n};\n response: {\n data?: {\n devices_by_status?: Array<Record<string, unknown>>;\n impressions_by_day?: Array<{\n /** Date (YYYY-MM-DD) */\n _id?: string;\n impressions?: number;\n }>;\n partner?: {\n active_devices?: number;\n pending_payout_cents?: number;\n total_devices?: number;\n total_impressions?: number;\n total_revenue_cents?: number;\n };\n period?: {\n end?: string;\n start?: string;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * Visitor-flow continuity graph across the partner's screens\n * GET /v1/partner/analytics/audience-continuity\n */\nexport interface getAudienceContinuityOperation {\n readonly path: \"/v1/partner/analytics/audience-continuity\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n windowMinutes?: number;\n};\n response: {\n data?: {\n confidence?: string;\n sampleSize?: number;\n topPaths?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Audience composition for the partner's screens\n * GET /v1/partner/analytics/audience-profile\n */\nexport interface getAudienceProfileOperation {\n readonly path: \"/v1/partner/analytics/audience-profile\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n sampleSize?: number;\n segments?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * BLE device discovery summary\n * GET /v1/partner/analytics/ble-summary\n */\nexport interface getBleSummaryOperation {\n readonly path: \"/v1/partner/analytics/ble-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n totalObservations?: number;\n uniqueDevices?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Content performance — ad lineage and measured audience reactions\n * GET /v1/partner/analytics/content-performance\n */\nexport interface getContentPerformanceOperation {\n readonly path: \"/v1/partner/analytics/content-performance\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n groupBy?: \"canonical\" | \"wrapper\";\n includeUnclassified?: boolean;\n limit?: number;\n offset?: number;\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n byScreen?: Record<string, unknown>;\n creativeResponse?: Array<{\n adId?: string;\n advertiserName?: string;\n ageRating?: string;\n attentiveSeconds?: number;\n audioTerms?: Array<string>;\n avgAttention?: number;\n brandName?: string;\n confidence?: number;\n firstSeen?: string;\n iabCategories?: Array<string>;\n lastSeen?: string;\n moderationStatus?: string;\n plays?: number;\n viewers?: number;\n }>;\n /** Whether another page of creativeResponse exists after this one. */\n has_more?: boolean;\n nextOffset?: number | null;\n topAdvertisers?: Array<Record<string, unknown>>;\n /** Exact number of cards the cursor walks: the feed statement's count over every filter, taken before the page slice. Every page holds exactly `limit` cards except the last, so a walk at any page size reaches the end in ceil(total / limit) pages, and `nextOffset`/`has_more` describe the same set. Null when the feed could not be read (`degraded_fields` then lists `creativeResponse`). Describes the programmatic cursor; the offset-0 all-content block is additive. */\n total?: number | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Free-text search across the partner's creative catalogue\n * GET /v1/partner/analytics/creative-catalog\n */\nexport interface searchCreativeCatalogOperation {\n readonly path: \"/v1/partner/analytics/creative-catalog\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n q?: string;\n};\n response: {\n data?: {\n creatives?: Array<{\n adId?: string;\n advertiserName?: string;\n assetUrl?: string | null;\n brandName?: string;\n iabCategories?: Array<string>;\n moderationStatus?: string;\n }>;\n /** Whether another page of results exists after this one. */\n has_more?: boolean;\n nextOffset?: number | null;\n /** Always null for catalogue search: the read over-fetches limit+1 for a free `has_more`, but an exact total would need a second COUNT round-trip the search path deliberately avoids. Page to completion via `has_more`. */\n total?: number | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Everything your screens measured while a creative played\n * GET /v1/partner/analytics/creative-observations\n */\nexport interface getCreativeObservationsOperation {\n readonly path: \"/v1/partner/analytics/creative-observations\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n adId?: string;\n adIds?: string;\n contentSha256?: string;\n creativeId?: string;\n exact?: boolean;\n families?: string;\n from?: string;\n identity?: string;\n playLimit?: number;\n screenId?: string;\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\" | \"historical\";\n to?: string;\n};\n response: {\n code?: number;\n data?: {\n /** One rollup per creative (identity_key), every family with its count. */\n creatives?: Array<Record<string, unknown>>;\n /** Families that could not be read this time (their values are null). Absent when every family answered. */\n degraded_fields?: Array<string>;\n /** Why each family in degraded_fields was not read, keyed by family: `read_failed` (with its `code`); `pg_budget` for verified attention read on its Postgres home that did not finish within its budget (`budget_ms`), with the plays it read (`plays_read_n` of `plays_total_n`, `page_plays_read_n` of `page_plays_total_n`; a part read is never returned as the whole); `over_play_limit` with `limit` and `plays_total_n`. Absent when every family answered. */\n degraded_reasons?: Record<string, {\n budget_ms?: number;\n code?: string;\n limit?: number;\n page_plays_read_n?: number;\n page_plays_total_n?: number;\n plays_read_n?: number;\n plays_total_n?: number;\n reason: \"read_failed\" | \"pg_budget\" | \"over_play_limit\";\n }>;\n families?: Array<string>;\n /** The keys read, whether the read was exact, and the files and canonicals they resolved to. */\n identity?: Record<string, unknown>;\n /** The newest plays, each with its creative and every family read for it. */\n plays?: Array<Record<string, unknown>>;\n /** Every play of the creatives in the window, programmatic and supplied. */\n plays_total?: number;\n screen_ids?: Array<string>;\n /** The supplied plays read (plays_n, evidence_plays_n); null when the family was not read. */\n supplied?: Record<string, unknown> | null;\n window?: {\n from?: string;\n to?: string;\n };\n };\n message?: string;\n status?: boolean;\n};\n}\n\n/**\n * Scene-level observations for a played creative\n * GET /v1/partner/analytics/creative-scenes\n */\nexport interface getCreativeScenesOperation {\n readonly path: \"/v1/partner/analytics/creative-scenes\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n adId?: string;\n cursor?: string;\n exact?: boolean;\n identity?: string;\n limit?: number;\n screenId?: string;\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n /** The adId read; absent on an identity read. */\n adId?: string;\n /** The identity keys read (an identity read only). */\n identity?: string;\n nextCursor?: string | null;\n scenes?: Array<Record<string, unknown>>;\n /** The screen read; absent on an identity read across all your screens. */\n screenId?: string;\n timeRange?: string;\n total?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Per-pair flow directionality + transition heatmap\n * GET /v1/partner/analytics/cross-screen-flow\n */\nexport interface getCrossScreenFlowOperation {\n readonly path: \"/v1/partner/analytics/cross-screen-flow\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n edges?: Array<Record<string, unknown>>;\n screens?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Unified portfolio dashboard (earnings, ads, audience, screens, insights)\n * GET /v1/partner/analytics/dashboard\n */\nexport interface getPartnerAnalyticsDashboardOperation {\n readonly path: \"/v1/partner/analytics/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n endDate?: string;\n period?: \"7d\" | \"30d\" | \"90d\" | \"custom\";\n startDate?: string;\n};\n response: {\n data?: {\n ads?: Record<string, unknown>;\n audience?: Record<string, unknown>;\n earnings?: {\n change?: Record<string, unknown>;\n current?: Record<string, unknown>;\n previous?: Record<string, unknown>;\n sparkline?: Array<Record<string, unknown>>;\n };\n insights?: Array<Record<string, unknown>>;\n period?: {\n endDate?: string | null;\n label?: string;\n startDate?: string | null;\n };\n screens?: Record<string, unknown>;\n topScreens?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Device-type / OS / browser-class distribution among repeat visitors\n * GET /v1/partner/analytics/device-suite-signature\n */\nexport interface getDeviceSuiteSignatureOperation {\n readonly path: \"/v1/partner/analytics/device-suite-signature\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n deviceTypes?: Array<Record<string, unknown>>;\n totalDevices?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * CSV export of partner-scope analytics (summary / daily / per-screen)\n * GET /v1/partner/analytics/export\n */\nexport interface exportPartnerAnalyticsOperation {\n readonly path: \"/v1/partner/analytics/export\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n endDate?: string;\n period?: \"7d\" | \"30d\" | \"90d\" | \"custom\";\n startDate?: string;\n type?: \"summary\" | \"daily-breakdown\" | \"screen-breakdown\";\n};\n response: unknown;\n}\n\n/**\n * Per-ad daily breakdown for the partner fleet\n * GET /v1/partner/analytics/export/ads-by-day\n */\nexport interface exportPartnerAdsByDayOperation {\n readonly path: \"/v1/partner/analytics/export/ads-by-day\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n endDate: string;\n format?: \"csv\" | \"json\";\n startDate: string;\n};\n response: {\n data?: Array<{\n ad_name?: string;\n advertiser_name?: string;\n campaign_type?: string;\n completion_rate?: number;\n date?: string;\n gross_revenue_cents?: number;\n plays_completed?: number;\n publisher_revenue_cents?: number;\n publisher_share_rate?: number;\n screen_name?: string;\n }>;\n status?: boolean;\n};\n}\n\n/**\n * 24-hour distribution across the partner's fleet\n * GET /v1/partner/analytics/fleet-hourly\n */\nexport interface getFleetHourlyOperation {\n readonly path: \"/v1/partner/analytics/fleet-hourly\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n /** One entry per hour of the day. A partner with no screens gets the empty form `{ hours: [], timeRange }` instead of an array. */\n data?: Array<Record<string, unknown>> | {\n hours?: Array<Record<string, unknown>>;\n timeRange?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * 4-stage discovery → awareness → engagement → conversion funnel\n * GET /v1/partner/analytics/halo-funnel\n */\nexport interface getHaloFunnelOperation {\n readonly path: \"/v1/partner/analytics/halo-funnel\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n stages?: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * 24-hour returning-vs-first-timer audience clock\n * GET /v1/partner/analytics/loyalty-clock\n */\nexport interface getLoyaltyClockOperation {\n readonly path: \"/v1/partner/analytics/loyalty-clock\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n hours?: Array<{\n firstTimerShare?: number;\n hour?: number;\n returningShare?: number;\n sampleSize?: number;\n }>;\n sampleSize?: number;\n timeRange?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * Fleet-wide audience summary for the partner's screens\n * GET /v1/partner/analytics/network-summary\n */\nexport interface getNetworkSummaryOperation {\n readonly path: \"/v1/partner/analytics/network-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n dataAvailable?: boolean;\n queriedAt?: string;\n timeRange?: string;\n totalScreens?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Daily/hourly fleet-wide audience timeseries\n * GET /v1/partner/analytics/network-trend\n */\nexport interface getNetworkTrendOperation {\n readonly path: \"/v1/partner/analytics/network-trend\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n interval?: \"1h\" | \"1d\";\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n /** One bucket per `interval`. A partner with no screens gets the empty form `{ series: [], interval, timeRange }` instead of an array. */\n data?: Array<Record<string, unknown>> | {\n interval?: string;\n series?: Array<Record<string, unknown>>;\n timeRange?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * Cross-screen proximity-graph summary\n * GET /v1/partner/analytics/proximity-summary\n */\nexport interface getProximitySummaryOperation {\n readonly path: \"/v1/partner/analytics/proximity-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n continuityEdges?: Array<Record<string, unknown>>;\n crossScreenSignals?: number;\n gateDiagnostic?: Record<string, unknown>;\n repeatSignals?: number;\n sourceBreakdown?: Record<string, unknown>;\n topPaths?: Array<Record<string, unknown>>;\n uniqueSignals?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Per-creative scatter of avg-attention vs revenue-per-impression\n * GET /v1/partner/analytics/revenue-attention-correlation\n */\nexport interface getRevenueAttentionCorrelationOperation {\n readonly path: \"/v1/partner/analytics/revenue-attention-correlation\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n timeRange?: \"today\" | \"last_7d\" | \"last_30d\";\n};\n response: {\n data?: {\n points?: Array<Record<string, unknown>>;\n trendLine?: Record<string, unknown> | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Paginated chronological feed of scene observations\n * GET /v1/partner/analytics/scene-feed\n */\nexport interface getSceneFeedOperation {\n readonly path: \"/v1/partner/analytics/scene-feed\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n /** Distinct calendar days with observations over the last 90 days. */\n activeDays?: number;\n /** Whether another page exists after this one. */\n has_more?: boolean;\n nextOffset?: number | null;\n scenes?: Array<Record<string, unknown>>;\n /** Distinct observations within the feed window — the exact set the feed pages over. */\n total?: number;\n /** Distinct (screen, scene-prefix) observations over the last 90 days (gamification stat; independent of the page window). */\n totalObservations?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Latest scene description per screen\n * GET /v1/partner/analytics/scene-intelligence\n */\nexport interface getSceneIntelligenceOperation {\n readonly path: \"/v1/partner/analytics/scene-intelligence\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Present on EVERY response, success included. A field that appeared only on failure would make its absence the signal, and an absent field is indistinguishable from an old client or a version skew. */\n sceneDiagnostic: {\n /** True when the scene read completed and `scenes` reflects the fleet. False when it did not run to completion — `scenes` is then empty for want of an answer, not because the fleet is quiet. */\n measured: boolean;\n /** Null when `measured` is true. Otherwise names the operational failure. */\n reason: \"timeout\" | \"error\" | \"dependency_disabled\" | \"unknown\" | null | null;\n };\n scenes: Array<Record<string, unknown>>;\n };\n status?: boolean;\n};\n}\n\n/**\n * Rotate API key\n * POST /v1/partner/api-key/rotate\n */\nexport interface rotateApiKeyOperation {\n readonly path: \"/v1/partner/api-key/rotate\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** New API key — shown only once! */\n api_key?: string;\n grace_period_hours?: number;\n message?: string;\n /** When the old key stops working */\n previous_key_expires_at?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get partner-wide audience analytics\n * GET /v1/partner/audience-analytics\n */\nexport interface getAudienceAnalyticsOperation {\n readonly path: \"/v1/partner/audience-analytics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n period?: \"24h\" | \"7d\" | \"30d\";\n};\n response: AudienceAnalyticsResponse;\n}\n\n/**\n * Export audience data\n * GET /v1/partner/audience-export\n */\nexport interface exportAudienceDataOperation {\n readonly path: \"/v1/partner/audience-export\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n aggregation?: \"hourly\" | \"daily\" | \"weekly\";\n end_date?: string;\n format?: \"json\" | \"csv\";\n screen_ids: string;\n start_date?: string;\n};\n response: AudienceExportResponse;\n}\n\n/**\n * Get audience heatmap data\n * GET /v1/partner/audience/heatmap\n */\nexport interface getAudienceHeatmapOperation {\n readonly path: \"/v1/partner/audience/heatmap\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n days?: number;\n screen_ids?: string;\n};\n response: {\n cells?: number;\n heatmap?: Array<Record<string, unknown>>;\n lookback_days?: number;\n object?: string;\n request_id?: string;\n screens_included?: number;\n};\n}\n\n/**\n * Get live audience data for a screen\n * GET /v1/partner/audience/live/{screenId}\n */\nexport interface getLiveAudienceOperation {\n readonly path: \"/v1/partner/audience/live/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n /** Null when screen is offline */\n audience?: {\n ad_receptivity?: number | null;\n attention_score?: number;\n crowd_density?: number;\n dominant_ambience?: string | null;\n dwell_time_ms?: number | null;\n emotional_engagement?: number | null;\n face_count?: number;\n income_level?: string | null;\n lifestyle_segment?: string | null;\n mood?: string | null;\n noise_level?: number | null;\n occupancy?: string | null;\n /** The speech classifier's reading when the screen reported one (`BROWSING`, `RESEARCHING`, `COMPARING`, `READY_TO_BUY`, `POST_PURCHASE`, `COMPLAINING`, `NONE`), otherwise the segment the purchase-journey stage maps to (`high`, `medium`, `low`), otherwise null. */\n purchase_intent?: \"BROWSING\" | \"RESEARCHING\" | \"COMPARING\" | \"READY_TO_BUY\" | \"POST_PURCHASE\" | \"COMPLAINING\" | \"NONE\" | \"high\" | \"medium\" | \"low\" | null | null;\n } | null;\n last_updated?: string | null;\n /** Present when screen is offline */\n message?: string;\n object?: string;\n request_id?: string;\n screen_id?: string;\n status?: \"live\" | \"offline\";\n};\n}\n\n/**\n * Find lookalike screens\n * GET /v1/partner/audience/lookalikes/{screenId}\n */\nexport interface getLookalikeScreensOperation {\n readonly path: \"/v1/partner/audience/lookalikes/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n country?: string;\n limit?: number;\n min_similarity?: number;\n venue_type?: string;\n};\n response: {\n filters?: {\n country?: string | null;\n min_similarity?: number;\n venue_type?: string | null;\n };\n matches?: Array<Record<string, unknown>>;\n matches_count?: number;\n object?: string;\n request_id?: string;\n source_screen_id?: string;\n};\n}\n\n/**\n * Predict screen audience\n * GET /v1/partner/audience/predict/{screenId}\n */\nexport interface predictScreenAudienceOperation {\n readonly path: \"/v1/partner/audience/predict/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n day: number;\n hour: number;\n lookback_days?: number;\n};\n response: {\n day_of_week?: number;\n hour_utc?: number;\n lookback_days?: number;\n /** Present when prediction is null */\n message?: string;\n object?: string;\n /** Null if insufficient historical data */\n prediction?: Record<string, unknown> | null;\n request_id?: string;\n screen_id?: string;\n};\n}\n\n/**\n * Resolved household reach for a campaign\n * GET /v1/partner/audience/resolved-household-reach/{campaignId}\n */\nexport interface getResolvedHouseholdReachOperation {\n readonly path: \"/v1/partner/audience/resolved-household-reach/{campaignId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n campaignId: string;\n};\n query: Record<string, unknown>;\n response: {\n audience_composition?: Array<Record<string, unknown>>;\n campaign_id?: string;\n confidence_interval?: {\n lower?: number;\n upper?: number;\n };\n households_reached?: number;\n overlap_with_first_party?: number | null;\n};\n}\n\n/**\n * List audience segments\n * GET /v1/partner/audience/segments\n */\nexport interface listAudienceSegmentsOperation {\n readonly path: \"/v1/partner/audience/segments\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<AudienceSegment>;\n has_more?: boolean;\n object?: string;\n request_id?: string;\n total_count?: number;\n};\n}\n\n/**\n * Create audience segment\n * POST /v1/partner/audience/segments\n */\nexport interface createAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments\";\n readonly method: \"POST\";\n request: {\n description?: string;\n /** Segment name */\n name: string;\n rules: Array<{\n /** Rule field (e.g., venue_type, country, city, state) */\n field: string;\n /** Comparison operator (e.g., eq, neq, in, gt, lt) */\n operator: string;\n /** Rule value */\n value: unknown;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: AudienceSegment;\n}\n\n/**\n * Delete audience segment\n * DELETE /v1/partner/audience/segments/{segmentId}\n */\nexport interface deleteAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: {\n deleted?: boolean;\n id?: string;\n object?: string;\n request_id?: string;\n};\n}\n\n/**\n * Get audience segment\n * GET /v1/partner/audience/segments/{segmentId}\n */\nexport interface getAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: AudienceSegment;\n}\n\n/**\n * Update audience segment\n * PATCH /v1/partner/audience/segments/{segmentId}\n */\nexport interface updateAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}\";\n readonly method: \"PATCH\";\n request: {\n description?: string;\n is_active?: boolean;\n name?: string;\n rules?: Array<{\n field?: string;\n operator?: string;\n value?: unknown;\n }>;\n};\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: AudienceSegment;\n}\n\n/**\n * Match screens to segment\n * POST /v1/partner/audience/segments/{segmentId}/match\n */\nexport interface matchAudienceSegmentOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}/match\";\n readonly method: \"POST\";\n request: never;\n params: {\n segmentId: string;\n};\n query: {\n limit?: number;\n own_screens_only?: \"true\" | \"false\";\n};\n response: {\n matched_count?: number;\n matches?: Array<Record<string, unknown>>;\n object?: string;\n own_screens_only?: boolean;\n request_id?: string;\n segment_id?: string;\n segment_name?: string;\n};\n}\n\n/**\n * Estimate segment reach\n * POST /v1/partner/audience/segments/{segmentId}/reach\n */\nexport interface estimateSegmentReachOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}/reach\";\n readonly method: \"POST\";\n request: never;\n params: {\n segmentId: string;\n};\n query: {\n own_screens_only?: \"true\" | \"false\";\n};\n response: {\n country_breakdown?: Record<string, number>;\n estimated_daily_cpm?: number;\n estimated_daily_impressions?: number;\n estimated_daily_revenue?: number;\n has_historical_data?: boolean;\n matched_screens?: number;\n object?: string;\n online_screens?: number;\n segment_id?: string;\n segment_name?: string;\n venue_breakdown?: Record<string, number>;\n};\n}\n\n/**\n * Generate VAST tag for segment\n * POST /v1/partner/audience/segments/{segmentId}/vast-tag\n */\nexport interface generateSegmentVastTagOperation {\n readonly path: \"/v1/partner/audience/segments/{segmentId}/vast-tag\";\n readonly method: \"POST\";\n request: {\n /** Click-through landing page URL */\n click_through?: string;\n /** Video creative URL */\n creative_url: string;\n /** Video duration in seconds */\n duration?: number;\n own_screens_only?: boolean;\n};\n params: {\n segmentId: string;\n};\n query: Record<string, unknown>;\n response: {\n creative?: {\n click_through?: string | null;\n duration?: number;\n url?: string;\n };\n cust_params?: Array<string>;\n object?: string;\n screen_ids?: Array<string>;\n segment_id?: string;\n segment_name?: string;\n targeted_screens?: number;\n vast_tag_url?: string;\n};\n}\n\n/**\n * Get audience data statistics\n * GET /v1/partner/audience/stats\n */\nexport interface getAudienceStatsOperation {\n readonly path: \"/v1/partner/audience/stats\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data_access_tier?: \"basic\" | \"developer\" | \"enterprise\";\n newest_data?: string | null;\n object?: string;\n oldest_data?: string | null;\n request_id?: string;\n screens_with_data?: number;\n total_screens?: number;\n total_vectors?: number;\n};\n}\n\n/**\n * Cancel the partner's subscription at period end\n * POST /v1/partner/billing/cancel\n */\nexport interface cancelBillingSubscriptionOperation {\n readonly path: \"/v1/partner/billing/cancel\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n effective_at?: string;\n status?: \"canceled\" | \"scheduled_for_cancellation\";\n};\n}\n\n/**\n * Purchase committed-use credits\n * POST /v1/partner/billing/credits\n */\nexport interface purchaseCreditsOperation {\n readonly path: \"/v1/partner/billing/credits\";\n readonly method: \"POST\";\n request: {\n /** Credit purchase tier */\n tier: \"tier_500\" | \"tier_2000\" | \"tier_5000\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** Amount charged in cents */\n charged_cents?: number;\n /** Present when Stripe confirmation requires action; handle as a secret */\n client_secret?: string;\n /** Verified credit added in exact decimal cents; zero until capture settles */\n credits_added_cents?: string;\n /** Legacy field name: additional credit as a percentage of the charged amount */\n discount_pct?: number;\n object?: string;\n /** Durable purchase operation identifier */\n operation_id?: string;\n /** Stripe PaymentIntent ID */\n payment_intent_id?: string;\n request_id?: string;\n /** Complete Stripe confirmation before credit can settle */\n requires_action?: boolean;\n /** Native Stripe PaymentIntent status */\n status?: string;\n};\n}\n\n/**\n * Create Stripe Checkout session for credits\n * POST /v1/partner/billing/credits/checkout\n */\nexport interface createCreditCheckoutOperation {\n readonly path: \"/v1/partner/billing/credits/checkout\";\n readonly method: \"POST\";\n request: {\n /** URL to redirect if payment is cancelled */\n cancel_url?: string;\n /** URL to redirect after successful payment */\n success_url?: string;\n tier: \"tier_500\" | \"tier_2000\" | \"tier_5000\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** Stripe Checkout URL — redirect user here */\n checkout_url?: string;\n message?: string;\n object?: string;\n /** Durable credit-purchase operation identifier */\n operation_id?: string;\n request_id?: string;\n /** Stripe Checkout session ID */\n session_id?: string;\n};\n}\n\n/**\n * List available partner billing plans\n * GET /v1/partner/billing/plans\n */\nexport interface listBillingPlansOperation {\n readonly path: \"/v1/partner/billing/plans\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n plans?: Array<{\n included_ads?: number;\n included_impressions?: number;\n overage_per_1k_impressions_cents?: number;\n price_cents_monthly?: number;\n tier?: string;\n }>;\n};\n}\n\n/**\n * Set up usage-based billing\n * POST /v1/partner/billing/setup\n */\nexport interface setupBillingOperation {\n readonly path: \"/v1/partner/billing/setup\";\n readonly method: \"POST\";\n request: {\n /** Stripe payment method token obtained from Stripe.js or Stripe Elements */\n payment_method_id: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n billing_status?: string;\n message?: string;\n object?: string;\n request_id?: string;\n stripe_customer_id?: string;\n};\n}\n\n/**\n * Subscribe the partner to a billing plan\n * POST /v1/partner/billing/subscribe\n */\nexport interface createBillingSubscriptionOperation {\n readonly path: \"/v1/partner/billing/subscribe\";\n readonly method: \"POST\";\n request: {\n tier: \"developer\" | \"enterprise\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n checkout_url?: string | null;\n status?: \"active\" | \"requires_payment\";\n};\n}\n\n/**\n * Get the partner's current subscription\n * GET /v1/partner/billing/subscription\n */\nexport interface getBillingSubscriptionOperation {\n readonly path: \"/v1/partner/billing/subscription\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n current_period_end?: string;\n status?: \"active\" | \"past_due\" | \"canceled\" | \"trialing\";\n stripe_customer_id?: string | null;\n tier?: string;\n};\n}\n\n/**\n * Get the partner's current-period usage\n * GET /v1/partner/billing/usage\n */\nexport interface getBillingUsageOperation {\n readonly path: \"/v1/partner/billing/usage\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n ads_served?: number;\n audience_api_calls?: number;\n impressions?: number;\n overage_projection_cents?: number;\n period_end?: string;\n period_start?: string;\n};\n}\n\n/**\n * Get current billing period usage\n * GET /v1/partner/billing/usage-summary\n */\nexport interface getBillingUsageSummaryOperation {\n readonly path: \"/v1/partner/billing/usage-summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n billing_status: \"free\" | \"none\" | \"active\" | \"suspended\";\n /** Committed credit balance in cents, with eight decimal places */\n credit_balance_cents: string;\n /** Credit held by in-flight reservations, in cents with eight decimal places */\n credit_reserved_cents: string;\n object: string;\n /** Partner billing account identifier */\n partner_mongo_id: string;\n /** Exclusive end of the current UTC calendar month */\n period_end: string;\n period_start: string;\n products: Record<string, {\n meters: Record<string, {\n cost_cents: string;\n free_quantity: string;\n legacy_unknown_cents: string;\n paid_quantity: string;\n postpaid_cents: string;\n prepaid_cents: string;\n /** Total quantity in the published meter unit */\n total_quantity: string;\n }>;\n /** Product cost in cents with eight decimal places */\n total_cost_cents: string;\n }>;\n request_id: string;\n /** Period cost in cents with eight decimal places */\n total_cost_cents: string;\n};\n}\n\n/**\n * Stripe webhook callback\n * POST /v1/partner/billing/webhook\n */\nexport interface stripeWebhookCallbackOperation {\n readonly path: \"/v1/partner/billing/webhook\";\n readonly method: \"POST\";\n request: Record<string, unknown>;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * Get partner dashboard overview\n * GET /v1/partner/connect/dashboard\n */\nexport interface getConnectDashboardOperation {\n readonly path: \"/v1/partner/connect/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n period?: \"7d\" | \"30d\" | \"90d\";\n};\n response: {\n data?: {\n charts?: {\n daily_impressions?: Array<{\n date?: string;\n earnings_cents?: number;\n impressions?: number;\n }>;\n hourly_today?: Array<{\n hour?: number;\n impressions?: number;\n }>;\n };\n earnings?: {\n available_cents?: number;\n daily_average_cents?: number;\n lifetime_cents?: number;\n pending_payout_cents?: number;\n period_cents?: number;\n today_cents?: number;\n };\n impressions?: {\n all_time?: number;\n daily_average?: number;\n period?: number;\n today?: number;\n trend_percent?: number;\n };\n partner?: {\n cpm_cents?: number;\n name?: string;\n revenue_share_percent?: number;\n slug?: string;\n status?: string;\n stripe_status?: \"pending\" | \"active\" | \"restricted\" | \"not_connected\";\n };\n period?: {\n days?: number;\n end?: string;\n start?: string;\n };\n screens?: {\n offline?: number;\n online?: number;\n pending?: number;\n total?: number;\n };\n top_screens?: Array<{\n earnings_cents?: number;\n impressions?: number;\n location?: string | null;\n name?: string;\n screen_id?: string;\n status?: \"online\" | \"offline\" | \"unknown\";\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get earnings chart data\n * GET /v1/partner/connect/earnings\n */\nexport interface getConnectEarningsChartOperation {\n readonly path: \"/v1/partner/connect/earnings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n group_by?: \"day\" | \"week\";\n period?: \"7d\" | \"30d\" | \"90d\";\n};\n response: {\n data?: {\n chart?: Array<{\n avg_view_duration_ms?: number;\n date?: string;\n earnings_cents?: number;\n impressions?: number;\n label?: string;\n unique_screens?: number;\n }>;\n period?: {\n days?: number;\n end?: string;\n start?: string;\n };\n summary?: {\n data_points?: number;\n group_by?: string;\n total_earnings_cents?: number;\n total_impressions?: number;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * Get screen health status\n * GET /v1/partner/connect/health\n */\nexport interface getConnectScreenHealthOperation {\n readonly path: \"/v1/partner/connect/health\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n status?: \"online\" | \"offline\" | \"all\";\n};\n response: {\n data?: {\n checked_at?: string;\n filter?: string;\n screens?: Array<{\n device_id?: string;\n external_device_id?: string;\n fingerprint?: string;\n last_heartbeat?: string | null;\n last_seen?: string | null;\n location?: {\n city?: string | null;\n lat?: number | null;\n lng?: number | null;\n state?: string | null;\n };\n name?: string;\n registered_at?: string;\n screen_id?: string | null;\n screen_status?: \"pending\" | \"active\" | \"inactive\";\n status?: \"online\" | \"offline\" | \"never_connected\" | \"unknown\";\n time_since_last_seen_seconds?: number | null;\n uptime_24h_percent?: number | null;\n venue_type?: string | null;\n }>;\n summary?: {\n never_connected?: number;\n offline?: number;\n online?: number;\n total?: number;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * List content presets\n * GET /v1/partner/content-presets\n */\nexport interface listContentPresetsOperation {\n readonly path: \"/v1/partner/content-presets\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Array<ContentPreset>;\n has_more?: boolean;\n object?: string;\n total_count?: number;\n url?: string;\n};\n}\n\n/**\n * Get content preset\n * GET /v1/partner/content-presets/{presetId}\n */\nexport interface getContentPresetOperation {\n readonly path: \"/v1/partner/content-presets/{presetId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n presetId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreset;\n}\n\n/**\n * Create an experiment on a funded native media-buy placement\n * POST /v1/partner/creative-experiments\n */\nexport interface createCreativeFeedbackExperimentOperation {\n readonly path: \"/v1/partner/creative-experiments\";\n readonly method: \"POST\";\n request: FeedbackCreateRequest;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Read your native experiment, policy and latest 500 owned creative recovery records\n * GET /v1/partner/creative-experiments/{experiment_id}\n */\nexport interface getCreativeFeedbackExperimentOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentDetailResponse;\n}\n\n/**\n * Configure your native brand profile and enable its booked reactive campaign\n * POST /v1/partner/creative-experiments/{experiment_id}/brand\n */\nexport interface configureCreativeFeedbackBrandOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/brand\";\n readonly method: \"POST\";\n request: FeedbackBrandRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackBrandResponse;\n}\n\n/**\n * Generate a native brand creative for explicit review and moderation\n * POST /v1/partner/creative-experiments/{experiment_id}/creatives/generate\n */\nexport interface generateCreativeFeedbackCreativeOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/creatives/generate\";\n readonly method: \"POST\";\n request: FeedbackGenerateRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackGenerateResponse;\n}\n\n/**\n * Import an AI model’s image through native bytes, moderation and brand review\n * POST /v1/partner/creative-experiments/{experiment_id}/creatives/import\n */\nexport interface importCreativeFeedbackCreativeOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/creatives/import\";\n readonly method: \"POST\";\n request: FeedbackImportRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackGenerateResponse;\n}\n\n/**\n * Approve or reject your generated creative using native brand review\n * POST /v1/partner/creative-experiments/{experiment_id}/creatives/review\n */\nexport interface reviewCreativeFeedbackCreativeOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/creatives/review\";\n readonly method: \"POST\";\n request: FeedbackReviewRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackReviewResponse;\n}\n\n/**\n * Replace native creative weights at the expected policy version\n * PUT /v1/partner/creative-experiments/{experiment_id}/policy\n */\nexport interface updateCreativeFeedbackPolicyOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/policy\";\n readonly method: \"PUT\";\n request: FeedbackPolicyRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Read a metered page of latest measured native play states\n * GET /v1/partner/creative-experiments/{experiment_id}/rewards\n */\nexport interface getCreativeFeedbackRewardsOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/rewards\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: {\n /** Opaque next_cursor from this same date scope; rewind after scan_complete. */\n cursor?: string;\n /** Inclusive first play date, YYYY-MM-DD; date range is at most 31 days. */\n from: string;\n /** Unique caller-owned billing key for this page; committed retries return the receipt, not another read. */\n idempotency_key: string;\n /** Maximum native play states returned on this metered page. */\n limit?: number;\n /** Inclusive last play date, YYYY-MM-DD; date range is at most 31 days. */\n to: string;\n};\n response: FeedbackRewardsResponse;\n}\n\n/**\n * Stop the native experiment at the expected policy version\n * POST /v1/partner/creative-experiments/{experiment_id}/stop\n */\nexport interface stopCreativeFeedbackExperimentOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/stop\";\n readonly method: \"POST\";\n request: FeedbackStopRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Register approved native generated creative variants\n * POST /v1/partner/creative-experiments/{experiment_id}/variants\n */\nexport interface registerCreativeFeedbackVariantsOperation {\n readonly path: \"/v1/partner/creative-experiments/{experiment_id}/variants\";\n readonly method: \"POST\";\n request: FeedbackRegisterVariantsRequest;\n params: {\n /** Native experiment ID returned by create_creative_experiment. */\n experiment_id: string;\n};\n query: Record<string, unknown>;\n response: FeedbackExperimentResponse;\n}\n\n/**\n * Submit a creative for classification\n * POST /v1/partner/creatives\n */\nexport interface submitPartnerCreativeOperation {\n readonly path: \"/v1/partner/creatives\";\n readonly method: \"POST\";\n request: {\n /** Optional advertiser/brand label to attach. */\n advertiser_name?: string;\n /** Public http(s) URL of the creative image or video. Must resolve to a public address — private/internal/cloud-metadata addresses are rejected. */\n media_url: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: CreativeClassification;\n}\n\n/**\n * Get a creative classification\n * GET /v1/partner/creatives/{ref}\n */\nexport interface getPartnerCreativeOperation {\n readonly path: \"/v1/partner/creatives/{ref}\";\n readonly method: \"GET\";\n request: never;\n params: {\n ref: string;\n};\n query: Record<string, unknown>;\n response: CreativeClassification;\n}\n\n/**\n * Get dashboard overview\n * GET /v1/partner/dashboard\n */\nexport interface getDashboardOperation {\n readonly path: \"/v1/partner/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: DashboardResponse;\n success?: boolean;\n};\n}\n\n/**\n * Export the cross-screen proximity graph edge list\n * GET /v1/partner/data-export/proximity-graph-edges\n */\nexport interface exportProximityGraphEdgesOperation {\n readonly path: \"/v1/partner/data-export/proximity-graph-edges\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n cursor?: string;\n days?: number;\n limit?: number;\n};\n response: {\n data?: {\n limit: number;\n lookback_days: number;\n /** The `cursor` of the next page, or `null` on the last page. */\n next_cursor: string | null;\n rows: Array<{\n destination_screen_id: string;\n /** Distinct transitions from the source screen to the destination screen. */\n edge_count: number;\n /** Median minutes between the source and destination sightings. */\n lag_p50: number;\n source_screen_id: string;\n /** Distinct devices behind those transitions. */\n unique_devices: number;\n }>;\n /** Number of edges in this page. */\n total: number;\n /** `true` when more edges follow this page: pass `next_cursor` back as `cursor`. */\n truncated: boolean;\n /** The UTC second the window ends at (`YYYY-MM-DD HH:MM:SS`), pinned by the first page. */\n window_end: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * List available datasets and per-dataset record counts\n * GET /v1/partner/data-export/summary\n */\nexport interface getDataExportSummaryOperation {\n readonly path: \"/v1/partner/data-export/summary\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n days?: number;\n};\n response: DataExportSummaryResponse;\n}\n\n/**\n * Export a partner-scoped dataset\n * GET /v1/partner/data-export/{dataset}\n */\nexport interface exportDatasetOperation {\n readonly path: \"/v1/partner/data-export/{dataset}\";\n readonly method: \"GET\";\n request: never;\n params: {\n dataset: \"audience_metrics\" | \"signal_audience\" | \"attention_ledger\" | \"impression_ledger\" | \"waterfall_events\" | \"intent_signals\" | \"audience_loyalty_features\" | \"screen_metadata\";\n};\n query: {\n days?: number;\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n lookback_days?: number;\n /** Row shape depends on the requested `dataset`. For `audience_loyalty_features` see `AudienceLoyaltyFeaturesRow`. For other datasets the row shape is documented per-dataset in the Trillboards data dictionary. */\n rows?: Array<AudienceLoyaltyFeaturesRow | Record<string, unknown>>;\n total?: number;\n truncated?: boolean;\n };\n success?: boolean;\n};\n}\n\n/**\n * Geographic audience panel (data-licensing)\n * GET /v1/partner/data/geohash-audience-panel\n */\nexport interface getGeohashAudiencePanelOperation {\n readonly path: \"/v1/partner/data/geohash-audience-panel\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n date?: string;\n geohash_prefix?: string;\n limit?: number;\n offset?: number;\n venue_category?: string;\n};\n response: {\n data?: {\n /** The build of the day this page read (UTC, `YYYY-MM-DD HH:MM:SS.mmm`). A day with no build is answered `404` `day_not_built`. */\n built_at: string;\n /** Day exported (UTC). */\n date: string;\n /** The panel's definition (2 since 2026-10-19). */\n definition_version: number;\n /** Rows per page this response was read with. */\n limit: number;\n /** The `offset` of the next page, or `null` on the last page. */\n next_offset: number | null;\n /** Rows skipped before this page. */\n offset: number;\n /** Integer partner_id (`partners.partner_id`). */\n partner_id: number;\n /** One row per (hour, geohash6, venue_category), every cell with its counts. */\n rows: Array<{\n /** Mean device head-pose index 0-1 over the camera windows. `null` when the cell-hour holds no camera window. */\n avg_attention: number | null;\n /** Mean dwell per window in milliseconds, each window's dwell capped at its own length, over the windows that carry a start time (dwell_capped_windows). `null`: No window of the row carries a start time (dwell_capped_windows = 0). */\n avg_dwell_ms: number | null;\n /** Mean capped dwell per camera window, seconds (`avg_dwell_ms` / 1000). `null` when no camera window of the cell-hour carries a start time. */\n avg_dwell_seconds: number | null;\n /** Mean faces per camera window. `null` when the cell-hour holds no camera window. */\n avg_face_count: number | null;\n /** The windows avg_dwell_ms averages: camera windows that carry a start time. */\n dwell_capped_windows: number;\n /** Of those, the face-backed windows. */\n face_backed_windows: number;\n /** Of those, the identifiers whose strongest signal was below it: the devices around the screen. Sources that report no signal strength (mDNS, SSDP, HTTP probe) are in neither split. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_key_slots: number | null;\n /** far_key_slots / radio_slots. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n far_keys_per_slot: number | null;\n /** Median age of those fixes at the window's instant. `null`: No camera window of the row was placed by a trail fix. */\n fix_age_p50_s: number | null;\n /** 90th-percentile age of those fixes. `null`: No camera window of the row was placed by a trail fix. */\n fix_age_p90_s: number | null;\n /** Camera windows of a fixed screen with no trail fix in the lookback, placed at its registered site. */\n fixed_site_positioned_windows: number;\n /** Geohash-6 cell (about 1.2 x 0.6 km) where the screen was at the unit's instant: on its map-matched path, else at its last GPS trail fix, else (a fixed screen) at its registered site. */\n geohash6: string;\n /** Start of the UTC hour, `YYYY-MM-DD HH:MM:SS`. A camera window counts in the hour it closed, a radio slot in the hour of its midpoint. */\n hour: string;\n /** `null` on every row: no income source joins the panel (definition 1 wrote `unknown`). */\n income_tier: string | null;\n /** Camera windows placed at the screen's last GPS fix at or before their instant. */\n last_fix_positioned_windows: number;\n /** The near-field boundary of the row's day: the active pass_audience method register's rf_near_rssi_dbm, the boundary the in-cab radio uses. */\n near_field_rssi_dbm: number;\n /** Of those, the identifiers whose strongest signal in the slot was at or above near_field_rssi_dbm: in the vehicle or against the screen. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_key_slots: number | null;\n /** near_key_slots / radio_slots: near-field identifiers concurrent in one slot. The approved metric radio_identifiers_per_person converts near-field passenger Bluetooth identifiers to people: it is measured in the cab, where the driver's phone and the vehicle's own devices are removed by role. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n near_keys_per_slot: number | null;\n /** Radio observations (pings) of those identifiers in the cell-hour (`radio_pings`). `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n observation_count: number | null;\n /** Camera-graded windows (face- or person-backed, ~10 s each) placed in the cell. */\n observation_windows: number;\n /** Exact 95th percentile of the per-window face reading over the row's windows. `null`: No camera window in the row. */\n p95_face_count: number | null;\n /** Camera windows placed on the map-matched vehicle path at their instant. */\n path_positioned_windows: number;\n /** Of those, the person-backed windows. */\n person_backed_windows: number;\n /** The windows persons_per_window averages. */\n person_reading_windows: number;\n /** Mean people in view per camera window, faced or not: per window the larger of its mean person count and its mean face count (the in-cab panel's persons reading), over the windows that carry one. `null`: No camera window of the row carries a persons reading (person_reading_windows = 0). */\n persons_per_window: number | null;\n /** Radio slots of a fixed screen with no trail fix in the lookback, placed at its registered site. */\n radio_fixed_site_positioned_slots: number;\n /** Radio slots placed at the screen's last GPS fix at or before their midpoint. */\n radio_last_fix_positioned_slots: number;\n /** Radio slots placed on the map-matched path at their midpoint. */\n radio_path_positioned_slots: number;\n /** Radio observations of the visitor identifiers in the row's slots. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_pings: number | null;\n /** Distinct screens whose radio slots the row holds. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n radio_screens: number | null;\n /** 6-minute radio slots of screens placed in the cell: a slot in which the screen's visitor radio read an identifier (a slot in which the scanner reported only the screen's own Wi-Fi access point does not show the visitor radio ran, and is no slot here). 0 when only camera windows fell in the row. */\n radio_slots: number;\n /** Distinct screens whose radio slots the cell-hour holds (`radio_screens`). `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n screen_count: number | null;\n /** Distinct screens whose camera windows the row holds. */\n screens: number;\n /** Distinct visitor-source radio identifiers (BLE, mDNS, SSDP, HTTP probe) over the cell-hour's radio slots, exact. A distinct count: rows do not add. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n unique_devices: number | null;\n /** The screen's registered venue category (`transit` for a vehicle screen); empty when the registry holds none. */\n venue_category: string;\n /** Visitor-source radio identifiers (BLE, mDNS, SSDP, HTTP probe) distinct within each slot, summed over the slots. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_key_slots: number | null;\n /** visitor_key_slots / radio_slots: identifiers concurrent in one 6-minute slot, every visitor source and both fields. `null`: No radio slot in the row (radio_slots = 0): only camera windows were placed there, and the radio was not read. */\n visitor_keys_per_slot: number | null;\n }>;\n /** `true` when more cells follow this page: request `next_offset`. */\n truncated: boolean;\n };\n success?: boolean;\n};\n}\n\n/**\n * Outcome-attribution export (data-licensing)\n * GET /v1/partner/data/outcome-attribution\n */\nexport interface getOutcomeAttributionOperation {\n readonly path: \"/v1/partner/data/outcome-attribution\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n creative_id?: string;\n cursor?: string;\n days?: number;\n grain?: \"person\" | \"device\";\n limit?: number;\n};\n response: {\n data?: {\n /** The reach grain applied (echoes the `grain` query param; defaults to `person`). */\n grain: \"person\" | \"device\";\n /** Rows per page this response was read with. */\n limit: number;\n /** The validated lookback window used. */\n lookback_days: number;\n /** The `cursor` of the next page, or `null` on the last page. */\n next_cursor: string | null;\n /** Per-(creative, screen) outcome aggregates, every cell with its counts. */\n rows: Array<{\n /** Average exposures per reach-identity within the (creative, screen) cell (count of detail rows / distinct reach keys). A frequency over PEOPLE under person grain, over devices under device grain. */\n avg_frequency: number;\n /** Creative identifier from `completed_impressions.creative_id`. */\n creative_id: string;\n /** Count of exposed identities also seen on another screen. */\n cross_screen_devices: number;\n /** Count of distinct devices exposed to the creative on the screen. */\n exposed_devices: number;\n /** returned_devices / exposed_devices. */\n return_rate: number;\n /** Count of exposed devices that returned (≤ exposed_devices). */\n returned_devices: number;\n /** The partner's own screen identifier. */\n screen_mongo_id: string;\n }>;\n /** Number of rows in this page. */\n total: number;\n /** `true` when more cells follow this page: pass `next_cursor` back as `cursor`. */\n truncated: boolean;\n /** The UTC date the window ends on, pinned by the first page; the window is `window_end - lookback_days` through `window_end`. */\n window_end: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Register a device\n * POST /v1/partner/device\n */\nexport interface registerDeviceOperation {\n readonly path: \"/v1/partner/device\";\n readonly method: \"POST\";\n request: {\n /** Any additional metadata for your records */\n custom_metadata?: Record<string, unknown>;\n /** Screen or venue description for enrichment */\n description?: string;\n /** Your internal device identifier */\n device_id: string;\n /** Mutable partner category; defaults to other only on a new registration. Omit it to preserve an existing device's category. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Screen display specification. `width`/`height` are pixel resolution; `width_in`/`height_in` are physical inches. For accurate floor pricing we need physical inches — pass `width_in` + `height_in` if you've measured the screen, OR `ppi` so the server can derive inches from the pixel resolution. Pixel-only inputs (no `ppi`, no `*_in`) will NOT be recorded as physical size; they're still used for orientation detection and DSP slot dimensions. */\n display?: {\n /** Display resolution height in pixels (e.g. 1080) */\n height?: number;\n /** Physical screen height in INCHES. Pairs with `width_in`. */\n height_in?: number;\n orientation?: \"landscape\" | \"portrait\";\n /** Pixels per inch. Required if you want physical screen size derived from `width`/`height` (server computes widthInches = width / ppi). Typical: 40 (large TV), 96 (desktop monitor), 264 (tablet). */\n ppi?: number;\n /** Display resolution width in pixels (e.g. 1920) */\n width?: number;\n /** Physical screen width in INCHES. Overrides ppi-based derivation. Use this when you've measured the actual screen (most accurate for pricing). */\n width_in?: number;\n };\n display_settings?: PartnerRegistrationDisplaySettings;\n location?: {\n address?: string;\n city?: string;\n country?: string;\n lat?: number;\n lng?: number;\n state?: string;\n timezone?: string;\n venue_name?: string;\n venue_type?: \"mall\" | \"airport\" | \"retail\" | \"restaurant\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"other\";\n zip?: string;\n };\n /** Reporting hints for moving screens (mobility_type mobile/semi_mobile). */\n mobile_settings?: {\n /** Minimum displacement before a fix is sent (device-side hint). */\n distance_threshold_meters?: number;\n /** Target GPS reporting interval (floor — the platform adapts to speed/battery). */\n update_interval_seconds?: number;\n vehicle_type?: \"taxi\" | \"rideshare\" | \"delivery\" | \"bus\" | \"food_truck\" | \"other\";\n };\n /** Declare a moving screen. `mobile` (taxi-top, transit) and `semi_mobile` (food truck, pop-up) screens report GPS via the heartbeat `location` field; `static` (default) screens ignore it. */\n mobility_type?: \"static\" | \"mobile\" | \"semi_mobile\";\n /** Friendly name for the device */\n name?: string;\n /** Photo URL for enrichment context */\n photo_url?: string;\n /** Optional additional photos for enrichment */\n photos?: Array<{\n /** photo type (context, close, angle, other) */\n type?: string;\n url?: string;\n }>;\n /** Physical placement details (optional) */\n placement?: {\n height_from_floor_ft?: number;\n mounting_type?: \"wall\" | \"ceiling\" | \"tabletop\" | \"window\" | \"stand\" | \"freestanding\" | \"floor_stand\" | \"counter\" | \"pole\" | \"vehicle\" | \"other\" | \"unknown\";\n orientation?: \"landscape\" | \"portrait\";\n viewing_distance_ft?: number;\n };\n /** Venue classification details (optional). Subcategory is free text and may be auto-enriched by AI. */\n venue?: {\n business_name?: string;\n category?: \"retail\" | \"restaurant\" | \"bar\" | \"cafe\" | \"hotel\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"mall\" | \"airport\" | \"gas_station\" | \"convenience_store\" | \"laundromat\" | \"salon\" | \"auto_shop\" | \"other\";\n context_notes?: string;\n environment_type?: \"indoor\" | \"outdoor\" | \"semi_outdoor\" | \"transit\";\n placement_type?: \"digital_signage\" | \"point_of_sale\" | \"waiting_area\" | \"window_display\" | \"kiosk\" | \"other\";\n /** Free text subcategory (may be auto-enriched by AI) */\n subcategory?: string;\n };\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Our internal device ID */\n device_id?: string;\n /** Saved partner category, independent of advertising classification. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Load this URL in your WebView */\n embed_url?: string;\n /** Enrichment completion state */\n enrichment_status?: string;\n /** Your device ID */\n external_device_id?: string;\n /** Device fingerprint for SDK */\n fingerprint?: string;\n location_capability?: PartnerLocationCapability;\n /** Stripe-style readiness. `ready` — the screen has its own coordinates and its venue is classified. `limited` — servable, but not on every rail: the venue is not yet classified, or the screen has no position of its own and is listed in inventory feeds at your fleet's market location. `blocked` — no rail has a location, or classification permanently failed. A device is never refused registration for missing location. */\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n requirements?: PartnerMonetizationRequirements;\n /** Linked screen ID */\n screen_id?: string;\n status?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Delete a device\n * DELETE /v1/partner/device/{deviceId}\n */\nexport interface deleteDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get device info\n * GET /v1/partner/device/{deviceId}\n */\nexport interface getDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: Device;\n success?: boolean;\n};\n}\n\n/**\n * Update device metadata\n * PATCH /v1/partner/device/{deviceId}\n */\nexport interface updateDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}\";\n readonly method: \"PATCH\";\n request: {\n /** Any additional metadata for your records */\n custom_metadata?: Record<string, unknown>;\n /** Screen or venue description */\n description?: string;\n /** Mutable partner category. Omit it to preserve the current value; changing it does not alter advertising classification. */\n device_type?: \"tv\" | \"tablet\" | \"display\" | \"kiosk\" | \"other\" | \"mobile\" | \"connected_tv\" | \"digital_signage\" | \"vending_machine\";\n /** Screen display specification. `width`/`height` are pixels; pass `width_in`/`height_in` (inches) or `ppi` to record physical screen size for floor pricing. See POST /device for full unit semantics. */\n display?: {\n /** Display resolution height in pixels */\n height?: number;\n /** Physical screen height in inches (pairs with width_in) */\n height_in?: number;\n orientation?: \"landscape\" | \"portrait\";\n /** Pixels per inch (required to derive physical size from width/height) */\n ppi?: number;\n /** Display resolution width in pixels */\n width?: number;\n /** Physical screen width in inches (overrides ppi-based derivation) */\n width_in?: number;\n };\n /** Partner-owned device ID used for idempotent lookup and reconciliation */\n external_device_id?: string;\n location?: {\n address?: string;\n city?: string;\n country?: string;\n lat?: number;\n lng?: number;\n state?: string;\n timezone?: string;\n /** Alias for `venue.category` — a granular venue type. Accepted on PATCH (previously documented on register only). When both are sent, `venue.category` wins. On the response this field returns the OpenOOH CHILD slug (e.g. \"hotels\"/\"malls\"); `venue.category` returns the parent. */\n venue_type?: \"mall\" | \"airport\" | \"retail\" | \"restaurant\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"other\";\n zip?: string;\n };\n /** Reporting hints for moving screens. Merges with existing settings. */\n mobile_settings?: {\n distance_threshold_meters?: number;\n update_interval_seconds?: number;\n vehicle_type?: \"taxi\" | \"rideshare\" | \"delivery\" | \"bus\" | \"food_truck\" | \"other\";\n };\n /** Update the screen's mobility. Set `mobile`/`semi_mobile` to have the heartbeat `location` field accepted for a moving screen. */\n mobility_type?: \"static\" | \"mobile\" | \"semi_mobile\";\n /** Friendly name for the device */\n name?: string;\n photo_url?: string;\n photos?: Array<{\n type?: string;\n url?: string;\n }>;\n placement?: {\n height_from_floor_ft?: number;\n mounting_type?: \"wall\" | \"ceiling\" | \"tabletop\" | \"window\" | \"stand\" | \"freestanding\" | \"floor_stand\" | \"counter\" | \"pole\" | \"vehicle\" | \"other\" | \"unknown\";\n orientation?: \"landscape\" | \"portrait\";\n viewing_distance_ft?: number;\n };\n venue?: {\n business_name?: string;\n /** Granular venue type on WRITE (child-level slug). On READ this returns the resolved OpenOOH PARENT (e.g. \"hotel\" write -> \"entertainment\" read); the child slug rides `venue.subcategory` and the numeric child id rides `venue.openooh_venue_type_id`. */\n category?: \"retail\" | \"restaurant\" | \"bar\" | \"cafe\" | \"hotel\" | \"office\" | \"gym\" | \"hospital\" | \"school\" | \"mall\" | \"airport\" | \"gas_station\" | \"convenience_store\" | \"laundromat\" | \"salon\" | \"auto_shop\" | \"other\";\n context_notes?: string;\n environment_type?: \"indoor\" | \"outdoor\" | \"semi_outdoor\" | \"transit\";\n /** Response-only. Canonical OpenOOH child id to reconcile the declared venue type against (e.g. 807 for hotels). */\n openooh_venue_type_id?: number;\n placement_type?: \"digital_signage\" | \"point_of_sale\" | \"waiting_area\" | \"window_display\" | \"kiosk\" | \"other\";\n /** OpenOOH child slug (e.g. \"hotels\"). Free text on write; resolved on read. */\n subcategory?: string;\n };\n};\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: Device;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get ads for device\n * GET /v1/partner/device/{deviceId}/ads\n */\nexport interface getAdsForDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}/ads\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: {\n autoplay?: boolean;\n ipd?: string;\n lang?: string;\n muted?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n slot_h?: number;\n slot_w?: number;\n test?: \"1\" | \"true\";\n ua?: string;\n};\n response: {\n data?: {\n ads?: Array<Ad>;\n cache_until?: string;\n /** Pending device commands to execute (remote management). */\n commands?: Array<{\n command?: string;\n id?: string;\n payload?: Record<string, unknown>;\n queued_at?: string;\n }>;\n /** Venue/content keywords for contextual targeting. Omitted from the response when empty. */\n content_keywords?: Array<string>;\n device?: {\n display?: {\n height?: number | null;\n width?: number | null;\n };\n fingerprint?: string;\n };\n /** DOOH context signals (venue type, geo, audience) forwarded to demand. */\n dooh_signals?: Record<string, unknown>;\n header_bidding_settings?: HeaderBiddingSettings;\n /** URL of the Trillboards-hosted IMA renderer for this screen, or null when the IMA player is not enabled for this deployment / there is no waterfall source. */\n ima_player_url?: string | null;\n screen_dimensions?: {\n height?: number;\n orientation?: \"portrait\" | \"landscape\";\n width?: number;\n };\n screen_id?: string;\n /** Serve locale derived from the venue country (e.g. \"en\", \"fr\"). */\n screen_locale?: string;\n screen_name?: string | null;\n screen_orientation?: \"portrait\" | \"landscape\";\n settings?: AdSettings;\n };\n success?: boolean;\n};\n}\n\n/**\n * Acknowledge a device command\n * POST /v1/partner/device/{deviceId}/commands/{commandId}/ack\n */\nexport interface ackDeviceCommandOperation {\n readonly path: \"/v1/partner/device/{deviceId}/commands/{commandId}/ack\";\n readonly method: \"POST\";\n request: {\n /** Command execution result */\n result?: Record<string, unknown>;\n /** Acknowledgment status */\n status?: string;\n};\n params: {\n commandId: string;\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Read live device heartbeat state\n * GET /v1/partner/device/{deviceId}/heartbeat\n */\nexport interface getDeviceHeartbeatOperation {\n readonly path: \"/v1/partner/device/{deviceId}/heartbeat\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: PartnerHeartbeatQueryResponse;\n}\n\n/**\n * Device heartbeat\n * POST /v1/partner/device/{deviceId}/heartbeat\n */\nexport interface heartbeatOperation {\n readonly path: \"/v1/partner/device/{deviceId}/heartbeat\";\n readonly method: \"POST\";\n request: PartnerHeartbeatRequest | PartnerDeviceHeartbeatBody;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: PartnerHeartbeatResponse;\n}\n\n/**\n * Update a device's publisher impression multiplier\n * PATCH /v1/partner/device/{deviceId}/impression-multiplier\n */\nexport interface updateDeviceImpressionMultiplierOperation {\n readonly path: \"/v1/partner/device/{deviceId}/impression-multiplier\";\n readonly method: \"PATCH\";\n request: {\n /** Publisher-declared audience impressions per ad play; stored to four decimal places */\n impression_multiplier: number;\n};\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n device_id?: string;\n external_device_id?: string;\n impression_multiplier?: number;\n screen_id?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Report a rider interaction from the partner SDK (reportInteraction)\n * POST /v1/partner/device/{deviceId}/interactions\n */\nexport interface recordPartnerDeviceInteractionOperation {\n readonly path: \"/v1/partner/device/{deviceId}/interactions\";\n readonly method: \"POST\";\n request: PartnerInteraction;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data: {\n interaction_id: string;\n /** The screen this device is bound to. */\n screen_id: string;\n status: \"accepted\" | \"duplicate\";\n type: \"tap\" | \"qr_shown\" | \"qr_scanned\" | \"dwell_prompt\" | \"seatbelt_reminder_shown\";\n };\n success: true;\n};\n}\n\n/**\n * Report a play from the partner SDK (reportPlay)\n * POST /v1/partner/device/{deviceId}/plays\n */\nexport interface recordPartnerDevicePlayOperation {\n readonly path: \"/v1/partner/device/{deviceId}/plays\";\n readonly method: \"POST\";\n request: PartnerDevicePlay;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data: {\n content_sha256: string;\n play_id: string;\n /** The screen this device is bound to. */\n screen_id: string;\n status: \"accepted\" | \"duplicate\";\n };\n success: true;\n};\n}\n\n/**\n * Record programmatic ad event (Server-side Analytics)\n * POST /v1/partner/device/{deviceId}/programmatic-event\n */\nexport interface recordProgrammaticEventOperation {\n readonly path: \"/v1/partner/device/{deviceId}/programmatic-event\";\n readonly method: \"POST\";\n request: {\n ad_id?: string;\n error_code?: string;\n error_message?: string;\n event: \"ad_started\" | \"ad_ended\" | \"no_fill\" | \"error\";\n reason?: string;\n request_id?: string;\n screen_orientation?: \"portrait\" | \"landscape\";\n slot_height?: number;\n slot_width?: number;\n variant_name?: string;\n};\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Report a taxi-meter state change from the partner SDK (setTripState)\n * POST /v1/partner/device/{deviceId}/trips\n */\nexport interface recordPartnerDeviceTripStateOperation {\n readonly path: \"/v1/partner/device/{deviceId}/trips\";\n readonly method: \"POST\";\n request: PartnerTripState;\n params: {\n deviceId: string;\n};\n query: Record<string, unknown>;\n response: {\n data: {\n event_seq: number;\n /** The screen this device is bound to. */\n screen_id: string;\n status: \"accepted\" | \"duplicate\";\n trip_id: string;\n };\n success: true;\n};\n}\n\n/**\n * Get fresh VAST for a registered device\n * GET /v1/partner/device/{deviceId}/vast\n */\nexport interface getVastForDeviceOperation {\n readonly path: \"/v1/partner/device/{deviceId}/vast\";\n readonly method: \"GET\";\n request: never;\n params: {\n deviceId: string;\n};\n query: {\n autoplay?: boolean;\n connection_type?: string;\n content_id?: string;\n device_memory?: number;\n dpr?: number;\n ipd?: string;\n lang?: string;\n make?: string;\n model?: string;\n muted?: boolean;\n orientation?: \"portrait\" | \"landscape\";\n os?: string;\n platform_hint?: string;\n screen_h?: number;\n screen_w?: number;\n sdk_type?: string;\n sdk_version?: string;\n slot_h?: number;\n slot_w?: number;\n stream_type?: string;\n test?: \"1\" | \"true\";\n ua?: string;\n vp_h?: number;\n vp_w?: number;\n};\n response: unknown;\n}\n\n/**\n * List all devices\n * GET /v1/partner/devices\n */\nexport interface listDevicesOperation {\n readonly path: \"/v1/partner/devices\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n status?: \"pending\" | \"active\" | \"offline\" | \"suspended\";\n};\n response: {\n data?: {\n devices?: Array<DeviceSummary>;\n limit?: number;\n offset?: number;\n total?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Register a device (V2 single-call onboarding)\n * POST /v1/partner/devices\n */\nexport interface registerDeviceV2Operation {\n readonly path: \"/v1/partner/devices\";\n readonly method: \"POST\";\n request: {\n /** Optional display dimensions. One of three modes — the `mode` discriminator is required. */\n display?: {\n /** Physical screen height in INCHES. Pairs with `width_in`. */\n height_in: number;\n mode: \"inches\";\n /** Physical screen width in INCHES. No upper bound — large-format / billboard inventory is valid. */\n width_in: number;\n } | {\n height: number;\n mode: \"pixels_with_ppi\";\n ppi: number;\n width: number;\n } | {\n height: number;\n mode: \"pixels_only\";\n width: number;\n };\n /** Your stable per-device identifier (e.g. \"REC00005\"). */\n external_id: string;\n /** Optional hardware identity — improves DSP device matching. */\n hardware?: {\n make?: string;\n model?: string;\n os?: \"Android\" | \"iOS\" | \"Tizen\" | \"WebOS\" | \"Linux\" | \"FireOS\" | \"Other\";\n osv?: string;\n };\n /** Optional venue location — either lat/lng coordinates or a street address. */\n location?: {\n lat: number;\n lng: number;\n } | {\n address: string;\n };\n /** The device's real WebView User-Agent. Must include a Build fingerprint and be unique per device. */\n ua: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n device_id?: string;\n diagnostics_url?: string;\n /** Paste into an iframe to start serving. */\n embed_url?: string;\n /** Server-derived canonical device identity. */\n identity?: {\n derivation_confidence?: number | null;\n derivation_source?: string | null;\n device_class?: string | null;\n make?: string | null;\n model?: string | null;\n os?: string | null;\n osv?: string | null;\n };\n };\n success?: boolean;\n};\n}\n\n/**\n * Bulk register devices\n * POST /v1/partner/devices/batch\n */\nexport interface registerDevicesBatchOperation {\n readonly path: \"/v1/partner/devices/batch\";\n readonly method: \"POST\";\n request: {\n /** Default fields applied to each device */\n defaults?: {\n display_settings?: PartnerRegistrationDisplaySettings;\n };\n devices: Array<{\n device_id: string;\n device_type?: string;\n display?: Record<string, unknown>;\n display_settings?: PartnerRegistrationDisplaySettings;\n location?: Record<string, unknown>;\n name?: string;\n placement?: Record<string, unknown>;\n venue?: Record<string, unknown>;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n devices?: Array<{\n device_id?: string;\n fingerprint?: string;\n location_capability?: PartnerLocationCapability;\n monetization_status?: \"ready\" | \"limited\" | \"blocked\";\n requirements?: PartnerMonetizationRequirements;\n screen_id?: string;\n status?: string;\n trillboard_id?: string;\n }>;\n errors?: Array<{\n device_id?: string;\n error?: string;\n /** Stable code, e.g. DEVICE_ID_CLAIMED (409 — a device that already reports to Trillboards under this id is registered to another account), REGISTRATION_CHECK_UNAVAILABLE (503 — retry), INVALID_COUNTRY (400). */\n error_code?: string;\n status?: string;\n }>;\n success?: boolean;\n summary?: {\n created?: number;\n failed?: number;\n total?: number;\n updated?: number;\n };\n};\n}\n\n/**\n * Batch update screen orientation\n * POST /v1/partner/devices/batch/orientation\n */\nexport interface batchUpdateDeviceOrientationOperation {\n readonly path: \"/v1/partner/devices/batch/orientation\";\n readonly method: \"POST\";\n request: {\n device_ids: Array<string>;\n screen_orientation: \"portrait\" | \"landscape\" | \"mixed\" | \"unknown\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n matched_devices?: number;\n missing_device_ids?: Array<string>;\n success?: boolean;\n total_devices?: number;\n updated_screens?: number;\n};\n}\n\n/**\n * Reconcile device fleet\n * POST /v1/partner/devices/reconcile\n */\nexport interface reconcileDevicesOperation {\n readonly path: \"/v1/partner/devices/reconcile\";\n readonly method: \"POST\";\n request: {\n /** Your device external IDs to reconcile. */\n external_ids: Array<string>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n duplicate?: Array<Record<string, unknown>>;\n malformed?: Array<Record<string, unknown>>;\n matched?: Array<Record<string, unknown>>;\n missing?: Array<string>;\n orphan?: Array<Record<string, unknown>>;\n success?: boolean;\n summary?: {\n duplicate?: number;\n malformed?: number;\n matched?: number;\n missing?: number;\n orphan?: number;\n registered_active?: number;\n requested?: number;\n };\n truncated?: Record<string, unknown>;\n};\n}\n\n/**\n * Browsable HTML documentation index\n * GET /v1/partner/docs\n */\nexport interface partnerDocsBrowserOperation {\n readonly path: \"/v1/partner/docs\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: unknown;\n}\n\n/**\n * Get earnings summary\n * GET /v1/partner/earnings\n */\nexport interface getEarningsOperation {\n readonly path: \"/v1/partner/earnings\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: EarningsResponse;\n success?: boolean;\n};\n}\n\n/**\n * Get detailed earnings breakdown\n * GET /v1/partner/earnings/breakdown\n */\nexport interface getEarningsBreakdownOperation {\n readonly path: \"/v1/partner/earnings/breakdown\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n end_date?: string;\n group_by?: \"day\" | \"week\" | \"screen\";\n start_date?: string;\n};\n response: {\n data?: EarningsBreakdownResponse;\n success?: boolean;\n};\n}\n\n/**\n * Request a payout\n * POST /v1/partner/earnings/payout\n */\nexport interface requestPayoutOperation {\n readonly path: \"/v1/partner/earnings/payout\";\n readonly method: \"POST\";\n request: {\n /** Amount to payout in cents (optional, defaults to available balance) */\n amount_cents?: number;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: PayoutResponse;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get transaction history\n * GET /v1/partner/earnings/transactions\n */\nexport interface getTransactionsOperation {\n readonly path: \"/v1/partner/earnings/transactions\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n type?: \"all\" | \"earning\" | \"payout\";\n};\n response: {\n data?: {\n pagination?: Pagination;\n transactions?: Array<Transaction>;\n };\n success?: boolean;\n};\n}\n\n/**\n * List active SSE connections\n * GET /v1/partner/events/connections\n */\nexport interface getActiveSSEConnectionsOperation {\n readonly path: \"/v1/partner/events/connections\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n connections?: Array<{\n connected_at?: string;\n connection_id?: string;\n ip?: string;\n subscribed_events?: Array<string>;\n }>;\n count?: number;\n max_connections?: number;\n object?: string;\n};\n}\n\n/**\n * Subscribe to real-time events (SSE)\n * GET /v1/partner/events/stream\n */\nexport interface subscribeToEventsOperation {\n readonly path: \"/v1/partner/events/stream\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n events?: string;\n};\n response: unknown;\n}\n\n/**\n * Poll a fleet-command job\n * GET /v1/partner/fleet-commands/{id}\n */\nexport interface getFleetCommandOperation {\n readonly path: \"/v1/partner/fleet-commands/{id}\";\n readonly method: \"GET\";\n request: never;\n params: {\n id: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n fleet_command?: FleetCommand;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get fleet analytics\n * GET /v1/partner/fleet/analytics\n */\nexport interface getFleetAnalyticsOperation {\n readonly path: \"/v1/partner/fleet/analytics\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Average attention score (0-1) over the fleet's audience windows in the last 24 hours. Omitted when it was not measured — no screen in scope had an audience window, or the audience read failed (see `avg_attention_outcome`); never a `0` that stands in for a missing measurement. */\n avg_attention?: number;\n /** Whether the attention average above was measured. `kind: ok` — the read ran (the average is omitted only when no screen had an audience window); `kind: unavailable` — the audience read failed, so the average is omitted. Independent of the other fields, which are served either way. */\n avg_attention_outcome?: {\n kind?: \"ok\" | \"unavailable\";\n message?: string;\n };\n /** Average CPM in dollars */\n avg_cpm?: number;\n /** Fill rate percentage (0-100) */\n fill_rate_pct?: number;\n impressions_24h?: number;\n screen_count?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Push command to fleet\n * POST /v1/partner/fleet/command\n */\nexport interface pushFleetCommandOperation {\n readonly path: \"/v1/partner/fleet/command\";\n readonly method: \"POST\";\n request: {\n command: {\n /** Command-specific data */\n payload?: Record<string, unknown>;\n type: \"reload\" | \"update_settings\" | \"restart\" | \"screenshot\" | \"clear_cache\" | \"update_content\" | \"refresh_ads\" | \"update_config\" | \"get_state\" | \"show_ad\" | \"play_ad\";\n };\n /** Optional filter to target specific devices */\n filter?: {\n country?: string;\n /** A screen group id (sg_) whose members are targeted (unioned with screenIds). */\n group?: string;\n screenIds?: Array<string>;\n venueType?: string;\n };\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n errors?: Array<{\n error?: string;\n screenId?: string;\n }>;\n /** Devices successfully queued */\n queued?: number;\n /** Total devices matching filter */\n targeted?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get fleet overview\n * GET /v1/partner/fleet/overview\n */\nexport interface getFleetOverviewOperation {\n readonly path: \"/v1/partner/fleet/overview\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n countries?: Record<string, number>;\n offline?: number;\n online?: number;\n programmatic_enabled?: number;\n total_devices?: number;\n venue_types?: Record<string, number>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Update fleet-wide settings\n * POST /v1/partner/fleet/settings\n */\nexport interface updateFleetSettingsOperation {\n readonly path: \"/v1/partner/fleet/settings\";\n readonly method: \"POST\";\n request: {\n filter?: {\n country?: string;\n /** A screen group id (sg_) whose members are targeted (unioned with screenIds). */\n group?: string;\n screenIds?: Array<string>;\n venueType?: string;\n };\n /** Settings to update (merged with existing) */\n settings: {\n content_preferences?: Record<string, unknown>;\n display_settings?: Record<string, unknown>;\n header_bidding_settings?: {\n allocation?: number;\n enabled?: boolean;\n force_request?: boolean;\n min_interval_seconds?: number;\n };\n };\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n errors?: Array<Record<string, unknown>>;\n targeted?: number;\n updated?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Record impression (pixel)\n * GET /v1/partner/impression\n */\nexport interface recordImpressionGetOperation {\n readonly path: \"/v1/partner/impression\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n adid: string;\n aid?: string;\n completed?: boolean;\n did?: string;\n display_area_ratio?: number;\n display_mode?: \"fullscreen\" | \"l-bar\" | \"pip\";\n duration?: number;\n impid: string;\n lbar_position?: \"bottom\" | \"right\";\n lbar_size?: number;\n lbar_slot_count?: number;\n lbar_slot_index?: number;\n sid?: string;\n sig?: string;\n sig_ts?: number;\n};\n response: {\n duplicate?: boolean;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Record impression (POST)\n * POST /v1/partner/impression\n */\nexport interface recordImpressionPostOperation {\n readonly path: \"/v1/partner/impression\";\n readonly method: \"POST\";\n request: {\n adid: string;\n aid?: string;\n completed?: boolean;\n did?: string;\n display_area_ratio?: number;\n display_mode?: \"fullscreen\" | \"l-bar\" | \"pip\";\n duration?: number;\n impid: string;\n lbar_position?: \"bottom\" | \"right\";\n lbar_size?: number;\n lbar_slot_count?: number;\n lbar_slot_index?: number;\n sid?: string;\n sig?: string;\n sig_ts?: number;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n duplicate?: boolean;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Batch record impressions\n * POST /v1/partner/impressions/batch\n */\nexport interface recordImpressionsBatchOperation {\n readonly path: \"/v1/partner/impressions/batch\";\n readonly method: \"POST\";\n request: {\n impressions: Array<{\n adid: string;\n aid?: string;\n completed?: boolean;\n device_fingerprint?: string;\n did?: string;\n display_area_ratio?: number;\n display_mode?: \"fullscreen\" | \"l-bar\" | \"pip\";\n duration?: number;\n impid: string;\n lbar_position?: \"bottom\" | \"right\";\n lbar_size?: number;\n lbar_slot_count?: number;\n lbar_slot_index?: number;\n sid?: string;\n sig?: string;\n sig_ts?: number;\n timestamp?: string;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n errors?: Array<{\n error?: string;\n impid?: string;\n }>;\n failed?: number;\n recorded?: number;\n skipped?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get partner info\n * GET /v1/partner/info\n */\nexport interface getPartnerInfoOperation {\n readonly path: \"/v1/partner/info\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: Partner;\n success?: boolean;\n};\n}\n\n/**\n * List intent categories\n * GET /v1/partner/intent/categories\n */\nexport interface listIntentCategoriesOperation {\n readonly path: \"/v1/partner/intent/categories\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n count?: number;\n data?: Array<{\n description?: string;\n id?: string;\n /** Minimum intent score to match this category */\n min_intent_score?: number;\n name?: string;\n /** CPM multiplier applied when this intent is detected */\n premium_multiplier?: number;\n purchase_stages?: Array<\"READY_TO_BUY\" | \"COMPARING\" | \"CONSIDERING\" | \"BROWSING\">;\n }>;\n object?: string;\n};\n}\n\n/**\n * Get intent category details\n * GET /v1/partner/intent/categories/{categoryId}\n */\nexport interface getIntentCategoryOperation {\n readonly path: \"/v1/partner/intent/categories/{categoryId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n categoryId: string;\n};\n query: Record<string, unknown>;\n response: {\n description?: string;\n iab_segments?: Array<Record<string, unknown>>;\n id?: string;\n min_intent_score?: number;\n name?: string;\n object?: string;\n premium_multiplier?: number;\n purchase_stages?: Array<string>;\n triggers?: Array<string>;\n};\n}\n\n/**\n * Get intent-based pricing for a screen\n * GET /v1/partner/intent/pricing/{screenId}\n */\nexport interface getIntentPricingOperation {\n readonly path: \"/v1/partner/intent/pricing/{screenId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n category_match?: {\n category_id?: string;\n category_name?: string;\n intent_score?: number;\n premium_multiplier?: number;\n purchase_stage?: string;\n } | null;\n current_intent?: {\n categories?: Array<string>;\n purchase_stage?: \"NONE\" | \"BROWSING\" | \"CONSIDERING\" | \"COMPARING\" | \"READY_TO_BUY\";\n /** Intent confidence score (0-1) */\n score?: number;\n /** Whether an ad swap should be triggered */\n should_trigger?: boolean;\n };\n object?: string;\n pricing?: {\n base_cpm?: number;\n category_id?: string;\n category_name?: string;\n /** Effective CPM after intent premium */\n intent_cpm?: number;\n /** Additional CPM from intent detection */\n intent_premium?: number;\n premium_multiplier?: number;\n };\n screen_id?: string;\n};\n}\n\n/**\n * Trillboards measurement methodology disclosure\n * GET /v1/partner/measurement-methodology\n */\nexport interface getMeasurementMethodologyOperation {\n readonly path: \"/v1/partner/measurement-methodology\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n format?: \"json\";\n};\n response: MeasurementMethodology;\n}\n\n/**\n * Measurement methodology disclosure (JSON, no negotiation)\n * GET /v1/partner/measurement-methodology.json\n */\nexport interface getMeasurementMethodologyJsonOperation {\n readonly path: \"/v1/partner/measurement-methodology.json\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: MeasurementMethodology;\n}\n\n/**\n * Get network configuration\n * GET /v1/partner/network-config\n */\nexport interface getNetworkConfigOperation {\n readonly path: \"/v1/partner/network-config\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n network_config?: PartnerNetworkConfig;\n object?: string;\n parent_partner_id?: string | null;\n};\n}\n\n/**\n * Partial update network configuration\n * PATCH /v1/partner/network-config\n */\nexport interface patchNetworkConfigOperation {\n readonly path: \"/v1/partner/network-config\";\n readonly method: \"PATCH\";\n request: PartnerNetworkConfigUpdate;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n network_config?: PartnerNetworkConfig;\n object?: string;\n parent_partner_id?: string | null;\n};\n}\n\n/**\n * Update network configuration\n * PUT /v1/partner/network-config\n */\nexport interface updateNetworkConfigOperation {\n readonly path: \"/v1/partner/network-config\";\n readonly method: \"PUT\";\n request: PartnerNetworkConfigUpdate;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n network_config?: PartnerNetworkConfig;\n object?: string;\n parent_partner_id?: string | null;\n};\n}\n\n/**\n * Network-wide audience and inventory trends\n * GET /v1/partner/network/trends\n */\nexport interface getNetworkTrendsOperation {\n readonly path: \"/v1/partner/network/trends\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n days?: number;\n};\n response: {\n audience_shift?: Array<Record<string, unknown>>;\n days?: number;\n venue_type_mix?: Array<Record<string, unknown>>;\n};\n}\n\n/**\n * Unauthenticated liveness probe\n * GET /v1/partner/ping\n */\nexport interface partnerPingOperation {\n readonly path: \"/v1/partner/ping\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n ok?: boolean;\n service?: string;\n};\n}\n\n/**\n * Authenticated liveness probe\n * GET /v1/partner/ping/auth\n */\nexport interface partnerPingAuthOperation {\n readonly path: \"/v1/partner/ping/auth\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n ok?: boolean;\n partner_id?: string;\n tier?: \"basic\" | \"developer\" | \"enterprise\";\n};\n}\n\n/**\n * Record a log-level play\n * POST /v1/partner/plays\n */\nexport interface recordPartnerPlayOperation {\n readonly path: \"/v1/partner/plays\";\n readonly method: \"POST\";\n request: PartnerPlay;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** The content hash the play named. Absent when the play sent no creative_ref. */\n content_sha256?: string;\n object?: string;\n play_id?: string;\n status?: \"accepted\" | \"duplicate\";\n};\n}\n\n/**\n * Record a batch of log-level plays\n * POST /v1/partner/plays/batch\n */\nexport interface recordPartnerPlaysBatchOperation {\n readonly path: \"/v1/partner/plays/batch\";\n readonly method: \"POST\";\n request: {\n plays: Array<PartnerPlay>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n accepted?: number;\n duplicate?: number;\n errors?: Array<{\n play_id?: string | null;\n reason?: string;\n }>;\n object?: string;\n rejected?: number;\n total?: number;\n};\n}\n\n/**\n * Get machine-readable pricing\n * GET /v1/partner/pricing\n */\nexport interface getPricingOperation {\n readonly path: \"/v1/partner/pricing\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n agent_register_url?: string;\n billing_setup_url?: string;\n /** Volume discount tiers for prepaid credits */\n committed_use?: Record<string, {\n credits_usd?: number;\n discount_pct?: number;\n price_usd?: number;\n }>;\n currency?: string;\n description?: string;\n /** Free tier limits per product and meter */\n free_tiers?: Record<string, unknown>;\n model?: string;\n object?: string;\n /** Pricing details per product */\n products?: {\n attribution?: {\n description?: string;\n meters?: Record<string, {\n first_campaign_free?: boolean;\n per_unit?: string;\n unit_price_usd?: number;\n }>;\n name?: string;\n };\n data_api?: {\n description?: string;\n name?: string;\n notes?: string;\n tiers?: Array<{\n unit_price_usd?: number;\n /** null means unlimited (final tier) */\n up_to?: number | null;\n }>;\n unit?: string;\n };\n data_marketplace?: {\n description?: string;\n meters?: Record<string, {\n free_quota_per_month?: number;\n per_unit?: string;\n unit_price_usd?: number;\n }>;\n name?: string;\n notes?: string;\n revenue_share?: Record<string, unknown>;\n };\n fein_edge_ai?: {\n description?: string;\n name?: string;\n pricing?: string;\n };\n partner_platform?: {\n description?: string;\n name?: string;\n pricing?: string;\n revenue_share?: {\n distributor?: number;\n earner?: number;\n platform?: number;\n };\n };\n programmatic?: {\n description?: string;\n name?: string;\n pricing?: string;\n };\n proof_of_play?: {\n description?: string;\n name?: string;\n notes?: string;\n tiers?: Array<{\n unit_price_usd?: number;\n up_to?: number | null;\n }>;\n unit?: string;\n };\n };\n request_id?: string;\n};\n}\n\n/**\n * Record programmatic ad event (legacy SDK alias)\n * POST /v1/partner/programmatic-event\n */\nexport interface recordProgrammaticEventLegacyAliasOperation {\n readonly path: \"/v1/partner/programmatic-event\";\n readonly method: \"POST\";\n request: {\n ad_id?: string;\n /** Device fingerprint or external device ID */\n device_id?: string;\n /** Short legacy device identifier alias */\n did?: string;\n error_code?: string;\n error_message?: string;\n event: \"ad_started\" | \"ad_ended\" | \"no_fill\" | \"error\";\n reason?: string;\n request_id?: string;\n type?: \"ad_started\" | \"ad_ended\" | \"no_fill\" | \"error\";\n variant_name?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Quick start — register partner and first device in one call\n * POST /v1/partner/quick-start\n */\nexport interface quickStartOperation {\n readonly path: \"/v1/partner/quick-start\";\n readonly method: \"POST\";\n request: {\n /** Company or partner name */\n company_name: string;\n /** Display configuration for the first device */\n device_display?: Record<string, unknown>;\n /** Location for the first device */\n device_location?: Record<string, unknown>;\n /** Name for the first device */\n device_name?: string;\n email: string;\n /** Optional legacy classification. Omit for the default self-serve Partner API key. */\n partner_type?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n credentials?: {\n /** Store securely — shown only once! */\n api_key?: string;\n api_key_prefix?: string;\n warning?: string;\n };\n device?: {\n device_id?: string;\n embed_url?: string;\n external_device_id?: string;\n fingerprint?: string;\n name?: string;\n screen_id?: string;\n status?: string;\n };\n integration?: {\n api_base?: string;\n docs_url?: string;\n embed_url?: string;\n iframe_snippet?: string;\n sdk_snippet?: string;\n sdk_url?: string;\n };\n next_steps?: Array<string>;\n partner?: {\n name?: string;\n partner_id?: string;\n revenue_share_percent?: number;\n slug?: string;\n status?: string;\n };\n sdk_config?: {\n ad_interval?: number;\n allowed_ad_types?: Array<string>;\n cache_size?: number;\n image_duration?: number;\n max_ads_per_hour?: number;\n sound_enabled?: boolean;\n };\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Register a new partner\n * POST /v1/partner/register\n */\nexport interface registerPartnerOperation {\n readonly path: \"/v1/partner/register\";\n readonly method: \"POST\";\n request: {\n /** Whitelist of allowed referrer domains */\n allowed_domains?: Array<string>;\n contact_email: string;\n contact_name?: string;\n /** Company or partner name */\n name: string;\n /** Optional legacy classification. Omit this field — it does not change which API key you receive. Existing integrations may continue sending historical values (including `ctv_publisher`) for backward compatibility; every partner_type mints the same self-serve Partner API key. */\n partner_type?: \"vending_machine\" | \"kiosk\" | \"digital_signage\" | \"retail_display\" | \"ctv_publisher\" | \"other\";\n /** Partner's revenue share percentage (negotiated per partner) */\n revenue_share_percent?: number;\n /** URL-safe identifier (lowercase, no spaces) */\n slug: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Store this securely - only shown once. This ONE self-serve Partner API key authenticates the general Partner API surface in this spec AND the CTV Measurement SDK ingestion surface (`/v2/sdk/*`, `/v2/csi`) — it carries `sdk:*` and `mcp:tools` by default, so no separate CTV or MCP key is issued. Reuse it during OpenRTB onboarding to add buyer capabilities. */\n api_key?: string;\n partner_id?: string;\n /** Optional portal onboarding details for the partner owner account */\n portal_access?: {\n claim_complete_endpoint?: string;\n claim_request_endpoint?: string;\n claim_required?: boolean;\n claim_verify_endpoint?: string;\n email?: string;\n message?: string;\n new_account?: boolean;\n portal_auth_url?: string;\n portal_url?: string;\n user_id?: string;\n };\n revenue_share_percent?: number;\n slug?: string;\n status?: \"pending\" | \"active\";\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Generate a test event\n * POST /v1/partner/sandbox/event\n */\nexport interface generateSandboxEventOperation {\n readonly path: \"/v1/partner/sandbox/event\";\n readonly method: \"POST\";\n request: {\n /** Event type to generate */\n event_type: string;\n /** Target sandbox screen (auto-selects first if omitted) */\n screen_id?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n /** Event payload (varies by event type) */\n data?: Record<string, unknown>;\n event?: string;\n event_id?: string;\n is_sandbox?: boolean;\n object?: string;\n screen_id?: string | null;\n /** Number of SSE connections that received this event */\n sse_delivered?: number;\n timestamp?: string;\n};\n}\n\n/**\n * Reset sandbox data\n * POST /v1/partner/sandbox/reset\n */\nexport interface resetSandboxOperation {\n readonly path: \"/v1/partner/sandbox/reset\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n events_cleared?: number;\n object?: string;\n reset_at?: string;\n screens_cleared?: number;\n success?: boolean;\n};\n}\n\n/**\n * Create a sandbox screen\n * POST /v1/partner/sandbox/screen\n */\nexport interface createSandboxScreenOperation {\n readonly path: \"/v1/partner/sandbox/screen\";\n readonly method: \"POST\";\n request: {\n /** Custom screen name */\n name?: string;\n /** Override venue type */\n venue_type?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n audience?: {\n avg_dwell_time_sec?: number;\n current_viewers?: number;\n demographics?: Record<string, unknown>;\n };\n created_at?: string;\n device_id?: string;\n display_settings?: Record<string, unknown>;\n fingerprint?: string;\n id?: string;\n is_sandbox?: boolean;\n last_heartbeat?: string;\n location?: {\n city?: string;\n latitude?: number;\n longitude?: number;\n name?: string;\n state?: string;\n venue_type?: string;\n };\n name?: string;\n object?: string;\n partner_id?: string;\n screen_id?: string;\n status?: string;\n};\n}\n\n/**\n * Get sandbox status\n * GET /v1/partner/sandbox/status\n */\nexport interface getSandboxStatusOperation {\n readonly path: \"/v1/partner/sandbox/status\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n last_activity?: string | null;\n object?: string;\n recent_events?: Array<{\n event?: string;\n event_id?: string;\n timestamp?: string;\n }>;\n sandbox_screens?: Array<{\n created_at?: string;\n id?: string;\n last_heartbeat?: string;\n location?: Record<string, unknown>;\n name?: string;\n status?: string;\n }>;\n total_screens?: number;\n total_test_events?: number;\n};\n}\n\n/**\n * List screen groups\n * GET /v1/partner/screen-groups\n */\nexport interface listScreenGroupsOperation {\n readonly path: \"/v1/partner/screen-groups\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n has_more?: boolean;\n object?: string;\n screen_groups?: Array<ScreenGroup>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create a screen group\n * POST /v1/partner/screen-groups\n */\nexport interface createScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups\";\n readonly method: \"POST\";\n request: {\n description?: string;\n name: string;\n screen_ids?: Array<string>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n screen_group?: ScreenGroup;\n };\n success?: boolean;\n};\n}\n\n/**\n * Delete (archive) a screen group\n * DELETE /v1/partner/screen-groups/{groupId}\n */\nexport interface deleteScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n deleted?: boolean;\n id?: string;\n object?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Retrieve a screen group\n * GET /v1/partner/screen-groups/{groupId}\n */\nexport interface getScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n screen_group?: ScreenGroup;\n };\n success?: boolean;\n};\n}\n\n/**\n * Update a screen group\n * POST /v1/partner/screen-groups/{groupId}\n */\nexport interface updateScreenGroupOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}\";\n readonly method: \"POST\";\n request: {\n description?: string;\n name?: string;\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n screen_group?: ScreenGroup;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get analytics for a screen group\n * GET /v1/partner/screen-groups/{groupId}/analytics\n */\nexport interface getScreenGroupAnalyticsOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/analytics\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n /** Fleet analytics scoped to the group's live member screens — the same payload as GET /fleet/analytics (which also returns an average attention score alongside the fields below). */\n data?: {\n avg_cpm?: number;\n fill_rate_pct?: number;\n group_id?: string;\n impressions_24h?: number;\n screen_count?: number;\n [key: string]: unknown;\n };\n success?: boolean;\n};\n}\n\n/**\n * Run a fleet command against a screen group\n * POST /v1/partner/screen-groups/{groupId}/commands\n */\nexport interface createScreenGroupCommandOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/commands\";\n readonly method: \"POST\";\n request: {\n command: {\n payload?: Record<string, unknown>;\n type: \"reload\" | \"update_settings\" | \"restart\" | \"screenshot\" | \"clear_cache\" | \"update_content\" | \"refresh_ads\" | \"update_config\" | \"get_state\" | \"show_ad\" | \"play_ad\";\n };\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n fleet_command?: FleetCommand;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get a screen group's content policy\n * GET /v1/partner/screen-groups/{groupId}/content-policy\n */\nexport interface getScreenGroupContentPolicyOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/content-policy\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n content_policy?: ScreenGroupContentPolicy;\n };\n success?: boolean;\n};\n}\n\n/**\n * Set a screen group's content policy\n * PUT /v1/partner/screen-groups/{groupId}/content-policy\n */\nexport interface updateScreenGroupContentPolicyOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/content-policy\";\n readonly method: \"PUT\";\n request: ScreenGroupContentPolicyInput;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n content_policy?: ScreenGroupContentPolicy;\n };\n success?: boolean;\n};\n}\n\n/**\n * Remove members from a screen group\n * DELETE /v1/partner/screen-groups/{groupId}/members\n */\nexport interface removeScreenGroupMembersOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/members\";\n readonly method: \"DELETE\";\n request: {\n screen_ids: Array<string>;\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n removed?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * List a screen group's members\n * GET /v1/partner/screen-groups/{groupId}/members\n */\nexport interface listScreenGroupMembersOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/members\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: {\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n data?: Array<{\n id?: string;\n object?: string;\n }>;\n has_more?: boolean;\n object?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Add members to a screen group\n * POST /v1/partner/screen-groups/{groupId}/members\n */\nexport interface addScreenGroupMembersOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/members\";\n readonly method: \"POST\";\n request: {\n screen_ids: Array<string>;\n};\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n added?: number;\n rejected?: Array<{\n id?: string;\n reason?: string;\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get a screen group's sensing config\n * GET /v1/partner/screen-groups/{groupId}/sensing-config\n */\nexport interface getScreenGroupSensingConfigOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/sensing-config\";\n readonly method: \"GET\";\n request: never;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n sensing_config?: ScreenGroupSensingConfig;\n };\n success?: boolean;\n};\n}\n\n/**\n * Set a screen group's sensing config\n * PUT /v1/partner/screen-groups/{groupId}/sensing-config\n */\nexport interface updateScreenGroupSensingConfigOperation {\n readonly path: \"/v1/partner/screen-groups/{groupId}/sensing-config\";\n readonly method: \"PUT\";\n request: ScreenGroupSensingConfigInput;\n params: {\n groupId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n sensing_config?: ScreenGroupSensingConfig;\n };\n success?: boolean;\n};\n}\n\n/**\n * OpenRTB SDA payload for a screen\n * GET /v1/partner/screen/{external_code}/audience-segments\n */\nexport interface getScreenAudienceSegmentsOperation {\n readonly path: \"/v1/partner/screen/{external_code}/audience-segments\";\n readonly method: \"GET\";\n request: never;\n params: {\n external_code: string;\n};\n query: {\n lookback_minutes?: number;\n};\n response: {\n device: {\n ext: {\n dooh?: {\n venuetypeid: number;\n };\n };\n };\n ext: {\n trillboards: {\n ad_fit_verdict?: Record<string, unknown>;\n authenticity_score?: number;\n freshness_seconds: number | null;\n iab_taxonomy_version: string;\n lookback_minutes: number;\n moment_count: number;\n profile_fields?: Record<string, unknown>;\n screen_external_code: string;\n signal_derived?: Record<string, unknown>;\n trillboards_taxonomy_version: string;\n [key: string]: unknown;\n };\n };\n user: {\n /** IAB Audience 1.1 blocks declare ext.segtax=4. Publisher-defined tb:* blocks omit ext.segtax. */\n data: Array<{\n ext?: {\n segtax: 4;\n };\n name: string;\n segment: Array<{\n id: string;\n }>;\n }>;\n };\n};\n}\n\n/**\n * Batch update content preferences\n * POST /v1/partner/screens/batch/content-preferences\n */\nexport interface batchUpdateContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/batch/content-preferences\";\n readonly method: \"POST\";\n request: {\n preferences?: ContentPreferencesInput;\n /** Preset ID to apply (alternative to preferences) */\n preset_id?: string;\n /** Array of screen IDs to update */\n screen_ids: Array<string>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: BatchResult;\n}\n\n/**\n * Batch update display settings\n * POST /v1/partner/screens/batch/display-settings\n */\nexport interface batchUpdateDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/batch/display-settings\";\n readonly method: \"POST\";\n request: {\n screen_ids: Array<string>;\n settings: DisplaySettingsInput;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: BatchResult;\n}\n\n/**\n * Batch update programmatic settings\n * POST /v1/partner/screens/batch/programmatic-settings\n */\nexport interface batchUpdateProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/batch/programmatic-settings\";\n readonly method: \"POST\";\n request: {\n screen_ids: Array<string>;\n settings: ProgrammaticSettingsInput;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: BatchResult;\n}\n\n/**\n * Resolve screen ID by device identifier\n * GET /v1/partner/screens/resolve\n */\nexport interface resolvePartnerScreenOperation {\n readonly path: \"/v1/partner/screens/resolve\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n device_id?: string;\n external_device_id?: string;\n fingerprint?: string;\n};\n response: {\n data?: {\n device_id?: string;\n external_device_id?: string;\n fingerprint?: string;\n screen_id?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get per-screen analytics\n * GET /v1/partner/screens/{screenId}/analytics\n */\nexport interface getScreenAnalyticsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n period?: \"7d\" | \"30d\" | \"90d\";\n};\n response: {\n data?: ScreenAnalyticsResponse;\n success?: boolean;\n};\n}\n\n/**\n * Current atmosphere (mood, noise, crowd density)\n * GET /v1/partner/screens/{screenId}/analytics/atmosphere\n */\nexport interface getPartnerScreenAtmosphereOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/atmosphere\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n crowdDensity?: string | null;\n currentViewers?: number | null;\n dataAge?: string;\n engagement?: number | null;\n lastUpdated?: string | null;\n mood?: string | null;\n noiseLevel?: string | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Time-bucketed venue intelligence with Lincoln-Petersen dedup\n * GET /v1/partner/screens/{screenId}/analytics/intelligence\n */\nexport interface getPartnerScreenIntelligenceOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/intelligence\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n from: string;\n interval?: \"5min\" | \"15min\" | \"1h\" | \"1d\";\n to: string;\n};\n response: {\n data?: {\n dedup?: {\n camera_count?: number;\n method?: string;\n raw_total?: number;\n unique_total?: number;\n };\n from?: string;\n interval?: string;\n screen_id?: string;\n summary?: {\n avg_attention?: number;\n buckets?: number;\n total_unique_viewers?: number;\n };\n timeseries?: Array<Record<string, unknown>>;\n to?: string;\n };\n status?: boolean;\n};\n}\n\n/**\n * Per-screen taste profile + top-5 creative categories\n * GET /v1/partner/screens/{screenId}/analytics/taste-profile\n */\nexport interface getPartnerScreenTasteProfileOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/taste-profile\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n computedAt?: string | null;\n daypartDistribution?: Record<string, unknown> | null;\n ready?: boolean;\n sampleCount?: number;\n screenId?: string;\n tasteVersionHash?: string | null;\n topCategories?: Array<Record<string, unknown>>;\n updatedAt?: string | null;\n venueType?: string | null;\n windowEnd?: string | null;\n windowStart?: string | null;\n };\n status?: boolean;\n};\n}\n\n/**\n * Hourly foot-traffic patterns for a screen\n * GET /v1/partner/screens/{screenId}/analytics/traffic\n */\nexport interface getPartnerScreenTrafficOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/traffic\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n};\n response: {\n data?: {\n busyScore?: number;\n hourlyTraffic?: Array<Record<string, unknown>>;\n periodDays?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Verified Attention Seconds + CPM tier for a screen\n * GET /v1/partner/screens/{screenId}/analytics/vas\n */\nexport interface getPartnerScreenVASOperation {\n readonly path: \"/v1/partner/screens/{screenId}/analytics/vas\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n avgAttentionScore?: number;\n avgFaceCount?: number;\n avgVasWeighted?: number;\n lastMeasurement?: string | null;\n medianVas?: number;\n multiplier?: number;\n p90Vas?: number;\n tier?: string;\n totalMeasurements?: number;\n };\n status?: boolean;\n};\n}\n\n/**\n * Apply content preset to screen\n * POST /v1/partner/screens/{screenId}/apply-preset\n */\nexport interface applyContentPresetOperation {\n readonly path: \"/v1/partner/screens/{screenId}/apply-preset\";\n readonly method: \"POST\";\n request: {\n /** ID of the preset to apply */\n preset_id: string;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse & {\n preset_applied?: string;\n };\n}\n\n/**\n * Get real-time audience metrics\n * GET /v1/partner/screens/{screenId}/audience-metrics\n */\nexport interface getAudienceMetricsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/audience-metrics\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n include_history?: boolean;\n period?: \"1h\" | \"6h\" | \"24h\";\n};\n response: AudienceMetricsResponse;\n}\n\n/**\n * Get screen content preferences\n * GET /v1/partner/screens/{screenId}/content-preferences\n */\nexport interface getContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/content-preferences\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse;\n}\n\n/**\n * Update content preferences (partial)\n * PATCH /v1/partner/screens/{screenId}/content-preferences\n */\nexport interface patchContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/content-preferences\";\n readonly method: \"PATCH\";\n request: ContentPreferencesInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse;\n}\n\n/**\n * Update content preferences (full)\n * PUT /v1/partner/screens/{screenId}/content-preferences\n */\nexport interface updateContentPreferencesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/content-preferences\";\n readonly method: \"PUT\";\n request: ContentPreferencesInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ContentPreferencesResponse;\n}\n\n/**\n * List default streams for a screen\n * GET /v1/partner/screens/{screenId}/default-streams\n */\nexport interface listPartnerDefaultStreamsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n current?: PartnerDefaultStream;\n streams?: Array<PartnerDefaultStream>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create a default stream (URL-based)\n * POST /v1/partner/screens/{screenId}/default-streams\n */\nexport interface createPartnerDefaultStreamOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams\";\n readonly method: \"POST\";\n request: PartnerDefaultStreamCreate;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Upload image carousel default stream\n * POST /v1/partner/screens/{screenId}/default-streams/images\n */\nexport interface createPartnerDefaultStreamImagesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/images\";\n readonly method: \"POST\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Reorder default streams\n * PUT /v1/partner/screens/{screenId}/default-streams/order\n */\nexport interface reorderPartnerDefaultStreamsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/order\";\n readonly method: \"PUT\";\n request: {\n order: Array<string>;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Upload a video default stream\n * POST /v1/partner/screens/{screenId}/default-streams/upload\n */\nexport interface createPartnerDefaultStreamUploadOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/upload\";\n readonly method: \"POST\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Delete a default stream\n * DELETE /v1/partner/screens/{screenId}/default-streams/{streamId}\n */\nexport interface deletePartnerDefaultStreamOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/{streamId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n screenId: string;\n streamId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Update a default stream\n * PUT /v1/partner/screens/{screenId}/default-streams/{streamId}\n */\nexport interface updatePartnerDefaultStreamOperation {\n readonly path: \"/v1/partner/screens/{screenId}/default-streams/{streamId}\";\n readonly method: \"PUT\";\n request: PartnerDefaultStreamUpdate;\n params: {\n screenId: string;\n streamId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerDefaultStream;\n success?: boolean;\n};\n}\n\n/**\n * Get screen demographics\n * GET /v1/partner/screens/{screenId}/demographics\n */\nexport interface getScreenDemographicsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/demographics\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n period?: \"24h\" | \"7d\" | \"30d\";\n};\n response: DemographicsResponse;\n}\n\n/**\n * Get display settings\n * GET /v1/partner/screens/{screenId}/display-settings\n */\nexport interface getDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/display-settings\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DisplaySettingsResponse;\n}\n\n/**\n * Update display settings (partial)\n * PATCH /v1/partner/screens/{screenId}/display-settings\n */\nexport interface patchDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/display-settings\";\n readonly method: \"PATCH\";\n request: DisplaySettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DisplaySettingsResponse;\n}\n\n/**\n * Update display settings (full)\n * PUT /v1/partner/screens/{screenId}/display-settings\n */\nexport interface updateDisplaySettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/display-settings\";\n readonly method: \"PUT\";\n request: DisplaySettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: DisplaySettingsResponse;\n}\n\n/**\n * Get L-Bar settings\n * GET /v1/partner/screens/{screenId}/l-bar\n */\nexport interface getPartnerLBarSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/l-bar\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerLBarSettings;\n success?: boolean;\n};\n}\n\n/**\n * Update L-Bar settings\n * PUT /v1/partner/screens/{screenId}/l-bar\n */\nexport interface updatePartnerLBarSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/l-bar\";\n readonly method: \"PUT\";\n request: {\n display_preferences?: PartnerLBarDisplayPreferences;\n l_bar_content?: PartnerLBarContent;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: PartnerLBarSettings;\n success?: boolean;\n};\n}\n\n/**\n * Update L-Bar live updates\n * PUT /v1/partner/screens/{screenId}/l-bar/live-updates\n */\nexport interface updatePartnerLBarLiveUpdatesOperation {\n readonly path: \"/v1/partner/screens/{screenId}/l-bar/live-updates\";\n readonly method: \"PUT\";\n request: {\n custom_status?: string;\n promotion?: string;\n queue_number?: string;\n wait_time_minutes?: number;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n success?: boolean;\n};\n}\n\n/**\n * Get programmatic settings\n * GET /v1/partner/screens/{screenId}/programmatic-settings\n */\nexport interface getProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/programmatic-settings\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ProgrammaticSettingsResponse;\n}\n\n/**\n * Update programmatic settings (partial)\n * PATCH /v1/partner/screens/{screenId}/programmatic-settings\n */\nexport interface patchProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/programmatic-settings\";\n readonly method: \"PATCH\";\n request: ProgrammaticSettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ProgrammaticSettingsResponse;\n}\n\n/**\n * Update programmatic settings (full)\n * PUT /v1/partner/screens/{screenId}/programmatic-settings\n */\nexport interface updateProgrammaticSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/programmatic-settings\";\n readonly method: \"PUT\";\n request: ProgrammaticSettingsInput;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: ProgrammaticSettingsResponse;\n}\n\n/**\n * Resolve the effective content policy for a screen\n * GET /v1/partner/screens/{screenId}/resolved-content-policy\n */\nexport interface getResolvedContentPolicyOperation {\n readonly path: \"/v1/partner/screens/{screenId}/resolved-content-policy\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: ResolvedContentPolicy;\n success?: boolean;\n};\n}\n\n/**\n * Resolve the effective sensing config for a screen\n * GET /v1/partner/screens/{screenId}/resolved-sensing-config\n */\nexport interface getResolvedSensingConfigOperation {\n readonly path: \"/v1/partner/screens/{screenId}/resolved-sensing-config\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: ResolvedSensingConfig;\n success?: boolean;\n};\n}\n\n/**\n * Read the custom sensing chips a screen is producing\n * GET /v1/partner/screens/{screenId}/sensing/chips\n */\nexport interface getScreenSensingChipsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/chips\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n limit?: number;\n offset?: number;\n};\n response: {\n data?: {\n /** The custom field_keys this screen senses (from its active profile) */\n fields?: Array<{\n description?: string;\n field_key?: string;\n type?: string;\n }>;\n /** Recent chip observations (one row per field_key per observation) */\n rows?: Array<Record<string, unknown>>;\n screen_id?: string;\n total?: number;\n truncated?: boolean;\n };\n success?: boolean;\n};\n}\n\n/**\n * Generate a custom sensing profile from a natural-language intent\n * POST /v1/partner/screens/{screenId}/sensing/interpret-intent\n */\nexport interface interpretScreenSensingIntentOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/interpret-intent\";\n readonly method: \"POST\";\n request: {\n /** Optional device-capability hint for model selection */\n deviceTier?: string;\n /** Natural-language description of what to sense */\n intent: string;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n /** The generated profile — pass to /sensing/profile to deploy */\n profile?: Record<string, unknown>;\n screen_id?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Deploy a custom sensing profile to a screen\n * POST /v1/partner/screens/{screenId}/sensing/profile\n */\nexport interface deployScreenSensingProfileOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/profile\";\n readonly method: \"POST\";\n request: {\n /** The sensing profile object returned by interpret-intent */\n profile: Record<string, unknown>;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n command?: Record<string, unknown>;\n profile?: Record<string, unknown>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Read a screen's AI sensing performance settings\n * GET /v1/partner/screens/{screenId}/sensing/settings\n */\nexport interface getScreenSensingSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/settings\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: SensingSettingsResponse;\n success?: boolean;\n};\n}\n\n/**\n * Update a screen's AI sensing performance mode\n * PATCH /v1/partner/screens/{screenId}/sensing/settings\n */\nexport interface updateScreenSensingSettingsOperation {\n readonly path: \"/v1/partner/screens/{screenId}/sensing/settings\";\n readonly method: \"PATCH\";\n request: {\n performance_mode: SensingPerformanceMode;\n};\n params: {\n screenId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n command?: Record<string, unknown>;\n profile?: Record<string, unknown>;\n settings?: SensingSettingsResponse;\n };\n success?: boolean;\n};\n}\n\n/**\n * List your Sense Anything Routes\n * GET /v1/partner/sensing/routes\n */\nexport interface listPartnerSensingRoutesOperation {\n readonly path: \"/v1/partner/sensing/routes\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n includeDisabled?: boolean;\n};\n response: {\n data?: {\n routes?: Array<SensingRoute>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create a Sense Anything Route (threshold or scheduled-digest alert)\n * POST /v1/partner/sensing/routes\n */\nexport interface createPartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes\";\n readonly method: \"POST\";\n request: CreatePartnerSensingRouteRequest;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n route?: SensingRoute;\n };\n success?: boolean;\n};\n}\n\n/**\n * Delete (soft) a Sense Anything Route\n * DELETE /v1/partner/sensing/routes/{routeId}\n */\nexport interface deletePartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes/{routeId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n routeId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n routeId?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get one Sense Anything Route\n * GET /v1/partner/sensing/routes/{routeId}\n */\nexport interface getPartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes/{routeId}\";\n readonly method: \"GET\";\n request: never;\n params: {\n routeId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n route?: SensingRoute;\n };\n success?: boolean;\n};\n}\n\n/**\n * Update a Sense Anything Route (partial, non-clobbering)\n * PATCH /v1/partner/sensing/routes/{routeId}\n */\nexport interface updatePartnerSensingRouteOperation {\n readonly path: \"/v1/partner/sensing/routes/{routeId}\";\n readonly method: \"PATCH\";\n request: UpdatePartnerSensingRouteRequest;\n params: {\n routeId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n route?: SensingRoute;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create Stripe Connect account\n * POST /v1/partner/stripe/connect\n */\nexport interface createStripeConnectAccountOperation {\n readonly path: \"/v1/partner/stripe/connect\";\n readonly method: \"POST\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string;\n charges_enabled?: boolean;\n country?: string;\n default_currency?: string;\n details_submitted?: boolean;\n next_step?: string | null;\n payouts_enabled?: boolean;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get Stripe dashboard login link\n * GET /v1/partner/stripe/login-link\n */\nexport interface getStripeLoginLinkOperation {\n readonly path: \"/v1/partner/stripe/login-link\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string;\n instructions?: string;\n login_url?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get Stripe onboarding link\n * GET /v1/partner/stripe/onboarding-link\n */\nexport interface getStripeOnboardingLinkOperation {\n readonly path: \"/v1/partner/stripe/onboarding-link\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string;\n expires_at?: string;\n instructions?: string;\n onboarding_url?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Request a payout\n * POST /v1/partner/stripe/payout\n */\nexport interface requestStripePayoutOperation {\n readonly path: \"/v1/partner/stripe/payout\";\n readonly method: \"POST\";\n request: {\n /** Payout amount in cents (minimum $5.00) */\n amount_cents: number;\n /** Optional description for the payout */\n description?: string;\n /** Deduplication key to prevent duplicate payouts */\n idempotency_key?: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n amount_cents?: number;\n created?: string;\n currency?: string;\n description?: string;\n destination?: string;\n /** Estimated arrival date (2-3 business days) */\n estimated_arrival?: string;\n status?: \"pending\" | \"reversed\";\n transfer_id?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get payout history\n * GET /v1/partner/stripe/payouts\n */\nexport interface getStripePayoutHistoryOperation {\n readonly path: \"/v1/partner/stripe/payouts\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n limit?: number;\n};\n response: {\n data?: {\n has_more?: boolean;\n total?: number;\n transfers?: Array<{\n amount_cents?: number;\n created?: string;\n currency?: string;\n description?: string;\n status?: \"completed\" | \"reversed\";\n transfer_id?: string;\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get Stripe account status\n * GET /v1/partner/stripe/status\n */\nexport interface getStripeAccountStatusOperation {\n readonly path: \"/v1/partner/stripe/status\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n account_id?: string | null;\n charges_enabled?: boolean;\n country?: string;\n default_currency?: string;\n details_submitted?: boolean;\n has_account?: boolean;\n payouts_enabled?: boolean;\n requirements?: {\n currently_due?: Array<string>;\n disabled_reason?: string | null;\n eventually_due?: Array<string>;\n past_due?: Array<string>;\n };\n status?: \"not_connected\" | \"pending\" | \"active\" | \"restricted\";\n };\n success?: boolean;\n};\n}\n\n/**\n * Stripe webhook receiver\n * POST /v1/partner/stripe/webhook\n */\nexport interface handleStripeWebhookOperation {\n readonly path: \"/v1/partner/stripe/webhook\";\n readonly method: \"POST\";\n request: Record<string, unknown>;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n event_type?: string;\n received?: boolean;\n};\n}\n\n/**\n * List team members\n * GET /v1/partner/team\n */\nexport interface listTeamMembersOperation {\n readonly path: \"/v1/partner/team\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n status?: \"active\" | \"pending\" | \"all\";\n};\n response: {\n data?: {\n members?: Array<TeamMember>;\n partner?: {\n name?: string;\n slug?: string;\n };\n total?: number;\n };\n success?: boolean;\n};\n}\n\n/**\n * Accept team invitation\n * POST /v1/partner/team/accept\n */\nexport interface acceptInvitationOperation {\n readonly path: \"/v1/partner/team/accept\";\n readonly method: \"POST\";\n request: {\n /** Invitation token from email link */\n token: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n partner?: {\n id?: string;\n name?: string;\n slug?: string;\n };\n permissions?: RolePermissions;\n portal_url?: string;\n role?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Invite a team member\n * POST /v1/partner/team/invite\n */\nexport interface inviteTeamMemberOperation {\n readonly path: \"/v1/partner/team/invite\";\n readonly method: \"POST\";\n request: {\n /** Email address of the invitee */\n email: string;\n /** Optional name of the invitee */\n name?: string;\n /** Role to assign to the team member */\n role?: \"admin\" | \"viewer\";\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: TeamInviteResponse;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get invitation details\n * GET /v1/partner/team/invite/{token}\n */\nexport interface getInvitationByTokenOperation {\n readonly path: \"/v1/partner/team/invite/{token}\";\n readonly method: \"GET\";\n request: never;\n params: {\n token: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n email?: string;\n expires_at?: string;\n invited_at?: string;\n partner?: {\n name?: string;\n slug?: string;\n };\n role?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Resend invitation\n * POST /v1/partner/team/{membershipId}/resend\n */\nexport interface resendInvitationOperation {\n readonly path: \"/v1/partner/team/{membershipId}/resend\";\n readonly method: \"POST\";\n request: never;\n params: {\n membershipId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n email?: string;\n expires_at?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Remove a team member\n * DELETE /v1/partner/team/{userId}\n */\nexport interface removeTeamMemberOperation {\n readonly path: \"/v1/partner/team/{userId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n userId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Change team member role\n * PATCH /v1/partner/team/{userId}/role\n */\nexport interface changeTeamMemberRoleOperation {\n readonly path: \"/v1/partner/team/{userId}/role\";\n readonly method: \"PATCH\";\n request: {\n role: \"admin\" | \"viewer\";\n};\n params: {\n userId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n new_role?: string;\n old_role?: string;\n permissions?: RolePermissions;\n user_id?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get public key for proof verification\n * GET /v1/partner/tracking/.well-known/public-key\n */\nexport interface getTrackingPublicKeyOperation {\n readonly path: \"/v1/partner/tracking/.well-known/public-key\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Signature algorithm (ed25519 for public key, sha256 for HMAC fallback) */\n algorithm?: \"ed25519\" | \"sha256\";\n documentation?: string;\n /** Key identifier for rotation support */\n keyId?: string;\n /** Hex-encoded Ed25519 public key (null if using HMAC fallback) */\n publicKey?: string | null;\n verificationUrl?: string;\n version?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * Record batch impressions with proof generation\n * POST /v1/partner/tracking/batch\n */\nexport interface recordTrackingBatchOperation {\n readonly path: \"/v1/partner/tracking/batch\";\n readonly method: \"POST\";\n request: {\n impressions: Array<{\n /** Ad identifier from VAST response */\n ad_id: string;\n /** Optional audience metrics */\n audience?: {\n /** Attention score (0-1) */\n attention?: number;\n /** How long viewers were present */\n dwell_time_ms?: number;\n /** Number of viewers detected */\n face_count?: number;\n };\n /** Partner's device identifier */\n device_id: string;\n /** Video duration played in milliseconds */\n duration_ms?: number;\n /** VAST event type */\n event?: \"start\" | \"complete\" | \"error\" | \"firstQuartile\" | \"midpoint\" | \"thirdQuartile\";\n /** Optional client-generated ID (auto-generated if not provided) */\n impression_id?: string;\n /** When the event occurred (defaults to now) */\n timestamp?: string;\n }>;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n /** Number of duplicate impressions skipped */\n duplicates?: number;\n /** Details of failed impressions (max 10 shown) */\n errors?: Array<{\n error?: string;\n impression_id?: string;\n }>;\n /** Number of impressions that failed validation */\n failed?: number;\n /** Number of impressions successfully recorded */\n processed?: number;\n /** Time to process the batch */\n processing_time_ms?: number;\n /** Cryptographic proofs for each processed impression */\n proofs?: Array<{\n impression_id?: string;\n public_key_id?: string;\n /** Ed25519 signature (or SHA256 fallback) */\n signature?: string;\n }>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Get API usage summary\n * GET /v1/partner/usage\n */\nexport interface getUsageSummaryOperation {\n readonly path: \"/v1/partner/usage\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n end_date?: string;\n start_date?: string;\n};\n response: {\n /** Average response time in milliseconds */\n avgResponseTime?: number;\n dailyBreakdown?: Array<{\n avg_response_ms?: number;\n /** The UTC day, sent as the timestamp of its midnight. */\n date?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n /** Error rate percentage (0-100) */\n errorRate?: number;\n object?: string;\n period?: {\n end_date?: string;\n start_date?: string;\n };\n topEndpoints?: Array<{\n endpoint?: string;\n method?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n totalCalls?: number;\n totalErrors?: number;\n};\n}\n\n/**\n * Get real-time usage dashboard\n * GET /v1/partner/usage/dashboard\n */\nexport interface getUsageDashboardOperation {\n readonly path: \"/v1/partner/usage/dashboard\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n last_7_days?: {\n avg_response_ms?: number;\n daily_breakdown?: Array<{\n avg_response_ms?: number;\n /** The UTC day, sent as the timestamp of its midnight. */\n date?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n error_rate?: number;\n total_calls?: number;\n total_errors?: number;\n };\n object?: string;\n rate_limit?: {\n current_rate?: number;\n max_rate?: number;\n percent_used?: number;\n window_reset?: string;\n window_seconds?: number;\n };\n today?: {\n avg_response_ms?: number;\n error_rate?: number;\n top_endpoints?: Array<{\n avg_response_ms?: number;\n endpoint?: string;\n method?: string;\n total_calls?: number;\n total_errors?: number;\n }>;\n total_calls?: number;\n total_errors?: number;\n };\n};\n}\n\n/**\n * Get rate limit status\n * GET /v1/partner/usage/rate-limit\n */\nexport interface getRateLimitStatusOperation {\n readonly path: \"/v1/partner/usage/rate-limit\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n current_rate?: number;\n max_rate?: number;\n object?: string;\n percent_used?: number;\n tier?: \"basic\" | \"developer\" | \"enterprise\";\n window_reset?: string;\n window_seconds?: number;\n};\n}\n\n/**\n * Get VAST configuration for direct Google integration\n * GET /v1/partner/vast/config\n */\nexport interface getVastConfigOperation {\n readonly path: \"/v1/partner/vast/config\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n device_id?: string;\n screen_id?: string;\n};\n response: {\n data?: {\n /** Google Ad Manager ad unit path */\n ad_unit?: string;\n /** IAB content categories to block */\n blocked_categories?: Array<string>;\n /** How long to cache this config */\n cache_ttl_seconds?: number;\n /** Floor price in cents (CPM) */\n floor_price_cpm?: number;\n integration_guide?: string;\n parameters?: {\n height?: number;\n /** Maximum ad duration in seconds */\n max_duration?: number;\n /** Minimum ad duration in seconds */\n min_duration?: number;\n /** Venue type code for targeting */\n venuetype?: number;\n width?: number;\n };\n /** Recommended VAST fetch timeout */\n timeout_ms?: number;\n tracking?: {\n batch_endpoint?: string;\n max_batch_size?: number;\n single_endpoint?: string;\n };\n /** Configuration variant name for debugging */\n variant?: string;\n /** VAST URL template with placeholders for {width} and {height}. Partner replaces placeholders and appends correlator. */\n vast_tag_template?: string;\n };\n success?: boolean;\n};\n}\n\n/**\n * List nearby Trillboards venues\n * GET /v1/partner/venues/nearby\n */\nexport interface getVenuesNearbyOperation {\n readonly path: \"/v1/partner/venues/nearby\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: {\n lat: number;\n lng: number;\n radius_km?: number;\n};\n response: {\n count?: number;\n venues?: Array<{\n distance_m?: number;\n screen_id?: string;\n venue_type?: string;\n }>;\n};\n}\n\n/**\n * Real-world atmosphere signals for a venue\n * GET /v1/partner/venues/{screenId}/atmosphere\n */\nexport interface getVenueAtmosphereOperation {\n readonly path: \"/v1/partner/venues/{screenId}/atmosphere\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n};\n response: {\n days?: number;\n dominant_ambience?: string;\n lighting_band?: \"dark\" | \"dim\" | \"lit\" | \"bright\";\n motion_intensity?: number;\n noise_level_db?: number;\n screen_id?: string;\n};\n}\n\n/**\n * Foot-traffic profile for a venue\n * GET /v1/partner/venues/{screenId}/traffic\n */\nexport interface getVenueTrafficOperation {\n readonly path: \"/v1/partner/venues/{screenId}/traffic\";\n readonly method: \"GET\";\n request: never;\n params: {\n screenId: string;\n};\n query: {\n days?: number;\n};\n response: {\n daily?: Array<Record<string, unknown>>;\n hourly?: Array<{\n face_count_avg?: number;\n hour?: number;\n }>;\n screen_id?: string;\n};\n}\n\n/**\n * Get venue intelligence report\n * GET /v1/partner/venues/{venueId}/intelligence\n */\nexport interface getVenueIntelligenceOperation {\n readonly path: \"/v1/partner/venues/{venueId}/intelligence\";\n readonly method: \"GET\";\n request: never;\n params: {\n venueId: string;\n};\n query: {\n from: string;\n interval?: \"5min\" | \"15min\" | \"1h\" | \"1d\";\n to: string;\n};\n response: {\n dedup?: {\n camera_count?: number;\n method?: \"lincoln_petersen\" | \"single_camera\";\n raw_total?: number;\n unique_total?: number;\n };\n from?: string;\n interval?: string;\n summary?: {\n avg_attention?: number;\n buckets?: number;\n total_unique_viewers?: number;\n };\n timeseries?: Array<{\n age_distribution?: Record<string, number>;\n avg_attention?: number;\n avg_engagement?: number;\n avg_noise_level?: number | null;\n brand_mention_windows?: number;\n bucket?: string;\n gender_distribution?: {\n female?: number;\n male?: number;\n };\n income_level?: string | null;\n measurements?: number;\n mood?: string | null;\n peak_viewers?: number;\n raw_viewers?: number;\n screen_count?: number;\n /** Deduplicated viewer count */\n viewers?: number;\n weather?: {\n condition?: string | null;\n is_raining?: boolean;\n temperature_f?: number | null;\n };\n }>;\n to?: string;\n venue_id?: string;\n};\n}\n\n/**\n * List webhooks\n * GET /v1/partner/webhooks\n */\nexport interface listWebhooksOperation {\n readonly path: \"/v1/partner/webhooks\";\n readonly method: \"GET\";\n request: never;\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n webhooks?: Array<Webhook>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Create webhook subscription\n * POST /v1/partner/webhooks\n */\nexport interface createWebhookOperation {\n readonly path: \"/v1/partner/webhooks\";\n readonly method: \"POST\";\n request: {\n /** Events to subscribe to */\n events: Array<\"device.online\" | \"device.offline\" | \"device.requirements_updated\" | \"impression.recorded\" | \"creative.rewards_ready\" | \"campaign.allocated\" | \"payout.processed\" | \"sensing.threshold_crossed\" | \"audience.spike\" | \"audience.venue_busy\" | \"audience.purchase_intent\" | \"audience.demographics_update\" | \"venue.traffic_summary\" | \"programmatic.ad_started\" | \"programmatic.ad_ended\" | \"programmatic.no_fill\" | \"programmatic.error\" | \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\" | \"fleet_command.completed\" | \"fleet_command.failed\">;\n /** Webhook endpoint URL (HTTPS required in production) */\n url: string;\n};\n params: Record<string, unknown>;\n query: Record<string, unknown>;\n response: {\n data?: {\n events?: Array<string>;\n /** Webhook signing secret (shown only once!) */\n secret?: string;\n status?: \"active\" | \"inactive\";\n url?: string;\n webhook_id?: string;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Delete webhook\n * DELETE /v1/partner/webhooks/{webhookId}\n */\nexport interface deleteWebhookOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}\";\n readonly method: \"DELETE\";\n request: never;\n params: {\n webhookId: string;\n};\n query: Record<string, unknown>;\n response: {\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Update webhook\n * PATCH /v1/partner/webhooks/{webhookId}\n */\nexport interface updateWebhookOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}\";\n readonly method: \"PATCH\";\n request: {\n events?: Array<\"device.online\" | \"device.offline\" | \"device.requirements_updated\" | \"impression.recorded\" | \"creative.rewards_ready\" | \"campaign.allocated\" | \"payout.processed\" | \"sensing.threshold_crossed\" | \"audience.spike\" | \"audience.venue_busy\" | \"audience.purchase_intent\" | \"audience.demographics_update\" | \"venue.traffic_summary\" | \"programmatic.ad_started\" | \"programmatic.ad_ended\" | \"programmatic.no_fill\" | \"programmatic.error\" | \"screen_group.created\" | \"screen_group.updated\" | \"screen_group.deleted\" | \"screen_group.member.added\" | \"screen_group.member.removed\" | \"screen_group.content_policy.updated\" | \"screen_group.sensing_config.updated\" | \"fleet_command.completed\" | \"fleet_command.failed\">;\n status?: \"active\" | \"inactive\";\n url?: string;\n};\n params: {\n webhookId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: Webhook;\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Get delivery history\n * GET /v1/partner/webhooks/{webhookId}/deliveries\n */\nexport interface getWebhookDeliveriesOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}/deliveries\";\n readonly method: \"GET\";\n request: never;\n params: {\n webhookId: string;\n};\n query: {\n limit?: number;\n};\n response: {\n data?: {\n deliveries?: Array<WebhookDelivery>;\n };\n success?: boolean;\n};\n}\n\n/**\n * Test webhook\n * POST /v1/partner/webhooks/{webhookId}/test\n */\nexport interface testWebhookOperation {\n readonly path: \"/v1/partner/webhooks/{webhookId}/test\";\n readonly method: \"POST\";\n request: never;\n params: {\n webhookId: string;\n};\n query: Record<string, unknown>;\n response: {\n data?: {\n error?: string | null;\n response_time_ms?: number;\n status?: number;\n };\n message?: string;\n success?: boolean;\n};\n}\n\n/**\n * Dry-run validate a request body against an operation schema\n * POST /v1/playground/{operation_id}\n */\nexport interface playgroundDryRunOperation {\n readonly path: \"/v1/playground/{operation_id}\";\n readonly method: \"POST\";\n request: never;\n params: {\n /** The operationId of the endpoint to validate against. */\n operation_id: string;\n};\n query: Record<string, unknown>;\n response: PlaygroundResult;\n}\n\n/**\n * Look up metadata for a recent API request\n * GET /v1/requests/{request_id}\n */\nexport interface getRequestMetadataOperation {\n readonly path: \"/v1/requests/{request_id}\";\n readonly method: \"GET\";\n request: never;\n params: {\n /** Server-generated request ID to look up. */\n request_id: string;\n};\n query: Record<string, unknown>;\n response: RequestMetadataResponse;\n}\n\n\n// ─── Type registry ───────────────────────────────────────────────────────\n\nexport const generatedTypes = {\n schemaCount: 329,\n operationCount: 298,\n schemas: [\"Ad\",\"AdSettings\",\"AdvertisingIdentity\",\"AnalyticsData\",\"AudienceAnalyticsResponse\",\"AudienceAttentionPrediction\",\"AudienceData\",\"AudienceExportResponse\",\"AudienceLoyaltyFeaturesRow\",\"AudienceMetricsResponse\",\"AudienceSegment\",\"AudienceSocialAttention\",\"BatchResult\",\"BillingInfo\",\"BleScanResultData\",\"CanonicalError\",\"ChangelogEntry\",\"ChangelogResponse\",\"CompletedImpressions\",\"ContentFitSettings\",\"ContentPreferencesInput\",\"ContentPreferencesResponse\",\"ContentPreset\",\"CreatePartnerSensingRouteRequest\",\"CreativeClassification\",\"CreativeRewardsReadyEvent\",\"DashboardResponse\",\"DataApi_AdSightingRecord\",\"DataApi_AdSightingsHistoryResponse\",\"DataApi_AdSightingsResponse\",\"DataApi_AggregateResponse\",\"DataApi_CreativeBrandHistoryRow\",\"DataApi_DataDelivery_ad_delivery_hourly\",\"DataApi_DataDelivery_attention_ledger\",\"DataApi_DataDelivery_auction_results\",\"DataApi_DataDelivery_audience_composition_weekly\",\"DataApi_DataDelivery_audience_metrics\",\"DataApi_DataDelivery_board_creative_sighting\",\"DataApi_DataDelivery_board_currency_multiweek\",\"DataApi_DataDelivery_board_flow_hourly\",\"DataApi_DataDelivery_board_pass_daily\",\"DataApi_DataDelivery_camera_frame_corpus\",\"DataApi_DataDelivery_camera_video_corpus\",\"DataApi_DataDelivery_completed_impressions\",\"DataApi_DataDelivery_creative_flights\",\"DataApi_DataDelivery_cross_screen_edges_daily\",\"DataApi_DataDelivery_curated_inventory_packages\",\"DataApi_DataDelivery_device_exposure_hourly\",\"DataApi_DataDelivery_device_exposure_windows\",\"DataApi_DataDelivery_dim_screen\",\"DataApi_DataDelivery_event_tracking\",\"DataApi_DataDelivery_geohash_activity_hourly\",\"DataApi_DataDelivery_impression_events\",\"DataApi_DataDelivery_inference_outcomes\",\"DataApi_DataDelivery_ip_geo_observations\",\"DataApi_DataDelivery_mobility_flows_daily\",\"DataApi_DataDelivery_observation_demographics\",\"DataApi_DataDelivery_omsdk_sessions\",\"DataApi_DataDelivery_panel_segment_cells\",\"DataApi_DataDelivery_place_activity_hourly\",\"DataApi_DataDelivery_play_audience\",\"DataApi_DataDelivery_play_audience_window\",\"DataApi_DataDelivery_play_device_exposure\",\"DataApi_DataDelivery_proximity_graph_edges_hourly\",\"DataApi_DataDelivery_public_attention_city_venue_hourly\",\"DataApi_DataDelivery_ride_places\",\"DataApi_DataDelivery_screen_hourly_presence\",\"DataApi_DataDelivery_screen_panel_monthly\",\"DataApi_DataDelivery_sighted_creatives\",\"DataApi_DataDelivery_vast_requests\",\"DataApi_DataProducts_AudienceRow\",\"DataApi_DataProducts_AuthError\",\"DataApi_DataProducts_Benchmark\",\"DataApi_DataProducts_BoardAudience\",\"DataApi_DataProducts_BoardAudienceResponse\",\"DataApi_DataProducts_BoardCurrency\",\"DataApi_DataProducts_BoardCurrencyResponse\",\"DataApi_DataProducts_BoardLookedShare\",\"DataApi_DataProducts_BoardLookedShareResponse\",\"DataApi_DataProducts_BoardPointCollection\",\"DataApi_DataProducts_BoardPointMeta\",\"DataApi_DataProducts_BoardPointProperties\",\"DataApi_DataProducts_BoardTiles\",\"DataApi_DataProducts_BoardTilesResponse\",\"DataApi_DataProducts_BrandMarket\",\"DataApi_DataProducts_BrandSearch\",\"DataApi_DataProducts_BrandSearchResponse\",\"DataApi_DataProducts_Calibration\",\"DataApi_DataProducts_CalibrationCell\",\"DataApi_DataProducts_CalibrationResponse\",\"DataApi_DataProducts_CalibrationVersion\",\"DataApi_DataProducts_CalibrationVersions\",\"DataApi_DataProducts_CalibrationVersionsResponse\",\"DataApi_DataProducts_CurationSet\",\"DataApi_DataProducts_CurationSetList\",\"DataApi_DataProducts_CurationSetListResponse\",\"DataApi_DataProducts_CurrencyAbsent\",\"DataApi_DataProducts_CurrencyBoard\",\"DataApi_DataProducts_CurrencyCell\",\"DataApi_DataProducts_DeliveryReport\",\"DataApi_DataProducts_DeliveryReportResponse\",\"DataApi_DataProducts_DmaFormatIndex\",\"DataApi_DataProducts_DmaFormatIndexResponse\",\"DataApi_DataProducts_DmaFormatIndexRow\",\"DataApi_DataProducts_FacingVerdict\",\"DataApi_DataProducts_FeedPublication\",\"DataApi_DataProducts_GeohashTileCollection\",\"DataApi_DataProducts_GeohashTileMeta\",\"DataApi_DataProducts_GeohashTileProperties\",\"DataApi_DataProducts_Geometry\",\"DataApi_DataProducts_LookedShareRow\",\"DataApi_DataProducts_MeasurementError\",\"DataApi_DataProducts_Method\",\"DataApi_DataProducts_MetricAnswer\",\"DataApi_DataProducts_MetricAnswerResponse\",\"DataApi_DataProducts_MetricBoardMeasuredImpressionsPerSpotResponse\",\"DataApi_DataProducts_MetricBoardPassAudienceResponse\",\"DataApi_DataProducts_MetricCameraDwellCappedMsResponse\",\"DataApi_DataProducts_MetricCameraGazePctResponse\",\"DataApi_DataProducts_MetricCameraHeadPoseIndexResponse\",\"DataApi_DataProducts_MetricCameraPeoplePerScreenHourResponse\",\"DataApi_DataProducts_MetricCatalog\",\"DataApi_DataProducts_MetricCatalogEntry\",\"DataApi_DataProducts_MetricCatalogResponse\",\"DataApi_DataProducts_MetricCreativeBrandHistoryResponse\",\"DataApi_DataProducts_MetricCreativeShareOfVoiceResponse\",\"DataApi_DataProducts_MetricCreativeSightingsResponse\",\"DataApi_DataProducts_MetricCreativeStreetPresenceResponse\",\"DataApi_DataProducts_MetricCreativeVacancyRateResponse\",\"DataApi_DataProducts_MetricDemographicShareResponse\",\"DataApi_DataProducts_MetricMeasure\",\"DataApi_DataProducts_MetricRadioIdentifiersPerPersonResponse\",\"DataApi_DataProducts_MetricSamePanelIndexResponse\",\"DataApi_DataProducts_MetricSeatbeltComplianceResponse\",\"DataApi_DataProducts_MetricSeatbeltUnbuckledRideRateResponse\",\"DataApi_DataProducts_MetricSensingCensusResponse\",\"DataApi_DataProducts_MultiplierFeed\",\"DataApi_DataProducts_MultiplierFeedResponse\",\"DataApi_DataProducts_OccluderCollection\",\"DataApi_DataProducts_OccluderMeta\",\"DataApi_DataProducts_OccluderProperties\",\"DataApi_DataProducts_OwnerFace\",\"DataApi_DataProducts_OwnerFaceDetail\",\"DataApi_DataProducts_OwnerFaceResponse\",\"DataApi_DataProducts_OwnerFaces\",\"DataApi_DataProducts_OwnerFacesResponse\",\"DataApi_DataProducts_OwnerUploadResponse\",\"DataApi_DataProducts_PassReplay\",\"DataApi_DataProducts_PassReplayResponse\",\"DataApi_DataProducts_Release\",\"DataApi_DataProducts_ReleaseRegistry\",\"DataApi_DataProducts_ReleaseRegistryResponse\",\"DataApi_DataProducts_ReplayPass\",\"DataApi_DataProducts_RoadCollection\",\"DataApi_DataProducts_RoadProperties\",\"DataApi_DataProducts_SetCoverage\",\"DataApi_DataProducts_SetCoverageEnvelope\",\"DataApi_DataProducts_SetCoverageResponse\",\"DataApi_DataProducts_SightedBrand\",\"DataApi_DataProducts_TileSum\",\"DataApi_DataProducts_ViewshedCollection\",\"DataApi_DataProducts_ViewshedMeta\",\"DataApi_DataProducts_ViewshedProperties\",\"DataApi_DataProducts_Watermark\",\"DataApi_DataProducts_Window\",\"DataApi_DataProducts_YieldReport\",\"DataApi_DataProducts_YieldReportResponse\",\"DataApi_Error\",\"DataApi_ErrorCode\",\"DataApi_FeedbackRewardQuery\",\"DataApi_LookalikeResponse\",\"DataApi_QueryDslBody\",\"DataApi_QueryDslResponse\",\"DataApi_QueryFilter\",\"DataApi_QueryOrderBy\",\"DataApi_ScreenAudienceResponse\",\"DataApi_ScreenHistoryResponse\",\"DataApi_ScreensListResponse\",\"DataApi_SemanticSearchResponse\",\"DataApi_StatsResponse\",\"DataApi_StreamResponse\",\"DataApi_UsageResponse\",\"DataExportSummaryResponse\",\"DemandPartners\",\"DemographicsResponse\",\"Device\",\"DeviceAuthRefusal\",\"DeviceCapabilityPayload\",\"DeviceSummary\",\"DisplaySettingsInput\",\"DisplaySettingsResponse\",\"EarnerScreens\",\"EarningsBreakdownResponse\",\"EarningsData\",\"EarningsResponse\",\"EarningsSources\",\"Error\",\"ErrorCode\",\"ErrorCodeResponse\",\"ErrorEntry\",\"ErrorEnvelope\",\"ErrorListItem\",\"ErrorListResponse\",\"ErrorType\",\"ExtendedIdentity\",\"FeedbackBrand\",\"FeedbackBrandRequest\",\"FeedbackBrandResponse\",\"FeedbackCreateRequest\",\"FeedbackCreativeReview\",\"FeedbackExperiment\",\"FeedbackExperimentDetail\",\"FeedbackExperimentDetailResponse\",\"FeedbackExperimentResponse\",\"FeedbackGenerateRequest\",\"FeedbackGenerateResponse\",\"FeedbackGeneratedCreative\",\"FeedbackImportRequest\",\"FeedbackPolicyRequest\",\"FeedbackRecoveredCreative\",\"FeedbackRegisterVariantsRequest\",\"FeedbackReviewRequest\",\"FeedbackReviewResponse\",\"FeedbackRewardQuery\",\"FeedbackRewardRow\",\"FeedbackRewards\",\"FeedbackRewardsResponse\",\"FeedbackStopRequest\",\"FeedbackVariant\",\"FleetCommand\",\"FleetCommandEvent\",\"HeaderBiddingSettings\",\"HttpProbeResult\",\"HybridError\",\"Impression\",\"LegacyCodedError\",\"LegacyError\",\"Mcp_create_media_buy_Args\",\"Mcp_discover_inventory_Args\",\"Mcp_get_media_buy_delivery_Args\",\"Mcp_get_media_buys_Args\",\"Mcp_get_products_Args\",\"Mcp_list_accounts_Args\",\"Mcp_sync_accounts_Args\",\"Mcp_sync_creatives_Args\",\"Mcp_update_media_buy_Args\",\"MdnsNetworkDevice\",\"MeasurementMethodology\",\"OpenrtbRevenueScreenHourly\",\"Pagination\",\"Partner\",\"PartnerAdDeliveryProfile\",\"PartnerCreativeWarnings\",\"PartnerDefaultStream\",\"PartnerDefaultStreamCreate\",\"PartnerDefaultStreamUpdate\",\"PartnerDeviceBatchRegistrationInput\",\"PartnerDeviceHeartbeatBody\",\"PartnerDevicePlay\",\"PartnerDeviceRegistrationInput\",\"PartnerHeartbeatCommand\",\"PartnerHeartbeatData\",\"PartnerHeartbeatMeasurementMetadata\",\"PartnerHeartbeatQueryData\",\"PartnerHeartbeatQueryResponse\",\"PartnerHeartbeatRequest\",\"PartnerHeartbeatResponse\",\"PartnerHeartbeatTelemetry\",\"PartnerInteraction\",\"PartnerLBarContent\",\"PartnerLBarDisplayPreferences\",\"PartnerLBarSettings\",\"PartnerLocationCapability\",\"PartnerLocationRail\",\"PartnerMonetizationRequirements\",\"PartnerNetworkConfig\",\"PartnerNetworkConfigUpdate\",\"PartnerPlay\",\"PartnerReconciliationReports\",\"PartnerRegistrationDisplaySettings\",\"PartnerRequirement\",\"PartnerSafeHeartbeatTelemetry\",\"PartnerSelfPromoAd\",\"PartnerSelfPromoCreate\",\"PartnerSelfPromoPlacement\",\"PartnerStats\",\"PartnerTripState\",\"PartnerVariants\",\"PartnerZoneCpmDaily\",\"PayoutResponse\",\"PlaygroundResult\",\"PlaygroundValidationError\",\"ProgrammaticSettingsInput\",\"ProgrammaticSettingsResponse\",\"RequestMetadataResponse\",\"ResolvedContentPolicy\",\"ResolvedSensingConfig\",\"RolePermissions\",\"SDKConfig\",\"Screen\",\"ScreenAnalyticsResponse\",\"ScreenGroup\",\"ScreenGroupContentPolicy\",\"ScreenGroupContentPolicyInput\",\"ScreenGroupEvent\",\"ScreenGroupSensingConfig\",\"ScreenGroupSensingConfigInput\",\"SensingPerformanceMode\",\"SensingRoute\",\"SensingRouteAction\",\"SensingRouteCondition\",\"SensingRouteReviewTimingMode\",\"SensingRouteReviewWaitSeconds\",\"SensingRouteScreenFocusRegion\",\"SensingSettingsResponse\",\"SensingThresholdCrossedEvent\",\"SsdpDeviceInfo\",\"TeamInviteResponse\",\"TeamMember\",\"Transaction\",\"TrillboardsError\",\"UpdatePartnerSensingRouteRequest\",\"VastWaterfall\",\"VastWaterfallSource\",\"Webhook\",\"WebhookDelivery\",\"WebhookEvent\",\"WifiEnvironmentSnapshot\",\"WifiScanResult\"] as const,\n operations: [\"getAdSightingFrame\",\"getAdSightingPhoto\",\"listAdSightingsInPortal\",\"listAdSightingHistoryInPortal\",\"listMeasuredBoards\",\"getMeasuredBoardAudience\",\"getMeasuredBoardCurrency\",\"getMeasuredBoardLookedShare\",\"getMeasuredBoardOccluders\",\"getMeasuredBoardPassReplay\",\"getMeasuredBoardTiles\",\"getMeasuredBoardViewshed\",\"searchSightedBrands\",\"getMeasurementCalibration\",\"listMeasurementCalibrationVersions\",\"listCurationSets\",\"getCurationSetCoverage\",\"getCurationSetRoads\",\"getCurationSetViewsheds\",\"getMeasuredMultiplierFeed\",\"getMeasuredDmaFormatIndex\",\"listApprovedMetrics\",\"getMetricBoardMeasuredImpressionsPerSpot\",\"getMetricBoardPassAudience\",\"getMetricCameraDwellCappedMs\",\"getMetricCameraGazePct\",\"getMetricCameraHeadPoseIndex\",\"getMetricCameraPeoplePerScreenHour\",\"getMetricCreativeBrandHistory\",\"getMetricCreativeShareOfVoice\",\"getMetricCreativeSightings\",\"getMetricCreativeStreetPresence\",\"getMetricCreativeVacancyRate\",\"getMetricDemographicShare\",\"getMetricRadioIdentifiersPerPerson\",\"getMetricSamePanelIndex\",\"getMetricSeatbeltCompliance\",\"getMetricSeatbeltUnbuckledRideRate\",\"getMetricSensingCensus\",\"getApprovedMetric\",\"listMeasurementReleases\",\"listMeasuredRoads\",\"listMeasuredGeohashTiles\",\"queryChangelog\",\"dataApiAdSightings\",\"dataApiAdSightingsHistory\",\"dataApiAggregate\",\"dataApiLookalikeScreens\",\"dataApiQueryDsl\",\"dataApiListScreens\",\"dataApiScreenAudienceLive\",\"dataApiScreenAudienceHistory\",\"dataApiSemanticSearch\",\"dataApiStats\",\"dataApiStream\",\"dataApiUsage\",\"listErrorCodes\",\"getErrorCode\",\"getOwnerBoardAudience\",\"getOwnerBoardCurrency\",\"getOwnerDeliveryReport\",\"getOwnerBoardLookedShare\",\"getOwnerBoardTiles\",\"getOwnerBoardViewshed\",\"listOwnerFaces\",\"getOwnerFace\",\"getOwnerMultiplierFeed\",\"uploadOwnerPlayLogs\",\"getOwnerPublisherYieldByQuery\",\"getOwnerPublisherYield\",\"listOwnerMeasurementReleases\",\"uploadOwnerFaceSpecs\",\"listPartnerSelfPromoAds\",\"createPartnerSelfPromoAd\",\"listPartnerSelfPromoPlacements\",\"schedulePartnerSelfPromo\",\"createPartnerSelfPromoUpload\",\"disableSelfPromoAd\",\"registerAgent\",\"getAnalytics\",\"getAudienceContinuity\",\"getAudienceProfile\",\"getBleSummary\",\"getContentPerformance\",\"searchCreativeCatalog\",\"getCreativeObservations\",\"getCreativeScenes\",\"getCrossScreenFlow\",\"getPartnerAnalyticsDashboard\",\"getDeviceSuiteSignature\",\"exportPartnerAnalytics\",\"exportPartnerAdsByDay\",\"getFleetHourly\",\"getHaloFunnel\",\"getLoyaltyClock\",\"getNetworkSummary\",\"getNetworkTrend\",\"getProximitySummary\",\"getRevenueAttentionCorrelation\",\"getSceneFeed\",\"getSceneIntelligence\",\"rotateApiKey\",\"getAudienceAnalytics\",\"exportAudienceData\",\"getAudienceHeatmap\",\"getLiveAudience\",\"getLookalikeScreens\",\"predictScreenAudience\",\"getResolvedHouseholdReach\",\"listAudienceSegments\",\"createAudienceSegment\",\"deleteAudienceSegment\",\"getAudienceSegment\",\"updateAudienceSegment\",\"matchAudienceSegment\",\"estimateSegmentReach\",\"generateSegmentVastTag\",\"getAudienceStats\",\"cancelBillingSubscription\",\"purchaseCredits\",\"createCreditCheckout\",\"listBillingPlans\",\"setupBilling\",\"createBillingSubscription\",\"getBillingSubscription\",\"getBillingUsage\",\"getBillingUsageSummary\",\"stripeWebhookCallback\",\"getConnectDashboard\",\"getConnectEarningsChart\",\"getConnectScreenHealth\",\"listContentPresets\",\"getContentPreset\",\"createCreativeFeedbackExperiment\",\"getCreativeFeedbackExperiment\",\"configureCreativeFeedbackBrand\",\"generateCreativeFeedbackCreative\",\"importCreativeFeedbackCreative\",\"reviewCreativeFeedbackCreative\",\"updateCreativeFeedbackPolicy\",\"getCreativeFeedbackRewards\",\"stopCreativeFeedbackExperiment\",\"registerCreativeFeedbackVariants\",\"submitPartnerCreative\",\"getPartnerCreative\",\"getDashboard\",\"exportProximityGraphEdges\",\"getDataExportSummary\",\"exportDataset\",\"getGeohashAudiencePanel\",\"getOutcomeAttribution\",\"registerDevice\",\"deleteDevice\",\"getDevice\",\"updateDevice\",\"getAdsForDevice\",\"ackDeviceCommand\",\"getDeviceHeartbeat\",\"heartbeat\",\"updateDeviceImpressionMultiplier\",\"recordPartnerDeviceInteraction\",\"recordPartnerDevicePlay\",\"recordProgrammaticEvent\",\"recordPartnerDeviceTripState\",\"getVastForDevice\",\"listDevices\",\"registerDeviceV2\",\"registerDevicesBatch\",\"batchUpdateDeviceOrientation\",\"reconcileDevices\",\"partnerDocsBrowser\",\"getEarnings\",\"getEarningsBreakdown\",\"requestPayout\",\"getTransactions\",\"getActiveSSEConnections\",\"subscribeToEvents\",\"getFleetCommand\",\"getFleetAnalytics\",\"pushFleetCommand\",\"getFleetOverview\",\"updateFleetSettings\",\"recordImpressionGet\",\"recordImpressionPost\",\"recordImpressionsBatch\",\"getPartnerInfo\",\"listIntentCategories\",\"getIntentCategory\",\"getIntentPricing\",\"getMeasurementMethodology\",\"getMeasurementMethodologyJson\",\"getNetworkConfig\",\"patchNetworkConfig\",\"updateNetworkConfig\",\"getNetworkTrends\",\"partnerPing\",\"partnerPingAuth\",\"recordPartnerPlay\",\"recordPartnerPlaysBatch\",\"getPricing\",\"recordProgrammaticEventLegacyAlias\",\"quickStart\",\"registerPartner\",\"generateSandboxEvent\",\"resetSandbox\",\"createSandboxScreen\",\"getSandboxStatus\",\"listScreenGroups\",\"createScreenGroup\",\"deleteScreenGroup\",\"getScreenGroup\",\"updateScreenGroup\",\"getScreenGroupAnalytics\",\"createScreenGroupCommand\",\"getScreenGroupContentPolicy\",\"updateScreenGroupContentPolicy\",\"removeScreenGroupMembers\",\"listScreenGroupMembers\",\"addScreenGroupMembers\",\"getScreenGroupSensingConfig\",\"updateScreenGroupSensingConfig\",\"getScreenAudienceSegments\",\"batchUpdateContentPreferences\",\"batchUpdateDisplaySettings\",\"batchUpdateProgrammaticSettings\",\"resolvePartnerScreen\",\"getScreenAnalytics\",\"getPartnerScreenAtmosphere\",\"getPartnerScreenIntelligence\",\"getPartnerScreenTasteProfile\",\"getPartnerScreenTraffic\",\"getPartnerScreenVAS\",\"applyContentPreset\",\"getAudienceMetrics\",\"getContentPreferences\",\"patchContentPreferences\",\"updateContentPreferences\",\"listPartnerDefaultStreams\",\"createPartnerDefaultStream\",\"createPartnerDefaultStreamImages\",\"reorderPartnerDefaultStreams\",\"createPartnerDefaultStreamUpload\",\"deletePartnerDefaultStream\",\"updatePartnerDefaultStream\",\"getScreenDemographics\",\"getDisplaySettings\",\"patchDisplaySettings\",\"updateDisplaySettings\",\"getPartnerLBarSettings\",\"updatePartnerLBarSettings\",\"updatePartnerLBarLiveUpdates\",\"getProgrammaticSettings\",\"patchProgrammaticSettings\",\"updateProgrammaticSettings\",\"getResolvedContentPolicy\",\"getResolvedSensingConfig\",\"getScreenSensingChips\",\"interpretScreenSensingIntent\",\"deployScreenSensingProfile\",\"getScreenSensingSettings\",\"updateScreenSensingSettings\",\"listPartnerSensingRoutes\",\"createPartnerSensingRoute\",\"deletePartnerSensingRoute\",\"getPartnerSensingRoute\",\"updatePartnerSensingRoute\",\"createStripeConnectAccount\",\"getStripeLoginLink\",\"getStripeOnboardingLink\",\"requestStripePayout\",\"getStripePayoutHistory\",\"getStripeAccountStatus\",\"handleStripeWebhook\",\"listTeamMembers\",\"acceptInvitation\",\"inviteTeamMember\",\"getInvitationByToken\",\"resendInvitation\",\"removeTeamMember\",\"changeTeamMemberRole\",\"getTrackingPublicKey\",\"recordTrackingBatch\",\"getUsageSummary\",\"getUsageDashboard\",\"getRateLimitStatus\",\"getVastConfig\",\"getVenuesNearby\",\"getVenueAtmosphere\",\"getVenueTraffic\",\"getVenueIntelligence\",\"listWebhooks\",\"createWebhook\",\"deleteWebhook\",\"updateWebhook\",\"getWebhookDeliveries\",\"testWebhook\",\"playgroundDryRun\",\"getRequestMetadata\"] as const,\n} as const;\n\nexport type GeneratedSchemaName = (typeof generatedTypes.schemas)[number];\nexport type GeneratedOperationName = (typeof generatedTypes.operations)[number];\n"]}
|