@reveldigital/mcp-graphql-proxy 1.20.0 → 2.1.0

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.
@@ -3,6 +3,784 @@ schema {
3
3
  mutation: Mutation
4
4
  }
5
5
 
6
+ type Query {
7
+ """
8
+ Get play logs - records of when media content was played on devices.
9
+ Useful for tracking content playback history and calculating media impressions.
10
+ """
11
+ playLogs(
12
+ "Optional list of device IDs to filter by"
13
+ deviceId: [String!]
14
+ "Optional list of file IDs to filter by"
15
+ fileId: [String!]
16
+ "Start date for the query (required)"
17
+ startDate: DateTime!
18
+ "End date for the query (required)"
19
+ endDate: DateTime!
20
+ "Maximum number of results (default: 1000, max: 10000)"
21
+ limit: Int! = 1000
22
+ where: AdHawkPlayLogFilterInput @cost(weight: "10")
23
+ order: [AdHawkPlayLogSortInput!] @cost(weight: "10")
24
+ ): [AdHawkPlayLog] @cost(weight: "10")
25
+ """
26
+ Get ping logs - device heartbeat/health data including CPU, memory, and disk usage.
27
+ Useful for monitoring device health and identifying performance issues.
28
+ Example: Find devices with average CPU usage over 90%.
29
+ """
30
+ pingLogs(
31
+ "Optional list of device IDs to filter by"
32
+ deviceId: [String!]
33
+ "Optional list of ping types to filter by (1=alive, 2=downloading, 4=playing)"
34
+ type: [Int!]
35
+ "Optional minimum CPU usage percentage to filter by"
36
+ minCpuUsage: Float
37
+ "Optional minimum memory usage percentage to filter by"
38
+ minMemoryUsage: Float
39
+ "Start date for the query (required)"
40
+ startDate: DateTime!
41
+ "End date for the query (required)"
42
+ endDate: DateTime!
43
+ "Maximum number of results (default: 1000, max: 10000)"
44
+ limit: Int! = 1000
45
+ where: AdHawkPingLogFilterInput @cost(weight: "10")
46
+ order: [AdHawkPingLogSortInput!] @cost(weight: "10")
47
+ ): [AdHawkPingLog] @cost(weight: "10")
48
+ """
49
+ Get event logs - custom events generated by devices or applications.
50
+ Useful for tracking user interactions, button clicks, page views, etc.
51
+ """
52
+ eventLogs(
53
+ "Optional list of device IDs to filter by"
54
+ deviceId: [String!]
55
+ "Optional list of event names to filter by"
56
+ eventName: [String!]
57
+ "Optional session ID to filter by"
58
+ sessionId: String
59
+ "Start date for the query (required)"
60
+ startDate: DateTime!
61
+ "End date for the query (required)"
62
+ endDate: DateTime!
63
+ "Maximum number of results (default: 1000, max: 10000)"
64
+ limit: Int! = 1000
65
+ where: AdHawkEventLogFilterInput @cost(weight: "10")
66
+ order: [AdHawkEventLogSortInput!] @cost(weight: "10")
67
+ ): [AdHawkEventLog] @cost(weight: "10")
68
+ """
69
+ Get aggregated event metrics for devices over a time period.
70
+ Useful for analyzing event patterns, user engagement, and interaction trends.
71
+ Metrics include total events, unique sessions, and event breakdowns.
72
+ """
73
+ eventMetrics(
74
+ "Optional list of device IDs to filter by"
75
+ deviceId: [String!]
76
+ "Optional list of event names to filter by"
77
+ eventName: [String!]
78
+ "Time interval for aggregation (minute, hour, day, week, month)"
79
+ interval: AdHawkIntervalType! = DAY
80
+ "Group results by device (default: true)"
81
+ groupByDevice: Boolean! = false
82
+ "Group results by event name (default: false)"
83
+ groupByEvent: Boolean! = false
84
+ "Start date for the query (required)"
85
+ startDate: DateTime!
86
+ "End date for the query (required)"
87
+ endDate: DateTime!
88
+ "Maximum number of results (default: 1000, max: 10000)"
89
+ limit: Int! = 1000
90
+ where: AdHawkEventMetricsFilterInput @cost(weight: "10")
91
+ order: [AdHawkEventMetricsSortInput!] @cost(weight: "10")
92
+ ): [AdHawkEventMetrics] @cost(weight: "10")
93
+ """
94
+ Get impressions - audience detection data from sensors (motion, face detection, BLE, WiFi).
95
+ Useful for analyzing visitor demographics, dwell time, and traffic patterns.
96
+ """
97
+ impressions(
98
+ "Optional list of device IDs to filter by"
99
+ deviceId: [String!]
100
+ "Optional list of impression types to filter by (8=motion, 64=audience, 128=ble, 256=wifi)"
101
+ type: [Int!]
102
+ "Optional gender to filter by"
103
+ gender: AdHawkGender
104
+ "Optional minimum dwell time in milliseconds"
105
+ minDwellTime: Long
106
+ "Start date for the query (required)"
107
+ startDate: DateTime!
108
+ "End date for the query (required)"
109
+ endDate: DateTime!
110
+ "Maximum number of results (default: 1000, max: 10000)"
111
+ limit: Int! = 1000
112
+ where: AdHawkImpressionFilterInput @cost(weight: "10")
113
+ order: [AdHawkImpressionSortInput!] @cost(weight: "10")
114
+ ): [AdHawkImpression] @cost(weight: "10")
115
+ """
116
+ Get aggregated device health metrics over a time period.
117
+ Useful for monitoring fleet health, identifying problematic devices, and capacity planning.
118
+ Metrics include CPU, memory, disk usage, and network traffic.
119
+ """
120
+ deviceMetrics(
121
+ "Optional list of device IDs to filter by"
122
+ deviceId: [String!]
123
+ "Time interval for aggregation (minute, hour, day, week, month)"
124
+ interval: AdHawkIntervalType! = DAY
125
+ "Start date for the query (required)"
126
+ startDate: DateTime!
127
+ "End date for the query (required)"
128
+ endDate: DateTime!
129
+ "Maximum number of results (default: 1000, max: 10000)"
130
+ limit: Int! = 1000
131
+ where: AdHawkDeviceMetricsFilterInput @cost(weight: "10")
132
+ order: [AdHawkDeviceMetricsSortInput!] @cost(weight: "10")
133
+ ): [AdHawkDeviceMetrics] @cost(weight: "10")
134
+ """
135
+ Get aggregated audience metrics for devices over a time period.
136
+ Useful for analyzing visitor demographics, traffic patterns, and engagement.
137
+ Metrics include impressions, unique visitors, dwell time, gender, and age breakdowns.
138
+ """
139
+ audienceMetrics(
140
+ "Optional list of device IDs to filter by"
141
+ deviceId: [String!]
142
+ "Time interval for aggregation (minute, hour, day, week, month)"
143
+ interval: AdHawkIntervalType! = DAY
144
+ "Group results by device (default: false)"
145
+ groupByDevice: Boolean! = false
146
+ "When true, queries exit events with dwell time data. When false (default), queries enter events without dwell time."
147
+ includeDwellTime: Boolean! = false
148
+ "Start date for the query (required)"
149
+ startDate: DateTime!
150
+ "End date for the query (required)"
151
+ endDate: DateTime!
152
+ "Maximum number of results (default: 1000, max: 10000)"
153
+ limit: Int! = 1000
154
+ where: AdHawkAudienceMetricsFilterInput @cost(weight: "10")
155
+ order: [AdHawkAudienceMetricsSortInput!] @cost(weight: "10")
156
+ ): [AdHawkAudienceMetrics] @cost(weight: "10")
157
+ """
158
+ Get media play statistics - aggregated play counts and durations for media files.
159
+ Useful for analyzing content performance and identifying popular media.
160
+ """
161
+ mediaPlayStats(
162
+ "Optional list of device IDs to filter by"
163
+ deviceId: [String!]
164
+ "Optional list of file IDs to filter by"
165
+ fileId: [String!]
166
+ "Start date for the query (required)"
167
+ startDate: DateTime!
168
+ "End date for the query (required)"
169
+ endDate: DateTime!
170
+ "Maximum number of results (default: 100, max: 10000)"
171
+ limit: Int! = 100
172
+ where: AdHawkMediaPlayStatsFilterInput @cost(weight: "10")
173
+ order: [AdHawkMediaPlayStatsSortInput!] @cost(weight: "10")
174
+ ): [AdHawkMediaPlayStats] @cost(weight: "10")
175
+ """
176
+ Get device play statistics - aggregated play counts and duration for each device.
177
+ Useful for DooH reporting to analyze device performance and content distribution.
178
+ Example: Find which devices played the most content in a date range.
179
+ """
180
+ devicePlayStats(
181
+ "Optional list of device IDs to filter by"
182
+ deviceId: [String!]
183
+ "Optional list of file IDs to filter by"
184
+ fileId: [String!]
185
+ "Start date for the query (required)"
186
+ startDate: DateTime!
187
+ "End date for the query (required)"
188
+ endDate: DateTime!
189
+ "Maximum number of results (default: 100, max: 10000)"
190
+ limit: Int! = 100
191
+ where: AdHawkDevicePlayStatsFilterInput @cost(weight: "10")
192
+ order: [AdHawkDevicePlayStatsSortInput!] @cost(weight: "10")
193
+ ): [AdHawkDevicePlayStats] @cost(weight: "10")
194
+ """
195
+ Get device and media combined play statistics - shows what content played on which devices.
196
+ Useful for DooH reporting to analyze device/content performance matrix.
197
+ Example: Find which devices played a specific ad campaign most frequently.
198
+ """
199
+ deviceMediaPlayStats(
200
+ "Optional list of device IDs to filter by"
201
+ deviceId: [String!]
202
+ "Optional list of file IDs to filter by"
203
+ fileId: [String!]
204
+ "Start date for the query (required)"
205
+ startDate: DateTime!
206
+ "End date for the query (required)"
207
+ endDate: DateTime!
208
+ "Maximum number of results (default: 100, max: 10000)"
209
+ limit: Int! = 100
210
+ where: AdHawkDeviceMediaPlayStatsFilterInput @cost(weight: "10")
211
+ order: [AdHawkDeviceMediaPlayStatsSortInput!] @cost(weight: "10")
212
+ ): [AdHawkDeviceMediaPlayStats] @cost(weight: "10")
213
+ """
214
+ Get time-series play statistics - aggregated play data by time intervals.
215
+ Useful for DooH reporting to analyze playback trends over time (hourly, daily, weekly, etc.).
216
+ Example: Chart daily play counts for a specific media file over the past month.
217
+ """
218
+ playStatsByTime(
219
+ "Optional list of device IDs to filter by"
220
+ deviceId: [String!]
221
+ "Optional list of file IDs to filter by"
222
+ fileId: [String!]
223
+ "Time interval for aggregation (minute, hour, day, week, month)"
224
+ interval: AdHawkIntervalType! = DAY
225
+ "Group results by device (default: false)"
226
+ groupByDevice: Boolean! = false
227
+ "Group results by file (default: false)"
228
+ groupByFile: Boolean! = false
229
+ "Start date for the query (required)"
230
+ startDate: DateTime!
231
+ "End date for the query (required)"
232
+ endDate: DateTime!
233
+ "Maximum number of results (default: 1000, max: 10000)"
234
+ limit: Int! = 1000
235
+ where: AdHawkPlayStatsByTimeFilterInput @cost(weight: "10")
236
+ order: [AdHawkPlayStatsByTimeSortInput!] @cost(weight: "10")
237
+ ): [AdHawkPlayStatsByTime] @cost(weight: "10")
238
+ """
239
+ Get event flow data for Sankey-type visualizations.
240
+ Builds a chronological sequence of events indicating the path users took through sessions.
241
+ Useful for analyzing user navigation patterns and behavior flows.
242
+ """
243
+ eventFlow(
244
+ "Optional list of device IDs to filter by"
245
+ deviceId: [String!]
246
+ "Optional list of event names to filter by"
247
+ eventName: [String!]
248
+ "Maximum depth level for event flow (default: 6). Controls how many event transitions to include."
249
+ eventDepthLevel: Int! = 6
250
+ "Start date for the query (required)"
251
+ startDate: DateTime!
252
+ "End date for the query (required)"
253
+ endDate: DateTime!
254
+ "Maximum number of results (default: 1000, max: 10000)"
255
+ limit: Int! = 1000
256
+ where: AdHawkEventFlowFilterInput @cost(weight: "10")
257
+ order: [AdHawkEventFlowSortInput!] @cost(weight: "10")
258
+ ): [AdHawkEventFlow] @cost(weight: "10")
259
+ """
260
+ Get geographic heatmap data aggregated by location.
261
+ Groups impression data by geographic region returning a dataset aggregated by location.
262
+ Useful for heatmap or geographic visualizations.
263
+ """
264
+ heatMapData(
265
+ "Optional list of device IDs to filter by"
266
+ deviceId: [String!]
267
+ "Time interval for aggregation (minute, hour, day, week, month)"
268
+ interval: AdHawkIntervalType! = DAY
269
+ "Start date for the query (required)"
270
+ startDate: DateTime!
271
+ "End date for the query (required)"
272
+ endDate: DateTime!
273
+ "Maximum number of results (default: 1000, max: 10000)"
274
+ limit: Int! = 1000
275
+ where: AdHawkHeatMapDataFilterInput @cost(weight: "10")
276
+ order: [AdHawkHeatMapDataSortInput!] @cost(weight: "10")
277
+ ): [AdHawkHeatMapData] @cost(weight: "10")
278
+ """
279
+ Get geographic heatmap data for events aggregated by location.
280
+ Groups event data by geographic region returning a dataset aggregated by location.
281
+ Useful for heatmap or geographic visualizations of event activity.
282
+ """
283
+ eventHeatMapData(
284
+ "Optional list of device IDs to filter by"
285
+ deviceId: [String!]
286
+ "Optional list of event names to filter by"
287
+ eventName: [String!]
288
+ "Time interval for aggregation (minute, hour, day, week, month)"
289
+ interval: AdHawkIntervalType! = DAY
290
+ "Start date for the query (required)"
291
+ startDate: DateTime!
292
+ "End date for the query (required)"
293
+ endDate: DateTime!
294
+ "Maximum number of results (default: 1000, max: 10000)"
295
+ limit: Int! = 1000
296
+ where: AdHawkEventHeatMapDataFilterInput @cost(weight: "10")
297
+ order: [AdHawkEventHeatMapDataSortInput!] @cost(weight: "10")
298
+ ): [AdHawkEventHeatMapData] @cost(weight: "10")
299
+ """
300
+ Get media impressions (OTS - Opportunity To See) data aggregated by media file.
301
+ Joins audience/impression data with play logs to determine which audience members
302
+ had an opportunity to see specific media content during playback.
303
+ Useful for measuring media effectiveness and audience engagement.
304
+ """
305
+ mediaImpressions(
306
+ "Optional list of device IDs to filter by"
307
+ deviceId: [String!]
308
+ "Optional list of file/media IDs to filter by"
309
+ fileId: [String!]
310
+ "Minimum dwell time in milliseconds to count as \"viewed\" (default: 100ms)"
311
+ minDwellThreshold: Long! = 100
312
+ "Start date for the query (required)"
313
+ startDate: DateTime!
314
+ "End date for the query (required)"
315
+ endDate: DateTime!
316
+ "Maximum number of results (default: 100, max: 10000)"
317
+ limit: Int! = 100
318
+ where: AdHawkMediaImpressionsFilterInput @cost(weight: "10")
319
+ order: [AdHawkMediaImpressionsSortInput!] @cost(weight: "10")
320
+ ): [AdHawkMediaImpressions] @cost(weight: "10")
321
+ """
322
+ Get media impressions (OTS - Opportunity To See) data aggregated by device.
323
+ Joins audience/impression data with play logs to determine which devices
324
+ had the most audience engagement during media playback.
325
+ Useful for identifying high-performing locations and devices.
326
+ """
327
+ deviceMediaImpressions(
328
+ "Optional list of device IDs to filter by"
329
+ deviceId: [String!]
330
+ "Optional list of file/media IDs to filter by"
331
+ fileId: [String!]
332
+ "Minimum dwell time in milliseconds to count as \"viewed\" (default: 100ms)"
333
+ minDwellThreshold: Long! = 100
334
+ "Start date for the query (required)"
335
+ startDate: DateTime!
336
+ "End date for the query (required)"
337
+ endDate: DateTime!
338
+ "Maximum number of results (default: 100, max: 10000)"
339
+ limit: Int! = 100
340
+ where: AdHawkDeviceMediaImpressionsFilterInput @cost(weight: "10")
341
+ order: [AdHawkDeviceMediaImpressionsSortInput!] @cost(weight: "10")
342
+ ): [AdHawkDeviceMediaImpressions] @cost(weight: "10")
343
+ """
344
+ Gets alerts for the authenticated account.
345
+
346
+
347
+ **Returns:**
348
+ List of alerts
349
+ """
350
+ alert(
351
+ "Filter by specific alert IDs (encrypted)"
352
+ id: [String!]
353
+ "Filter by device IDs (encrypted)"
354
+ deviceId: [String!]
355
+ "Filter to show only active alerts"
356
+ activeOnly: Boolean
357
+ "Filter by resolved state"
358
+ resolved: Boolean
359
+ "Filter by organization ID (encrypted)"
360
+ orgId: String
361
+ "Maximum number of items to return"
362
+ limit: Int
363
+ where: AlertFilterInput @cost(weight: "10")
364
+ order: [AlertSortInput!] @cost(weight: "10")
365
+ ): [Alert] @cost(weight: "10")
366
+ """
367
+ Gets audit events for the authenticated account.
368
+ Requires the user to be an account owner.
369
+
370
+
371
+ **Returns:**
372
+ List of audit events
373
+ """
374
+ auditEvent(
375
+ "Filter by user ID (encrypted)"
376
+ userId: String
377
+ "Filter by event type"
378
+ eventType: String
379
+ "Filter by HTTP method (GET, POST, PUT, DELETE, etc.)"
380
+ httpMethod: String
381
+ "Filter by controller name"
382
+ controllerName: String
383
+ "Filter by action name"
384
+ actionName: String
385
+ "Filter events after this date"
386
+ startDate: DateTime
387
+ "Filter events before this date"
388
+ endDate: DateTime
389
+ "Filter by IP address"
390
+ ipAddress: String
391
+ "Filter by HTTP response code"
392
+ responseCode: String
393
+ "Maximum number of items to return"
394
+ limit: Int
395
+ where: AuditEventFilterInput @cost(weight: "10")
396
+ order: [AuditEventSortInput!] @cost(weight: "10")
397
+ ): [AuditEvent!]! @cost(weight: "10")
398
+ "Lists data tables in the account, with optional group filtering."
399
+ dataTables(
400
+ "Optional group ID to filter by"
401
+ groupId: String
402
+ "Number of tables per page (default 50)"
403
+ pageSize: Int! = 50
404
+ "Token for fetching the next page"
405
+ continuationToken: String
406
+ ): DataTableListResponse @cost(weight: "10")
407
+ "Gets a single data table definition by ID, including column schema."
408
+ dataTable("The data table ID" tableId: String): DataTableDetail
409
+ @cost(weight: "10")
410
+ "Lists rows in a data table, with optional filtering, sorting, and field selection."
411
+ dataTableRows(
412
+ "The data table ID"
413
+ tableId: String
414
+ """
415
+ Optional row filter as a JSON object encoded as a string. All conditions are
416
+ AND-ed together at the top level. Use the special key `$or` to express
417
+ disjunction.
418
+
419
+ Two shapes are accepted per column:
420
+
421
+ 1. Equality shortcut (string/number/boolean literal):
422
+ {"status": "active"} // equivalent to {"status": {"op":"eq","value":"active"}}
423
+
424
+ 2. Operator object form:
425
+ {"<columnKey>": {"op": "<operator>", ...args}}
426
+
427
+ Supported operators
428
+ -------------------
429
+ Value operators (require `value`):
430
+ eq equal
431
+ neq not equal
432
+ contains substring match (string columns)
433
+ notContains substring non-match
434
+ gt, gte greater than / greater or equal (number, date)
435
+ lt, lte less than / less or equal (number, date)
436
+
437
+ Range operators (require `from` and `to`):
438
+ inRange value is between from and to (inclusive)
439
+ outOfRange value is outside [from, to]
440
+
441
+ No-value operators (no `value` / `from` / `to`):
442
+ isEmpty column is null / empty string
443
+ isNotEmpty column has a value
444
+ positive number > 0
445
+ negative number < 0
446
+ beforeNow date < now (UTC)
447
+ afterNow date > now (UTC)
448
+ isToday date is on the current UTC calendar day
449
+
450
+ Composition
451
+ -----------
452
+ Use `$or` at the top level for disjunction. Each element is a normal filter
453
+ object whose own conditions are AND-ed:
454
+
455
+ {
456
+ "$or": [
457
+ { "category": "Entree" },
458
+ { "price": { "op": "lt", "value": 10 } }
459
+ ]
460
+ }
461
+
462
+ Examples
463
+ --------
464
+ {"active": true}
465
+ {"price": {"op": "gte", "value": 25}}
466
+ {"name": {"op": "contains", "value": "pizza"}}
467
+ {"score": {"op": "inRange", "from": 0, "to": 100}}
468
+ {"deletedAt": {"op": "isEmpty"}}
469
+ {"publishAt": {"op": "beforeNow"}}
470
+
471
+ Validation errors
472
+ -----------------
473
+ Invalid JSON, unknown operators, or missing required arguments produce a
474
+ GraphQL error with `extensions.code = "BAD_REQUEST"` and no stack trace.
475
+ """
476
+ filter: String
477
+ "Column key to sort by"
478
+ sort: String
479
+ "Sort direction: \"asc\" or \"desc\""
480
+ sortDir: String = "asc"
481
+ "Number of rows per page (default 50)"
482
+ pageSize: Int! = 50
483
+ "Token for fetching the next page"
484
+ continuationToken: String
485
+ "Comma-separated list of column keys to return"
486
+ fields: String
487
+ ): RowListResponse @cost(weight: "10")
488
+ "Gets a single row by ID."
489
+ dataTableRow("The data table ID" tableId: String, "The row ID" rowId: String): DataTableRowModel
490
+ @cost(weight: "10")
491
+ "Exports all rows from a data table as a CSV string."
492
+ exportDataTableRows("The data table ID" tableId: String): String
493
+ @cost(weight: "10")
494
+ "Lists version history for a row (newest first)."
495
+ dataTableRowVersions(
496
+ "The data table ID"
497
+ tableId: String
498
+ "The row ID"
499
+ rowId: String
500
+ "Number of versions per page (default 25)"
501
+ pageSize: Int! = 25
502
+ "Token for fetching the next page"
503
+ continuationToken: String
504
+ ): VersionListResponse @cost(weight: "10")
505
+ "Gets a specific version snapshot of a row."
506
+ dataTableRowVersion(
507
+ "The data table ID"
508
+ tableId: String
509
+ "The row ID"
510
+ rowId: String
511
+ "The version number to retrieve"
512
+ version: Int!
513
+ ): RowVersionModel @cost(weight: "10")
514
+ device(
515
+ id: [String!]
516
+ groupId: [String!]
517
+ groupName: [String!]
518
+ deviceTypeId: [String!]
519
+ includeSnap: Boolean
520
+ orgId: String
521
+ tag: [String!]
522
+ limit: Int
523
+ where: DeviceFilterInput @cost(weight: "10")
524
+ order: [DeviceSortInput!] @cost(weight: "10")
525
+ ): [Device] @cost(weight: "10")
526
+ deviceGroups(
527
+ id: String
528
+ tree: Boolean
529
+ limit: Int
530
+ where: GroupFilterInput @cost(weight: "10")
531
+ order: [GroupSortInput!] @cost(weight: "10")
532
+ ): [Group] @cost(weight: "10")
533
+ """
534
+ Gets the display commands configured for the authenticated account.
535
+ These commands define the available actions that can be sent to devices
536
+ (e.g., via the sendDeviceCommand mutation).
537
+ """
538
+ displayCommands(
539
+ where: DisplayCommandFilterInput @cost(weight: "10")
540
+ order: [DisplayCommandSortInput!] @cost(weight: "10")
541
+ ): [DisplayCommand] @cost(weight: "10")
542
+ media(
543
+ id: [String!]
544
+ groupId: [String!]
545
+ groupName: [String!]
546
+ orgId: String
547
+ tag: [String!]
548
+ limit: Int
549
+ where: MediaFilterInput @cost(weight: "10")
550
+ order: [MediaSortInput!] @cost(weight: "10")
551
+ ): [Media] @cost(weight: "10")
552
+ mediaGroups(
553
+ id: String
554
+ tree: Boolean
555
+ limit: Int
556
+ where: GroupFilterInput @cost(weight: "10")
557
+ order: [GroupSortInput!] @cost(weight: "10")
558
+ ): [Group] @cost(weight: "10")
559
+ """
560
+ Get the permissions for the currently authenticated user or API key.
561
+ Returns per-resource view/edit/delete flags and lists of allowed/denied mutation tool names.
562
+ AI agents should call this query at the start of every session to determine which action tools are available.
563
+ """
564
+ permissions: PermissionsResult @cost(weight: "10")
565
+ playlist(
566
+ id: [String!]
567
+ groupId: [String!]
568
+ groupName: [String!]
569
+ orgId: String
570
+ tag: [String!]
571
+ limit: Int
572
+ where: PlaylistFilterInput @cost(weight: "10")
573
+ order: [PlaylistSortInput!] @cost(weight: "10")
574
+ ): [Playlist] @cost(weight: "10")
575
+ playlistGroups(
576
+ id: String
577
+ tree: Boolean
578
+ limit: Int
579
+ where: GroupFilterInput @cost(weight: "10")
580
+ order: [GroupSortInput!] @cost(weight: "10")
581
+ ): [Group] @cost(weight: "10")
582
+ schedule(
583
+ id: [String!]
584
+ groupId: [String!]
585
+ groupName: [String!]
586
+ deviceId: String
587
+ orgId: String
588
+ tag: [String!]
589
+ limit: Int
590
+ where: ScheduleFilterInput @cost(weight: "10")
591
+ order: [ScheduleSortInput!] @cost(weight: "10")
592
+ ): [Schedule] @cost(weight: "10")
593
+ scheduleGroups(
594
+ id: String
595
+ tree: Boolean
596
+ limit: Int
597
+ where: GroupFilterInput @cost(weight: "10")
598
+ order: [GroupSortInput!] @cost(weight: "10")
599
+ ): [Group] @cost(weight: "10")
600
+ template(
601
+ id: [String!]
602
+ groupId: [String!]
603
+ groupName: [String!]
604
+ orgId: String
605
+ tag: [String!]
606
+ limit: Int
607
+ where: TemplateFilterInput @cost(weight: "10")
608
+ order: [TemplateSortInput!] @cost(weight: "10")
609
+ ): [Template] @cost(weight: "10")
610
+ templateGroups(
611
+ id: String
612
+ tree: Boolean
613
+ limit: Int
614
+ where: GroupFilterInput @cost(weight: "10")
615
+ order: [GroupSortInput!] @cost(weight: "10")
616
+ ): [Group] @cost(weight: "10")
617
+ user(
618
+ id: [String!]
619
+ limit: Int
620
+ where: UserFilterInput @cost(weight: "10")
621
+ order: [UserSortInput!] @cost(weight: "10")
622
+ ): [User] @cost(weight: "10")
623
+ }
624
+
625
+ type Mutation {
626
+ """
627
+ Create a new data table with the specified column schema.
628
+ Example: Create a menu board table with columns for item name, price, description, and image.
629
+ """
630
+ createDataTable(input: CreateDataTableInput): DataTableMutationResult
631
+ @cost(weight: "10")
632
+ """
633
+ Update an existing data table definition. Only provided fields are changed.
634
+ Example: Add a new "calories" column to a menu board table.
635
+ """
636
+ updateDataTable(input: UpdateDataTableInput): DataTableMutationResult
637
+ @cost(weight: "10")
638
+ "Delete a data table and all its rows."
639
+ deleteDataTable(tableId: String): DeleteResult @cost(weight: "10")
640
+ """
641
+ Create a new row in a data table.
642
+ Example: Add a new menu item to a menu board table.
643
+ """
644
+ createDataTableRow(input: CreateDataTableRowInput): DataTableRowMutationResult
645
+ @cost(weight: "10")
646
+ """
647
+ Update an existing row in a data table (partial update — only provided keys are changed).
648
+ Example: Update the price of a menu item.
649
+ """
650
+ updateDataTableRow(input: UpdateDataTableRowInput): DataTableRowMutationResult
651
+ @cost(weight: "10")
652
+ "Delete a row from a data table."
653
+ deleteDataTableRow(tableId: String, rowId: String): DeleteResult
654
+ @cost(weight: "10")
655
+ """
656
+ Batch create multiple rows in a data table (max 100 rows per call).
657
+ Example: Bulk-load menu items into a table from an external data source.
658
+ """
659
+ batchCreateDataTableRows(input: BatchCreateDataTableRowsInput): BatchCreateDataTableRowsResult
660
+ @cost(weight: "10")
661
+ "Batch delete multiple rows from a data table (max 100 row IDs per call)."
662
+ batchDeleteDataTableRows(input: BatchDeleteDataTableRowsInput): BatchDeleteDataTableRowsResult
663
+ @cost(weight: "10")
664
+ """
665
+ Import rows from CSV content into a data table.
666
+ Example: Import a spreadsheet of menu items. Use replace mode to overwrite all existing rows.
667
+ """
668
+ importDataTableRows(input: ImportDataTableRowsInput): ImportDataTableRowsResult
669
+ @cost(weight: "10")
670
+ "Reorder rows in a data table by specifying the desired row ID sequence."
671
+ reorderDataTableRows(input: ReorderDataTableRowsInput): DeleteResult
672
+ @cost(weight: "10")
673
+ """
674
+ Roll back a row to a previous version, creating a new version for the rollback action.
675
+ Example: Undo an accidental price change by restoring a previous version.
676
+ """
677
+ rollbackDataTableRow(input: RollbackDataTableRowInput): RollbackDataTableRowResult
678
+ @cost(weight: "10")
679
+ """
680
+ Send commands to a specific device.
681
+ Commands are dispatched via Azure SignalR, FCM, Pusher, and legacy SignalR channels
682
+ depending on the device type.
683
+
684
+ Known commands: restart, reboot, screenshot, refresh, display_on, display_off, volume (arg: 0-100), clear_cache, update.
685
+ """
686
+ sendDeviceCommand(deviceId: String, commands: [CommandInput]): CommandResult
687
+ @cost(weight: "10")
688
+ """
689
+ Send commands to multiple devices at once.
690
+
691
+ Known commands: restart, reboot, screenshot, refresh, display_on, display_off, volume (arg: 0-100), clear_cache, update.
692
+ """
693
+ sendBulkDeviceCommands(input: BulkCommandInput): BulkCommandResult
694
+ @cost(weight: "10")
695
+ """
696
+ Create a new device group (organizational folder for player devices).
697
+ Mirrors the REST POST /api/devices/groups endpoint.
698
+ Example: An AI agent organizes newly provisioned players into a "Lobby Displays" group.
699
+ """
700
+ createDeviceGroup(input: CreateGroupInput): GroupMutationResult
701
+ @cost(weight: "10")
702
+ """
703
+ Create a new media group (organizational folder for uploaded content files).
704
+ Mirrors the REST POST /api/media/groups endpoint.
705
+ """
706
+ createMediaGroup(input: CreateGroupInput): GroupMutationResult
707
+ @cost(weight: "10")
708
+ """
709
+ Create a new playlist group (organizational folder for playlists).
710
+ Mirrors the REST POST /api/playlists/groups endpoint.
711
+ """
712
+ createPlaylistGroup(input: CreateGroupInput): GroupMutationResult
713
+ @cost(weight: "10")
714
+ """
715
+ Create a new schedule group (organizational folder for schedules).
716
+ Mirrors the REST POST /api/schedules/groups endpoint.
717
+ """
718
+ createScheduleGroup(input: CreateGroupInput): GroupMutationResult
719
+ @cost(weight: "10")
720
+ """
721
+ Create a new template group (organizational folder for screen layouts/templates).
722
+ Mirrors the REST POST /api/templates/groups endpoint.
723
+ """
724
+ createTemplateGroup(input: CreateGroupInput): GroupMutationResult
725
+ @cost(weight: "10")
726
+ """
727
+ Create a new media asset by downloading from a URL.
728
+ Useful for AI agents that generate images/videos and need to add them to the CMS.
729
+ Example: AI generates a promotional image via DALL-E and uploads it for digital signage display.
730
+ """
731
+ createMediaFromUrl(input: CreateMediaFromUrlInput): CreateMediaResult
732
+ @cost(weight: "10")
733
+ """
734
+ Update media metadata. Does not replace the media file itself.
735
+ Example: Set an end date on underperforming media to automatically stop playback.
736
+ """
737
+ updateMedia(input: UpdateMediaInput): UpdateMediaResult @cost(weight: "10")
738
+ """
739
+ Approve a media asset so it becomes eligible for playback. Reversible — a
740
+ subsequent DeclineMedia call will move the file back to declined state.
741
+ Example: AI agent automatically approves uploads that pass content moderation.
742
+ """
743
+ approveMedia(input: ApproveMediaInput): UpdateMediaResult @cost(weight: "10")
744
+ """
745
+ Decline a media asset so it is excluded from playback. Reversible — a
746
+ subsequent ApproveMedia call will move the file back to approved state.
747
+ Example: AI agent rejects uploads that fail content moderation, with a recorded reason.
748
+ """
749
+ declineMedia(input: DeclineMediaInput): UpdateMediaResult @cost(weight: "10")
750
+ """
751
+ Delete a media asset by ID.
752
+ Example: Remove AI-generated content that is no longer needed.
753
+
754
+ TEMPORARY: Short-circuited as a no-op until validated in production.
755
+ TODO: Re-enable actual deletion once testing is complete.
756
+ """
757
+ deleteMedia(id: String): DeleteResult @cost(weight: "10")
758
+ """
759
+ Add a content source to an existing playlist.
760
+ Example: AI generates a new image and adds it to the lobby playlist to improve engagement.
761
+ """
762
+ addPlaylistSource(input: AddPlaylistSourceInput): PlaylistMutationResult
763
+ @cost(weight: "10")
764
+ """
765
+ Update a source within a playlist.
766
+ Example: Change the duration of an ad slot based on engagement metrics.
767
+ """
768
+ updatePlaylistSource(input: UpdatePlaylistSourceInput): PlaylistMutationResult
769
+ @cost(weight: "10")
770
+ """
771
+ Remove a source from a playlist by source ID.
772
+ Example: Remove under-performing media from a playlist to improve overall engagement.
773
+ """
774
+ removePlaylistSource(playlistId: String, sourceId: String): PlaylistMutationResult
775
+ @cost(weight: "10")
776
+ """
777
+ Reorder sources within a playlist.
778
+ Example: Promote high-performing content to play first based on analytics data.
779
+ """
780
+ reorderPlaylistSources(input: ReorderPlaylistSourcesInput): PlaylistMutationResult
781
+ @cost(weight: "10")
782
+ }
783
+
6
784
  "Aggregated audience metrics for a device over a time period"
7
785
  type AdHawkAudienceMetrics {
8
786
  "The device ID"
@@ -43,7 +821,7 @@ type AdHawkAudienceMetrics {
43
821
  ageOver74: Long!
44
822
  "Number of motion sensor detections"
45
823
  motionCount: Long!
46
- "Number of audience\/face detections"
824
+ "Number of audience/face detections"
47
825
  audienceCount: Long!
48
826
  "Number of BLE beacon detections"
49
827
  bleCount: Long!
@@ -92,13 +870,13 @@ type AdHawkDeviceMediaPlayStats {
92
870
  fileName: String
93
871
  "Total number of times this media was played on this device"
94
872
  totalPlays: Long!
95
- "Total duration of all plays in milliseconds"
873
+ "Total duration of all plays in seconds"
96
874
  totalDuration: Long!
97
- "Average play duration in milliseconds"
875
+ "Average play duration in seconds"
98
876
  avgDuration: Decimal
99
- "First play timestamp for this device\/media combination"
877
+ "First play timestamp for this device/media combination"
100
878
  firstPlay: DateTime
101
- "Last play timestamp for this device\/media combination"
879
+ "Last play timestamp for this device/media combination"
102
880
  lastPlay: DateTime
103
881
  }
104
882
 
@@ -145,9 +923,9 @@ type AdHawkDevicePlayStats {
145
923
  deviceName: String
146
924
  "Total number of media files played on this device"
147
925
  totalPlays: Long!
148
- "Total duration of all plays in milliseconds"
926
+ "Total duration of all plays in seconds"
149
927
  totalDuration: Long!
150
- "Average play duration in milliseconds"
928
+ "Average play duration in seconds"
151
929
  avgDuration: Decimal
152
930
  "Number of unique media files played on this device"
153
931
  fileCount: Long!
@@ -208,7 +986,7 @@ type AdHawkEventLog {
208
986
  "Name of the event (e.g., \"button_click\", \"page_view\")"
209
987
  eventName: String
210
988
  "Additional properties associated with the event as key-value pairs"
211
- properties: [KeyValuePairOfStringAndObject!]
989
+ properties: [KeyValuePairOfNullableStringAndNullableObject!]
212
990
  "UTC offset of the device at the time of the event"
213
991
  utcOffset: Int
214
992
  }
@@ -256,11 +1034,11 @@ type AdHawkHeatMapData {
256
1034
  wifiCount: Long!
257
1035
  "Count of motion sensor impressions"
258
1036
  motionCount: Long!
259
- "Count of audience\/face detection impressions"
1037
+ "Count of audience/face detection impressions"
260
1038
  audienceCount: Long!
261
1039
  }
262
1040
 
263
- "Represents an audience impression\/detection entry"
1041
+ "Represents an audience impression/detection entry"
264
1042
  type AdHawkImpression {
265
1043
  "Unique identifier for this impression entry"
266
1044
  id: String
@@ -288,7 +1066,7 @@ type AdHawkImpression {
288
1066
  age: Int
289
1067
  "Age range classification"
290
1068
  ageRange: AdHawkAgeRange
291
- "Received Signal Strength Indicator for BLE\/WiFi detections"
1069
+ "Received Signal Strength Indicator for BLE/WiFi detections"
292
1070
  rssi: Int
293
1071
  "UTC offset of the device at the time of detection"
294
1072
  utcOffset: Int
@@ -300,9 +1078,9 @@ Joins audience/impression data with media play logs to determine which audience
300
1078
  members had an opportunity to see specific media content.
301
1079
  """
302
1080
  type AdHawkMediaImpressions {
303
- "The file\/media ID"
1081
+ "The file/media ID"
304
1082
  fileId: String
305
- "The file\/media name"
1083
+ "The file/media name"
306
1084
  fileName: String
307
1085
  "Total number of impressions that occurred during media playback"
308
1086
  totalImpressions: Long!
@@ -334,15 +1112,15 @@ type AdHawkMediaPlayStats {
334
1112
  fileName: String
335
1113
  "Total number of times this media was played"
336
1114
  totalPlays: Long!
337
- "Total duration of all plays in milliseconds"
1115
+ "Total duration of all plays in seconds"
338
1116
  totalDuration: Long!
339
- "Average play duration in milliseconds"
1117
+ "Average play duration in seconds"
340
1118
  avgDuration: Decimal
341
1119
  "Number of unique devices that played this media"
342
1120
  deviceCount: Long!
343
1121
  }
344
1122
 
345
- "Represents a device ping\/heartbeat log entry - records device health and status"
1123
+ "Represents a device ping/heartbeat log entry - records device health and status"
346
1124
  type AdHawkPingLog {
347
1125
  "Unique identifier for this ping log entry"
348
1126
  id: String
@@ -386,7 +1164,7 @@ type AdHawkPlayLog {
386
1164
  fileId: String
387
1165
  "The name of the media file"
388
1166
  fileName: String
389
- "Duration of the play in milliseconds"
1167
+ "Duration of the play in seconds"
390
1168
  duration: Int
391
1169
  "Type of play (internal use)"
392
1170
  type: Int
@@ -413,9 +1191,9 @@ type AdHawkPlayStatsByTime {
413
1191
  periodEnd: DateTime!
414
1192
  "Total number of plays during this period"
415
1193
  totalPlays: Long!
416
- "Total duration of all plays in milliseconds"
1194
+ "Total duration of all plays in seconds"
417
1195
  totalDuration: Long!
418
- "Average play duration in milliseconds"
1196
+ "Average play duration in seconds"
419
1197
  avgDuration: Decimal
420
1198
  "Number of unique devices (if aggregated by file)"
421
1199
  deviceCount: Long
@@ -661,7 +1439,7 @@ type DataTableColumnModel {
661
1439
  sortable: Boolean!
662
1440
  locked: Boolean!
663
1441
  options: [String]
664
- default: JSON
1442
+ default: Any
665
1443
  }
666
1444
 
667
1445
  type DataTableDetail {
@@ -694,8 +1472,20 @@ type DataTableMutationResult {
694
1472
  type DataTableRowModel {
695
1473
  id: String
696
1474
  sortOrder: Int!
697
- data: JSON
1475
+ """
1476
+ Stored row data as a JSON object keyed by column `key`. Values follow each
1477
+ column's `ColumnType` rules: STRING/RICHTEXT/HIDDEN/SELECT/URL/DATE/TIME are
1478
+ JSON strings, NUMBER is a JSON number, BOOLEAN is JSON true/false, and MEDIA is
1479
+ always a normalized object `{ url, thumbnailUrl, name, mimeType, mediaId? }`
1480
+ (id and id-object input forms are expanded server-side at write time).
1481
+ """
1482
+ data: Any
698
1483
  updatedAt: DateTime!
1484
+ """
1485
+ Optimistic concurrency token. Pass this value back as `eTag` in
1486
+ `updateDataTableRow` to ensure the row hasn't been changed since you read it.
1487
+ """
1488
+ eTag: String
699
1489
  }
700
1490
 
701
1491
  "Result from a data table row create or update mutation."
@@ -706,8 +1496,17 @@ type DataTableRowMutationResult {
706
1496
  row: DataTableRowModel
707
1497
  "Error message if the operation failed."
708
1498
  error: String
709
- "Validation errors if the row data failed schema validation."
1499
+ """
1500
+ Validation errors if the row data failed schema validation.
1501
+ Deprecated string-array form retained for backwards compatibility — new
1502
+ integrations should use StructuredValidationErrors.
1503
+ """
710
1504
  validationErrors: [String]
1505
+ """
1506
+ Structured validation errors with machine-readable codes, suitable for
1507
+ programmatic retry logic. Always populated when validation fails.
1508
+ """
1509
+ structuredValidationErrors: [ValidationError]
711
1510
  }
712
1511
 
713
1512
  type DataTableSummary {
@@ -755,9 +1554,9 @@ type Device {
755
1554
  languageCode: String
756
1555
  "The timestamp of the last content sync with the server"
757
1556
  lastUpdate: DateTime
758
- "The physical location\/address of the device"
1557
+ "The physical location/address of the device"
759
1558
  location: Location
760
- "The device ping\/heartbeat data"
1559
+ "The device ping/heartbeat data"
761
1560
  pingData: PingData
762
1561
  "The device registration key"
763
1562
  registrationKey: String
@@ -849,6 +1648,16 @@ type Group {
849
1648
  children: [Group]
850
1649
  }
851
1650
 
1651
+ "Result from a group mutation (e.g., creating a new group)."
1652
+ type GroupMutationResult {
1653
+ "Whether the operation was successful."
1654
+ success: Boolean!
1655
+ "The newly created (or updated) group."
1656
+ group: Group
1657
+ "Error message if the operation failed."
1658
+ error: String
1659
+ }
1660
+
852
1661
  "Result from an import rows mutation."
853
1662
  type ImportDataTableRowsResult {
854
1663
  "Whether the overall operation was successful."
@@ -868,13 +1677,14 @@ type ImportRowErrorModel {
868
1677
  error: String
869
1678
  }
870
1679
 
871
- type KeyValuePairOfStringAndObject {
872
- key: String!
1680
+ type KeyValuePairOfNullableStringAndNullableObject {
1681
+ key: String
1682
+ value: Any
873
1683
  }
874
1684
 
875
- type KeyValuePairOfStringAndString {
876
- key: String!
877
- value: String!
1685
+ type KeyValuePairOfNullableStringAndNullableString {
1686
+ key: String
1687
+ value: String
878
1688
  }
879
1689
 
880
1690
  type Location {
@@ -925,6 +1735,14 @@ type Media {
925
1735
  width: Int
926
1736
  "The height of the media"
927
1737
  height: Int
1738
+ "Approval state. True = approved for playback, false = declined, null = pending review."
1739
+ isApproved: Boolean
1740
+ "Timestamp the media was approved, if applicable."
1741
+ approvedOn: DateTime
1742
+ "Timestamp the media was declined, if applicable."
1743
+ declinedOn: DateTime
1744
+ "Reason recorded when the media was declined, if any."
1745
+ declinedReason: String
928
1746
  "The media name"
929
1747
  name: String
930
1748
  "The group id"
@@ -966,105 +1784,6 @@ type Module {
966
1784
  sequence: Int
967
1785
  }
968
1786
 
969
- type Mutation @authorize {
970
- """
971
- Create a new data table with the specified column schema.
972
- Example: Create a menu board table with columns for item name, price, description, and image.
973
- """
974
- createDataTable(input: CreateDataTableInput): DataTableMutationResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
975
- """
976
- Update an existing data table definition. Only provided fields are changed.
977
- Example: Add a new "calories" column to a menu board table.
978
- """
979
- updateDataTable(input: UpdateDataTableInput): DataTableMutationResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
980
- "Delete a data table and all its rows."
981
- deleteDataTable(tableId: String): DeleteResult @authorize(policy: "DataTables_Delete") @cost(weight: "10")
982
- """
983
- Create a new row in a data table.
984
- Example: Add a new menu item to a menu board table.
985
- """
986
- createDataTableRow(input: CreateDataTableRowInput): DataTableRowMutationResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
987
- """
988
- Update an existing row in a data table (partial update — only provided keys are changed).
989
- Example: Update the price of a menu item.
990
- """
991
- updateDataTableRow(input: UpdateDataTableRowInput): DataTableRowMutationResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
992
- "Delete a row from a data table."
993
- deleteDataTableRow(tableId: String rowId: String): DeleteResult @authorize(policy: "DataTables_Delete") @cost(weight: "10")
994
- """
995
- Batch create multiple rows in a data table (max 100 rows per call).
996
- Example: Bulk-load menu items into a table from an external data source.
997
- """
998
- batchCreateDataTableRows(input: BatchCreateDataTableRowsInput): BatchCreateDataTableRowsResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
999
- "Batch delete multiple rows from a data table (max 100 row IDs per call)."
1000
- batchDeleteDataTableRows(input: BatchDeleteDataTableRowsInput): BatchDeleteDataTableRowsResult @authorize(policy: "DataTables_Delete") @cost(weight: "10")
1001
- """
1002
- Import rows from CSV content into a data table.
1003
- Example: Import a spreadsheet of menu items. Use replace mode to overwrite all existing rows.
1004
- """
1005
- importDataTableRows(input: ImportDataTableRowsInput): ImportDataTableRowsResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
1006
- "Reorder rows in a data table by specifying the desired row ID sequence."
1007
- reorderDataTableRows(input: ReorderDataTableRowsInput): DeleteResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
1008
- """
1009
- Roll back a row to a previous version, creating a new version for the rollback action.
1010
- Example: Undo an accidental price change by restoring a previous version.
1011
- """
1012
- rollbackDataTableRow(input: RollbackDataTableRowInput): RollbackDataTableRowResult @authorize(policy: "DataTables_Edit") @cost(weight: "10")
1013
- """
1014
- Send commands to a specific device.
1015
- Commands are dispatched via Azure SignalR, FCM, Pusher, and legacy SignalR channels
1016
- depending on the device type.
1017
-
1018
- Known commands: restart, reboot, screenshot, refresh, display_on, display_off, volume (arg: 0-100), clear_cache, update.
1019
- """
1020
- sendDeviceCommand(deviceId: String commands: [CommandInput]): CommandResult @authorize(policy: "Devices_Edit") @cost(weight: "10")
1021
- """
1022
- Send commands to multiple devices at once.
1023
-
1024
- Known commands: restart, reboot, screenshot, refresh, display_on, display_off, volume (arg: 0-100), clear_cache, update.
1025
- """
1026
- sendBulkDeviceCommands(input: BulkCommandInput): BulkCommandResult @authorize(policy: "Devices_Edit") @cost(weight: "10")
1027
- """
1028
- Create a new media asset by downloading from a URL.
1029
- Useful for AI agents that generate images/videos and need to add them to the CMS.
1030
- Example: AI generates a promotional image via DALL-E and uploads it for digital signage display.
1031
- """
1032
- createMediaFromUrl(input: CreateMediaFromUrlInput): CreateMediaResult @authorize(policy: "Files_Edit") @cost(weight: "10")
1033
- """
1034
- Update media metadata. Does not replace the media file itself.
1035
- Example: Set an end date on underperforming media to automatically stop playback.
1036
- """
1037
- updateMedia(input: UpdateMediaInput): UpdateMediaResult @authorize(policy: "Files_Edit") @cost(weight: "10")
1038
- """
1039
- Delete a media asset by ID.
1040
- Example: Remove AI-generated content that is no longer needed.
1041
-
1042
- TEMPORARY: Short-circuited as a no-op until validated in production.
1043
- TODO: Re-enable actual deletion once testing is complete.
1044
- """
1045
- deleteMedia(id: String): DeleteResult @authorize(policy: "Files_Delete") @cost(weight: "10")
1046
- """
1047
- Add a content source to an existing playlist.
1048
- Example: AI generates a new image and adds it to the lobby playlist to improve engagement.
1049
- """
1050
- addPlaylistSource(input: AddPlaylistSourceInput): PlaylistMutationResult @authorize(policy: "Playlists_Edit") @cost(weight: "10")
1051
- """
1052
- Update a source within a playlist.
1053
- Example: Change the duration of an ad slot based on engagement metrics.
1054
- """
1055
- updatePlaylistSource(input: UpdatePlaylistSourceInput): PlaylistMutationResult @authorize(policy: "Playlists_Edit") @cost(weight: "10")
1056
- """
1057
- Remove a source from a playlist by source ID.
1058
- Example: Remove under-performing media from a playlist to improve overall engagement.
1059
- """
1060
- removePlaylistSource(playlistId: String sourceId: String): PlaylistMutationResult @authorize(policy: "Playlists_Edit") @cost(weight: "10")
1061
- """
1062
- Reorder sources within a playlist.
1063
- Example: Promote high-performing content to play first based on analytics data.
1064
- """
1065
- reorderPlaylistSources(input: ReorderPlaylistSourcesInput): PlaylistMutationResult @authorize(policy: "Playlists_Edit") @cost(weight: "10")
1066
- }
1067
-
1068
1787
  """
1069
1788
  Result from the getPermissions query.
1070
1789
  Tells AI agents and MCP tools which operations are available for the current authenticated user or API key.
@@ -1090,7 +1809,7 @@ type PingData {
1090
1809
  "Ping type"
1091
1810
  type: String
1092
1811
  "Snapshot (screenshot) of live player content"
1093
- snap: [Byte!]
1812
+ snap: [UnsignedByte!]
1094
1813
  "Player version number"
1095
1814
  playerVersion: String
1096
1815
  "Player OS version"
@@ -1136,7 +1855,7 @@ type PingData {
1136
1855
  "Package download progress (percentage)"
1137
1856
  downloadPctComplete: Long
1138
1857
  "Dictionary of meta data"
1139
- meta: [KeyValuePairOfStringAndString!]
1858
+ meta: [KeyValuePairOfNullableStringAndNullableString!]
1140
1859
  "Current CPU temperature"
1141
1860
  cpuTemperature: Float
1142
1861
  }
@@ -1193,157 +1912,6 @@ type PlaylistMutationResult {
1193
1912
  error: String
1194
1913
  }
1195
1914
 
1196
- type Query @authorize {
1197
- """
1198
- Get play logs - records of when media content was played on devices.
1199
- Useful for tracking content playback history and calculating media impressions.
1200
- """
1201
- playLogs("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of file IDs to filter by" fileId: [String!] "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkPlayLogFilterInput @cost(weight: "10") order: [AdHawkPlayLogSortInput!] @cost(weight: "10")): [AdHawkPlayLog] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1202
- """
1203
- Get ping logs - device heartbeat/health data including CPU, memory, and disk usage.
1204
- Useful for monitoring device health and identifying performance issues.
1205
- Example: Find devices with average CPU usage over 90%.
1206
- """
1207
- pingLogs("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of ping types to filter by (1=alive, 2=downloading, 4=playing)" type: [Int!] "Optional minimum CPU usage percentage to filter by" minCpuUsage: Float "Optional minimum memory usage percentage to filter by" minMemoryUsage: Float "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkPingLogFilterInput @cost(weight: "10") order: [AdHawkPingLogSortInput!] @cost(weight: "10")): [AdHawkPingLog] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1208
- """
1209
- Get event logs - custom events generated by devices or applications.
1210
- Useful for tracking user interactions, button clicks, page views, etc.
1211
- """
1212
- eventLogs("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of event names to filter by" eventName: [String!] "Optional session ID to filter by" sessionId: String "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkEventLogFilterInput @cost(weight: "10") order: [AdHawkEventLogSortInput!] @cost(weight: "10")): [AdHawkEventLog] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1213
- """
1214
- Get aggregated event metrics for devices over a time period.
1215
- Useful for analyzing event patterns, user engagement, and interaction trends.
1216
- Metrics include total events, unique sessions, and event breakdowns.
1217
- """
1218
- eventMetrics("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of event names to filter by" eventName: [String!] "Time interval for aggregation (minute, hour, day, week, month)" interval: AdHawkIntervalType! = DAY "Group results by device (default: true)" groupByDevice: Boolean! = false "Group results by event name (default: false)" groupByEvent: Boolean! = false "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkEventMetricsFilterInput @cost(weight: "10") order: [AdHawkEventMetricsSortInput!] @cost(weight: "10")): [AdHawkEventMetrics] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1219
- """
1220
- Get impressions - audience detection data from sensors (motion, face detection, BLE, WiFi).
1221
- Useful for analyzing visitor demographics, dwell time, and traffic patterns.
1222
- """
1223
- impressions("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of impression types to filter by (8=motion, 64=audience, 128=ble, 256=wifi)" type: [Int!] "Optional gender to filter by" gender: AdHawkGender "Optional minimum dwell time in milliseconds" minDwellTime: Long "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkImpressionFilterInput @cost(weight: "10") order: [AdHawkImpressionSortInput!] @cost(weight: "10")): [AdHawkImpression] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1224
- """
1225
- Get aggregated device health metrics over a time period.
1226
- Useful for monitoring fleet health, identifying problematic devices, and capacity planning.
1227
- Metrics include CPU, memory, disk usage, and network traffic.
1228
- """
1229
- deviceMetrics("Optional list of device IDs to filter by" deviceId: [String!] "Time interval for aggregation (minute, hour, day, week, month)" interval: AdHawkIntervalType! = DAY "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkDeviceMetricsFilterInput @cost(weight: "10") order: [AdHawkDeviceMetricsSortInput!] @cost(weight: "10")): [AdHawkDeviceMetrics] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1230
- """
1231
- Get aggregated audience metrics for devices over a time period.
1232
- Useful for analyzing visitor demographics, traffic patterns, and engagement.
1233
- Metrics include impressions, unique visitors, dwell time, gender, and age breakdowns.
1234
- """
1235
- audienceMetrics("Optional list of device IDs to filter by" deviceId: [String!] "Time interval for aggregation (minute, hour, day, week, month)" interval: AdHawkIntervalType! = DAY "Group results by device (default: false)" groupByDevice: Boolean! = false "When true, queries exit events with dwell time data. When false (default), queries enter events without dwell time." includeDwellTime: Boolean! = false "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkAudienceMetricsFilterInput @cost(weight: "10") order: [AdHawkAudienceMetricsSortInput!] @cost(weight: "10")): [AdHawkAudienceMetrics] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1236
- """
1237
- Get media play statistics - aggregated play counts and durations for media files.
1238
- Useful for analyzing content performance and identifying popular media.
1239
- """
1240
- mediaPlayStats("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of file IDs to filter by" fileId: [String!] "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 100, max: 10000)" limit: Int! = 100 where: AdHawkMediaPlayStatsFilterInput @cost(weight: "10") order: [AdHawkMediaPlayStatsSortInput!] @cost(weight: "10")): [AdHawkMediaPlayStats] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1241
- """
1242
- Get device play statistics - aggregated play counts and duration for each device.
1243
- Useful for DooH reporting to analyze device performance and content distribution.
1244
- Example: Find which devices played the most content in a date range.
1245
- """
1246
- devicePlayStats("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of file IDs to filter by" fileId: [String!] "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 100, max: 10000)" limit: Int! = 100 where: AdHawkDevicePlayStatsFilterInput @cost(weight: "10") order: [AdHawkDevicePlayStatsSortInput!] @cost(weight: "10")): [AdHawkDevicePlayStats] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1247
- """
1248
- Get device and media combined play statistics - shows what content played on which devices.
1249
- Useful for DooH reporting to analyze device/content performance matrix.
1250
- Example: Find which devices played a specific ad campaign most frequently.
1251
- """
1252
- deviceMediaPlayStats("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of file IDs to filter by" fileId: [String!] "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 100, max: 10000)" limit: Int! = 100 where: AdHawkDeviceMediaPlayStatsFilterInput @cost(weight: "10") order: [AdHawkDeviceMediaPlayStatsSortInput!] @cost(weight: "10")): [AdHawkDeviceMediaPlayStats] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1253
- """
1254
- Get time-series play statistics - aggregated play data by time intervals.
1255
- Useful for DooH reporting to analyze playback trends over time (hourly, daily, weekly, etc.).
1256
- Example: Chart daily play counts for a specific media file over the past month.
1257
- """
1258
- playStatsByTime("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of file IDs to filter by" fileId: [String!] "Time interval for aggregation (minute, hour, day, week, month)" interval: AdHawkIntervalType! = DAY "Group results by device (default: false)" groupByDevice: Boolean! = false "Group results by file (default: false)" groupByFile: Boolean! = false "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkPlayStatsByTimeFilterInput @cost(weight: "10") order: [AdHawkPlayStatsByTimeSortInput!] @cost(weight: "10")): [AdHawkPlayStatsByTime] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1259
- """
1260
- Get event flow data for Sankey-type visualizations.
1261
- Builds a chronological sequence of events indicating the path users took through sessions.
1262
- Useful for analyzing user navigation patterns and behavior flows.
1263
- """
1264
- eventFlow("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of event names to filter by" eventName: [String!] "Maximum depth level for event flow (default: 6). Controls how many event transitions to include." eventDepthLevel: Int! = 6 "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkEventFlowFilterInput @cost(weight: "10") order: [AdHawkEventFlowSortInput!] @cost(weight: "10")): [AdHawkEventFlow] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1265
- """
1266
- Get geographic heatmap data aggregated by location.
1267
- Groups impression data by geographic region returning a dataset aggregated by location.
1268
- Useful for heatmap or geographic visualizations.
1269
- """
1270
- heatMapData("Optional list of device IDs to filter by" deviceId: [String!] "Time interval for aggregation (minute, hour, day, week, month)" interval: AdHawkIntervalType! = DAY "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkHeatMapDataFilterInput @cost(weight: "10") order: [AdHawkHeatMapDataSortInput!] @cost(weight: "10")): [AdHawkHeatMapData] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1271
- """
1272
- Get geographic heatmap data for events aggregated by location.
1273
- Groups event data by geographic region returning a dataset aggregated by location.
1274
- Useful for heatmap or geographic visualizations of event activity.
1275
- """
1276
- eventHeatMapData("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of event names to filter by" eventName: [String!] "Time interval for aggregation (minute, hour, day, week, month)" interval: AdHawkIntervalType! = DAY "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 1000, max: 10000)" limit: Int! = 1000 where: AdHawkEventHeatMapDataFilterInput @cost(weight: "10") order: [AdHawkEventHeatMapDataSortInput!] @cost(weight: "10")): [AdHawkEventHeatMapData] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1277
- """
1278
- Get media impressions (OTS - Opportunity To See) data aggregated by media file.
1279
- Joins audience/impression data with play logs to determine which audience members
1280
- had an opportunity to see specific media content during playback.
1281
- Useful for measuring media effectiveness and audience engagement.
1282
- """
1283
- mediaImpressions("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of file\/media IDs to filter by" fileId: [String!] "Minimum dwell time in milliseconds to count as \"viewed\" (default: 100ms)" minDwellThreshold: Long! = 100 "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 100, max: 10000)" limit: Int! = 100 where: AdHawkMediaImpressionsFilterInput @cost(weight: "10") order: [AdHawkMediaImpressionsSortInput!] @cost(weight: "10")): [AdHawkMediaImpressions] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1284
- """
1285
- Get media impressions (OTS - Opportunity To See) data aggregated by device.
1286
- Joins audience/impression data with play logs to determine which devices
1287
- had the most audience engagement during media playback.
1288
- Useful for identifying high-performing locations and devices.
1289
- """
1290
- deviceMediaImpressions("Optional list of device IDs to filter by" deviceId: [String!] "Optional list of file\/media IDs to filter by" fileId: [String!] "Minimum dwell time in milliseconds to count as \"viewed\" (default: 100ms)" minDwellThreshold: Long! = 100 "Start date for the query (required)" startDate: DateTime! "End date for the query (required)" endDate: DateTime! "Maximum number of results (default: 100, max: 10000)" limit: Int! = 100 where: AdHawkDeviceMediaImpressionsFilterInput @cost(weight: "10") order: [AdHawkDeviceMediaImpressionsSortInput!] @cost(weight: "10")): [AdHawkDeviceMediaImpressions] @authorize(policy: "AdHawk_View") @cost(weight: "10")
1291
- """
1292
- Gets alerts for the authenticated account.
1293
-
1294
-
1295
- **Returns:**
1296
- List of alerts
1297
- """
1298
- alert("Filter by specific alert IDs (encrypted)" id: [String!] "Filter by device IDs (encrypted)" deviceId: [String!] "Filter to show only active alerts" activeOnly: Boolean "Filter by resolved state" resolved: Boolean "Filter by organization ID (encrypted)" orgId: String "Maximum number of items to return" limit: Int where: AlertFilterInput @cost(weight: "10") order: [AlertSortInput!] @cost(weight: "10")): [Alert] @authorize(policy: "Alerts_View") @cost(weight: "10")
1299
- """
1300
- Gets audit events for the authenticated account.
1301
- Requires the user to be an account owner.
1302
-
1303
-
1304
- **Returns:**
1305
- List of audit events
1306
- """
1307
- auditEvent("Filter by user ID (encrypted)" userId: String "Filter by event type" eventType: String "Filter by HTTP method (GET, POST, PUT, DELETE, etc.)" httpMethod: String "Filter by controller name" controllerName: String "Filter by action name" actionName: String "Filter events after this date" startDate: DateTime "Filter events before this date" endDate: DateTime "Filter by IP address" ipAddress: String "Filter by HTTP response code" responseCode: String "Maximum number of items to return" limit: Int where: AuditEventFilterInput @cost(weight: "10") order: [AuditEventSortInput!] @cost(weight: "10")): [AuditEvent!]! @authorize(policy: "AuditEventsOwnerOnly") @cost(weight: "10")
1308
- "Lists data tables in the account, with optional group filtering."
1309
- dataTables("Optional group ID to filter by" groupId: String "Number of tables per page (default 50)" pageSize: Int! = 50 "Token for fetching the next page" continuationToken: String): DataTableListResponse @authorize(policy: "DataTables_View") @cost(weight: "10")
1310
- "Gets a single data table definition by ID, including column schema."
1311
- dataTable("The data table ID" tableId: String): DataTableDetail @authorize(policy: "DataTables_View") @cost(weight: "10")
1312
- "Lists rows in a data table, with optional filtering, sorting, and field selection."
1313
- dataTableRows("The data table ID" tableId: String "Optional filter as a JSON string (e.g., {\"status\":\"active\"})" filter: String "Column key to sort by" sort: String "Sort direction: \"asc\" or \"desc\"" sortDir: String = "asc" "Number of rows per page (default 50)" pageSize: Int! = 50 "Token for fetching the next page" continuationToken: String "Comma-separated list of column keys to return" fields: String): RowListResponse @authorize(policy: "DataTables_View") @cost(weight: "10")
1314
- "Gets a single row by ID."
1315
- dataTableRow("The data table ID" tableId: String "The row ID" rowId: String): DataTableRowModel @authorize(policy: "DataTables_View") @cost(weight: "10")
1316
- "Exports all rows from a data table as a CSV string."
1317
- exportDataTableRows("The data table ID" tableId: String): String @authorize(policy: "DataTables_View") @cost(weight: "10")
1318
- "Lists version history for a row (newest first)."
1319
- dataTableRowVersions("The data table ID" tableId: String "The row ID" rowId: String "Number of versions per page (default 25)" pageSize: Int! = 25 "Token for fetching the next page" continuationToken: String): VersionListResponse @authorize(policy: "DataTables_View") @cost(weight: "10")
1320
- "Gets a specific version snapshot of a row."
1321
- dataTableRowVersion("The data table ID" tableId: String "The row ID" rowId: String "The version number to retrieve" version: Int!): RowVersionModel @authorize(policy: "DataTables_View") @cost(weight: "10")
1322
- device(id: [String!] groupId: [String!] groupName: [String!] deviceTypeId: [String!] includeSnap: Boolean orgId: String tag: [String!] limit: Int where: DeviceFilterInput @cost(weight: "10") order: [DeviceSortInput!] @cost(weight: "10")): [Device] @authorize(policy: "Devices_View") @cost(weight: "10")
1323
- deviceGroups(id: String tree: Boolean limit: Int where: GroupFilterInput @cost(weight: "10") order: [GroupSortInput!] @cost(weight: "10")): [Group] @authorize(policy: "Devices_View") @cost(weight: "10")
1324
- """
1325
- Gets the display commands configured for the authenticated account.
1326
- These commands define the available actions that can be sent to devices
1327
- (e.g., via the sendDeviceCommand mutation).
1328
- """
1329
- displayCommands(where: DisplayCommandFilterInput @cost(weight: "10") order: [DisplayCommandSortInput!] @cost(weight: "10")): [DisplayCommand] @authorize(policy: "Devices_View") @cost(weight: "10")
1330
- media(id: [String!] groupId: [String!] groupName: [String!] orgId: String tag: [String!] limit: Int where: MediaFilterInput @cost(weight: "10") order: [MediaSortInput!] @cost(weight: "10")): [Media] @authorize(policy: "Files_View") @cost(weight: "10")
1331
- mediaGroups(id: String tree: Boolean limit: Int where: GroupFilterInput @cost(weight: "10") order: [GroupSortInput!] @cost(weight: "10")): [Group] @authorize(policy: "Files_View") @cost(weight: "10")
1332
- """
1333
- Get the permissions for the currently authenticated user or API key.
1334
- Returns per-resource view/edit/delete flags and lists of allowed/denied mutation tool names.
1335
- AI agents should call this query at the start of every session to determine which action tools are available.
1336
- """
1337
- permissions: PermissionsResult @authorize @cost(weight: "10")
1338
- playlist(id: [String!] groupId: [String!] groupName: [String!] orgId: String tag: [String!] limit: Int where: PlaylistFilterInput @cost(weight: "10") order: [PlaylistSortInput!] @cost(weight: "10")): [Playlist] @authorize(policy: "Playlists_View") @cost(weight: "10")
1339
- playlistGroups(id: String tree: Boolean limit: Int where: GroupFilterInput @cost(weight: "10") order: [GroupSortInput!] @cost(weight: "10")): [Group] @authorize(policy: "Playlists_View") @cost(weight: "10")
1340
- schedule(id: [String!] groupId: [String!] groupName: [String!] deviceId: String orgId: String tag: [String!] limit: Int where: ScheduleFilterInput @cost(weight: "10") order: [ScheduleSortInput!] @cost(weight: "10")): [Schedule] @authorize(policy: "Schedules_View") @cost(weight: "10")
1341
- scheduleGroups(id: String tree: Boolean limit: Int where: GroupFilterInput @cost(weight: "10") order: [GroupSortInput!] @cost(weight: "10")): [Group] @authorize(policy: "Schedules_View") @cost(weight: "10")
1342
- template(id: [String!] groupId: [String!] groupName: [String!] orgId: String tag: [String!] limit: Int where: TemplateFilterInput @cost(weight: "10") order: [TemplateSortInput!] @cost(weight: "10")): [Template] @authorize(policy: "Templates_View") @cost(weight: "10")
1343
- templateGroups(id: String tree: Boolean limit: Int where: GroupFilterInput @cost(weight: "10") order: [GroupSortInput!] @cost(weight: "10")): [Group] @authorize(policy: "Templates_View") @cost(weight: "10")
1344
- user(id: [String!] limit: Int where: UserFilterInput @cost(weight: "10") order: [UserSortInput!] @cost(weight: "10")): [User] @authorize(policy: "Account_ManageUsers_View") @cost(weight: "10")
1345
- }
1346
-
1347
1915
  "Per-resource permission summary."
1348
1916
  type ResourcePermission {
1349
1917
  "The resource area (e.g., 'Devices', 'Files', 'Playlists', 'Schedules', 'Alerts', 'AdHawk')."
@@ -1379,9 +1947,9 @@ type RowVersionModel {
1379
1947
  rowId: String
1380
1948
  version: Int!
1381
1949
  action: String
1382
- data: JSON
1950
+ data: Any
1383
1951
  changedFields: [String]
1384
- previousValues: JSON
1952
+ previousValues: Any
1385
1953
  changedBy: String
1386
1954
  timestamp: DateTime!
1387
1955
  }
@@ -1614,12 +2182,35 @@ type User {
1614
2182
  isTwoFactor: Boolean
1615
2183
  }
1616
2184
 
2185
+ "Structured validation error suitable for programmatic handling and retry."
2186
+ type ValidationError {
2187
+ """
2188
+ The column key (matches `DataTableColumn.key`) that failed validation.
2189
+ May be null for table-level errors.
2190
+ """
2191
+ field: String
2192
+ "Machine-readable error code."
2193
+ code: ValidationErrorCode!
2194
+ "Human-readable error message describing the violation."
2195
+ message: String
2196
+ }
2197
+
1617
2198
  type VersionListResponse {
1618
2199
  data: [RowVersionModel]
1619
2200
  totalCount: Int!
1620
2201
  continuationToken: String
1621
2202
  }
1622
2203
 
2204
+ "Input for adding a content source to a playlist."
2205
+ input AddPlaylistSourceInput {
2206
+ "The playlist ID to add the source to."
2207
+ playlistId: String
2208
+ "The source to add."
2209
+ source: SourceInput
2210
+ "Optional position (0-based index). If omitted, appends to end."
2211
+ position: Int
2212
+ }
2213
+
1623
2214
  "Aggregated audience metrics for a device over a time period"
1624
2215
  input AdHawkAudienceMetricsFilterInput {
1625
2216
  and: [AdHawkAudienceMetricsFilterInput!]
@@ -1662,7 +2253,7 @@ input AdHawkAudienceMetricsFilterInput {
1662
2253
  ageOver74: LongOperationFilterInput
1663
2254
  "Number of motion sensor detections"
1664
2255
  motionCount: LongOperationFilterInput
1665
- "Number of audience\/face detections"
2256
+ "Number of audience/face detections"
1666
2257
  audienceCount: LongOperationFilterInput
1667
2258
  "Number of BLE beacon detections"
1668
2259
  bleCount: LongOperationFilterInput
@@ -1710,7 +2301,7 @@ input AdHawkAudienceMetricsSortInput {
1710
2301
  ageOver74: SortEnumType @cost(weight: "10")
1711
2302
  "Number of motion sensor detections"
1712
2303
  motionCount: SortEnumType @cost(weight: "10")
1713
- "Number of audience\/face detections"
2304
+ "Number of audience/face detections"
1714
2305
  audienceCount: SortEnumType @cost(weight: "10")
1715
2306
  "Number of BLE beacon detections"
1716
2307
  bleCount: SortEnumType @cost(weight: "10")
@@ -1789,13 +2380,13 @@ input AdHawkDeviceMediaPlayStatsFilterInput {
1789
2380
  fileName: StringOperationFilterInput
1790
2381
  "Total number of times this media was played on this device"
1791
2382
  totalPlays: LongOperationFilterInput
1792
- "Total duration of all plays in milliseconds"
2383
+ "Total duration of all plays in seconds"
1793
2384
  totalDuration: LongOperationFilterInput
1794
- "Average play duration in milliseconds"
2385
+ "Average play duration in seconds"
1795
2386
  avgDuration: DecimalOperationFilterInput
1796
- "First play timestamp for this device\/media combination"
2387
+ "First play timestamp for this device/media combination"
1797
2388
  firstPlay: DateTimeOperationFilterInput
1798
- "Last play timestamp for this device\/media combination"
2389
+ "Last play timestamp for this device/media combination"
1799
2390
  lastPlay: DateTimeOperationFilterInput
1800
2391
  }
1801
2392
 
@@ -1814,13 +2405,13 @@ input AdHawkDeviceMediaPlayStatsSortInput {
1814
2405
  fileName: SortEnumType @cost(weight: "10")
1815
2406
  "Total number of times this media was played on this device"
1816
2407
  totalPlays: SortEnumType @cost(weight: "10")
1817
- "Total duration of all plays in milliseconds"
2408
+ "Total duration of all plays in seconds"
1818
2409
  totalDuration: SortEnumType @cost(weight: "10")
1819
- "Average play duration in milliseconds"
2410
+ "Average play duration in seconds"
1820
2411
  avgDuration: SortEnumType @cost(weight: "10")
1821
- "First play timestamp for this device\/media combination"
2412
+ "First play timestamp for this device/media combination"
1822
2413
  firstPlay: SortEnumType @cost(weight: "10")
1823
- "Last play timestamp for this device\/media combination"
2414
+ "Last play timestamp for this device/media combination"
1824
2415
  lastPlay: SortEnumType @cost(weight: "10")
1825
2416
  }
1826
2417
 
@@ -1903,9 +2494,9 @@ input AdHawkDevicePlayStatsFilterInput {
1903
2494
  deviceName: StringOperationFilterInput
1904
2495
  "Total number of media files played on this device"
1905
2496
  totalPlays: LongOperationFilterInput
1906
- "Total duration of all plays in milliseconds"
2497
+ "Total duration of all plays in seconds"
1907
2498
  totalDuration: LongOperationFilterInput
1908
- "Average play duration in milliseconds"
2499
+ "Average play duration in seconds"
1909
2500
  avgDuration: DecimalOperationFilterInput
1910
2501
  "Number of unique media files played on this device"
1911
2502
  fileCount: LongOperationFilterInput
@@ -1926,9 +2517,9 @@ input AdHawkDevicePlayStatsSortInput {
1926
2517
  deviceName: SortEnumType @cost(weight: "10")
1927
2518
  "Total number of media files played on this device"
1928
2519
  totalPlays: SortEnumType @cost(weight: "10")
1929
- "Total duration of all plays in milliseconds"
2520
+ "Total duration of all plays in seconds"
1930
2521
  totalDuration: SortEnumType @cost(weight: "10")
1931
- "Average play duration in milliseconds"
2522
+ "Average play duration in seconds"
1932
2523
  avgDuration: SortEnumType @cost(weight: "10")
1933
2524
  "Number of unique media files played on this device"
1934
2525
  fileCount: SortEnumType @cost(weight: "10")
@@ -2123,7 +2714,7 @@ input AdHawkHeatMapDataFilterInput {
2123
2714
  wifiCount: LongOperationFilterInput
2124
2715
  "Count of motion sensor impressions"
2125
2716
  motionCount: LongOperationFilterInput
2126
- "Count of audience\/face detection impressions"
2717
+ "Count of audience/face detection impressions"
2127
2718
  audienceCount: LongOperationFilterInput
2128
2719
  }
2129
2720
 
@@ -2148,11 +2739,11 @@ input AdHawkHeatMapDataSortInput {
2148
2739
  wifiCount: SortEnumType @cost(weight: "10")
2149
2740
  "Count of motion sensor impressions"
2150
2741
  motionCount: SortEnumType @cost(weight: "10")
2151
- "Count of audience\/face detection impressions"
2742
+ "Count of audience/face detection impressions"
2152
2743
  audienceCount: SortEnumType @cost(weight: "10")
2153
2744
  }
2154
2745
 
2155
- "Represents an audience impression\/detection entry"
2746
+ "Represents an audience impression/detection entry"
2156
2747
  input AdHawkImpressionFilterInput {
2157
2748
  and: [AdHawkImpressionFilterInput!]
2158
2749
  or: [AdHawkImpressionFilterInput!]
@@ -2182,13 +2773,13 @@ input AdHawkImpressionFilterInput {
2182
2773
  age: IntOperationFilterInput
2183
2774
  "Age range classification"
2184
2775
  ageRange: NullableOfAdHawkAgeRangeOperationFilterInput
2185
- "Received Signal Strength Indicator for BLE\/WiFi detections"
2776
+ "Received Signal Strength Indicator for BLE/WiFi detections"
2186
2777
  rssi: IntOperationFilterInput
2187
2778
  "UTC offset of the device at the time of detection"
2188
2779
  utcOffset: IntOperationFilterInput
2189
2780
  }
2190
2781
 
2191
- "Represents an audience impression\/detection entry"
2782
+ "Represents an audience impression/detection entry"
2192
2783
  input AdHawkImpressionSortInput {
2193
2784
  "Unique identifier for this impression entry"
2194
2785
  id: SortEnumType @cost(weight: "10")
@@ -2216,7 +2807,7 @@ input AdHawkImpressionSortInput {
2216
2807
  age: SortEnumType @cost(weight: "10")
2217
2808
  "Age range classification"
2218
2809
  ageRange: SortEnumType @cost(weight: "10")
2219
- "Received Signal Strength Indicator for BLE\/WiFi detections"
2810
+ "Received Signal Strength Indicator for BLE/WiFi detections"
2220
2811
  rssi: SortEnumType @cost(weight: "10")
2221
2812
  "UTC offset of the device at the time of detection"
2222
2813
  utcOffset: SortEnumType @cost(weight: "10")
@@ -2230,9 +2821,9 @@ members had an opportunity to see specific media content.
2230
2821
  input AdHawkMediaImpressionsFilterInput {
2231
2822
  and: [AdHawkMediaImpressionsFilterInput!]
2232
2823
  or: [AdHawkMediaImpressionsFilterInput!]
2233
- "The file\/media ID"
2824
+ "The file/media ID"
2234
2825
  fileId: StringOperationFilterInput
2235
- "The file\/media name"
2826
+ "The file/media name"
2236
2827
  fileName: StringOperationFilterInput
2237
2828
  "Total number of impressions that occurred during media playback"
2238
2829
  totalImpressions: LongOperationFilterInput
@@ -2262,9 +2853,9 @@ Joins audience/impression data with media play logs to determine which audience
2262
2853
  members had an opportunity to see specific media content.
2263
2854
  """
2264
2855
  input AdHawkMediaImpressionsSortInput {
2265
- "The file\/media ID"
2856
+ "The file/media ID"
2266
2857
  fileId: SortEnumType @cost(weight: "10")
2267
- "The file\/media name"
2858
+ "The file/media name"
2268
2859
  fileName: SortEnumType @cost(weight: "10")
2269
2860
  "Total number of impressions that occurred during media playback"
2270
2861
  totalImpressions: SortEnumType @cost(weight: "10")
@@ -2298,9 +2889,9 @@ input AdHawkMediaPlayStatsFilterInput {
2298
2889
  fileName: StringOperationFilterInput
2299
2890
  "Total number of times this media was played"
2300
2891
  totalPlays: LongOperationFilterInput
2301
- "Total duration of all plays in milliseconds"
2892
+ "Total duration of all plays in seconds"
2302
2893
  totalDuration: LongOperationFilterInput
2303
- "Average play duration in milliseconds"
2894
+ "Average play duration in seconds"
2304
2895
  avgDuration: DecimalOperationFilterInput
2305
2896
  "Number of unique devices that played this media"
2306
2897
  deviceCount: LongOperationFilterInput
@@ -2314,15 +2905,15 @@ input AdHawkMediaPlayStatsSortInput {
2314
2905
  fileName: SortEnumType @cost(weight: "10")
2315
2906
  "Total number of times this media was played"
2316
2907
  totalPlays: SortEnumType @cost(weight: "10")
2317
- "Total duration of all plays in milliseconds"
2908
+ "Total duration of all plays in seconds"
2318
2909
  totalDuration: SortEnumType @cost(weight: "10")
2319
- "Average play duration in milliseconds"
2910
+ "Average play duration in seconds"
2320
2911
  avgDuration: SortEnumType @cost(weight: "10")
2321
2912
  "Number of unique devices that played this media"
2322
2913
  deviceCount: SortEnumType @cost(weight: "10")
2323
2914
  }
2324
2915
 
2325
- "Represents a device ping\/heartbeat log entry - records device health and status"
2916
+ "Represents a device ping/heartbeat log entry - records device health and status"
2326
2917
  input AdHawkPingLogFilterInput {
2327
2918
  and: [AdHawkPingLogFilterInput!]
2328
2919
  or: [AdHawkPingLogFilterInput!]
@@ -2356,7 +2947,7 @@ input AdHawkPingLogFilterInput {
2356
2947
  utcOffset: IntOperationFilterInput
2357
2948
  }
2358
2949
 
2359
- "Represents a device ping\/heartbeat log entry - records device health and status"
2950
+ "Represents a device ping/heartbeat log entry - records device health and status"
2360
2951
  input AdHawkPingLogSortInput {
2361
2952
  "Unique identifier for this ping log entry"
2362
2953
  id: SortEnumType @cost(weight: "10")
@@ -2402,7 +2993,7 @@ input AdHawkPlayLogFilterInput {
2402
2993
  fileId: StringOperationFilterInput
2403
2994
  "The name of the media file"
2404
2995
  fileName: StringOperationFilterInput
2405
- "Duration of the play in milliseconds"
2996
+ "Duration of the play in seconds"
2406
2997
  duration: IntOperationFilterInput
2407
2998
  "Type of play (internal use)"
2408
2999
  type: IntOperationFilterInput
@@ -2422,7 +3013,7 @@ input AdHawkPlayLogSortInput {
2422
3013
  fileId: SortEnumType @cost(weight: "10")
2423
3014
  "The name of the media file"
2424
3015
  fileName: SortEnumType @cost(weight: "10")
2425
- "Duration of the play in milliseconds"
3016
+ "Duration of the play in seconds"
2426
3017
  duration: SortEnumType @cost(weight: "10")
2427
3018
  "Type of play (internal use)"
2428
3019
  type: SortEnumType @cost(weight: "10")
@@ -2451,9 +3042,9 @@ input AdHawkPlayStatsByTimeFilterInput {
2451
3042
  periodEnd: DateTimeOperationFilterInput
2452
3043
  "Total number of plays during this period"
2453
3044
  totalPlays: LongOperationFilterInput
2454
- "Total duration of all plays in milliseconds"
3045
+ "Total duration of all plays in seconds"
2455
3046
  totalDuration: LongOperationFilterInput
2456
- "Average play duration in milliseconds"
3047
+ "Average play duration in seconds"
2457
3048
  avgDuration: DecimalOperationFilterInput
2458
3049
  "Number of unique devices (if aggregated by file)"
2459
3050
  deviceCount: LongOperationFilterInput
@@ -2480,9 +3071,9 @@ input AdHawkPlayStatsByTimeSortInput {
2480
3071
  periodEnd: SortEnumType @cost(weight: "10")
2481
3072
  "Total number of plays during this period"
2482
3073
  totalPlays: SortEnumType @cost(weight: "10")
2483
- "Total duration of all plays in milliseconds"
3074
+ "Total duration of all plays in seconds"
2484
3075
  totalDuration: SortEnumType @cost(weight: "10")
2485
- "Average play duration in milliseconds"
3076
+ "Average play duration in seconds"
2486
3077
  avgDuration: SortEnumType @cost(weight: "10")
2487
3078
  "Number of unique devices (if aggregated by file)"
2488
3079
  deviceCount: SortEnumType @cost(weight: "10")
@@ -2490,16 +3081,6 @@ input AdHawkPlayStatsByTimeSortInput {
2490
3081
  fileCount: SortEnumType @cost(weight: "10")
2491
3082
  }
2492
3083
 
2493
- "Input for adding a content source to a playlist."
2494
- input AddPlaylistSourceInput {
2495
- "The playlist ID to add the source to."
2496
- playlistId: String
2497
- "The source to add."
2498
- source: SourceInput
2499
- "Optional position (0-based index). If omitted, appends to end."
2500
- position: Int
2501
- }
2502
-
2503
3084
  "Device associated with an alert"
2504
3085
  input AlertDeviceFilterInput {
2505
3086
  and: [AlertDeviceFilterInput!]
@@ -2576,6 +3157,15 @@ input AlertSortInput {
2576
3157
  isActive: SortEnumType @cost(weight: "10")
2577
3158
  }
2578
3159
 
3160
+ """
3161
+ Inputs for approving a media asset. Approval is reversible — calling DeclineMedia
3162
+ on a previously approved file will move it back to declined state.
3163
+ """
3164
+ input ApproveMediaInput {
3165
+ "The media ID to approve."
3166
+ id: String
3167
+ }
3168
+
2579
3169
  "Audit event model representing account activity"
2580
3170
  input AuditEventFilterInput {
2581
3171
  and: [AuditEventFilterInput!]
@@ -2654,8 +3244,14 @@ input AuditEventSortInput {
2654
3244
  input BatchCreateDataTableRowsInput {
2655
3245
  "The table ID to add rows to."
2656
3246
  tableId: String
2657
- "Row data objects to create (max 100)."
2658
- rows: [JSON]
3247
+ """
3248
+ Row data objects to create (max 100). Each object follows the same key/value
3249
+ rules as `createDataTableRow.input.data` — keys must match column keys and
3250
+ values must match each column's declared `ColumnType` (MEDIA accepts an encrypted
3251
+ media id string, `{ "mediaId": "..." }`, or a fully-resolved `{ url, thumbnailUrl,
3252
+ name, mimeType }` object).
3253
+ """
3254
+ rows: [Any]
2659
3255
  }
2660
3256
 
2661
3257
  "Input for batch deleting rows."
@@ -2828,21 +3424,6 @@ input BulkCommandInput {
2828
3424
  commands: [CommandInput]
2829
3425
  }
2830
3426
 
2831
- input ByteOperationFilterInput {
2832
- eq: Byte @cost(weight: "10")
2833
- neq: Byte @cost(weight: "10")
2834
- in: [Byte] @cost(weight: "10")
2835
- nin: [Byte] @cost(weight: "10")
2836
- gt: Byte @cost(weight: "10")
2837
- ngt: Byte @cost(weight: "10")
2838
- gte: Byte @cost(weight: "10")
2839
- ngte: Byte @cost(weight: "10")
2840
- lt: Byte @cost(weight: "10")
2841
- nlt: Byte @cost(weight: "10")
2842
- lte: Byte @cost(weight: "10")
2843
- nlte: Byte @cost(weight: "10")
2844
- }
2845
-
2846
3427
  "A command to send to a device."
2847
3428
  input CommandInput {
2848
3429
  """
@@ -2914,7 +3495,7 @@ input CreateDataTableInput {
2914
3495
  groupId: String
2915
3496
  "Column definitions (at least one required)."
2916
3497
  columns: [DataTableColumnInput]
2917
- "Optional cache TTL in seconds for gadget\/player reads."
3498
+ "Optional cache TTL in seconds for gadget/player reads."
2918
3499
  cacheTtlSeconds: Int
2919
3500
  }
2920
3501
 
@@ -2922,8 +3503,31 @@ input CreateDataTableInput {
2922
3503
  input CreateDataTableRowInput {
2923
3504
  "The table ID to add the row to."
2924
3505
  tableId: String
2925
- "Row data as a JSON object. Keys must match column keys defined in the table schema."
2926
- data: JSON
3506
+ """
3507
+ Row data as a JSON object. Each key MUST match a `key` from the table's column
3508
+ definitions, and each value MUST match that column's `ColumnType` value rules
3509
+ (e.g. STRING → JSON string, NUMBER → JSON number, BOOLEAN → JSON true/false,
3510
+ DATE → ISO 8601 string, SELECT → a value from the column's `options`,
3511
+ MEDIA → encrypted media id string OR `{ "mediaId": "..." }` OR a fully-resolved
3512
+ `{ url, thumbnailUrl, name, mimeType }` object — the server normalizes id/id-object
3513
+ forms to the canonical object before storage).
3514
+
3515
+ Best practice for agents: query `dataTable(tableId: "…") { columns { key type required options } }`
3516
+ first to discover the schema, then construct `data` accordingly. Validation
3517
+ failures return structured details in `structuredValidationErrors`.
3518
+ """
3519
+ data: Any
3520
+ }
3521
+
3522
+ """
3523
+ Input for creating a new organizational group (folder) for a resource type
3524
+ (devices, media, playlists, schedules, or templates).
3525
+ """
3526
+ input CreateGroupInput {
3527
+ "The name of the new group."
3528
+ name: String
3529
+ "Optional parent group ID to nest this group under. If omitted, the group is created at the root level."
3530
+ parentId: String
2927
3531
  }
2928
3532
 
2929
3533
  "Input for creating a media asset by downloading from a URL."
@@ -2934,7 +3538,7 @@ input CreateMediaFromUrlInput {
2934
3538
  groupId: String
2935
3539
  "Display name for the media."
2936
3540
  name: String
2937
- "Optional description\/tags."
3541
+ "Optional description/tags."
2938
3542
  description: String
2939
3543
  "Whether to share with sub-accounts."
2940
3544
  shared: Boolean!
@@ -2952,16 +3556,20 @@ input DataTableColumnInput {
2952
3556
  name: String
2953
3557
  "Unique key used in row data objects."
2954
3558
  key: String
2955
- "Data type of the column."
3559
+ """
3560
+ Data type of the column. See the `ColumnType` enum value descriptions for the
3561
+ per-type row-value contract (e.g. MEDIA accepts an encrypted media id, an
3562
+ id-object, or a fully-resolved media object).
3563
+ """
2956
3564
  type: ColumnType!
2957
- "Whether a value is required for this column."
2958
- required: Boolean!
2959
- "Whether the column supports sorting."
2960
- sortable: Boolean!
3565
+ "Whether a value is required for this column. Defaults to false when omitted."
3566
+ required: Boolean
3567
+ "Whether the column supports sorting. Defaults to false when omitted."
3568
+ sortable: Boolean
2961
3569
  "Allowed values for Select-type columns."
2962
3570
  options: [String]
2963
3571
  "Default value for the column."
2964
- default: JSON
3572
+ default: Any
2965
3573
  }
2966
3574
 
2967
3575
  input DateTimeOperationFilterInput {
@@ -2994,6 +3602,17 @@ input DecimalOperationFilterInput {
2994
3602
  nlte: Decimal @cost(weight: "10")
2995
3603
  }
2996
3604
 
3605
+ """
3606
+ Inputs for declining a media asset. Decline is reversible — calling ApproveMedia
3607
+ on a previously declined file will move it back to approved state.
3608
+ """
3609
+ input DeclineMediaInput {
3610
+ "The media ID to decline."
3611
+ id: String
3612
+ "Optional reason recorded on the file for audit purposes."
3613
+ reason: String
3614
+ }
3615
+
2997
3616
  """
2998
3617
  Represents a digital signage player device in the RevelDigital platform.
2999
3618
  A device is a registered hardware unit that displays content according to assigned schedules and templates.
@@ -3023,9 +3642,9 @@ input DeviceFilterInput {
3023
3642
  languageCode: StringOperationFilterInput
3024
3643
  "The timestamp of the last content sync with the server"
3025
3644
  lastUpdate: DateTimeOperationFilterInput
3026
- "The physical location\/address of the device"
3645
+ "The physical location/address of the device"
3027
3646
  location: LocationFilterInput
3028
- "The device ping\/heartbeat data"
3647
+ "The device ping/heartbeat data"
3029
3648
  pingData: PingDataFilterInput
3030
3649
  "The device registration key"
3031
3650
  registrationKey: StringOperationFilterInput
@@ -3079,9 +3698,9 @@ input DeviceSortInput {
3079
3698
  languageCode: SortEnumType @cost(weight: "10")
3080
3699
  "The timestamp of the last content sync with the server"
3081
3700
  lastUpdate: SortEnumType @cost(weight: "10")
3082
- "The physical location\/address of the device"
3701
+ "The physical location/address of the device"
3083
3702
  location: LocationSortInput @cost(weight: "10")
3084
- "The device ping\/heartbeat data"
3703
+ "The device ping/heartbeat data"
3085
3704
  pingData: PingDataSortInput @cost(weight: "10")
3086
3705
  "The device registration key"
3087
3706
  registrationKey: SortEnumType @cost(weight: "10")
@@ -3295,13 +3914,6 @@ input KeyValuePairOfStringAndStringFilterInput {
3295
3914
  value: StringOperationFilterInput
3296
3915
  }
3297
3916
 
3298
- input ListByteOperationFilterInput {
3299
- all: ByteOperationFilterInput @cost(weight: "10")
3300
- none: ByteOperationFilterInput @cost(weight: "10")
3301
- some: ByteOperationFilterInput @cost(weight: "10")
3302
- any: Boolean @cost(weight: "10")
3303
- }
3304
-
3305
3917
  input ListFilterInputTypeOfAlertDeviceFilterInput {
3306
3918
  all: AlertDeviceFilterInput @cost(weight: "10")
3307
3919
  none: AlertDeviceFilterInput @cost(weight: "10")
@@ -3365,6 +3977,13 @@ input ListStringOperationFilterInput {
3365
3977
  any: Boolean @cost(weight: "10")
3366
3978
  }
3367
3979
 
3980
+ input ListUnsignedByteOperationFilterInput {
3981
+ all: UnsignedByteOperationFilterInput @cost(weight: "10")
3982
+ none: UnsignedByteOperationFilterInput @cost(weight: "10")
3983
+ some: UnsignedByteOperationFilterInput @cost(weight: "10")
3984
+ any: Boolean @cost(weight: "10")
3985
+ }
3986
+
3368
3987
  input LocationFilterInput {
3369
3988
  and: [LocationFilterInput!]
3370
3989
  or: [LocationFilterInput!]
@@ -3451,6 +4070,14 @@ input MediaFilterInput {
3451
4070
  width: IntOperationFilterInput
3452
4071
  "The height of the media"
3453
4072
  height: IntOperationFilterInput
4073
+ "Approval state. True = approved for playback, false = declined, null = pending review."
4074
+ isApproved: BooleanOperationFilterInput
4075
+ "Timestamp the media was approved, if applicable."
4076
+ approvedOn: DateTimeOperationFilterInput
4077
+ "Timestamp the media was declined, if applicable."
4078
+ declinedOn: DateTimeOperationFilterInput
4079
+ "Reason recorded when the media was declined, if any."
4080
+ declinedReason: StringOperationFilterInput
3454
4081
  "The media name"
3455
4082
  name: StringOperationFilterInput
3456
4083
  "The group id"
@@ -3496,6 +4123,14 @@ input MediaSortInput {
3496
4123
  width: SortEnumType @cost(weight: "10")
3497
4124
  "The height of the media"
3498
4125
  height: SortEnumType @cost(weight: "10")
4126
+ "Approval state. True = approved for playback, false = declined, null = pending review."
4127
+ isApproved: SortEnumType @cost(weight: "10")
4128
+ "Timestamp the media was approved, if applicable."
4129
+ approvedOn: SortEnumType @cost(weight: "10")
4130
+ "Timestamp the media was declined, if applicable."
4131
+ declinedOn: SortEnumType @cost(weight: "10")
4132
+ "Reason recorded when the media was declined, if any."
4133
+ declinedReason: SortEnumType @cost(weight: "10")
3499
4134
  "The media name"
3500
4135
  name: SortEnumType @cost(weight: "10")
3501
4136
  "The group id"
@@ -3573,7 +4208,7 @@ input PingDataFilterInput {
3573
4208
  "Ping type"
3574
4209
  type: StringOperationFilterInput
3575
4210
  "Snapshot (screenshot) of live player content"
3576
- snap: ListByteOperationFilterInput
4211
+ snap: ListUnsignedByteOperationFilterInput
3577
4212
  "Player version number"
3578
4213
  playerVersion: StringOperationFilterInput
3579
4214
  "Player OS version"
@@ -4170,6 +4805,21 @@ input TemplateSortInput {
4170
4805
  orientation: SortEnumType @cost(weight: "10")
4171
4806
  }
4172
4807
 
4808
+ input UnsignedByteOperationFilterInput {
4809
+ eq: UnsignedByte @cost(weight: "10")
4810
+ neq: UnsignedByte @cost(weight: "10")
4811
+ in: [UnsignedByte] @cost(weight: "10")
4812
+ nin: [UnsignedByte] @cost(weight: "10")
4813
+ gt: UnsignedByte @cost(weight: "10")
4814
+ ngt: UnsignedByte @cost(weight: "10")
4815
+ gte: UnsignedByte @cost(weight: "10")
4816
+ ngte: UnsignedByte @cost(weight: "10")
4817
+ lt: UnsignedByte @cost(weight: "10")
4818
+ nlt: UnsignedByte @cost(weight: "10")
4819
+ lte: UnsignedByte @cost(weight: "10")
4820
+ nlte: UnsignedByte @cost(weight: "10")
4821
+ }
4822
+
4173
4823
  """
4174
4824
  Input for updating an existing data table definition.
4175
4825
  Only provided fields are changed.
@@ -4195,8 +4845,18 @@ input UpdateDataTableRowInput {
4195
4845
  tableId: String
4196
4846
  "The row ID to update."
4197
4847
  rowId: String
4198
- "Partial row data. Only provided keys are updated."
4199
- data: JSON
4848
+ """
4849
+ Partial row data. Only provided keys are updated; omitted keys are left unchanged.
4850
+ Each provided key MUST match a column `key` from the table schema, and each value
4851
+ MUST match that column's `ColumnType` value rules. For MEDIA columns you may pass
4852
+ an encrypted media id string, `{ "mediaId": "..." }`, or a fully-resolved
4853
+ `{ url, thumbnailUrl, name, mimeType }` object — id/id-object forms are
4854
+ normalized server-side to the canonical object before storage.
4855
+
4856
+ Best practice for agents: use the row's current `eTag` (from `dataTableRow` or
4857
+ a prior mutation result) in the `eTag` argument below to prevent lost updates.
4858
+ """
4859
+ data: Any
4200
4860
  "Optional ETag for optimistic concurrency. Pass the row's current ETag to prevent conflicting writes."
4201
4861
  eTag: String
4202
4862
  }
@@ -4207,7 +4867,7 @@ input UpdateMediaInput {
4207
4867
  id: String
4208
4868
  "New name. Null leaves unchanged."
4209
4869
  name: String
4210
- "New description\/tags. Null leaves unchanged."
4870
+ "New description/tags. Null leaves unchanged."
4211
4871
  description: String
4212
4872
  "New start date. Null leaves unchanged."
4213
4873
  startDate: DateTime
@@ -4359,16 +5019,33 @@ enum ApplyPolicy {
4359
5019
  VALIDATION
4360
5020
  }
4361
5021
 
5022
+ "Logical type of a data table column. Determines how row `data` values are validated and stored. Use the value descriptions below to choose the right type for each column."
4362
5023
  enum ColumnType {
5024
+ "Scalar text up to 1000 characters. Row values must be JSON strings."
4363
5025
  STRING
5026
+ "JSON number (integer or floating-point). Row values must be JSON numbers, not numeric strings."
4364
5027
  NUMBER
5028
+ "JSON boolean. Row values must be true or false (not the strings \"true\"/\"false\")."
4365
5029
  BOOLEAN
5030
+ "ISO 8601 date or date-time string (e.g. \"2025-01-31\" or \"2025-01-31T12:34:56Z\")."
4366
5031
  DATE
5032
+ "One of a fixed list of strings. The column's `options` array MUST be supplied at table creation; row values must exactly match one of those options."
4367
5033
  SELECT
5034
+ """
5035
+ Reference to a media asset (image or video). Row values may be supplied in any of three shapes — the server normalizes them to the canonical object below before storage so the CMS grid and players can render them:
5036
+ 1. **Encrypted media id (string)** — e.g. "AbCd1234...". The server looks up the asset and expands it into the canonical shape. This is the recommended form for API/agent callers.
5037
+ 2. **Id-bearing object** — `{ "mediaId": "<encrypted id>" }` (any extra fields you supply, e.g. `caption`, are preserved). Resolved the same way as a bare id.
5038
+ 3. **Canonical object** (what the CMS UI writes) — `{ "url": "<absolute CDN URL>", "thumbnailUrl": "<absolute thumb URL>", "name": "<display name>", "mimeType": "<MIME type>" }`. Passed through as-is when `url` is already populated.
5039
+ After normalization, `thumbnailUrl` is what the grid renders and `url` is what the player consumes. Unresolved ids (asset not found / not in account) are left as-supplied; required-field validation will then surface the failure. Empty / null clears the cell.
5040
+ """
4368
5041
  MEDIA
5042
+ "Absolute URL string (must include scheme, e.g. https://example.com)."
4369
5043
  URL
4370
- RICH_TEXT
5044
+ "Rich-text HTML/markdown string. No length cap; row values must be JSON strings."
5045
+ RICHTEXT
5046
+ "Time-of-day string parseable as TimeSpan (e.g. \"14:30\", \"14:30:00\")."
4371
5047
  TIME
5048
+ "Scalar text up to 1000 characters, not shown in default UI listings. Same value rules as STRING."
4372
5049
  HIDDEN
4373
5050
  }
4374
5051
 
@@ -4713,7 +5390,7 @@ enum SourceType {
4713
5390
  COMMAND
4714
5391
  "Adobe Flash content (SWF). Legacy format with limited device support."
4715
5392
  FLASH
4716
- "Interactive gadget\/widget. Custom HTML5 applications with RevelDigital gadget API integration."
5393
+ "Interactive gadget/widget. Custom HTML5 applications with RevelDigital gadget API integration."
4717
5394
  GADGET
4718
5395
  "Static image display (JPEG, PNG, GIF, BMP). Most widely supported content type."
4719
5396
  IMAGE
@@ -4725,15 +5402,15 @@ enum SourceType {
4725
5402
  PLAYLIST
4726
5403
  "Microsoft PowerPoint presentation. Legacy format, converted to images on upload."
4727
5404
  POWER_POINT
4728
- "RSS\/Atom feed display. Renders feed items as scrolling text or formatted content."
5405
+ "RSS/Atom feed display. Renders feed items as scrolling text or formatted content."
4729
5406
  RSS
4730
5407
  "SVG vector graphic. Scalable graphics that render crisply at any resolution."
4731
5408
  SVG
4732
5409
  "Embedded template. Displays a full template layout as a source within a playlist."
4733
5410
  TEMPLATE
4734
- "Plain text content for ticker\/marquee display. Scrolls horizontally or vertically."
5411
+ "Plain text content for ticker/marquee display. Scrolls horizontally or vertically."
4735
5412
  TEXT
4736
- "Twitter\/X feed integration. Displays tweets from specified accounts or hashtags."
5413
+ "Twitter/X feed integration. Displays tweets from specified accounts or hashtags."
4737
5414
  TWITTER
4738
5415
  "URL redirect or web link. Opens specified URL in the content zone."
4739
5416
  URL
@@ -4750,27 +5427,53 @@ enum SourceType {
4750
5427
  YOU_TUBE
4751
5428
  "Extended Vistar Media integration with additional targeting and reporting features."
4752
5429
  VISTAR_MEDIA_EX
5430
+ "Data table content. Each row is extrapolated into individual text entries for ticker/marquee display."
5431
+ DATA_TABLE
4753
5432
  }
4754
5433
 
4755
- "The authorize directive."
4756
- directive @authorize("The name of the authorization policy that determines access to the annotated resource." policy: String "Roles that are allowed to access the annotated resource." roles: [String!] "Defines when when the authorize directive shall be applied.By default the authorize directives are applied during the validation phase." apply: ApplyPolicy! = BEFORE_RESOLVER) repeatable on OBJECT | FIELD_DEFINITION
4757
-
4758
- "The purpose of the `cost` directive is to define a `weight` for GraphQL types, fields, and arguments. Static analysis can use these weights when calculating the overall cost of a query or response."
4759
- directive @cost("The `weight` argument defines what value to add to the overall cost for every appearance, or possible appearance, of a type, field, argument, etc." weight: String!) on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM | INPUT_FIELD_DEFINITION
4760
-
4761
- "The `@specifiedBy` directive is used within the type system definition language to provide a URL for specifying the behavior of custom scalar definitions."
4762
- directive @specifiedBy("The specifiedBy URL points to a human-readable specification. This field will only read a result for scalar types." url: String!) on SCALAR
5434
+ "Machine-readable code identifying the kind of validation failure."
5435
+ enum ValidationErrorCode {
5436
+ "A required field was missing from the row data."
5437
+ REQUIRED
5438
+ "The value's JSON type did not match the column's declared type."
5439
+ INVALID_TYPE
5440
+ "The value violated a length, range, or option constraint."
5441
+ OUT_OF_RANGE
5442
+ "The value could not be parsed (e.g. invalid ISO 8601 date, malformed URL)."
5443
+ INVALID_FORMAT
5444
+ "Catch-all when no more specific code applies."
5445
+ INVALID
5446
+ }
4763
5447
 
4764
- "The `Byte` scalar type represents non-fractional whole numeric values. Byte can represent values between 0 and 255."
4765
- scalar Byte
5448
+ "The `Any` scalar type represents any valid GraphQL value."
5449
+ scalar Any @specifiedBy(url: "https://scalars.graphql.org/chillicream/any.html")
4766
5450
 
4767
- "The `DateTime` scalar represents an ISO-8601 compliant date time type."
4768
- scalar DateTime @specifiedBy(url: "https:\/\/www.graphql-scalars.com\/date-time")
5451
+ "The `DateTime` scalar type represents a date and time with time zone offset information."
5452
+ scalar DateTime
5453
+ @specifiedBy(url: "https://scalars.graphql.org/chillicream/date-time.html")
4769
5454
 
4770
- "The `Decimal` scalar type represents a decimal floating-point number."
5455
+ "The `Decimal` scalar type represents a decimal floating-point number with high precision."
4771
5456
  scalar Decimal
5457
+ @specifiedBy(url: "https://scalars.graphql.org/chillicream/decimal.html")
5458
+
5459
+ "The `Long` scalar type represents a signed 64-bit integer."
5460
+ scalar Long
5461
+ @specifiedBy(url: "https://scalars.graphql.org/chillicream/long.html")
4772
5462
 
4773
- scalar JSON
5463
+ "The `UnsignedByte` scalar type represents an unsigned 8-bit integer."
5464
+ scalar UnsignedByte
5465
+ @specifiedBy(
5466
+ url: "https://scalars.graphql.org/chillicream/unsigned-byte.html"
5467
+ )
4774
5468
 
4775
- "The `Long` scalar type represents non-fractional signed whole 64-bit numeric values. Long can represent values between -(2^63) and 2^63 - 1."
4776
- scalar Long
5469
+ "The purpose of the `cost` directive is to define a `weight` for GraphQL types, fields, and arguments. Static analysis can use these weights when calculating the overall cost of a query or response."
5470
+ directive @cost(
5471
+ "The `weight` argument defines what value to add to the overall cost for every appearance, or possible appearance, of a type, field, argument, etc."
5472
+ weight: String!
5473
+ ) on
5474
+ | SCALAR
5475
+ | OBJECT
5476
+ | FIELD_DEFINITION
5477
+ | ARGUMENT_DEFINITION
5478
+ | ENUM
5479
+ | INPUT_FIELD_DEFINITION