haystack-contracts 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -88
- package/dist/index.d.mts +1371 -144
- package/dist/index.d.ts +1371 -144
- package/dist/index.js +107 -0
- package/dist/index.mjs +96 -0
- package/openapi.json +1380 -0
- package/package.json +51 -34
package/openapi.json
ADDED
|
@@ -0,0 +1,1380 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.3",
|
|
3
|
+
"paths": {
|
|
4
|
+
"/auth/login": {
|
|
5
|
+
"post": {
|
|
6
|
+
"description": "Authenticates a user using a globally unique email address and password. This endpoint is public and does not require a bearer token.",
|
|
7
|
+
"requestBody": {
|
|
8
|
+
"required": true,
|
|
9
|
+
"content": {
|
|
10
|
+
"application/json": {
|
|
11
|
+
"schema": {
|
|
12
|
+
"$ref": "#/components/schemas/LoginDto"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"responses": {
|
|
18
|
+
"200": {
|
|
19
|
+
"description": "Authenticated successfully and returned access/refresh tokens.",
|
|
20
|
+
"content": {
|
|
21
|
+
"application/json": {
|
|
22
|
+
"schema": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
25
|
+
"properties": {
|
|
26
|
+
"success": {
|
|
27
|
+
"type": "boolean",
|
|
28
|
+
"example": true
|
|
29
|
+
},
|
|
30
|
+
"statusCode": {
|
|
31
|
+
"type": "integer",
|
|
32
|
+
"example": 200
|
|
33
|
+
},
|
|
34
|
+
"timestamp": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"format": "date-time",
|
|
37
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
38
|
+
},
|
|
39
|
+
"data": {
|
|
40
|
+
"$ref": "#/components/schemas/AuthResponseDto"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"400": {
|
|
48
|
+
"description": "Validation failed. Check that all required fields are present and correctly typed.",
|
|
49
|
+
"content": {
|
|
50
|
+
"application/json": {
|
|
51
|
+
"example": {
|
|
52
|
+
"success": false,
|
|
53
|
+
"statusCode": 400,
|
|
54
|
+
"error": "Bad Request",
|
|
55
|
+
"message": "email must be an email"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"401": {
|
|
61
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
62
|
+
"content": {
|
|
63
|
+
"application/json": {
|
|
64
|
+
"example": {
|
|
65
|
+
"success": false,
|
|
66
|
+
"statusCode": 401,
|
|
67
|
+
"error": "Unauthorized",
|
|
68
|
+
"message": "Unauthorized"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"summary": "Login with email and password",
|
|
75
|
+
"tags": ["auth"]
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"/robots": {
|
|
79
|
+
"get": {
|
|
80
|
+
"description": "Returns all robots registered in the configured tenant, ordered by online status and name. Each record includes the robot name, tenant, fleet assignment, online status, subscription status, and last-seen timestamp. Any authenticated user can access this endpoint.",
|
|
81
|
+
"responses": {
|
|
82
|
+
"200": {
|
|
83
|
+
"description": "List of robots in the current tenant.",
|
|
84
|
+
"content": {
|
|
85
|
+
"application/json": {
|
|
86
|
+
"schema": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
89
|
+
"properties": {
|
|
90
|
+
"success": {
|
|
91
|
+
"type": "boolean",
|
|
92
|
+
"example": true
|
|
93
|
+
},
|
|
94
|
+
"statusCode": {
|
|
95
|
+
"type": "integer",
|
|
96
|
+
"example": 200
|
|
97
|
+
},
|
|
98
|
+
"timestamp": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"format": "date-time",
|
|
101
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
102
|
+
},
|
|
103
|
+
"data": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"items": {
|
|
106
|
+
"$ref": "#/components/schemas/RobotListItemDto"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"401": {
|
|
115
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
116
|
+
"content": {
|
|
117
|
+
"application/json": {
|
|
118
|
+
"example": {
|
|
119
|
+
"success": false,
|
|
120
|
+
"statusCode": 401,
|
|
121
|
+
"error": "Unauthorized",
|
|
122
|
+
"message": "Unauthorized"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"summary": "List all robots",
|
|
129
|
+
"tags": ["robots"]
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"/robots/{id}": {
|
|
133
|
+
"get": {
|
|
134
|
+
"description": "Returns the full record for a single robot, including its fleet assignment, online state, and timestamps.",
|
|
135
|
+
"parameters": [
|
|
136
|
+
{
|
|
137
|
+
"name": "id",
|
|
138
|
+
"required": true,
|
|
139
|
+
"in": "path",
|
|
140
|
+
"description": "UUID of the robot.",
|
|
141
|
+
"schema": {
|
|
142
|
+
"example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
143
|
+
"type": "string"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"responses": {
|
|
148
|
+
"200": {
|
|
149
|
+
"description": "Robot record.",
|
|
150
|
+
"content": {
|
|
151
|
+
"application/json": {
|
|
152
|
+
"schema": {
|
|
153
|
+
"type": "object",
|
|
154
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
155
|
+
"properties": {
|
|
156
|
+
"success": {
|
|
157
|
+
"type": "boolean",
|
|
158
|
+
"example": true
|
|
159
|
+
},
|
|
160
|
+
"statusCode": {
|
|
161
|
+
"type": "integer",
|
|
162
|
+
"example": 200
|
|
163
|
+
},
|
|
164
|
+
"timestamp": {
|
|
165
|
+
"type": "string",
|
|
166
|
+
"format": "date-time",
|
|
167
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
168
|
+
},
|
|
169
|
+
"data": {
|
|
170
|
+
"$ref": "#/components/schemas/RobotListItemDto"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"400": {
|
|
178
|
+
"description": "Validation failed. Check that all required fields are present and correctly typed.",
|
|
179
|
+
"content": {
|
|
180
|
+
"application/json": {
|
|
181
|
+
"example": {
|
|
182
|
+
"success": false,
|
|
183
|
+
"statusCode": 400,
|
|
184
|
+
"error": "Bad Request",
|
|
185
|
+
"message": "email must be an email"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"401": {
|
|
191
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
192
|
+
"content": {
|
|
193
|
+
"application/json": {
|
|
194
|
+
"example": {
|
|
195
|
+
"success": false,
|
|
196
|
+
"statusCode": 401,
|
|
197
|
+
"error": "Unauthorized",
|
|
198
|
+
"message": "Unauthorized"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"404": {
|
|
204
|
+
"description": "Robot not found in the current tenant.",
|
|
205
|
+
"content": {
|
|
206
|
+
"application/json": {
|
|
207
|
+
"example": {
|
|
208
|
+
"success": false,
|
|
209
|
+
"statusCode": 404,
|
|
210
|
+
"error": "Not Found",
|
|
211
|
+
"message": "Robot not found"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
"summary": "Get a robot by ID",
|
|
218
|
+
"tags": ["robots"]
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"/metrics/types": {
|
|
222
|
+
"get": {
|
|
223
|
+
"description": "Returns the full registry of metric types from the analytics store. Each entry includes an integer id, a human-readable name, and a description. Any authenticated user can access this endpoint.",
|
|
224
|
+
"responses": {
|
|
225
|
+
"200": {
|
|
226
|
+
"description": "List of all registered metric types.",
|
|
227
|
+
"content": {
|
|
228
|
+
"application/json": {
|
|
229
|
+
"schema": {
|
|
230
|
+
"type": "object",
|
|
231
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
232
|
+
"properties": {
|
|
233
|
+
"success": {
|
|
234
|
+
"type": "boolean",
|
|
235
|
+
"example": true
|
|
236
|
+
},
|
|
237
|
+
"statusCode": {
|
|
238
|
+
"type": "integer",
|
|
239
|
+
"example": 200
|
|
240
|
+
},
|
|
241
|
+
"timestamp": {
|
|
242
|
+
"type": "string",
|
|
243
|
+
"format": "date-time",
|
|
244
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
245
|
+
},
|
|
246
|
+
"data": {
|
|
247
|
+
"type": "array",
|
|
248
|
+
"items": {
|
|
249
|
+
"$ref": "#/components/schemas/MetricTypeResponseDto"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
"401": {
|
|
258
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
259
|
+
"content": {
|
|
260
|
+
"application/json": {
|
|
261
|
+
"example": {
|
|
262
|
+
"success": false,
|
|
263
|
+
"statusCode": 401,
|
|
264
|
+
"error": "Unauthorized",
|
|
265
|
+
"message": "Unauthorized"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
"summary": "List all metric types",
|
|
272
|
+
"tags": ["metrics"]
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
"/metrics/robot-values/{robotId}": {
|
|
276
|
+
"get": {
|
|
277
|
+
"description": "Returns the most recent reading for every metric type collected for the specified robot from the analytics (OLAP) store. Pass `metricType` as a query param to restrict results to a single type.",
|
|
278
|
+
"parameters": [
|
|
279
|
+
{
|
|
280
|
+
"name": "robotId",
|
|
281
|
+
"required": true,
|
|
282
|
+
"in": "path",
|
|
283
|
+
"description": "UUID of the robot.",
|
|
284
|
+
"schema": {
|
|
285
|
+
"example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
286
|
+
"type": "string"
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"name": "metricType",
|
|
291
|
+
"required": false,
|
|
292
|
+
"in": "query",
|
|
293
|
+
"description": "Integer id of a specific metric type to filter by.",
|
|
294
|
+
"schema": {
|
|
295
|
+
"example": 1,
|
|
296
|
+
"type": "number"
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
],
|
|
300
|
+
"responses": {
|
|
301
|
+
"200": {
|
|
302
|
+
"description": "Latest OLAP metric readings for the robot.",
|
|
303
|
+
"content": {
|
|
304
|
+
"application/json": {
|
|
305
|
+
"schema": {
|
|
306
|
+
"type": "object",
|
|
307
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
308
|
+
"properties": {
|
|
309
|
+
"success": {
|
|
310
|
+
"type": "boolean",
|
|
311
|
+
"example": true
|
|
312
|
+
},
|
|
313
|
+
"statusCode": {
|
|
314
|
+
"type": "integer",
|
|
315
|
+
"example": 200
|
|
316
|
+
},
|
|
317
|
+
"timestamp": {
|
|
318
|
+
"type": "string",
|
|
319
|
+
"format": "date-time",
|
|
320
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
321
|
+
},
|
|
322
|
+
"data": {
|
|
323
|
+
"type": "array",
|
|
324
|
+
"items": {
|
|
325
|
+
"$ref": "#/components/schemas/RobotMetricLiveDto"
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
"400": {
|
|
334
|
+
"description": "Validation failed. Check that all required fields are present and correctly typed.",
|
|
335
|
+
"content": {
|
|
336
|
+
"application/json": {
|
|
337
|
+
"example": {
|
|
338
|
+
"success": false,
|
|
339
|
+
"statusCode": 400,
|
|
340
|
+
"error": "Bad Request",
|
|
341
|
+
"message": "email must be an email"
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"401": {
|
|
347
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
348
|
+
"content": {
|
|
349
|
+
"application/json": {
|
|
350
|
+
"example": {
|
|
351
|
+
"success": false,
|
|
352
|
+
"statusCode": 401,
|
|
353
|
+
"error": "Unauthorized",
|
|
354
|
+
"message": "Unauthorized"
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
"summary": "List latest metric values for a robot",
|
|
361
|
+
"tags": ["metrics"]
|
|
362
|
+
}
|
|
363
|
+
},
|
|
364
|
+
"/disinfection/robots": {
|
|
365
|
+
"get": {
|
|
366
|
+
"description": "Returns aggregated disinfection statistics for every robot in the current tenant. Includes bot name, facility name, room count, total duration, and success/partial/failed job counts.",
|
|
367
|
+
"responses": {
|
|
368
|
+
"200": {
|
|
369
|
+
"description": "Per-robot disinfection statistics for the current tenant.",
|
|
370
|
+
"content": {
|
|
371
|
+
"application/json": {
|
|
372
|
+
"schema": {
|
|
373
|
+
"type": "object",
|
|
374
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
375
|
+
"properties": {
|
|
376
|
+
"success": {
|
|
377
|
+
"type": "boolean",
|
|
378
|
+
"example": true
|
|
379
|
+
},
|
|
380
|
+
"statusCode": {
|
|
381
|
+
"type": "integer",
|
|
382
|
+
"example": 200
|
|
383
|
+
},
|
|
384
|
+
"timestamp": {
|
|
385
|
+
"type": "string",
|
|
386
|
+
"format": "date-time",
|
|
387
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
388
|
+
},
|
|
389
|
+
"data": {
|
|
390
|
+
"type": "array",
|
|
391
|
+
"items": {
|
|
392
|
+
"$ref": "#/components/schemas/RobotDisinfectionStatsDto"
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
"401": {
|
|
401
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
402
|
+
"content": {
|
|
403
|
+
"application/json": {
|
|
404
|
+
"example": {
|
|
405
|
+
"success": false,
|
|
406
|
+
"statusCode": 401,
|
|
407
|
+
"error": "Unauthorized",
|
|
408
|
+
"message": "Unauthorized"
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
"summary": "Get per-robot disinfection stats",
|
|
415
|
+
"tags": ["disinfection"]
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
"/disinfection/ongoing-jobs": {
|
|
419
|
+
"get": {
|
|
420
|
+
"description": "Returns currently active disinfection jobs from OLTP. TODO: not yet implemented — returns an empty list until the OLTP query is defined.",
|
|
421
|
+
"responses": {
|
|
422
|
+
"200": {
|
|
423
|
+
"description": "List of ongoing disinfection jobs (currently empty).",
|
|
424
|
+
"content": {
|
|
425
|
+
"application/json": {
|
|
426
|
+
"schema": {
|
|
427
|
+
"type": "object",
|
|
428
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
429
|
+
"properties": {
|
|
430
|
+
"success": {
|
|
431
|
+
"type": "boolean",
|
|
432
|
+
"example": true
|
|
433
|
+
},
|
|
434
|
+
"statusCode": {
|
|
435
|
+
"type": "integer",
|
|
436
|
+
"example": 200
|
|
437
|
+
},
|
|
438
|
+
"timestamp": {
|
|
439
|
+
"type": "string",
|
|
440
|
+
"format": "date-time",
|
|
441
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
442
|
+
},
|
|
443
|
+
"data": {
|
|
444
|
+
"type": "array",
|
|
445
|
+
"items": {
|
|
446
|
+
"$ref": "#/components/schemas/DisinfectionJobDto"
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
"401": {
|
|
455
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
456
|
+
"content": {
|
|
457
|
+
"application/json": {
|
|
458
|
+
"example": {
|
|
459
|
+
"success": false,
|
|
460
|
+
"statusCode": 401,
|
|
461
|
+
"error": "Unauthorized",
|
|
462
|
+
"message": "Unauthorized"
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
"summary": "List ongoing disinfection jobs",
|
|
469
|
+
"tags": ["disinfection"]
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
"/disinfection/jobs": {
|
|
473
|
+
"get": {
|
|
474
|
+
"description": "Returns completed disinfection jobs from OLAP. Optionally filter by status (passed, partial, failed); omit status or use \"all\" for no status filter. Haystack tenant users see jobs across all tenants; other tenants are scoped to their own tenant. Optionally filter by robotId.",
|
|
475
|
+
"parameters": [
|
|
476
|
+
{
|
|
477
|
+
"name": "status",
|
|
478
|
+
"required": false,
|
|
479
|
+
"in": "query",
|
|
480
|
+
"description": "Job outcome filter. Defaults to \"all\" (no status filtering) when omitted.",
|
|
481
|
+
"schema": {
|
|
482
|
+
"enum": ["passed", "partial", "failed", "all"],
|
|
483
|
+
"type": "string"
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
"name": "robotId",
|
|
488
|
+
"required": false,
|
|
489
|
+
"in": "query",
|
|
490
|
+
"description": "UUID of a specific robot to filter by.",
|
|
491
|
+
"schema": {
|
|
492
|
+
"type": "string"
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
],
|
|
496
|
+
"responses": {
|
|
497
|
+
"200": {
|
|
498
|
+
"description": "List of disinfection jobs matching the filters.",
|
|
499
|
+
"content": {
|
|
500
|
+
"application/json": {
|
|
501
|
+
"schema": {
|
|
502
|
+
"type": "object",
|
|
503
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
504
|
+
"properties": {
|
|
505
|
+
"success": {
|
|
506
|
+
"type": "boolean",
|
|
507
|
+
"example": true
|
|
508
|
+
},
|
|
509
|
+
"statusCode": {
|
|
510
|
+
"type": "integer",
|
|
511
|
+
"example": 200
|
|
512
|
+
},
|
|
513
|
+
"timestamp": {
|
|
514
|
+
"type": "string",
|
|
515
|
+
"format": "date-time",
|
|
516
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
517
|
+
},
|
|
518
|
+
"data": {
|
|
519
|
+
"type": "array",
|
|
520
|
+
"items": {
|
|
521
|
+
"$ref": "#/components/schemas/DisinfectionJobDto"
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
"400": {
|
|
530
|
+
"description": "Validation failed. Check that all required fields are present and correctly typed.",
|
|
531
|
+
"content": {
|
|
532
|
+
"application/json": {
|
|
533
|
+
"example": {
|
|
534
|
+
"success": false,
|
|
535
|
+
"statusCode": 400,
|
|
536
|
+
"error": "Bad Request",
|
|
537
|
+
"message": "email must be an email"
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
"401": {
|
|
543
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
544
|
+
"content": {
|
|
545
|
+
"application/json": {
|
|
546
|
+
"example": {
|
|
547
|
+
"success": false,
|
|
548
|
+
"statusCode": 401,
|
|
549
|
+
"error": "Unauthorized",
|
|
550
|
+
"message": "Unauthorized"
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
"summary": "List disinfection jobs",
|
|
557
|
+
"tags": ["disinfection"]
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
"/analytics-agg/robots-count": {
|
|
561
|
+
"get": {
|
|
562
|
+
"description": "Returns total, online, offline, AI-enabled, and SW-update-pending robot counts. Haystack tenant users see aggregates across all tenants; other tenants are scoped to their own tenant.",
|
|
563
|
+
"responses": {
|
|
564
|
+
"200": {
|
|
565
|
+
"description": "Robot count statistics wrapped in AnalyticsResponse with timestamp and status.",
|
|
566
|
+
"content": {
|
|
567
|
+
"application/json": {
|
|
568
|
+
"schema": {
|
|
569
|
+
"type": "object",
|
|
570
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
571
|
+
"properties": {
|
|
572
|
+
"success": {
|
|
573
|
+
"type": "boolean",
|
|
574
|
+
"example": true
|
|
575
|
+
},
|
|
576
|
+
"statusCode": {
|
|
577
|
+
"type": "integer",
|
|
578
|
+
"example": 200
|
|
579
|
+
},
|
|
580
|
+
"timestamp": {
|
|
581
|
+
"type": "string",
|
|
582
|
+
"format": "date-time",
|
|
583
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
584
|
+
},
|
|
585
|
+
"data": {
|
|
586
|
+
"$ref": "#/components/schemas/RobotsCountAnalyticsDataDto"
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
"401": {
|
|
594
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
595
|
+
"content": {
|
|
596
|
+
"application/json": {
|
|
597
|
+
"example": {
|
|
598
|
+
"success": false,
|
|
599
|
+
"statusCode": 401,
|
|
600
|
+
"error": "Unauthorized",
|
|
601
|
+
"message": "Unauthorized"
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
"summary": "Get robot count statistics",
|
|
608
|
+
"tags": ["analytics-agg"]
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
"/analytics-agg/disinfection-count": {
|
|
612
|
+
"get": {
|
|
613
|
+
"description": "Returns top performing bot by total disinfection duration and aggregated job stats (total runtime, total successful, total partial jobs). Haystack tenant users see aggregates across all tenants; other tenants are scoped to their own tenant.",
|
|
614
|
+
"responses": {
|
|
615
|
+
"200": {
|
|
616
|
+
"description": "Disinfection count statistics wrapped in AnalyticsResponse with timestamp and status.",
|
|
617
|
+
"content": {
|
|
618
|
+
"application/json": {
|
|
619
|
+
"schema": {
|
|
620
|
+
"type": "object",
|
|
621
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
622
|
+
"properties": {
|
|
623
|
+
"success": {
|
|
624
|
+
"type": "boolean",
|
|
625
|
+
"example": true
|
|
626
|
+
},
|
|
627
|
+
"statusCode": {
|
|
628
|
+
"type": "integer",
|
|
629
|
+
"example": 200
|
|
630
|
+
},
|
|
631
|
+
"timestamp": {
|
|
632
|
+
"type": "string",
|
|
633
|
+
"format": "date-time",
|
|
634
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
635
|
+
},
|
|
636
|
+
"data": {
|
|
637
|
+
"$ref": "#/components/schemas/DisinfectionCountAnalyticsDataDto"
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
"401": {
|
|
645
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
646
|
+
"content": {
|
|
647
|
+
"application/json": {
|
|
648
|
+
"example": {
|
|
649
|
+
"success": false,
|
|
650
|
+
"statusCode": 401,
|
|
651
|
+
"error": "Unauthorized",
|
|
652
|
+
"message": "Unauthorized"
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
"summary": "Get disinfection job aggregate statistics",
|
|
659
|
+
"tags": ["analytics-agg"]
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
"/analytics-agg/disinfection-operator": {
|
|
663
|
+
"get": {
|
|
664
|
+
"description": "Returns operators ranked by number of successful/partial disinfection jobs. Haystack tenant users see data across all tenants; other tenants are scoped to their own tenant.",
|
|
665
|
+
"responses": {
|
|
666
|
+
"200": {
|
|
667
|
+
"description": "List of operators ranked by total jobs wrapped in AnalyticsResponse with timestamp and status.",
|
|
668
|
+
"content": {
|
|
669
|
+
"application/json": {
|
|
670
|
+
"schema": {
|
|
671
|
+
"type": "object",
|
|
672
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
673
|
+
"properties": {
|
|
674
|
+
"success": {
|
|
675
|
+
"type": "boolean",
|
|
676
|
+
"example": true
|
|
677
|
+
},
|
|
678
|
+
"statusCode": {
|
|
679
|
+
"type": "integer",
|
|
680
|
+
"example": 200
|
|
681
|
+
},
|
|
682
|
+
"timestamp": {
|
|
683
|
+
"type": "string",
|
|
684
|
+
"format": "date-time",
|
|
685
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
686
|
+
},
|
|
687
|
+
"data": {
|
|
688
|
+
"$ref": "#/components/schemas/DisinfectionOperatorsAnalyticsDataDto"
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
"401": {
|
|
696
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
697
|
+
"content": {
|
|
698
|
+
"application/json": {
|
|
699
|
+
"example": {
|
|
700
|
+
"success": false,
|
|
701
|
+
"statusCode": 401,
|
|
702
|
+
"error": "Unauthorized",
|
|
703
|
+
"message": "Unauthorized"
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
"summary": "Get operator rankings by disinfection jobs",
|
|
710
|
+
"tags": ["analytics-agg"]
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
"/analytics-agg/disinfection-status": {
|
|
714
|
+
"get": {
|
|
715
|
+
"description": "Returns status-wise counts of disinfection jobs. Haystack tenant users see aggregates across all tenants; other tenants are scoped to their own tenant.",
|
|
716
|
+
"responses": {
|
|
717
|
+
"200": {
|
|
718
|
+
"description": "Status-wise job counts wrapped in AnalyticsResponse with timestamp and status.",
|
|
719
|
+
"content": {
|
|
720
|
+
"application/json": {
|
|
721
|
+
"schema": {
|
|
722
|
+
"type": "object",
|
|
723
|
+
"required": ["success", "statusCode", "data", "timestamp"],
|
|
724
|
+
"properties": {
|
|
725
|
+
"success": {
|
|
726
|
+
"type": "boolean",
|
|
727
|
+
"example": true
|
|
728
|
+
},
|
|
729
|
+
"statusCode": {
|
|
730
|
+
"type": "integer",
|
|
731
|
+
"example": 200
|
|
732
|
+
},
|
|
733
|
+
"timestamp": {
|
|
734
|
+
"type": "string",
|
|
735
|
+
"format": "date-time",
|
|
736
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
737
|
+
},
|
|
738
|
+
"data": {
|
|
739
|
+
"$ref": "#/components/schemas/DisinfectionStatusAnalyticsDataDto"
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
"401": {
|
|
747
|
+
"description": "Authentication required. Provide a valid bearer token.",
|
|
748
|
+
"content": {
|
|
749
|
+
"application/json": {
|
|
750
|
+
"example": {
|
|
751
|
+
"success": false,
|
|
752
|
+
"statusCode": 401,
|
|
753
|
+
"error": "Unauthorized",
|
|
754
|
+
"message": "Unauthorized"
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
"summary": "Get disinfection job status distribution",
|
|
761
|
+
"tags": ["analytics-agg"]
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
"info": {
|
|
766
|
+
"title": "Haystack Robotics API",
|
|
767
|
+
"version": "1.0.0",
|
|
768
|
+
"description": "Customer-facing REST API for Haystack Robotics integrations.\n\nBase path: `/api/v1`\n\nAuthentication:\n- `POST /auth/login` — obtain access and refresh tokens.\n- Protected routes require `Authorization: Bearer <access_token>`.\n\nResponse envelope (success):\n`{ \"success\": true, \"statusCode\": 200, \"data\": { ... }, \"timestamp\": \"ISO-8601\" }`\n\nResponse envelope (error):\n`{ \"success\": false, \"statusCode\": 4xx, \"error\": \"...\", \"message\": \"...\" }`",
|
|
769
|
+
"contact": {
|
|
770
|
+
"name": "Haystack Robotics",
|
|
771
|
+
"url": "https://docs.haystack-robotics.com",
|
|
772
|
+
"email": "support@haystackrobotics.com"
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
"tags": [
|
|
776
|
+
{
|
|
777
|
+
"name": "analytics-agg",
|
|
778
|
+
"description": "Fleet-wide analytics summaries from the analytics store (robot counts, disinfection stats, operators, job status)."
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
"name": "auth",
|
|
782
|
+
"description": "Authentication. Use login to obtain tokens; protected routes require a bearer token."
|
|
783
|
+
},
|
|
784
|
+
{
|
|
785
|
+
"name": "disinfection",
|
|
786
|
+
"description": "UVC disinfection analytics — per-robot aggregates and job history."
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
"name": "metrics",
|
|
790
|
+
"description": "Metric type catalog and latest per-robot metric readings."
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"name": "robots",
|
|
794
|
+
"description": "Robot inventory for the authenticated tenant, including online status and fleet assignment."
|
|
795
|
+
}
|
|
796
|
+
],
|
|
797
|
+
"servers": [
|
|
798
|
+
{
|
|
799
|
+
"url": "https://api.haystackrobotics.com/api/v1",
|
|
800
|
+
"description": "Production"
|
|
801
|
+
}
|
|
802
|
+
],
|
|
803
|
+
"components": {
|
|
804
|
+
"schemas": {
|
|
805
|
+
"AuthResponseDto": {
|
|
806
|
+
"type": "object",
|
|
807
|
+
"properties": {
|
|
808
|
+
"accessToken": {
|
|
809
|
+
"type": "string",
|
|
810
|
+
"description": "Short-lived JWT access token (15 min).",
|
|
811
|
+
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.access-token-example.signature"
|
|
812
|
+
},
|
|
813
|
+
"refreshToken": {
|
|
814
|
+
"type": "string",
|
|
815
|
+
"description": "Long-lived refresh token (7 days).",
|
|
816
|
+
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.refresh-token-example.signature"
|
|
817
|
+
},
|
|
818
|
+
"expiresIn": {
|
|
819
|
+
"type": "number",
|
|
820
|
+
"description": "Access token lifetime in seconds.",
|
|
821
|
+
"example": 900
|
|
822
|
+
},
|
|
823
|
+
"user": {
|
|
824
|
+
"description": "Sanitized authenticated user snapshot returned with the token response.",
|
|
825
|
+
"allOf": [
|
|
826
|
+
{
|
|
827
|
+
"$ref": "#/components/schemas/PublicUserDto"
|
|
828
|
+
}
|
|
829
|
+
]
|
|
830
|
+
}
|
|
831
|
+
},
|
|
832
|
+
"required": ["accessToken", "refreshToken", "expiresIn", "user"]
|
|
833
|
+
},
|
|
834
|
+
"DisinfectionCountAnalyticsDataDto": {
|
|
835
|
+
"type": "object",
|
|
836
|
+
"properties": {
|
|
837
|
+
"data": {
|
|
838
|
+
"$ref": "#/components/schemas/DisinfectionCountResponseDto"
|
|
839
|
+
},
|
|
840
|
+
"timestamp": {
|
|
841
|
+
"type": "string",
|
|
842
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
843
|
+
},
|
|
844
|
+
"status": {
|
|
845
|
+
"type": "string",
|
|
846
|
+
"enum": ["success", "error"],
|
|
847
|
+
"example": "success"
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
"required": ["data", "timestamp", "status"]
|
|
851
|
+
},
|
|
852
|
+
"DisinfectionCountResponseDto": {
|
|
853
|
+
"type": "object",
|
|
854
|
+
"properties": {
|
|
855
|
+
"topBotName": {
|
|
856
|
+
"type": "string",
|
|
857
|
+
"example": "Warehouse Bot Alpha"
|
|
858
|
+
},
|
|
859
|
+
"topBotId": {
|
|
860
|
+
"type": "string",
|
|
861
|
+
"example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
862
|
+
},
|
|
863
|
+
"totalRuntime": {
|
|
864
|
+
"type": "number",
|
|
865
|
+
"example": 125000
|
|
866
|
+
},
|
|
867
|
+
"totalSuccessful": {
|
|
868
|
+
"type": "number",
|
|
869
|
+
"example": 320
|
|
870
|
+
},
|
|
871
|
+
"totalPartial": {
|
|
872
|
+
"type": "number",
|
|
873
|
+
"example": 45
|
|
874
|
+
}
|
|
875
|
+
},
|
|
876
|
+
"required": [
|
|
877
|
+
"topBotName",
|
|
878
|
+
"topBotId",
|
|
879
|
+
"totalRuntime",
|
|
880
|
+
"totalSuccessful",
|
|
881
|
+
"totalPartial"
|
|
882
|
+
]
|
|
883
|
+
},
|
|
884
|
+
"DisinfectionJobDto": {
|
|
885
|
+
"type": "object",
|
|
886
|
+
"properties": {
|
|
887
|
+
"robotName": {
|
|
888
|
+
"type": "string",
|
|
889
|
+
"example": "Warehouse Bot Alpha"
|
|
890
|
+
},
|
|
891
|
+
"startTime": {
|
|
892
|
+
"type": "string",
|
|
893
|
+
"example": "2026-05-28T14:00:00.000Z"
|
|
894
|
+
},
|
|
895
|
+
"endTime": {
|
|
896
|
+
"type": "string",
|
|
897
|
+
"example": "2026-05-28T14:45:00.000Z",
|
|
898
|
+
"nullable": true
|
|
899
|
+
},
|
|
900
|
+
"durationSeconds": {
|
|
901
|
+
"type": "number",
|
|
902
|
+
"example": 2700,
|
|
903
|
+
"nullable": true
|
|
904
|
+
},
|
|
905
|
+
"operatorName": {
|
|
906
|
+
"type": "string",
|
|
907
|
+
"example": "Alice Smith"
|
|
908
|
+
},
|
|
909
|
+
"roomName": {
|
|
910
|
+
"type": "string",
|
|
911
|
+
"example": "OR-3"
|
|
912
|
+
},
|
|
913
|
+
"disinfectMode": {
|
|
914
|
+
"type": "string",
|
|
915
|
+
"example": "AUTO"
|
|
916
|
+
},
|
|
917
|
+
"level": {
|
|
918
|
+
"type": "string",
|
|
919
|
+
"example": "HIGH"
|
|
920
|
+
},
|
|
921
|
+
"status": {
|
|
922
|
+
"type": "string",
|
|
923
|
+
"example": "COVERAGE_DONE"
|
|
924
|
+
}
|
|
925
|
+
},
|
|
926
|
+
"required": [
|
|
927
|
+
"robotName",
|
|
928
|
+
"startTime",
|
|
929
|
+
"endTime",
|
|
930
|
+
"durationSeconds",
|
|
931
|
+
"operatorName",
|
|
932
|
+
"roomName",
|
|
933
|
+
"disinfectMode",
|
|
934
|
+
"level",
|
|
935
|
+
"status"
|
|
936
|
+
]
|
|
937
|
+
},
|
|
938
|
+
"DisinfectionOperatorResponseDto": {
|
|
939
|
+
"type": "object",
|
|
940
|
+
"properties": {
|
|
941
|
+
"operatorName": {
|
|
942
|
+
"type": "string",
|
|
943
|
+
"example": "Alice Smith"
|
|
944
|
+
},
|
|
945
|
+
"totalJobs": {
|
|
946
|
+
"type": "number",
|
|
947
|
+
"example": 128
|
|
948
|
+
}
|
|
949
|
+
},
|
|
950
|
+
"required": ["operatorName", "totalJobs"]
|
|
951
|
+
},
|
|
952
|
+
"DisinfectionOperatorsAnalyticsDataDto": {
|
|
953
|
+
"type": "object",
|
|
954
|
+
"properties": {
|
|
955
|
+
"data": {
|
|
956
|
+
"type": "array",
|
|
957
|
+
"items": {
|
|
958
|
+
"$ref": "#/components/schemas/DisinfectionOperatorResponseDto"
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
"timestamp": {
|
|
962
|
+
"type": "string",
|
|
963
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
964
|
+
},
|
|
965
|
+
"status": {
|
|
966
|
+
"type": "string",
|
|
967
|
+
"enum": ["success", "error"],
|
|
968
|
+
"example": "success"
|
|
969
|
+
}
|
|
970
|
+
},
|
|
971
|
+
"required": ["data", "timestamp", "status"]
|
|
972
|
+
},
|
|
973
|
+
"DisinfectionStatusAnalyticsDataDto": {
|
|
974
|
+
"type": "object",
|
|
975
|
+
"properties": {
|
|
976
|
+
"data": {
|
|
977
|
+
"type": "array",
|
|
978
|
+
"items": {
|
|
979
|
+
"$ref": "#/components/schemas/DisinfectionStatusResponseDto"
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
"timestamp": {
|
|
983
|
+
"type": "string",
|
|
984
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
985
|
+
},
|
|
986
|
+
"status": {
|
|
987
|
+
"type": "string",
|
|
988
|
+
"enum": ["success", "error"],
|
|
989
|
+
"example": "success"
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
"required": ["data", "timestamp", "status"]
|
|
993
|
+
},
|
|
994
|
+
"DisinfectionStatusResponseDto": {
|
|
995
|
+
"type": "object",
|
|
996
|
+
"properties": {
|
|
997
|
+
"status": {
|
|
998
|
+
"type": "string",
|
|
999
|
+
"example": "COVERAGE_DONE"
|
|
1000
|
+
},
|
|
1001
|
+
"count": {
|
|
1002
|
+
"type": "number",
|
|
1003
|
+
"example": 500
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
1006
|
+
"required": ["status", "count"]
|
|
1007
|
+
},
|
|
1008
|
+
"LoginDto": {
|
|
1009
|
+
"type": "object",
|
|
1010
|
+
"properties": {
|
|
1011
|
+
"email": {
|
|
1012
|
+
"type": "string",
|
|
1013
|
+
"description": "Registered email address.",
|
|
1014
|
+
"example": "superadmin@haystackrobotics.com"
|
|
1015
|
+
},
|
|
1016
|
+
"password": {
|
|
1017
|
+
"type": "string",
|
|
1018
|
+
"description": "Account password (minimum 8 characters).",
|
|
1019
|
+
"example": "SuperAdmin123!",
|
|
1020
|
+
"minLength": 8
|
|
1021
|
+
}
|
|
1022
|
+
},
|
|
1023
|
+
"required": ["email", "password"]
|
|
1024
|
+
},
|
|
1025
|
+
"MetricTypeResponseDto": {
|
|
1026
|
+
"type": "object",
|
|
1027
|
+
"properties": {
|
|
1028
|
+
"metricType": {
|
|
1029
|
+
"type": "number",
|
|
1030
|
+
"description": "Integer id of the metric type.",
|
|
1031
|
+
"example": 1
|
|
1032
|
+
},
|
|
1033
|
+
"metricName": {
|
|
1034
|
+
"type": "string",
|
|
1035
|
+
"description": "Human-readable metric name.",
|
|
1036
|
+
"example": "Cpu"
|
|
1037
|
+
},
|
|
1038
|
+
"description": {
|
|
1039
|
+
"type": "string",
|
|
1040
|
+
"description": "What the metric measures.",
|
|
1041
|
+
"example": "CPU utilisation percentage"
|
|
1042
|
+
},
|
|
1043
|
+
"dataType": {
|
|
1044
|
+
"type": "string",
|
|
1045
|
+
"enum": ["numeric", "string"],
|
|
1046
|
+
"example": "numeric"
|
|
1047
|
+
},
|
|
1048
|
+
"sourceType": {
|
|
1049
|
+
"type": "string",
|
|
1050
|
+
"enum": ["non_stream", "stream"],
|
|
1051
|
+
"example": "stream"
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
"required": ["metricType", "metricName", "description", "dataType"]
|
|
1055
|
+
},
|
|
1056
|
+
"PublicUserDto": {
|
|
1057
|
+
"type": "object",
|
|
1058
|
+
"properties": {
|
|
1059
|
+
"id": {
|
|
1060
|
+
"type": "string",
|
|
1061
|
+
"example": "c3d4e5f6-a1b2-3456-abcd-789012345678"
|
|
1062
|
+
},
|
|
1063
|
+
"email": {
|
|
1064
|
+
"type": "string",
|
|
1065
|
+
"example": "admin@haystackrobotics.com"
|
|
1066
|
+
},
|
|
1067
|
+
"firstName": {
|
|
1068
|
+
"type": "string",
|
|
1069
|
+
"example": "Haystack"
|
|
1070
|
+
},
|
|
1071
|
+
"lastName": {
|
|
1072
|
+
"type": "string",
|
|
1073
|
+
"example": "Admin"
|
|
1074
|
+
},
|
|
1075
|
+
"isActive": {
|
|
1076
|
+
"type": "boolean",
|
|
1077
|
+
"example": true
|
|
1078
|
+
},
|
|
1079
|
+
"tenantId": {
|
|
1080
|
+
"type": "string",
|
|
1081
|
+
"example": "11111111-1111-4111-8111-111111111111"
|
|
1082
|
+
},
|
|
1083
|
+
"workspaceId": {
|
|
1084
|
+
"type": "string",
|
|
1085
|
+
"nullable": true
|
|
1086
|
+
},
|
|
1087
|
+
"facilityId": {
|
|
1088
|
+
"type": "string",
|
|
1089
|
+
"nullable": true
|
|
1090
|
+
},
|
|
1091
|
+
"fleetId": {
|
|
1092
|
+
"type": "string",
|
|
1093
|
+
"nullable": true
|
|
1094
|
+
},
|
|
1095
|
+
"role": {
|
|
1096
|
+
"type": "string",
|
|
1097
|
+
"enum": [
|
|
1098
|
+
"TENANT_ADMIN",
|
|
1099
|
+
"WORKSPACE_ADMIN",
|
|
1100
|
+
"FACILITY_ADMIN",
|
|
1101
|
+
"FLEET_OPERATOR",
|
|
1102
|
+
"FLEET_VIEWER"
|
|
1103
|
+
],
|
|
1104
|
+
"nullable": true
|
|
1105
|
+
},
|
|
1106
|
+
"scopeType": {
|
|
1107
|
+
"type": "string",
|
|
1108
|
+
"enum": ["tenant", "workspace", "facility", "fleet"],
|
|
1109
|
+
"nullable": true
|
|
1110
|
+
},
|
|
1111
|
+
"scopeId": {
|
|
1112
|
+
"type": "string",
|
|
1113
|
+
"nullable": true
|
|
1114
|
+
},
|
|
1115
|
+
"createdAt": {
|
|
1116
|
+
"format": "date-time",
|
|
1117
|
+
"type": "string",
|
|
1118
|
+
"example": "2026-01-15T08:00:00.000Z"
|
|
1119
|
+
},
|
|
1120
|
+
"updatedAt": {
|
|
1121
|
+
"format": "date-time",
|
|
1122
|
+
"type": "string",
|
|
1123
|
+
"example": "2026-05-20T10:00:00.000Z"
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
"required": [
|
|
1127
|
+
"id",
|
|
1128
|
+
"email",
|
|
1129
|
+
"firstName",
|
|
1130
|
+
"lastName",
|
|
1131
|
+
"isActive",
|
|
1132
|
+
"tenantId",
|
|
1133
|
+
"createdAt",
|
|
1134
|
+
"updatedAt"
|
|
1135
|
+
]
|
|
1136
|
+
},
|
|
1137
|
+
"RobotDisinfectionStatsDto": {
|
|
1138
|
+
"type": "object",
|
|
1139
|
+
"properties": {
|
|
1140
|
+
"robotId": {
|
|
1141
|
+
"type": "string",
|
|
1142
|
+
"example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
1143
|
+
},
|
|
1144
|
+
"roomCount": {
|
|
1145
|
+
"type": "number",
|
|
1146
|
+
"example": 12
|
|
1147
|
+
},
|
|
1148
|
+
"totalDurationSeconds": {
|
|
1149
|
+
"type": "number",
|
|
1150
|
+
"example": 86400
|
|
1151
|
+
},
|
|
1152
|
+
"successJobs": {
|
|
1153
|
+
"type": "number",
|
|
1154
|
+
"example": 45
|
|
1155
|
+
},
|
|
1156
|
+
"partialSuccessJobs": {
|
|
1157
|
+
"type": "number",
|
|
1158
|
+
"example": 8
|
|
1159
|
+
},
|
|
1160
|
+
"failedJobs": {
|
|
1161
|
+
"type": "number",
|
|
1162
|
+
"example": 3
|
|
1163
|
+
},
|
|
1164
|
+
"botName": {
|
|
1165
|
+
"type": "string",
|
|
1166
|
+
"example": "Warehouse Bot Alpha",
|
|
1167
|
+
"nullable": true
|
|
1168
|
+
},
|
|
1169
|
+
"facilityName": {
|
|
1170
|
+
"type": "string",
|
|
1171
|
+
"example": "Warehouse Operations",
|
|
1172
|
+
"nullable": true
|
|
1173
|
+
}
|
|
1174
|
+
},
|
|
1175
|
+
"required": [
|
|
1176
|
+
"robotId",
|
|
1177
|
+
"roomCount",
|
|
1178
|
+
"totalDurationSeconds",
|
|
1179
|
+
"successJobs",
|
|
1180
|
+
"partialSuccessJobs",
|
|
1181
|
+
"failedJobs",
|
|
1182
|
+
"botName",
|
|
1183
|
+
"facilityName"
|
|
1184
|
+
]
|
|
1185
|
+
},
|
|
1186
|
+
"RobotListItemDto": {
|
|
1187
|
+
"type": "object",
|
|
1188
|
+
"properties": {
|
|
1189
|
+
"id": {
|
|
1190
|
+
"type": "string",
|
|
1191
|
+
"description": "Unique identifier of the robot (UUID).",
|
|
1192
|
+
"example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
1193
|
+
},
|
|
1194
|
+
"tenantId": {
|
|
1195
|
+
"type": "string",
|
|
1196
|
+
"description": "UUID of the tenant that owns the robot.",
|
|
1197
|
+
"example": "11111111-1111-4111-8111-111111111111"
|
|
1198
|
+
},
|
|
1199
|
+
"tenantName": {
|
|
1200
|
+
"type": "string",
|
|
1201
|
+
"description": "Name of the tenant that owns the robot.",
|
|
1202
|
+
"example": "Haystack Robotics"
|
|
1203
|
+
},
|
|
1204
|
+
"name": {
|
|
1205
|
+
"type": "string",
|
|
1206
|
+
"description": "Human-readable display name for the robot.",
|
|
1207
|
+
"example": "Warehouse Bot Alpha"
|
|
1208
|
+
},
|
|
1209
|
+
"fleetId": {
|
|
1210
|
+
"type": "string",
|
|
1211
|
+
"description": "UUID of the fleet this robot is assigned to.",
|
|
1212
|
+
"example": "f1000000-0000-4000-8000-000000000001",
|
|
1213
|
+
"nullable": true
|
|
1214
|
+
},
|
|
1215
|
+
"fleetName": {
|
|
1216
|
+
"type": "string",
|
|
1217
|
+
"description": "Name of the fleet this robot is assigned to.",
|
|
1218
|
+
"example": "Warehouse Fleet A"
|
|
1219
|
+
},
|
|
1220
|
+
"isOnline": {
|
|
1221
|
+
"type": "boolean",
|
|
1222
|
+
"description": "Whether the robot is currently connected and transmitting data.",
|
|
1223
|
+
"example": true
|
|
1224
|
+
},
|
|
1225
|
+
"isSubscribed": {
|
|
1226
|
+
"type": "boolean",
|
|
1227
|
+
"description": "Whether the robot is subscribed for telemetry processing.",
|
|
1228
|
+
"example": true
|
|
1229
|
+
},
|
|
1230
|
+
"lastTimeSeen": {
|
|
1231
|
+
"type": "string",
|
|
1232
|
+
"description": "ISO-8601 timestamp of the last confirmed contact with the robot.",
|
|
1233
|
+
"example": "2026-03-07T18:30:00.000Z"
|
|
1234
|
+
},
|
|
1235
|
+
"createdAt": {
|
|
1236
|
+
"type": "string",
|
|
1237
|
+
"description": "When the robot record was created (ISO-8601).",
|
|
1238
|
+
"example": "2026-03-01T10:00:00.000Z"
|
|
1239
|
+
},
|
|
1240
|
+
"updatedAt": {
|
|
1241
|
+
"type": "string",
|
|
1242
|
+
"description": "When the robot record was last updated (ISO-8601).",
|
|
1243
|
+
"example": "2026-03-07T18:30:00.000Z"
|
|
1244
|
+
},
|
|
1245
|
+
"cpu": {
|
|
1246
|
+
"type": "string",
|
|
1247
|
+
"description": "Latest CPU usage reading (percent string), or null.",
|
|
1248
|
+
"example": "87.733",
|
|
1249
|
+
"nullable": true
|
|
1250
|
+
},
|
|
1251
|
+
"ram": {
|
|
1252
|
+
"type": "string",
|
|
1253
|
+
"description": "Latest RAM usage reading (percent string), or null.",
|
|
1254
|
+
"example": "77.33",
|
|
1255
|
+
"nullable": true
|
|
1256
|
+
},
|
|
1257
|
+
"disk": {
|
|
1258
|
+
"type": "string",
|
|
1259
|
+
"description": "Latest Disk usage reading (percent string), or null.",
|
|
1260
|
+
"example": "93",
|
|
1261
|
+
"nullable": true
|
|
1262
|
+
},
|
|
1263
|
+
"batteryPercent": {
|
|
1264
|
+
"type": "number",
|
|
1265
|
+
"description": "Battery charge level (0–100), or null if not yet streamed.",
|
|
1266
|
+
"example": 90,
|
|
1267
|
+
"nullable": true
|
|
1268
|
+
},
|
|
1269
|
+
"mode": {
|
|
1270
|
+
"type": "string",
|
|
1271
|
+
"description": "Current robot operating mode, or null if not yet streamed.",
|
|
1272
|
+
"example": "DISINFECT",
|
|
1273
|
+
"nullable": true
|
|
1274
|
+
},
|
|
1275
|
+
"emergency": {
|
|
1276
|
+
"type": "boolean",
|
|
1277
|
+
"description": "Whether the emergency button is active, or null if not yet streamed.",
|
|
1278
|
+
"example": false,
|
|
1279
|
+
"nullable": true
|
|
1280
|
+
},
|
|
1281
|
+
"lampLifeHours": {
|
|
1282
|
+
"type": "number",
|
|
1283
|
+
"description": "Remaining lamp life in hours, or null if not yet streamed.",
|
|
1284
|
+
"example": 9000,
|
|
1285
|
+
"nullable": true
|
|
1286
|
+
},
|
|
1287
|
+
"disinfectionRunning": {
|
|
1288
|
+
"type": "boolean",
|
|
1289
|
+
"description": "Whether a disinfection job is currently running, or null if not yet streamed.",
|
|
1290
|
+
"example": true,
|
|
1291
|
+
"nullable": true
|
|
1292
|
+
},
|
|
1293
|
+
"lastStreamed": {
|
|
1294
|
+
"type": "string",
|
|
1295
|
+
"description": "ISO-8601 timestamp of the last received status stream update, or null.",
|
|
1296
|
+
"example": "2026-05-20T10:00:00.000Z",
|
|
1297
|
+
"nullable": true
|
|
1298
|
+
}
|
|
1299
|
+
},
|
|
1300
|
+
"required": ["id", "tenantId", "name", "isSubscribed"]
|
|
1301
|
+
},
|
|
1302
|
+
"RobotMetricLiveDto": {
|
|
1303
|
+
"type": "object",
|
|
1304
|
+
"properties": {
|
|
1305
|
+
"metricId": {
|
|
1306
|
+
"type": "number",
|
|
1307
|
+
"description": "Integer id of the metric type.",
|
|
1308
|
+
"example": 1
|
|
1309
|
+
},
|
|
1310
|
+
"metricName": {
|
|
1311
|
+
"type": "string",
|
|
1312
|
+
"description": "Human-readable metric name.",
|
|
1313
|
+
"example": "Cpu"
|
|
1314
|
+
},
|
|
1315
|
+
"metricValue": {
|
|
1316
|
+
"type": "number",
|
|
1317
|
+
"description": "Latest recorded value.",
|
|
1318
|
+
"example": 42.5
|
|
1319
|
+
},
|
|
1320
|
+
"lastSyncTime": {
|
|
1321
|
+
"type": "object",
|
|
1322
|
+
"description": "ISO-8601 timestamp of the most recent reading.",
|
|
1323
|
+
"example": "2026-05-29T11:58:00.000Z"
|
|
1324
|
+
}
|
|
1325
|
+
},
|
|
1326
|
+
"required": ["metricId", "metricName", "metricValue", "lastSyncTime"]
|
|
1327
|
+
},
|
|
1328
|
+
"RobotsCountAnalyticsDataDto": {
|
|
1329
|
+
"type": "object",
|
|
1330
|
+
"properties": {
|
|
1331
|
+
"data": {
|
|
1332
|
+
"$ref": "#/components/schemas/RobotsCountResponseDto"
|
|
1333
|
+
},
|
|
1334
|
+
"timestamp": {
|
|
1335
|
+
"type": "string",
|
|
1336
|
+
"example": "2026-05-29T12:00:00.000Z"
|
|
1337
|
+
},
|
|
1338
|
+
"status": {
|
|
1339
|
+
"type": "string",
|
|
1340
|
+
"enum": ["success", "error"],
|
|
1341
|
+
"example": "success"
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
1344
|
+
"required": ["data", "timestamp", "status"]
|
|
1345
|
+
},
|
|
1346
|
+
"RobotsCountResponseDto": {
|
|
1347
|
+
"type": "object",
|
|
1348
|
+
"properties": {
|
|
1349
|
+
"total": {
|
|
1350
|
+
"type": "number",
|
|
1351
|
+
"example": 24
|
|
1352
|
+
},
|
|
1353
|
+
"online": {
|
|
1354
|
+
"type": "number",
|
|
1355
|
+
"example": 20
|
|
1356
|
+
},
|
|
1357
|
+
"offline": {
|
|
1358
|
+
"type": "number",
|
|
1359
|
+
"example": 4
|
|
1360
|
+
},
|
|
1361
|
+
"aiEnabled": {
|
|
1362
|
+
"type": "number",
|
|
1363
|
+
"example": 6
|
|
1364
|
+
},
|
|
1365
|
+
"swUpdatePending": {
|
|
1366
|
+
"type": "number",
|
|
1367
|
+
"example": 2
|
|
1368
|
+
}
|
|
1369
|
+
},
|
|
1370
|
+
"required": [
|
|
1371
|
+
"total",
|
|
1372
|
+
"online",
|
|
1373
|
+
"offline",
|
|
1374
|
+
"aiEnabled",
|
|
1375
|
+
"swUpdatePending"
|
|
1376
|
+
]
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|