@viewrium/sdk 0.1.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.
package/dist/index.d.ts CHANGED
@@ -1,350 +1,3535 @@
1
1
  /**
2
- * Typed error hierarchy for the Viewrium SDK.
3
- *
4
- * All API-originated failures inherit from `ViewriumError`. Network-level
5
- * failures (connection reset, DNS) bubble up as the underlying fetch error
6
- * unchanged.
2
+ * This file was auto-generated by openapi-typescript.
3
+ * Do not make direct changes to the file.
7
4
  */
8
- declare class ViewriumError extends Error {
9
- readonly statusCode: number | undefined;
10
- readonly responseBody: unknown;
11
- constructor(message: string, options?: {
12
- statusCode?: number;
13
- responseBody?: unknown;
14
- });
15
- }
16
- declare class AuthError extends ViewriumError {
17
- constructor(message: string, options?: {
18
- statusCode?: number;
19
- responseBody?: unknown;
20
- });
21
- }
22
- declare class NotFoundError extends ViewriumError {
23
- constructor(message: string, options?: {
24
- statusCode?: number;
25
- responseBody?: unknown;
26
- });
5
+ interface paths {
6
+ "/v1/products": {
7
+ parameters: {
8
+ query?: never;
9
+ header?: never;
10
+ path?: never;
11
+ cookie?: never;
12
+ };
13
+ /**
14
+ * List Products
15
+ * @description The catalog (D54): one org, the principal's only org when `org_id` is omitted, or
16
+ * `scope=all` for every org an agency member or staff reaches. Filters AND together.
17
+ */
18
+ get: operations["list_products_v1_products_get"];
19
+ put?: never;
20
+ /**
21
+ * Create Product
22
+ * @description Exactly one source (image_paths | image_urls | video_url | source_url | model_url |
23
+ * resume_token).
24
+ *
25
+ * - 200 {ProductParkedResponse} - the gate ALWAYS parks a fresh request (D24): the
26
+ * analysis ran synchronously and NOTHING was written; the plan, the flags and the cost
27
+ * come back with the token the Summary posts to commit.
28
+ * - 202 {ProductResponse} - resume_token or model_url: the product and its asset rows
29
+ * exist and the run has started. 409 on a replayed token or a duplicate custom_id.
30
+ *
31
+ * D76: the plan is IMMUTABLE once the token exists. A resume commits the plan, the model
32
+ * verdict and the price it was quoted for, and may still edit the `draft` (product
33
+ * columns, none of which reaches the plan). A resume that states a different `order`, or
34
+ * any `overrides`, is a 400 - changing what is generated means a new request.
35
+ */
36
+ post: operations["create_product_v1_products_post"];
37
+ /**
38
+ * Batch Delete Products
39
+ * @description 200 with per-id affected/not_found/forbidden buckets.
40
+ */
41
+ delete: operations["batch_delete_products_v1_products_delete"];
42
+ options?: never;
43
+ head?: never;
44
+ patch?: never;
45
+ trace?: never;
46
+ };
47
+ "/v1/products/publish": {
48
+ parameters: {
49
+ query?: never;
50
+ header?: never;
51
+ path?: never;
52
+ cookie?: never;
53
+ };
54
+ get?: never;
55
+ put?: never;
56
+ /**
57
+ * Publish Products
58
+ * @description The bulk publish toggle (D52). Single products toggle through PATCH. 402 when the org's
59
+ * plan does not allow publishing, or the batch would pass its active-product cap.
60
+ */
61
+ post: operations["publish_products_v1_products_publish_post"];
62
+ delete?: never;
63
+ options?: never;
64
+ head?: never;
65
+ patch?: never;
66
+ trace?: never;
67
+ };
68
+ "/v1/products/export": {
69
+ parameters: {
70
+ query?: never;
71
+ header?: never;
72
+ path?: never;
73
+ cookie?: never;
74
+ };
75
+ /**
76
+ * Export Products
77
+ * @description A ZIP of finished images (D52): select by `ids` or by the list's filters, choose which
78
+ * image review statuses (default accepted and pending). Each image is finished on demand -
79
+ * composited onto its background with its shadow - and reused while its settings are
80
+ * unchanged. The root `manifest.json` names every entry and every image skipped. The 3D
81
+ * model is never included.
82
+ *
83
+ * - 200 - the archive streams.
84
+ * - 202 {ProductExportQueuedResponse} - too many images need finishing for one request:
85
+ * they are finished in the background, a download link is emailed, and the same request
86
+ * streams the ZIP once they are done.
87
+ *
88
+ * 400 past 200 products.
89
+ */
90
+ get: operations["export_products_v1_products_export_get"];
91
+ put?: never;
92
+ post?: never;
93
+ delete?: never;
94
+ options?: never;
95
+ head?: never;
96
+ patch?: never;
97
+ trace?: never;
98
+ };
99
+ "/v1/products/tags": {
100
+ parameters: {
101
+ query?: never;
102
+ header?: never;
103
+ path?: never;
104
+ cookie?: never;
105
+ };
106
+ /**
107
+ * List Product Tags
108
+ * @description Distinct tags across the same scope the list takes (`org_id` / `scope=all`).
109
+ */
110
+ get: operations["list_product_tags_v1_products_tags_get"];
111
+ put?: never;
112
+ post?: never;
113
+ delete?: never;
114
+ options?: never;
115
+ head?: never;
116
+ patch?: never;
117
+ trace?: never;
118
+ };
119
+ "/v1/products/{id}": {
120
+ parameters: {
121
+ query?: never;
122
+ header?: never;
123
+ path?: never;
124
+ cookie?: never;
125
+ };
126
+ /**
127
+ * Get Product
128
+ * @description Two response shapes by principal kind: session/sk get the product with its assets; a
129
+ * pk key gets PublicProductResponse, the allow-listed subset safe to expose in
130
+ * browser-visible storefront JS, and only for a published product with a ready model.
131
+ */
132
+ get: operations["get_product_v1_products__id__get"];
133
+ put?: never;
134
+ post?: never;
135
+ /** Delete Product */
136
+ delete: operations["delete_product_v1_products__id__delete"];
137
+ options?: never;
138
+ head?: never;
139
+ /**
140
+ * Update Product
141
+ * @description The customer's fields, the user-set status and the publish toggle. 409 on a duplicate
142
+ * custom_id; 400 for `awaiting_review`; 402 when the publish toggle is refused by the plan.
143
+ */
144
+ patch: operations["update_product_v1_products__id__patch"];
145
+ trace?: never;
146
+ };
147
+ "/v1/products/{id}/order": {
148
+ parameters: {
149
+ query?: never;
150
+ header?: never;
151
+ path?: never;
152
+ cookie?: never;
153
+ };
154
+ get?: never;
155
+ put?: never;
156
+ /**
157
+ * Order Product
158
+ * @description Order the missing half - images onto a model-only product, or a model onto an images
159
+ * product. PARKS (D24): the additions and their cost come back inside a `resume_token`
160
+ * that `POST /v1/products` commits; nothing is written here. 409 with `details.reason`
161
+ * (`no_analysis`, `generating`, `images_ordered`, `model_exists`, `model_failed`) when the
162
+ * order cannot be placed; a failed model is never re-ordered through this route.
163
+ */
164
+ post: operations["order_product_v1_products__id__order_post"];
165
+ delete?: never;
166
+ options?: never;
167
+ head?: never;
168
+ patch?: never;
169
+ trace?: never;
170
+ };
171
+ "/v1/products/{id}/review": {
172
+ parameters: {
173
+ query?: never;
174
+ header?: never;
175
+ path?: never;
176
+ cookie?: never;
177
+ };
178
+ get?: never;
179
+ put?: never;
180
+ /**
181
+ * Review Product
182
+ * @description The review flush (E4 P5): the coalesced patches the UI batched - image review
183
+ * decisions and settings, the model's decision, the product's user-set status - validated
184
+ * together and written in order. Review records decisions only; the finished images are
185
+ * made by the export.
186
+ */
187
+ post: operations["review_product_v1_products__id__review_post"];
188
+ delete?: never;
189
+ options?: never;
190
+ head?: never;
191
+ patch?: never;
192
+ trace?: never;
193
+ };
194
+ "/v1/products/{id}/images/{image_id}": {
195
+ parameters: {
196
+ query?: never;
197
+ header?: never;
198
+ path?: never;
199
+ cookie?: never;
200
+ };
201
+ get?: never;
202
+ put?: never;
203
+ post?: never;
204
+ delete?: never;
205
+ options?: never;
206
+ head?: never;
207
+ /**
208
+ * Update Product Image
209
+ * @description One image: its review decision (one way out of pending), its shadow and background
210
+ * overrides, its filename and alt text. Answers the image as it now reads. 404 for a
211
+ * position the customer does not own.
212
+ */
213
+ patch: operations["update_product_image_v1_products__id__images__image_id__patch"];
214
+ trace?: never;
215
+ };
216
+ "/v1/products/{id}/model/rescale": {
217
+ parameters: {
218
+ query?: never;
219
+ header?: never;
220
+ path?: never;
221
+ cookie?: never;
222
+ };
223
+ get?: never;
224
+ put?: never;
225
+ /**
226
+ * Rescale Product Model
227
+ * @description Re-apply real-world scale to the GLB in place; the product keeps the axes the
228
+ * customer stated. 409 without a ready model, or for one with no measurable geometry; 502
229
+ * when the resize itself fails.
230
+ */
231
+ post: operations["rescale_product_model_v1_products__id__model_rescale_post"];
232
+ delete?: never;
233
+ options?: never;
234
+ head?: never;
235
+ patch?: never;
236
+ trace?: never;
237
+ };
238
+ "/v1/products/{id}/tickets": {
239
+ parameters: {
240
+ query?: never;
241
+ header?: never;
242
+ path?: never;
243
+ cookie?: never;
244
+ };
245
+ get?: never;
246
+ put?: never;
247
+ /**
248
+ * Create Product Ticket
249
+ * @description A single-use URL for the product's 3D file - the ONLY way to its bytes (there is no
250
+ * model file URL in any response). It answers `model/gltf-binary` ONCE, until `expires_at`
251
+ * (60 s for `view`, 30 s for `ar`). Mint it right before the viewer loads, never store it.
252
+ *
253
+ * - publishable key: a PUBLISHED product only; the ticket is bound to the page's Origin (one
254
+ * of the org's allowed domains).
255
+ * - secret key / session: the org's own products, drafts included; bound to `origin` (the
256
+ * page that will fetch the file), else the request's Origin.
257
+ *
258
+ * A `view` ticket streams only to its bound origin; an `ar` ticket also to Android's Scene
259
+ * Viewer, which sends none. 404 for a product the caller cannot see (or, for a pk, one that is
260
+ * not published); 409 without a ready model; 400 for an origin outside the allowed domains;
261
+ * 429 past the mint limits.
262
+ */
263
+ post: operations["create_product_ticket_v1_products__id__tickets_post"];
264
+ delete?: never;
265
+ options?: never;
266
+ head?: never;
267
+ patch?: never;
268
+ trace?: never;
269
+ };
270
+ "/v1/products/{id}/model": {
271
+ parameters: {
272
+ query?: never;
273
+ header?: never;
274
+ path?: never;
275
+ cookie?: never;
276
+ };
277
+ get?: never;
278
+ put?: never;
279
+ post?: never;
280
+ delete?: never;
281
+ options?: never;
282
+ head?: never;
283
+ /**
284
+ * Update Product Model
285
+ * @description The model's review decision (D14: independent of the images and of the product).
286
+ */
287
+ patch: operations["update_product_model_v1_products__id__model_patch"];
288
+ trace?: never;
289
+ };
290
+ "/v1/api_keys": {
291
+ parameters: {
292
+ query?: never;
293
+ header?: never;
294
+ path?: never;
295
+ cookie?: never;
296
+ };
297
+ /**
298
+ * List Api Keys
299
+ * @description sk auth sees only its own project's keys.
300
+ */
301
+ get: operations["list_api_keys_v1_api_keys_get"];
302
+ put?: never;
303
+ /**
304
+ * Create Api Key
305
+ * @description 201 - the full key is returned exactly once.
306
+ */
307
+ post: operations["create_api_key_v1_api_keys_post"];
308
+ delete?: never;
309
+ options?: never;
310
+ head?: never;
311
+ patch?: never;
312
+ trace?: never;
313
+ };
314
+ "/v1/api_keys/{id}": {
315
+ parameters: {
316
+ query?: never;
317
+ header?: never;
318
+ path?: never;
319
+ cookie?: never;
320
+ };
321
+ get?: never;
322
+ put?: never;
323
+ post?: never;
324
+ /**
325
+ * Revoke Api Key
326
+ * @description Soft revoke (sets revoked_at); the row is kept for usage attribution.
327
+ */
328
+ delete: operations["revoke_api_key_v1_api_keys__id__delete"];
329
+ options?: never;
330
+ head?: never;
331
+ patch?: never;
332
+ trace?: never;
333
+ };
334
+ "/v1/usage": {
335
+ parameters: {
336
+ query?: never;
337
+ header?: never;
338
+ path?: never;
339
+ cookie?: never;
340
+ };
341
+ /**
342
+ * Get Usage
343
+ * @description Buckets and totals over a window. One org (`org_id`, or the principal's only org), every
344
+ * org the session reaches (`scope=all`), or one product (`product_id`, which needs no
345
+ * `org_id`). Org-internal traffic is excluded unless `include_internal`.
346
+ *
347
+ * `group_by=product` adds `by_product`: the window's best-performing products, ranked by 3D
348
+ * views then AR entries and capped, each with its title. The buckets are unchanged - to break
349
+ * one period down, ask again with the window narrowed to it.
350
+ */
351
+ get: operations["get_usage_v1_usage_get"];
352
+ put?: never;
353
+ post?: never;
354
+ delete?: never;
355
+ options?: never;
356
+ head?: never;
357
+ patch?: never;
358
+ trace?: never;
359
+ };
360
+ "/v1/beacon": {
361
+ parameters: {
362
+ query?: never;
363
+ header?: never;
364
+ path?: never;
365
+ cookie?: never;
366
+ };
367
+ get?: never;
368
+ put?: never;
369
+ /**
370
+ * Ingest Beacon
371
+ * @description 204 No Content - never errors to the embed beyond 4xx auth/validation.
372
+ */
373
+ post: operations["ingest_beacon_v1_beacon_post"];
374
+ delete?: never;
375
+ options?: never;
376
+ head?: never;
377
+ patch?: never;
378
+ trace?: never;
379
+ };
380
+ "/v1/webhooks": {
381
+ parameters: {
382
+ query?: never;
383
+ header?: never;
384
+ path?: never;
385
+ cookie?: never;
386
+ };
387
+ /** List Webhook Endpoints */
388
+ get: operations["list_webhook_endpoints_v1_webhooks_get"];
389
+ put?: never;
390
+ /**
391
+ * Create Webhook Endpoint
392
+ * @description 201 - includes signing_secret (readable later too; parity with today).
393
+ */
394
+ post: operations["create_webhook_endpoint_v1_webhooks_post"];
395
+ delete?: never;
396
+ options?: never;
397
+ head?: never;
398
+ patch?: never;
399
+ trace?: never;
400
+ };
401
+ "/v1/webhooks/{id}": {
402
+ parameters: {
403
+ query?: never;
404
+ header?: never;
405
+ path?: never;
406
+ cookie?: never;
407
+ };
408
+ /** Get Webhook Endpoint */
409
+ get: operations["get_webhook_endpoint_v1_webhooks__id__get"];
410
+ put?: never;
411
+ post?: never;
412
+ /** Delete Webhook Endpoint */
413
+ delete: operations["delete_webhook_endpoint_v1_webhooks__id__delete"];
414
+ options?: never;
415
+ head?: never;
416
+ /** Update Webhook Endpoint */
417
+ patch: operations["update_webhook_endpoint_v1_webhooks__id__patch"];
418
+ trace?: never;
419
+ };
420
+ "/v1/webhooks/{id}/deliveries": {
421
+ parameters: {
422
+ query?: never;
423
+ header?: never;
424
+ path?: never;
425
+ cookie?: never;
426
+ };
427
+ /** List Webhook Deliveries */
428
+ get: operations["list_webhook_deliveries_v1_webhooks__id__deliveries_get"];
429
+ put?: never;
430
+ post?: never;
431
+ delete?: never;
432
+ options?: never;
433
+ head?: never;
434
+ patch?: never;
435
+ trace?: never;
436
+ };
437
+ "/v1/projects": {
438
+ parameters: {
439
+ query?: never;
440
+ header?: never;
441
+ path?: never;
442
+ cookie?: never;
443
+ };
444
+ /**
445
+ * List Projects
446
+ * @description sk auth: returns its one project.
447
+ */
448
+ get: operations["list_projects_v1_projects_get"];
449
+ put?: never;
450
+ post?: never;
451
+ delete?: never;
452
+ options?: never;
453
+ head?: never;
454
+ patch?: never;
455
+ trace?: never;
456
+ };
457
+ "/v1/projects/{id}": {
458
+ parameters: {
459
+ query?: never;
460
+ header?: never;
461
+ path?: never;
462
+ cookie?: never;
463
+ };
464
+ /** Get Project */
465
+ get: operations["get_project_v1_projects__id__get"];
466
+ put?: never;
467
+ post?: never;
468
+ delete?: never;
469
+ options?: never;
470
+ head?: never;
471
+ patch?: never;
472
+ trace?: never;
473
+ };
474
+ "/v1/health": {
475
+ parameters: {
476
+ query?: never;
477
+ header?: never;
478
+ path?: never;
479
+ cookie?: never;
480
+ };
481
+ /** Health */
482
+ get: operations["health_v1_health_get"];
483
+ put?: never;
484
+ post?: never;
485
+ delete?: never;
486
+ options?: never;
487
+ head?: never;
488
+ patch?: never;
489
+ trace?: never;
490
+ };
27
491
  }
28
- declare class ValidationError extends ViewriumError {
29
- constructor(message: string, options?: {
30
- statusCode?: number;
31
- responseBody?: unknown;
32
- });
492
+ interface components {
493
+ schemas: {
494
+ /** ApiKeyCreateRequest */
495
+ ApiKeyCreateRequest: {
496
+ key_type: components["schemas"]["KeyType"];
497
+ /** Org Id */
498
+ org_id?: string | null;
499
+ /** Project Id */
500
+ project_id?: string | null;
501
+ /** Name */
502
+ name?: string | null;
503
+ /**
504
+ * Scopes
505
+ * @default []
506
+ */
507
+ scopes: string[];
508
+ };
509
+ /**
510
+ * ApiKeyCreateResponse
511
+ * @description 201. `key` is the full key material. For secret keys this is the only time
512
+ * it is ever returned; publishable keys stay retrievable on later reads.
513
+ */
514
+ ApiKeyCreateResponse: {
515
+ /**
516
+ * Id
517
+ * Format: uuid
518
+ */
519
+ id: string;
520
+ /** Org Id */
521
+ org_id?: string | null;
522
+ /** Project Id */
523
+ project_id?: string | null;
524
+ key_type: components["schemas"]["KeyType"];
525
+ /** Key Prefix */
526
+ key_prefix: string;
527
+ /** Name */
528
+ name?: string | null;
529
+ /**
530
+ * Scopes
531
+ * @default []
532
+ */
533
+ scopes: string[];
534
+ /** Last Used At */
535
+ last_used_at?: string | null;
536
+ /** Revoked At */
537
+ revoked_at?: string | null;
538
+ /**
539
+ * Created At
540
+ * Format: date-time
541
+ */
542
+ created_at: string;
543
+ /** Key */
544
+ key: string;
545
+ };
546
+ /** ApiKeyListResponse */
547
+ ApiKeyListResponse: {
548
+ /** Data */
549
+ data: components["schemas"]["ApiKeyResponse"][];
550
+ };
551
+ /** ApiKeyResponse */
552
+ ApiKeyResponse: {
553
+ /**
554
+ * Id
555
+ * Format: uuid
556
+ */
557
+ id: string;
558
+ /** Org Id */
559
+ org_id?: string | null;
560
+ /** Project Id */
561
+ project_id?: string | null;
562
+ key_type: components["schemas"]["KeyType"];
563
+ /** Key Prefix */
564
+ key_prefix: string;
565
+ /** Name */
566
+ name?: string | null;
567
+ /**
568
+ * Scopes
569
+ * @default []
570
+ */
571
+ scopes: string[];
572
+ /** Last Used At */
573
+ last_used_at?: string | null;
574
+ /** Revoked At */
575
+ revoked_at?: string | null;
576
+ /**
577
+ * Created At
578
+ * Format: date-time
579
+ */
580
+ created_at: string;
581
+ /** Key */
582
+ key?: string | null;
583
+ };
584
+ /**
585
+ * AssetStatus
586
+ * @description product_images.status and product_models.status (CHECK-enforced). `skipped` is an
587
+ * image position nothing produced; a model row never carries it. Under E4 §6.1 a customer's
588
+ * WITHHELD position also reads `skipped` - the projection, not the row, says so.
589
+ * @enum {string}
590
+ */
591
+ AssetStatus: "planned" | "generating" | "ready" | "failed" | "skipped";
592
+ /**
593
+ * BeaconEventType
594
+ * @description The subset of UsageEventType that POST /v1/beacon may ingest.
595
+ * generation.* events are recorded server-side only, never via beacon.
596
+ * @enum {string}
597
+ */
598
+ BeaconEventType: "view" | "ar_enter" | "ar_session_ended";
599
+ /**
600
+ * BeaconRequest
601
+ * @description ONE ingest path, two auth modes (pk + Origin check for embeds; the first-party
602
+ * viewer posts without a key). DECIDED (Dave, 2026-07-20): anonymous first-party
603
+ * ingest is an accepted, signed-off risk. Writes usage_records; org/project/key
604
+ * attribution resolved server-side. Response: 204 No Content.
605
+ */
606
+ BeaconRequest: {
607
+ /**
608
+ * Model Id
609
+ * Format: uuid
610
+ */
611
+ model_id: string;
612
+ event_type: components["schemas"]["BeaconEventType"];
613
+ /** Session Id */
614
+ session_id?: string | null;
615
+ /** Duration Ms */
616
+ duration_ms?: number | null;
617
+ /** Metadata */
618
+ metadata?: {
619
+ [key: string]: unknown;
620
+ } | null;
621
+ };
622
+ /**
623
+ * DimensionUnit
624
+ * @description The unit `ModelCreateRequest.dimensions` is expressed in. API-boundary only:
625
+ * the endpoint converts to canonical cm (lib/units) before anything downstream sees
626
+ * the numbers - the DB, the workflow, and the SDKs' stored dims are always cm.
627
+ * @enum {string}
628
+ */
629
+ DimensionUnit: "mm" | "cm" | "m" | "in" | "ft";
630
+ /**
631
+ * DisplayStatus
632
+ * @description What a product LOOKS like, D13's vocabulary: the stored status, overridden by
633
+ * Generating while any asset is in flight and by Published once it is live. Values are
634
+ * the machine vocabulary; the customer copy is written from them on the surface.
635
+ * @enum {string}
636
+ */
637
+ DisplayStatus: "published" | "generating" | "failed" | "awaiting_review" | "needs_attention" | "ready_to_publish" | "complete";
638
+ /**
639
+ * GateFlags
640
+ * @description describe's structured read of the product (D25). `source_quality: poor` warns on both
641
+ * layers and gates neither.
642
+ */
643
+ GateFlags: {
644
+ /**
645
+ * Transparent
646
+ * @default false
647
+ */
648
+ transparent: boolean;
649
+ /**
650
+ * Geometry Risk
651
+ * @default false
652
+ */
653
+ geometry_risk: boolean;
654
+ /**
655
+ * Texture Risk
656
+ * @default false
657
+ */
658
+ texture_risk: boolean;
659
+ /**
660
+ * Source Quality
661
+ * @default ok
662
+ * @enum {string}
663
+ */
664
+ source_quality: "ok" | "poor";
665
+ /** Reasons */
666
+ reasons?: components["schemas"]["GateReason"][];
667
+ };
668
+ /**
669
+ * GateReason
670
+ * @description One raised flag, in describe's own words. Shown to the customer VERBATIM (D25).
671
+ */
672
+ GateReason: {
673
+ /** Code */
674
+ code: string;
675
+ /** Sentence */
676
+ sentence: string;
677
+ };
678
+ /** HTTPValidationError */
679
+ HTTPValidationError: {
680
+ /** Detail */
681
+ detail?: components["schemas"]["ValidationError"][];
682
+ };
683
+ /** HealthResponse */
684
+ HealthResponse: {
685
+ /**
686
+ * Status
687
+ * @default ok
688
+ * @constant
689
+ */
690
+ status: "ok";
691
+ /** Version */
692
+ version?: string | null;
693
+ };
694
+ /**
695
+ * KeyType
696
+ * @description api_keys.key_type (CHECK-enforced). Prefixes: pk_ (publishable), sk_ (secret).
697
+ * @enum {string}
698
+ */
699
+ KeyType: "publishable" | "secret";
700
+ /**
701
+ * ListScope
702
+ * @description GET /v1/products scope (II.4, D44): one org, or every org the principal reaches -
703
+ * an agency's clients, or everything for staff. Writes always name one org.
704
+ * @enum {string}
705
+ */
706
+ ListScope: "org" | "all";
707
+ /**
708
+ * ModelDimensions
709
+ * @description Real-world dimensions in cm (DB: products.height/width/depth numeric).
710
+ */
711
+ ModelDimensions: {
712
+ /** Height */
713
+ height?: number | null;
714
+ /** Width */
715
+ width?: number | null;
716
+ /** Depth */
717
+ depth?: number | null;
718
+ };
719
+ /**
720
+ * ModelPlanResponse
721
+ * @description The models layer's verdict. `views` is the D28 set for this form, in submission
722
+ * order; internal gap-fills are machinery and are deliberately NOT listed (D33).
723
+ *
724
+ * `unseen_views` are the views the model will be built from INVENTED rows (generated with
725
+ * `evidence: unseen`, the D28 fill excepted - `gate.invented_model_views`), listed whether or
726
+ * not they refuse it. Two or more put `unseen_views` in `blocked_by` (`gate.UNSEEN_BLOCK_AT`).
727
+ */
728
+ ModelPlanResponse: {
729
+ /** Ordered */
730
+ ordered: boolean;
731
+ /** Allowed */
732
+ allowed: boolean;
733
+ /** Blocked By */
734
+ blocked_by?: string[];
735
+ /** Views */
736
+ views?: string[];
737
+ /** Unseen Views */
738
+ unseen_views?: string[];
739
+ };
740
+ /**
741
+ * PlannedView
742
+ * @description One page position as it will be committed - a `product_images` row, pre-shaped.
743
+ *
744
+ * `reason_code` is the closed vocabulary of `lib/gate.py`; `reason` is routing's own
745
+ * factual sentence. The customer copy is written from the CODE on the surface that shows
746
+ * it (E6), never from this string.
747
+ */
748
+ PlannedView: {
749
+ /** View */
750
+ view: string;
751
+ /**
752
+ * Kind
753
+ * @enum {string}
754
+ */
755
+ kind: "wanted" | "extra";
756
+ /** Stands For */
757
+ stands_for: string;
758
+ /**
759
+ * Status
760
+ * @enum {string}
761
+ */
762
+ status: "planned" | "skipped";
763
+ /** Evidence */
764
+ evidence: string;
765
+ /** Reason Code */
766
+ reason_code: string;
767
+ /** Reason */
768
+ reason: string;
769
+ /** Deliverable */
770
+ deliverable: boolean;
771
+ /** Route */
772
+ route?: ("reuse" | "edit" | "generate") | null;
773
+ /** Photo */
774
+ photo?: number | null;
775
+ /** Pins */
776
+ pins?: number[];
777
+ /** Azimuth */
778
+ azimuth: string;
779
+ /** Tilt */
780
+ tilt: string;
781
+ /**
782
+ * Flagged
783
+ * @default false
784
+ */
785
+ flagged: boolean;
786
+ };
787
+ /**
788
+ * ProductBatchResponse
789
+ * @description Per-id outcome; 200 even when some ids were missing.
790
+ */
791
+ ProductBatchResponse: {
792
+ /** Affected */
793
+ affected: string[];
794
+ /** Not Found */
795
+ not_found: string[];
796
+ /** Forbidden */
797
+ forbidden: string[];
798
+ };
799
+ /**
800
+ * ProductCost
801
+ * @description What an order costs, in CREDITS (1 credit = $0.50): 1 per deliverable image, a flat 10
802
+ * for a model. Internal 3D gap-fills never enter the maths.
803
+ */
804
+ ProductCost: {
805
+ /** Images */
806
+ images: number;
807
+ /** Image Credits */
808
+ image_credits: number;
809
+ /** Model Credits */
810
+ model_credits: number;
811
+ /** Total Credits */
812
+ total_credits: number;
813
+ };
814
+ /**
815
+ * ProductCreateRequest
816
+ * @description POST /v1/products - park (200) or, with `resume_token`, commit (202).
817
+ *
818
+ * Exactly ONE source: image_paths | image_urls | video_url | source_url | model_url |
819
+ * resume_token.
820
+ * `image_paths` are UPLOADS-BUCKET object paths, not URLs: the wizard uploads
821
+ * direct-to-storage before any row exists (D24), so the gate is handed paths inside the
822
+ * caller's own org folder and re-hosts nothing (E1 P5).
823
+ */
824
+ ProductCreateRequest: {
825
+ /** Image Paths */
826
+ image_paths?: string[] | null;
827
+ /** Image Urls */
828
+ image_urls?: string[] | null;
829
+ /** Video Url */
830
+ video_url?: string | null;
831
+ /** Source Url */
832
+ source_url?: string | null;
833
+ /** Model Url */
834
+ model_url?: string | null;
835
+ /** Resume Token */
836
+ resume_token?: string | null;
837
+ /** Org Id */
838
+ org_id?: string | null;
839
+ draft?: components["schemas"]["ProductDraft"];
840
+ order?: components["schemas"]["ProductOrder"];
841
+ overrides?: components["schemas"]["ProductOverrides"];
842
+ };
843
+ /**
844
+ * ProductDraft
845
+ * @description The customer-editable half of a product, sent at park and again at resume.
846
+ *
847
+ * A resume may CHANGE these (D24: the wizard Summary is the park state, so its fields are
848
+ * still live when Generate is pressed), which is why they ride in the token rather than
849
+ * being frozen at the first call.
850
+ */
851
+ ProductDraft: {
852
+ /** Title */
853
+ title?: string | null;
854
+ /** Description */
855
+ description?: string | null;
856
+ /** Price */
857
+ price?: number | null;
858
+ /** Currency */
859
+ currency?: string | null;
860
+ /** Custom Id */
861
+ custom_id?: string | null;
862
+ /** Tags */
863
+ tags?: string[] | null;
864
+ /** Metadata */
865
+ metadata?: {
866
+ [key: string]: unknown;
867
+ } | null;
868
+ dimensions?: components["schemas"]["ModelDimensions"] | null;
869
+ unit?: components["schemas"]["DimensionUnit"] | null;
870
+ /** Wall Mounted */
871
+ wall_mounted?: boolean | null;
872
+ };
873
+ /**
874
+ * ProductExportQueuedResponse
875
+ * @description 202 from the export: more images need finishing than one request can do, so they are
876
+ * being finished in the background and nothing streamed. A download link is emailed to
877
+ * `notify_email` when they are done; repeating the same request then streams the ZIP
878
+ * (and repeating it earlier simply queues what is still missing).
879
+ */
880
+ ProductExportQueuedResponse: {
881
+ /**
882
+ * Status
883
+ * @default queued
884
+ * @constant
885
+ */
886
+ status: "queued";
887
+ /** Products */
888
+ products: number;
889
+ /** Images */
890
+ images: number;
891
+ /** To Finish */
892
+ to_finish: number;
893
+ /** Notify Email */
894
+ notify_email?: string | null;
895
+ };
896
+ /**
897
+ * ProductImagePatch
898
+ * @description PATCH /v1/products/{id}/images/{image_id}, and one item of the review flush.
899
+ *
900
+ * An explicit null CLEARS an override (the field is in `model_fields_set`); an omitted
901
+ * field leaves it alone. `review_status` is one way out of `pending` (Q7).
902
+ */
903
+ ProductImagePatch: {
904
+ review_status?: components["schemas"]["ReviewStatus"] | null;
905
+ shadow_override?: components["schemas"]["ShadowOverride"] | null;
906
+ /** Background Override */
907
+ background_override?: number[] | null;
908
+ /** Filename Override */
909
+ filename_override?: string | null;
910
+ /** Alt Override */
911
+ alt_override?: string | null;
912
+ };
913
+ /**
914
+ * ProductImageResponse
915
+ * @description One customer-visible image position (E4 plan §6.1). A withheld position reads
916
+ * `status: skipped` with a `skip_reason` and no files; a 3D-only row never appears.
917
+ * `filename` / `alt_text` are the override when set, else `lib/naming.py`'s.
918
+ */
919
+ ProductImageResponse: {
920
+ /**
921
+ * Id
922
+ * Format: uuid
923
+ */
924
+ id: string;
925
+ /** View */
926
+ view: string;
927
+ /**
928
+ * Kind
929
+ * @enum {string}
930
+ */
931
+ kind: "wanted" | "extra";
932
+ /** Stands For */
933
+ stands_for: string;
934
+ status: components["schemas"]["AssetStatus"];
935
+ /** Skip Reason */
936
+ skip_reason?: string | null;
937
+ /** Route */
938
+ route?: ("reuse" | "edit" | "generate") | null;
939
+ /** Source */
940
+ source?: ("photograph" | "edited" | "generated") | null;
941
+ /** Evidence */
942
+ evidence?: string | null;
943
+ /** Azimuth */
944
+ azimuth?: string | null;
945
+ /** Tilt */
946
+ tilt?: string | null;
947
+ /** Source Photo Id */
948
+ source_photo_id?: string | null;
949
+ /**
950
+ * Attempts
951
+ * @default 0
952
+ */
953
+ attempts: number;
954
+ /**
955
+ * Flagged
956
+ * @default false
957
+ */
958
+ flagged: boolean;
959
+ /**
960
+ * Cut Flagged
961
+ * @default false
962
+ */
963
+ cut_flagged: boolean;
964
+ /** Cut Problems */
965
+ cut_problems?: string | null;
966
+ /** @default pending */
967
+ review_status: components["schemas"]["ReviewStatus"];
968
+ /** Filename */
969
+ filename: string;
970
+ /** Alt Text */
971
+ alt_text: string;
972
+ /** Filename Override */
973
+ filename_override?: string | null;
974
+ /** Alt Override */
975
+ alt_override?: string | null;
976
+ shadow_override?: components["schemas"]["ShadowOverride"] | null;
977
+ /** Background Override */
978
+ background_override?: number[] | null;
979
+ /** Frame Scale */
980
+ frame_scale?: number | null;
981
+ /** Contact Regions */
982
+ contact_regions?: number[][];
983
+ /** Raw Url */
984
+ raw_url?: string | null;
985
+ /** Cutout Url */
986
+ cutout_url?: string | null;
987
+ /** Warnings */
988
+ warnings?: components["schemas"]["ProductWarning"][];
989
+ /**
990
+ * Created At
991
+ * Format: date-time
992
+ */
993
+ created_at: string;
994
+ /** Updated At */
995
+ updated_at?: string | null;
996
+ };
997
+ /** ProductListResponse */
998
+ ProductListResponse: {
999
+ /** Data */
1000
+ data: components["schemas"]["ProductSummary"][];
1001
+ /** Total */
1002
+ total: number;
1003
+ /** Limit */
1004
+ limit: number;
1005
+ /** Offset */
1006
+ offset: number;
1007
+ };
1008
+ /** ProductModelPatch */
1009
+ ProductModelPatch: {
1010
+ review_status?: components["schemas"]["ReviewStatus"] | null;
1011
+ };
1012
+ /**
1013
+ * ProductModelResponse
1014
+ * @description The product's 3D model. There is NO file URL here, on purpose (Dave, 2026-10-16: no
1015
+ * model file URL anywhere, merchants included): the bytes are reached only through a
1016
+ * single-use ticket, `POST /v1/products/{id}/tickets`.
1017
+ */
1018
+ ProductModelResponse: {
1019
+ /**
1020
+ * Id
1021
+ * Format: uuid
1022
+ */
1023
+ id: string;
1024
+ status: components["schemas"]["AssetStatus"];
1025
+ /** @default pending */
1026
+ review_status: components["schemas"]["ReviewStatus"];
1027
+ /** Thumbnail Url */
1028
+ thumbnail_url?: string | null;
1029
+ /** Scale Factor */
1030
+ scale_factor?: number | null;
1031
+ /** Width Axis */
1032
+ width_axis?: ("x" | "z") | null;
1033
+ flags?: components["schemas"]["GateFlags"];
1034
+ /** Warnings */
1035
+ warnings?: components["schemas"]["ProductWarning"][];
1036
+ /**
1037
+ * Created At
1038
+ * Format: date-time
1039
+ */
1040
+ created_at: string;
1041
+ /** Completed At */
1042
+ completed_at?: string | null;
1043
+ };
1044
+ /**
1045
+ * ProductOrder
1046
+ * @description What the customer asked to be produced. Either half may be ordered alone (plan §2.3).
1047
+ */
1048
+ ProductOrder: {
1049
+ /**
1050
+ * Images
1051
+ * @default true
1052
+ */
1053
+ images: boolean;
1054
+ /**
1055
+ * Model
1056
+ * @default false
1057
+ */
1058
+ model: boolean;
1059
+ };
1060
+ /**
1061
+ * ProductOrderParkedResponse
1062
+ * @description 200 from the order park: the ADDITIONS the commit will make, priced, inside a token.
1063
+ * Nothing was written.
1064
+ */
1065
+ ProductOrderParkedResponse: {
1066
+ /**
1067
+ * Status
1068
+ * @default parked
1069
+ * @constant
1070
+ */
1071
+ status: "parked";
1072
+ /** Resume Token */
1073
+ resume_token: string;
1074
+ /**
1075
+ * Expires At
1076
+ * Format: date-time
1077
+ */
1078
+ expires_at: string;
1079
+ order: components["schemas"]["ProductOrder"];
1080
+ flags: components["schemas"]["GateFlags"];
1081
+ /** Plan */
1082
+ plan?: components["schemas"]["PlannedView"][];
1083
+ model: components["schemas"]["ModelPlanResponse"];
1084
+ cost: components["schemas"]["ProductCost"];
1085
+ /** Warnings */
1086
+ warnings?: string[];
1087
+ /**
1088
+ * Generate Unseen
1089
+ * @default false
1090
+ */
1091
+ generate_unseen: boolean;
1092
+ /**
1093
+ * Force Model
1094
+ * @default false
1095
+ */
1096
+ force_model: boolean;
1097
+ };
1098
+ /**
1099
+ * ProductOrderRequest
1100
+ * @description POST /v1/products/{id}/order - the missing half (E4 plan §6.4). Parks; the commit is
1101
+ * POST /v1/products with the returned resume_token.
1102
+ */
1103
+ ProductOrderRequest: {
1104
+ order: components["schemas"]["ProductOrder"];
1105
+ overrides?: components["schemas"]["ProductOverrides"];
1106
+ };
1107
+ /**
1108
+ * ProductOverrides
1109
+ * @description The wizard's per-run answers. None = no answer, and the org preference stands - that
1110
+ * is the whole of D25's `wizard override ?? org preference`.
1111
+ */
1112
+ ProductOverrides: {
1113
+ /** Generate Unseen */
1114
+ generate_unseen?: boolean | null;
1115
+ /** Force Model */
1116
+ force_model?: boolean | null;
1117
+ };
1118
+ /**
1119
+ * ProductOwner
1120
+ * @description The profile that created a product, for a created-by initials badge (D54). Carries an
1121
+ * email, so it never reaches a pk principal - `PublicProductResponse` has no owner.
1122
+ */
1123
+ ProductOwner: {
1124
+ /**
1125
+ * Id
1126
+ * Format: uuid
1127
+ */
1128
+ id: string;
1129
+ /** Display Name */
1130
+ display_name?: string | null;
1131
+ /** Email */
1132
+ email: string;
1133
+ };
1134
+ /**
1135
+ * ProductParkedResponse
1136
+ * @description 200 from POST /v1/products - the gate ALWAYS parks (D24).
1137
+ *
1138
+ * No product row exists, nothing was written, and nothing can orphan: the analysis lives
1139
+ * only inside `resume_token`, which the Summary posts back to commit. `expires_at` mirrors
1140
+ * the Fernet TTL (7 days, fal's URL retention floor).
1141
+ */
1142
+ ProductParkedResponse: {
1143
+ /**
1144
+ * Status
1145
+ * @default parked
1146
+ * @constant
1147
+ */
1148
+ status: "parked";
1149
+ /** Resume Token */
1150
+ resume_token: string;
1151
+ /**
1152
+ * Expires At
1153
+ * Format: date-time
1154
+ */
1155
+ expires_at: string;
1156
+ /** Form */
1157
+ form: string;
1158
+ /** Title */
1159
+ title?: string | null;
1160
+ /** Description */
1161
+ description?: string | null;
1162
+ /**
1163
+ * Subject
1164
+ * @default
1165
+ */
1166
+ subject: string;
1167
+ /**
1168
+ * Wall Mounted
1169
+ * @default false
1170
+ */
1171
+ wall_mounted: boolean;
1172
+ dimensions?: components["schemas"]["ModelDimensions"] | null;
1173
+ display_unit?: components["schemas"]["DimensionUnit"] | null;
1174
+ flags: components["schemas"]["GateFlags"];
1175
+ /** Warnings */
1176
+ warnings?: string[];
1177
+ /** Plan */
1178
+ plan?: components["schemas"]["PlannedView"][];
1179
+ model: components["schemas"]["ModelPlanResponse"];
1180
+ cost: components["schemas"]["ProductCost"];
1181
+ /**
1182
+ * Generate Unseen
1183
+ * @default false
1184
+ */
1185
+ generate_unseen: boolean;
1186
+ /**
1187
+ * Force Model
1188
+ * @default false
1189
+ */
1190
+ force_model: boolean;
1191
+ };
1192
+ /**
1193
+ * ProductPublishRequest
1194
+ * @description POST /v1/products/publish - the bulk publish toggle (D52, E8).
1195
+ */
1196
+ ProductPublishRequest: {
1197
+ /** Ids */
1198
+ ids: string[];
1199
+ /** Published */
1200
+ published: boolean;
1201
+ };
1202
+ /**
1203
+ * ProductRescaleRequest
1204
+ * @description POST /v1/products/{id}/model/rescale. At least one axis; every supplied axis is applied
1205
+ * to the GEOMETRY; `unit` covers the values (absent = cm) and becomes the product's
1206
+ * display_unit; `width_axis` skips the ruler render and the VLM call.
1207
+ */
1208
+ ProductRescaleRequest: {
1209
+ /** Height */
1210
+ height?: number | null;
1211
+ /** Width */
1212
+ width?: number | null;
1213
+ /** Depth */
1214
+ depth?: number | null;
1215
+ unit?: components["schemas"]["DimensionUnit"] | null;
1216
+ /** Width Axis */
1217
+ width_axis?: ("x" | "z") | null;
1218
+ };
1219
+ /**
1220
+ * ProductResponse
1221
+ * @description The product WITH its assets: 202 from a committed POST, and GET /v1/products/{id}.
1222
+ *
1223
+ * `status` is the STORED review status; `display_status` is D13's fold of it with
1224
+ * `published` and whether any asset is still in flight - the one a surface shows.
1225
+ * `images` is the customer's list (§6.1), in page order; `warnings` is every warning for
1226
+ * the product, image ones first.
1227
+ */
1228
+ ProductResponse: {
1229
+ /**
1230
+ * Id
1231
+ * Format: uuid
1232
+ */
1233
+ id: string;
1234
+ /**
1235
+ * Org Id
1236
+ * Format: uuid
1237
+ */
1238
+ org_id: string;
1239
+ /** Title */
1240
+ title: string;
1241
+ /** Custom Id */
1242
+ custom_id?: string | null;
1243
+ /** Tags */
1244
+ tags?: string[];
1245
+ status: components["schemas"]["ProductStatus"];
1246
+ display_status: components["schemas"]["DisplayStatus"];
1247
+ /**
1248
+ * Published
1249
+ * @default false
1250
+ */
1251
+ published: boolean;
1252
+ /** Form */
1253
+ form?: string | null;
1254
+ source_type?: components["schemas"]["SourceType"] | null;
1255
+ /** Price */
1256
+ price?: number | null;
1257
+ /** Currency */
1258
+ currency?: string | null;
1259
+ /** Height */
1260
+ height?: number | null;
1261
+ /** Width */
1262
+ width?: number | null;
1263
+ /** Depth */
1264
+ depth?: number | null;
1265
+ display_unit?: components["schemas"]["DimensionUnit"] | null;
1266
+ /**
1267
+ * Images Ordered
1268
+ * @default false
1269
+ */
1270
+ images_ordered: boolean;
1271
+ /** Thumbnail Url */
1272
+ thumbnail_url?: string | null;
1273
+ /**
1274
+ * Has Warnings
1275
+ * @default false
1276
+ */
1277
+ has_warnings: boolean;
1278
+ /**
1279
+ * Warning Count
1280
+ * @default 0
1281
+ */
1282
+ warning_count: number;
1283
+ /**
1284
+ * Comment Count
1285
+ * @default 0
1286
+ */
1287
+ comment_count: number;
1288
+ /**
1289
+ * Image Count
1290
+ * @default 0
1291
+ */
1292
+ image_count: number;
1293
+ model_status?: components["schemas"]["AssetStatus"] | null;
1294
+ owner?: components["schemas"]["ProductOwner"] | null;
1295
+ /**
1296
+ * Created At
1297
+ * Format: date-time
1298
+ */
1299
+ created_at: string;
1300
+ /** Updated At */
1301
+ updated_at?: string | null;
1302
+ /** Description */
1303
+ description?: string | null;
1304
+ /**
1305
+ * Wall Mounted
1306
+ * @default false
1307
+ */
1308
+ wall_mounted: boolean;
1309
+ /** Product Type */
1310
+ product_type?: string | null;
1311
+ /** Material Words */
1312
+ material_words?: string | null;
1313
+ /**
1314
+ * Transparent
1315
+ * @default false
1316
+ */
1317
+ transparent: boolean;
1318
+ /** Metadata */
1319
+ metadata?: {
1320
+ [key: string]: unknown;
1321
+ };
1322
+ /** Sources */
1323
+ sources?: components["schemas"]["ProductSourceResponse"][];
1324
+ /** Images */
1325
+ images?: components["schemas"]["ProductImageResponse"][];
1326
+ model?: components["schemas"]["ProductModelResponse"] | null;
1327
+ /** Warnings */
1328
+ warnings?: components["schemas"]["ProductWarning"][];
1329
+ /**
1330
+ * Open Request Count
1331
+ * @default 0
1332
+ */
1333
+ open_request_count: number;
1334
+ };
1335
+ /** ProductReviewImagePatch */
1336
+ ProductReviewImagePatch: {
1337
+ review_status?: components["schemas"]["ReviewStatus"] | null;
1338
+ shadow_override?: components["schemas"]["ShadowOverride"] | null;
1339
+ /** Background Override */
1340
+ background_override?: number[] | null;
1341
+ /** Filename Override */
1342
+ filename_override?: string | null;
1343
+ /** Alt Override */
1344
+ alt_override?: string | null;
1345
+ /**
1346
+ * Image Id
1347
+ * Format: uuid
1348
+ */
1349
+ image_id: string;
1350
+ };
1351
+ /**
1352
+ * ProductReviewRequest
1353
+ * @description POST /v1/products/{id}/review - the write-behind flush (E4 P5): the coalesced patches
1354
+ * the UI batched, applied in order after every one has been validated.
1355
+ */
1356
+ ProductReviewRequest: {
1357
+ status?: components["schemas"]["ProductStatus"] | null;
1358
+ /** Images */
1359
+ images?: components["schemas"]["ProductReviewImagePatch"][];
1360
+ model?: components["schemas"]["ProductModelPatch"] | null;
1361
+ };
1362
+ /** ProductReviewResponse */
1363
+ ProductReviewResponse: {
1364
+ /**
1365
+ * Product Id
1366
+ * Format: uuid
1367
+ */
1368
+ product_id: string;
1369
+ /** Applied */
1370
+ applied: number;
1371
+ display_status: components["schemas"]["DisplayStatus"];
1372
+ };
1373
+ /**
1374
+ * ProductSortField
1375
+ * @description Sortable columns for GET /v1/products. D54's four sorts are these two, each way;
1376
+ * restricted to a closed set because the value reaches PostgREST's `order` as a column.
1377
+ * @enum {string}
1378
+ */
1379
+ ProductSortField: "created_at" | "title";
1380
+ /** ProductSourceResponse */
1381
+ ProductSourceResponse: {
1382
+ /**
1383
+ * Id
1384
+ * Format: uuid
1385
+ */
1386
+ id: string;
1387
+ /**
1388
+ * Kind
1389
+ * @enum {string}
1390
+ */
1391
+ kind: "photo" | "video";
1392
+ /** Url */
1393
+ url: string;
1394
+ /** Original Name */
1395
+ original_name?: string | null;
1396
+ /**
1397
+ * Position
1398
+ * @default 0
1399
+ */
1400
+ position: number;
1401
+ /** Azimuth */
1402
+ azimuth?: string | null;
1403
+ /** Tilt */
1404
+ tilt?: string | null;
1405
+ /** Clean */
1406
+ clean?: boolean | null;
1407
+ /**
1408
+ * Created At
1409
+ * Format: date-time
1410
+ */
1411
+ created_at: string;
1412
+ };
1413
+ /**
1414
+ * ProductStatus
1415
+ * @description products.status (CHECK-enforced, E1 WP3). The STORED review lifecycle only - what a
1416
+ * surface DISPLAYS also folds in `published` and whether any asset is still generating
1417
+ * (D13); `lib.product_status.displayed_status` is the one place that fold happens.
1418
+ * @enum {string}
1419
+ */
1420
+ ProductStatus: "awaiting_review" | "needs_attention" | "ready_to_publish" | "complete";
1421
+ /**
1422
+ * ProductSummary
1423
+ * @description A catalog row (D54): the product plus what its card needs. No nested assets.
1424
+ */
1425
+ ProductSummary: {
1426
+ /**
1427
+ * Id
1428
+ * Format: uuid
1429
+ */
1430
+ id: string;
1431
+ /**
1432
+ * Org Id
1433
+ * Format: uuid
1434
+ */
1435
+ org_id: string;
1436
+ /** Title */
1437
+ title: string;
1438
+ /** Custom Id */
1439
+ custom_id?: string | null;
1440
+ /** Tags */
1441
+ tags?: string[];
1442
+ status: components["schemas"]["ProductStatus"];
1443
+ display_status: components["schemas"]["DisplayStatus"];
1444
+ /**
1445
+ * Published
1446
+ * @default false
1447
+ */
1448
+ published: boolean;
1449
+ /** Form */
1450
+ form?: string | null;
1451
+ source_type?: components["schemas"]["SourceType"] | null;
1452
+ /** Price */
1453
+ price?: number | null;
1454
+ /** Currency */
1455
+ currency?: string | null;
1456
+ /** Height */
1457
+ height?: number | null;
1458
+ /** Width */
1459
+ width?: number | null;
1460
+ /** Depth */
1461
+ depth?: number | null;
1462
+ display_unit?: components["schemas"]["DimensionUnit"] | null;
1463
+ /**
1464
+ * Images Ordered
1465
+ * @default false
1466
+ */
1467
+ images_ordered: boolean;
1468
+ /** Thumbnail Url */
1469
+ thumbnail_url?: string | null;
1470
+ /**
1471
+ * Has Warnings
1472
+ * @default false
1473
+ */
1474
+ has_warnings: boolean;
1475
+ /**
1476
+ * Warning Count
1477
+ * @default 0
1478
+ */
1479
+ warning_count: number;
1480
+ /**
1481
+ * Comment Count
1482
+ * @default 0
1483
+ */
1484
+ comment_count: number;
1485
+ /**
1486
+ * Image Count
1487
+ * @default 0
1488
+ */
1489
+ image_count: number;
1490
+ model_status?: components["schemas"]["AssetStatus"] | null;
1491
+ owner?: components["schemas"]["ProductOwner"] | null;
1492
+ /**
1493
+ * Created At
1494
+ * Format: date-time
1495
+ */
1496
+ created_at: string;
1497
+ /** Updated At */
1498
+ updated_at?: string | null;
1499
+ };
1500
+ /**
1501
+ * ProductUpdateRequest
1502
+ * @description PATCH /v1/products/{id} - the customer's fields, the user-set status (D13; never
1503
+ * back to `awaiting_review`) and the publish toggle. Dimensions are stored WITHOUT a
1504
+ * rescale; `POST .../model/rescale` rewrites the GLB.
1505
+ */
1506
+ ProductUpdateRequest: {
1507
+ /** Title */
1508
+ title?: string | null;
1509
+ /** Description */
1510
+ description?: string | null;
1511
+ /** Price */
1512
+ price?: number | null;
1513
+ /** Currency */
1514
+ currency?: string | null;
1515
+ /** Custom Id */
1516
+ custom_id?: string | null;
1517
+ /** Tags */
1518
+ tags?: string[] | null;
1519
+ /** Metadata */
1520
+ metadata?: {
1521
+ [key: string]: unknown;
1522
+ } | null;
1523
+ dimensions?: components["schemas"]["ModelDimensions"] | null;
1524
+ unit?: components["schemas"]["DimensionUnit"] | null;
1525
+ display_unit?: components["schemas"]["DimensionUnit"] | null;
1526
+ /** Wall Mounted */
1527
+ wall_mounted?: boolean | null;
1528
+ status?: components["schemas"]["ProductStatus"] | null;
1529
+ /** Published */
1530
+ published?: boolean | null;
1531
+ };
1532
+ /**
1533
+ * ProductWarning
1534
+ * @description One customer-facing warning, derived at read time (D21) by `lib/warnings.py`.
1535
+ */
1536
+ ProductWarning: {
1537
+ kind: components["schemas"]["WarningKind"];
1538
+ /**
1539
+ * Scope
1540
+ * @enum {string}
1541
+ */
1542
+ scope: "image" | "product";
1543
+ /** Title */
1544
+ title: string;
1545
+ /** Detail */
1546
+ detail: string;
1547
+ /** View */
1548
+ view?: string | null;
1549
+ };
1550
+ /** ProjectListResponse */
1551
+ ProjectListResponse: {
1552
+ /** Data */
1553
+ data: components["schemas"]["ProjectResponse"][];
1554
+ };
1555
+ /** ProjectResponse */
1556
+ ProjectResponse: {
1557
+ /**
1558
+ * Id
1559
+ * Format: uuid
1560
+ */
1561
+ id: string;
1562
+ /**
1563
+ * Org Id
1564
+ * Format: uuid
1565
+ */
1566
+ org_id: string;
1567
+ /** Name */
1568
+ name: string;
1569
+ /**
1570
+ * Allowed Domains
1571
+ * @default []
1572
+ */
1573
+ allowed_domains: string[];
1574
+ /**
1575
+ * Always Generate
1576
+ * @default false
1577
+ */
1578
+ always_generate: boolean;
1579
+ /**
1580
+ * Created At
1581
+ * Format: date-time
1582
+ */
1583
+ created_at: string;
1584
+ };
1585
+ /**
1586
+ * PublicProductResponse
1587
+ * @description What a PUBLISHABLE key receives from GET /v1/products/{id} - an explicit ALLOW-LIST,
1588
+ * deliberately a separate model rather than a filtered ProductResponse.
1589
+ *
1590
+ * pk keys ship inside the embed script in browser-visible JS on merchants' public
1591
+ * storefronts, so anything here is world-readable. An allow-list fails closed: a field
1592
+ * added to ProductResponse tomorrow is NOT exposed here until someone adds it on purpose.
1593
+ * Only a PUBLISHED product with a READY model is served at all (the `public_products()`
1594
+ * gate, D72); the images half is post-launch backlog #4. The model file itself is NOT here:
1595
+ * the embed mints a single-use ticket for it (`POST /v1/products/{id}/tickets`).
1596
+ */
1597
+ PublicProductResponse: {
1598
+ /**
1599
+ * Id
1600
+ * Format: uuid
1601
+ */
1602
+ id: string;
1603
+ /** Title */
1604
+ title: string;
1605
+ /** Thumbnail Url */
1606
+ thumbnail_url?: string | null;
1607
+ model_status?: components["schemas"]["AssetStatus"] | null;
1608
+ /**
1609
+ * Wall Mounted
1610
+ * @default false
1611
+ */
1612
+ wall_mounted: boolean;
1613
+ };
1614
+ /**
1615
+ * ReviewStatus
1616
+ * @description product_images.review_status and product_models.review_status (CHECK-enforced, E1
1617
+ * WP3). One way out of `pending` (Dave, 2026-09-09): accepted and rejected swap freely,
1618
+ * nothing goes back to pending.
1619
+ * @enum {string}
1620
+ */
1621
+ ReviewStatus: "pending" | "accepted" | "rejected";
1622
+ /** ShadowContact */
1623
+ ShadowContact: {
1624
+ /** Trailpx */
1625
+ trailPx?: number | null;
1626
+ /** Dark */
1627
+ dark?: number | null;
1628
+ /** End */
1629
+ end?: number | null;
1630
+ /** Midpoint */
1631
+ midpoint?: number | null;
1632
+ /** Regionheight */
1633
+ regionHeight?: number | null;
1634
+ };
1635
+ /** ShadowGround */
1636
+ ShadowGround: {
1637
+ /** Nudge */
1638
+ nudge?: number | null;
1639
+ /** Tilt */
1640
+ tilt?: number | null;
1641
+ };
1642
+ /**
1643
+ * ShadowOverride
1644
+ * @description A per-image shadow override in the RENDERER'S own shape (`@repo/heinimex-render`'s
1645
+ * `ShadowSettings` minus `background`), every field optional: the compositor merges it over
1646
+ * CALIBRATED field by field, so a caller sends only what it overrides. Background is its
1647
+ * own column (`background_override`), as the review app keeps it.
1648
+ */
1649
+ ShadowOverride: {
1650
+ /** Mode */
1651
+ mode?: ("silhouette" | "contact" | "both") | null;
1652
+ /** Tone */
1653
+ tone?: number[] | null;
1654
+ silhouette?: components["schemas"]["ShadowSilhouette"] | null;
1655
+ contact?: components["schemas"]["ShadowContact"] | null;
1656
+ ground?: components["schemas"]["ShadowGround"] | null;
1657
+ };
1658
+ /** ShadowSilhouette */
1659
+ ShadowSilhouette: {
1660
+ /** Length */
1661
+ length?: number | null;
1662
+ /** Lean */
1663
+ lean?: number | null;
1664
+ /** Blurnear */
1665
+ blurNear?: number | null;
1666
+ /** Blurfar */
1667
+ blurFar?: number | null;
1668
+ /** Opacity */
1669
+ opacity?: number | null;
1670
+ /** Distancefade */
1671
+ distanceFade?: number | null;
1672
+ };
1673
+ /**
1674
+ * SortOrder
1675
+ * @enum {string}
1676
+ */
1677
+ SortOrder: "asc" | "desc";
1678
+ /**
1679
+ * SourceType
1680
+ * @description scans.source_type (unconstrained text in prod, default 'scan').
1681
+ *
1682
+ * DECIDED (Dave, 2026-07-20): v2 vocabulary is image | video | url | model with a
1683
+ * CHECK; legacy mapping upload -> model and scan -> video. Backfill drafted in the
1684
+ * pending migration (section 3); the CHECK itself waits for cutover because the live
1685
+ * v1 app still writes 'upload' and defaults to 'scan'.
1686
+ * @enum {string}
1687
+ */
1688
+ SourceType: "image" | "video" | "url" | "model" | "scan" | "upload";
1689
+ /** TagCount */
1690
+ TagCount: {
1691
+ /** Tag */
1692
+ tag: string;
1693
+ /** Count */
1694
+ count: number;
1695
+ };
1696
+ /**
1697
+ * TagMatch
1698
+ * @description How repeated ?tag= values combine (Dave ruling, 2026-07-22: caller-selectable,
1699
+ * the dashboard exposes an All/Any control inside the Tags dropdown).
1700
+ * @enum {string}
1701
+ */
1702
+ TagMatch: "all" | "any";
1703
+ /**
1704
+ * TagsResponse
1705
+ * @description Distinct tags across the list's scope (GET /v1/products/tags).
1706
+ */
1707
+ TagsResponse: {
1708
+ /** Data */
1709
+ data: components["schemas"]["TagCount"][];
1710
+ };
1711
+ /**
1712
+ * TicketKind
1713
+ * @description `model_tickets.kind` (migration section 46): what one single-use model ticket is for.
1714
+ * `view` streams to the page that minted it (its Origin must match); `ar` is Android's Scene
1715
+ * Viewer, which re-downloads the file outside the page and sends no Origin.
1716
+ * @enum {string}
1717
+ */
1718
+ TicketKind: "view" | "ar";
1719
+ /**
1720
+ * TicketRequest
1721
+ * @description POST /v1/products/{id}/tickets - one single-use ticket for the product's 3D file.
1722
+ *
1723
+ * `view` is for the page itself: the redeem streams the file only to a request whose Origin
1724
+ * is the one the ticket is bound to. `ar` is for Android's Scene Viewer, which downloads the
1725
+ * file outside the page (it sends no Origin) - mint it on the AR tap, it lives 30 s.
1726
+ *
1727
+ * `origin` is for a SERVER minting on a page's behalf (a secret key, or our dashboard's own
1728
+ * server): the origin of the page that will fetch the file. It must be one of the org's
1729
+ * allowed domains (or ours). A publishable key never sends it - a pk ticket is bound to the
1730
+ * request's own Origin, which the key's allowed domains already gated.
1731
+ */
1732
+ TicketRequest: {
1733
+ kind: components["schemas"]["TicketKind"];
1734
+ /** Origin */
1735
+ origin?: string | null;
1736
+ };
1737
+ /**
1738
+ * TicketResponse
1739
+ * @description A single-use URL for the product's 3D file (`model/gltf-binary`). It works ONCE, until
1740
+ * `expires_at`, and for a view ticket only from its bound origin. Do not store it.
1741
+ */
1742
+ TicketResponse: {
1743
+ /** Url */
1744
+ url: string;
1745
+ kind: components["schemas"]["TicketKind"];
1746
+ /**
1747
+ * Expires At
1748
+ * Format: date-time
1749
+ */
1750
+ expires_at: string;
1751
+ };
1752
+ /** UsageBucket */
1753
+ UsageBucket: {
1754
+ /**
1755
+ * Period Start
1756
+ * Format: date-time
1757
+ */
1758
+ period_start: string;
1759
+ event_type: components["schemas"]["UsageEventType"];
1760
+ /** Count */
1761
+ count: number;
1762
+ /** Cost Cents */
1763
+ cost_cents?: number | null;
1764
+ duration?: components["schemas"]["UsageDuration"] | null;
1765
+ };
1766
+ /**
1767
+ * UsageDuration
1768
+ * @description AR session length, as a SUM plus its own divisor - never a pre-computed average.
1769
+ *
1770
+ * The average is `total_ms / count`, so the same object serves a per-bucket mean (the
1771
+ * temporal distribution) and a window mean (the summary tile) from one response: a
1772
+ * pre-computed average could not be re-aggregated across buckets, a sum can.
1773
+ *
1774
+ * `count` is NOT UsageBucket.count. Only `ar_session_ended` carries a duration, and even
1775
+ * there `duration_ms` is optional on the beacon and arrives from an untrusted body, so
1776
+ * the events that contributed a usable value are counted separately and are the only
1777
+ * correct divisor.
1778
+ */
1779
+ UsageDuration: {
1780
+ /** Total Ms */
1781
+ total_ms: number;
1782
+ /** Count */
1783
+ count: number;
1784
+ };
1785
+ /**
1786
+ * UsageEventType
1787
+ * @description usage_records.event_type (CHECK-enforced, exact prod list - all six live in data).
1788
+ * @enum {string}
1789
+ */
1790
+ UsageEventType: "generation.created" | "generation.completed" | "generation.failed" | "view" | "ar_enter" | "ar_session_ended";
1791
+ /**
1792
+ * UsageProductTotals
1793
+ * @description One product's counts over the window - the `group_by=product` row.
1794
+ *
1795
+ * `title` is read from the product itself, so a caller ranking products needs no second request
1796
+ * to name them. A subject with no product row is a v1 SCAN and is left out entirely: v2 serves
1797
+ * no scan, and a ranking whose rows cannot be opened is a list of dead ends.
1798
+ */
1799
+ UsageProductTotals: {
1800
+ /**
1801
+ * Product Id
1802
+ * Format: uuid
1803
+ */
1804
+ product_id: string;
1805
+ /** Title */
1806
+ title?: string | null;
1807
+ /** Totals */
1808
+ totals: {
1809
+ [key: string]: number;
1810
+ };
1811
+ };
1812
+ /** UsageResponse */
1813
+ UsageResponse: {
1814
+ /**
1815
+ * Start
1816
+ * Format: date-time
1817
+ */
1818
+ start: string;
1819
+ /**
1820
+ * End
1821
+ * Format: date-time
1822
+ */
1823
+ end: string;
1824
+ /**
1825
+ * Granularity
1826
+ * @enum {string}
1827
+ */
1828
+ granularity: "hour" | "day";
1829
+ /** Buckets */
1830
+ buckets: components["schemas"]["UsageBucket"][];
1831
+ /** Totals */
1832
+ totals: {
1833
+ [key: string]: number;
1834
+ };
1835
+ /** Durations */
1836
+ durations?: {
1837
+ [key: string]: components["schemas"]["UsageDuration"];
1838
+ };
1839
+ /** By Product */
1840
+ by_product?: components["schemas"]["UsageProductTotals"][];
1841
+ };
1842
+ /** ValidationError */
1843
+ ValidationError: {
1844
+ /** Location */
1845
+ loc: (string | number)[];
1846
+ /** Message */
1847
+ msg: string;
1848
+ /** Error Type */
1849
+ type: string;
1850
+ /** Input */
1851
+ input?: unknown;
1852
+ /** Context */
1853
+ ctx?: Record<string, never>;
1854
+ };
1855
+ /**
1856
+ * WarningKind
1857
+ * @description The customer-facing warnings derived at read time (D21) - `lib/warnings.py` is the
1858
+ * rule, this is its vocabulary on the wire.
1859
+ * @enum {string}
1860
+ */
1861
+ WarningKind: "cut" | "generation" | "missing" | "lighting" | "model_failed" | "model_risk";
1862
+ /** WebhookDeliveryListResponse */
1863
+ WebhookDeliveryListResponse: {
1864
+ /** Data */
1865
+ data: components["schemas"]["WebhookDeliveryResponse"][];
1866
+ /** Limit */
1867
+ limit: number;
1868
+ /** Offset */
1869
+ offset: number;
1870
+ };
1871
+ /** WebhookDeliveryResponse */
1872
+ WebhookDeliveryResponse: {
1873
+ /**
1874
+ * Id
1875
+ * Format: uuid
1876
+ */
1877
+ id: string;
1878
+ /**
1879
+ * Endpoint Id
1880
+ * Format: uuid
1881
+ */
1882
+ endpoint_id: string;
1883
+ event_type: components["schemas"]["WebhookEventType"];
1884
+ /**
1885
+ * Event Id
1886
+ * Format: uuid
1887
+ */
1888
+ event_id: string;
1889
+ /** Http Status */
1890
+ http_status?: number | null;
1891
+ /** Attempts */
1892
+ attempts: number;
1893
+ /** Succeeded At */
1894
+ succeeded_at?: string | null;
1895
+ /** Last Attempt At */
1896
+ last_attempt_at?: string | null;
1897
+ /** Last Error */
1898
+ last_error?: string | null;
1899
+ /** Payload Json */
1900
+ payload_json?: {
1901
+ [key: string]: unknown;
1902
+ } | null;
1903
+ };
1904
+ /** WebhookEndpointCreateRequest */
1905
+ WebhookEndpointCreateRequest: {
1906
+ /** Url */
1907
+ url: string;
1908
+ /** Events */
1909
+ events: components["schemas"]["WebhookEventType"][];
1910
+ /** Description */
1911
+ description?: string | null;
1912
+ /** Org Id */
1913
+ org_id?: string | null;
1914
+ /** Project Id */
1915
+ project_id?: string | null;
1916
+ };
1917
+ /**
1918
+ * WebhookEndpointCreateResponse
1919
+ * @description 201. signing_secret returned on create; also readable later by org members
1920
+ * (DB stores it plaintext; dashboard shows it). PROPOSED: keep parity with current
1921
+ * behavior rather than show-once.
1922
+ */
1923
+ WebhookEndpointCreateResponse: {
1924
+ /**
1925
+ * Id
1926
+ * Format: uuid
1927
+ */
1928
+ id: string;
1929
+ /** Org Id */
1930
+ org_id?: string | null;
1931
+ /** Project Id */
1932
+ project_id?: string | null;
1933
+ /** Url */
1934
+ url: string;
1935
+ /** Description */
1936
+ description?: string | null;
1937
+ /** Events */
1938
+ events: components["schemas"]["WebhookEventType"][];
1939
+ /** Enabled */
1940
+ enabled: boolean;
1941
+ /**
1942
+ * Created At
1943
+ * Format: date-time
1944
+ */
1945
+ created_at: string;
1946
+ /**
1947
+ * Updated At
1948
+ * Format: date-time
1949
+ */
1950
+ updated_at: string;
1951
+ /** Signing Secret */
1952
+ signing_secret: string;
1953
+ };
1954
+ /** WebhookEndpointListResponse */
1955
+ WebhookEndpointListResponse: {
1956
+ /** Data */
1957
+ data: components["schemas"]["WebhookEndpointResponse"][];
1958
+ };
1959
+ /** WebhookEndpointResponse */
1960
+ WebhookEndpointResponse: {
1961
+ /**
1962
+ * Id
1963
+ * Format: uuid
1964
+ */
1965
+ id: string;
1966
+ /** Org Id */
1967
+ org_id?: string | null;
1968
+ /** Project Id */
1969
+ project_id?: string | null;
1970
+ /** Url */
1971
+ url: string;
1972
+ /** Description */
1973
+ description?: string | null;
1974
+ /** Events */
1975
+ events: components["schemas"]["WebhookEventType"][];
1976
+ /** Enabled */
1977
+ enabled: boolean;
1978
+ /**
1979
+ * Created At
1980
+ * Format: date-time
1981
+ */
1982
+ created_at: string;
1983
+ /**
1984
+ * Updated At
1985
+ * Format: date-time
1986
+ */
1987
+ updated_at: string;
1988
+ };
1989
+ /** WebhookEndpointUpdateRequest */
1990
+ WebhookEndpointUpdateRequest: {
1991
+ /** Url */
1992
+ url?: string | null;
1993
+ /** Events */
1994
+ events?: components["schemas"]["WebhookEventType"][] | null;
1995
+ /** Description */
1996
+ description?: string | null;
1997
+ /** Enabled */
1998
+ enabled?: boolean | null;
1999
+ };
2000
+ /**
2001
+ * WebhookEventType
2002
+ * @description webhook_endpoints.events / webhook_deliveries.event_type (unconstrained text).
2003
+ *
2004
+ * App-enforced vocabulary (docs + dashboard). Both prod tables are empty, so v2 can
2005
+ * rename/constrain freely with zero migration risk.
2006
+ * @enum {string}
2007
+ */
2008
+ WebhookEventType: "model.ready" | "model.failed" | "product.completed" | "product.failed";
2009
+ };
2010
+ responses: never;
2011
+ parameters: never;
2012
+ requestBodies: never;
2013
+ headers: never;
2014
+ pathItems: never;
33
2015
  }
34
- declare class RateLimitError extends ViewriumError {
35
- readonly retryAfter: number | undefined;
36
- constructor(message: string, options?: {
37
- statusCode?: number;
38
- responseBody?: unknown;
39
- retryAfter?: number;
40
- });
41
- }
42
- declare class APIError extends ViewriumError {
43
- constructor(message: string, options?: {
44
- statusCode?: number;
45
- responseBody?: unknown;
46
- });
2016
+ interface operations {
2017
+ list_products_v1_products_get: {
2018
+ parameters: {
2019
+ query?: {
2020
+ limit?: number;
2021
+ offset?: number;
2022
+ org_id?: string | null;
2023
+ scope?: components["schemas"]["ListScope"];
2024
+ q?: string | null;
2025
+ custom_id?: string | null;
2026
+ status?: components["schemas"]["DisplayStatus"][] | null;
2027
+ tag?: string[] | null;
2028
+ tag_match?: components["schemas"]["TagMatch"];
2029
+ created_after?: string | null;
2030
+ created_before?: string | null;
2031
+ created_by?: string[] | null;
2032
+ has_comments?: boolean | null;
2033
+ has_warnings?: boolean | null;
2034
+ form?: string[] | null;
2035
+ source_type?: components["schemas"]["SourceType"][] | null;
2036
+ sort?: components["schemas"]["ProductSortField"];
2037
+ order?: components["schemas"]["SortOrder"];
2038
+ };
2039
+ header?: never;
2040
+ path?: never;
2041
+ cookie?: never;
2042
+ };
2043
+ requestBody?: never;
2044
+ responses: {
2045
+ /** @description Successful Response */
2046
+ 200: {
2047
+ headers: {
2048
+ [name: string]: unknown;
2049
+ };
2050
+ content: {
2051
+ "application/json": components["schemas"]["ProductListResponse"];
2052
+ };
2053
+ };
2054
+ /** @description Validation Error */
2055
+ 422: {
2056
+ headers: {
2057
+ [name: string]: unknown;
2058
+ };
2059
+ content: {
2060
+ "application/json": components["schemas"]["HTTPValidationError"];
2061
+ };
2062
+ };
2063
+ };
2064
+ };
2065
+ create_product_v1_products_post: {
2066
+ parameters: {
2067
+ query?: never;
2068
+ header?: never;
2069
+ path?: never;
2070
+ cookie?: never;
2071
+ };
2072
+ requestBody: {
2073
+ content: {
2074
+ "application/json": components["schemas"]["ProductCreateRequest"];
2075
+ };
2076
+ };
2077
+ responses: {
2078
+ /** @description Successful Response */
2079
+ 200: {
2080
+ headers: {
2081
+ [name: string]: unknown;
2082
+ };
2083
+ content: {
2084
+ "application/json": components["schemas"]["ProductParkedResponse"];
2085
+ };
2086
+ };
2087
+ /** @description Accepted */
2088
+ 202: {
2089
+ headers: {
2090
+ [name: string]: unknown;
2091
+ };
2092
+ content: {
2093
+ "application/json": components["schemas"]["ProductResponse"];
2094
+ };
2095
+ };
2096
+ /** @description Validation Error */
2097
+ 422: {
2098
+ headers: {
2099
+ [name: string]: unknown;
2100
+ };
2101
+ content: {
2102
+ "application/json": components["schemas"]["HTTPValidationError"];
2103
+ };
2104
+ };
2105
+ };
2106
+ };
2107
+ batch_delete_products_v1_products_delete: {
2108
+ parameters: {
2109
+ query: {
2110
+ ids: string[];
2111
+ };
2112
+ header?: never;
2113
+ path?: never;
2114
+ cookie?: never;
2115
+ };
2116
+ requestBody?: never;
2117
+ responses: {
2118
+ /** @description Successful Response */
2119
+ 200: {
2120
+ headers: {
2121
+ [name: string]: unknown;
2122
+ };
2123
+ content: {
2124
+ "application/json": components["schemas"]["ProductBatchResponse"];
2125
+ };
2126
+ };
2127
+ /** @description Validation Error */
2128
+ 422: {
2129
+ headers: {
2130
+ [name: string]: unknown;
2131
+ };
2132
+ content: {
2133
+ "application/json": components["schemas"]["HTTPValidationError"];
2134
+ };
2135
+ };
2136
+ };
2137
+ };
2138
+ publish_products_v1_products_publish_post: {
2139
+ parameters: {
2140
+ query?: never;
2141
+ header?: never;
2142
+ path?: never;
2143
+ cookie?: never;
2144
+ };
2145
+ requestBody: {
2146
+ content: {
2147
+ "application/json": components["schemas"]["ProductPublishRequest"];
2148
+ };
2149
+ };
2150
+ responses: {
2151
+ /** @description Successful Response */
2152
+ 200: {
2153
+ headers: {
2154
+ [name: string]: unknown;
2155
+ };
2156
+ content: {
2157
+ "application/json": components["schemas"]["ProductBatchResponse"];
2158
+ };
2159
+ };
2160
+ /** @description Validation Error */
2161
+ 422: {
2162
+ headers: {
2163
+ [name: string]: unknown;
2164
+ };
2165
+ content: {
2166
+ "application/json": components["schemas"]["HTTPValidationError"];
2167
+ };
2168
+ };
2169
+ };
2170
+ };
2171
+ export_products_v1_products_export_get: {
2172
+ parameters: {
2173
+ query?: {
2174
+ org_id?: string | null;
2175
+ scope?: components["schemas"]["ListScope"];
2176
+ q?: string | null;
2177
+ custom_id?: string | null;
2178
+ status?: components["schemas"]["DisplayStatus"][] | null;
2179
+ tag?: string[] | null;
2180
+ tag_match?: components["schemas"]["TagMatch"];
2181
+ created_after?: string | null;
2182
+ created_before?: string | null;
2183
+ created_by?: string[] | null;
2184
+ has_comments?: boolean | null;
2185
+ has_warnings?: boolean | null;
2186
+ form?: string[] | null;
2187
+ source_type?: components["schemas"]["SourceType"][] | null;
2188
+ ids?: string[] | null;
2189
+ image_review_status?: components["schemas"]["ReviewStatus"][];
2190
+ };
2191
+ header?: never;
2192
+ path?: never;
2193
+ cookie?: never;
2194
+ };
2195
+ requestBody?: never;
2196
+ responses: {
2197
+ /** @description The archive */
2198
+ 200: {
2199
+ headers: {
2200
+ [name: string]: unknown;
2201
+ };
2202
+ content: {
2203
+ "application/json": unknown;
2204
+ "application/zip": unknown;
2205
+ };
2206
+ };
2207
+ /** @description Accepted */
2208
+ 202: {
2209
+ headers: {
2210
+ [name: string]: unknown;
2211
+ };
2212
+ content: {
2213
+ "application/json": components["schemas"]["ProductExportQueuedResponse"];
2214
+ };
2215
+ };
2216
+ /** @description Validation Error */
2217
+ 422: {
2218
+ headers: {
2219
+ [name: string]: unknown;
2220
+ };
2221
+ content: {
2222
+ "application/json": components["schemas"]["HTTPValidationError"];
2223
+ };
2224
+ };
2225
+ };
2226
+ };
2227
+ list_product_tags_v1_products_tags_get: {
2228
+ parameters: {
2229
+ query?: {
2230
+ org_id?: string | null;
2231
+ scope?: components["schemas"]["ListScope"];
2232
+ q?: string | null;
2233
+ custom_id?: string | null;
2234
+ status?: components["schemas"]["DisplayStatus"][] | null;
2235
+ tag?: string[] | null;
2236
+ tag_match?: components["schemas"]["TagMatch"];
2237
+ created_after?: string | null;
2238
+ created_before?: string | null;
2239
+ created_by?: string[] | null;
2240
+ has_comments?: boolean | null;
2241
+ has_warnings?: boolean | null;
2242
+ form?: string[] | null;
2243
+ source_type?: components["schemas"]["SourceType"][] | null;
2244
+ };
2245
+ header?: never;
2246
+ path?: never;
2247
+ cookie?: never;
2248
+ };
2249
+ requestBody?: never;
2250
+ responses: {
2251
+ /** @description Successful Response */
2252
+ 200: {
2253
+ headers: {
2254
+ [name: string]: unknown;
2255
+ };
2256
+ content: {
2257
+ "application/json": components["schemas"]["TagsResponse"];
2258
+ };
2259
+ };
2260
+ /** @description Validation Error */
2261
+ 422: {
2262
+ headers: {
2263
+ [name: string]: unknown;
2264
+ };
2265
+ content: {
2266
+ "application/json": components["schemas"]["HTTPValidationError"];
2267
+ };
2268
+ };
2269
+ };
2270
+ };
2271
+ get_product_v1_products__id__get: {
2272
+ parameters: {
2273
+ query?: never;
2274
+ header?: never;
2275
+ path: {
2276
+ id: string;
2277
+ };
2278
+ cookie?: never;
2279
+ };
2280
+ requestBody?: never;
2281
+ responses: {
2282
+ /** @description Successful Response */
2283
+ 200: {
2284
+ headers: {
2285
+ [name: string]: unknown;
2286
+ };
2287
+ content: {
2288
+ "application/json": components["schemas"]["ProductResponse"] | components["schemas"]["PublicProductResponse"];
2289
+ };
2290
+ };
2291
+ /** @description Validation Error */
2292
+ 422: {
2293
+ headers: {
2294
+ [name: string]: unknown;
2295
+ };
2296
+ content: {
2297
+ "application/json": components["schemas"]["HTTPValidationError"];
2298
+ };
2299
+ };
2300
+ };
2301
+ };
2302
+ delete_product_v1_products__id__delete: {
2303
+ parameters: {
2304
+ query?: never;
2305
+ header?: never;
2306
+ path: {
2307
+ id: string;
2308
+ };
2309
+ cookie?: never;
2310
+ };
2311
+ requestBody?: never;
2312
+ responses: {
2313
+ /** @description Successful Response */
2314
+ 204: {
2315
+ headers: {
2316
+ [name: string]: unknown;
2317
+ };
2318
+ content?: never;
2319
+ };
2320
+ /** @description Validation Error */
2321
+ 422: {
2322
+ headers: {
2323
+ [name: string]: unknown;
2324
+ };
2325
+ content: {
2326
+ "application/json": components["schemas"]["HTTPValidationError"];
2327
+ };
2328
+ };
2329
+ };
2330
+ };
2331
+ update_product_v1_products__id__patch: {
2332
+ parameters: {
2333
+ query?: never;
2334
+ header?: never;
2335
+ path: {
2336
+ id: string;
2337
+ };
2338
+ cookie?: never;
2339
+ };
2340
+ requestBody: {
2341
+ content: {
2342
+ "application/json": components["schemas"]["ProductUpdateRequest"];
2343
+ };
2344
+ };
2345
+ responses: {
2346
+ /** @description Successful Response */
2347
+ 200: {
2348
+ headers: {
2349
+ [name: string]: unknown;
2350
+ };
2351
+ content: {
2352
+ "application/json": components["schemas"]["ProductResponse"];
2353
+ };
2354
+ };
2355
+ /** @description Validation Error */
2356
+ 422: {
2357
+ headers: {
2358
+ [name: string]: unknown;
2359
+ };
2360
+ content: {
2361
+ "application/json": components["schemas"]["HTTPValidationError"];
2362
+ };
2363
+ };
2364
+ };
2365
+ };
2366
+ order_product_v1_products__id__order_post: {
2367
+ parameters: {
2368
+ query?: never;
2369
+ header?: never;
2370
+ path: {
2371
+ id: string;
2372
+ };
2373
+ cookie?: never;
2374
+ };
2375
+ requestBody: {
2376
+ content: {
2377
+ "application/json": components["schemas"]["ProductOrderRequest"];
2378
+ };
2379
+ };
2380
+ responses: {
2381
+ /** @description Successful Response */
2382
+ 200: {
2383
+ headers: {
2384
+ [name: string]: unknown;
2385
+ };
2386
+ content: {
2387
+ "application/json": components["schemas"]["ProductOrderParkedResponse"];
2388
+ };
2389
+ };
2390
+ /** @description Validation Error */
2391
+ 422: {
2392
+ headers: {
2393
+ [name: string]: unknown;
2394
+ };
2395
+ content: {
2396
+ "application/json": components["schemas"]["HTTPValidationError"];
2397
+ };
2398
+ };
2399
+ };
2400
+ };
2401
+ review_product_v1_products__id__review_post: {
2402
+ parameters: {
2403
+ query?: never;
2404
+ header?: never;
2405
+ path: {
2406
+ id: string;
2407
+ };
2408
+ cookie?: never;
2409
+ };
2410
+ requestBody: {
2411
+ content: {
2412
+ "application/json": components["schemas"]["ProductReviewRequest"];
2413
+ };
2414
+ };
2415
+ responses: {
2416
+ /** @description Successful Response */
2417
+ 200: {
2418
+ headers: {
2419
+ [name: string]: unknown;
2420
+ };
2421
+ content: {
2422
+ "application/json": components["schemas"]["ProductReviewResponse"];
2423
+ };
2424
+ };
2425
+ /** @description Validation Error */
2426
+ 422: {
2427
+ headers: {
2428
+ [name: string]: unknown;
2429
+ };
2430
+ content: {
2431
+ "application/json": components["schemas"]["HTTPValidationError"];
2432
+ };
2433
+ };
2434
+ };
2435
+ };
2436
+ update_product_image_v1_products__id__images__image_id__patch: {
2437
+ parameters: {
2438
+ query?: never;
2439
+ header?: never;
2440
+ path: {
2441
+ id: string;
2442
+ image_id: string;
2443
+ };
2444
+ cookie?: never;
2445
+ };
2446
+ requestBody: {
2447
+ content: {
2448
+ "application/json": components["schemas"]["ProductImagePatch"];
2449
+ };
2450
+ };
2451
+ responses: {
2452
+ /** @description Successful Response */
2453
+ 200: {
2454
+ headers: {
2455
+ [name: string]: unknown;
2456
+ };
2457
+ content: {
2458
+ "application/json": components["schemas"]["ProductImageResponse"];
2459
+ };
2460
+ };
2461
+ /** @description Validation Error */
2462
+ 422: {
2463
+ headers: {
2464
+ [name: string]: unknown;
2465
+ };
2466
+ content: {
2467
+ "application/json": components["schemas"]["HTTPValidationError"];
2468
+ };
2469
+ };
2470
+ };
2471
+ };
2472
+ rescale_product_model_v1_products__id__model_rescale_post: {
2473
+ parameters: {
2474
+ query?: never;
2475
+ header?: never;
2476
+ path: {
2477
+ id: string;
2478
+ };
2479
+ cookie?: never;
2480
+ };
2481
+ requestBody: {
2482
+ content: {
2483
+ "application/json": components["schemas"]["ProductRescaleRequest"];
2484
+ };
2485
+ };
2486
+ responses: {
2487
+ /** @description Successful Response */
2488
+ 200: {
2489
+ headers: {
2490
+ [name: string]: unknown;
2491
+ };
2492
+ content: {
2493
+ "application/json": components["schemas"]["ProductResponse"];
2494
+ };
2495
+ };
2496
+ /** @description Validation Error */
2497
+ 422: {
2498
+ headers: {
2499
+ [name: string]: unknown;
2500
+ };
2501
+ content: {
2502
+ "application/json": components["schemas"]["HTTPValidationError"];
2503
+ };
2504
+ };
2505
+ };
2506
+ };
2507
+ create_product_ticket_v1_products__id__tickets_post: {
2508
+ parameters: {
2509
+ query?: never;
2510
+ header?: never;
2511
+ path: {
2512
+ id: string;
2513
+ };
2514
+ cookie?: never;
2515
+ };
2516
+ requestBody: {
2517
+ content: {
2518
+ "application/json": components["schemas"]["TicketRequest"];
2519
+ };
2520
+ };
2521
+ responses: {
2522
+ /** @description Successful Response */
2523
+ 200: {
2524
+ headers: {
2525
+ [name: string]: unknown;
2526
+ };
2527
+ content: {
2528
+ "application/json": components["schemas"]["TicketResponse"];
2529
+ };
2530
+ };
2531
+ /** @description Validation Error */
2532
+ 422: {
2533
+ headers: {
2534
+ [name: string]: unknown;
2535
+ };
2536
+ content: {
2537
+ "application/json": components["schemas"]["HTTPValidationError"];
2538
+ };
2539
+ };
2540
+ };
2541
+ };
2542
+ update_product_model_v1_products__id__model_patch: {
2543
+ parameters: {
2544
+ query?: never;
2545
+ header?: never;
2546
+ path: {
2547
+ id: string;
2548
+ };
2549
+ cookie?: never;
2550
+ };
2551
+ requestBody: {
2552
+ content: {
2553
+ "application/json": components["schemas"]["ProductModelPatch"];
2554
+ };
2555
+ };
2556
+ responses: {
2557
+ /** @description Successful Response */
2558
+ 200: {
2559
+ headers: {
2560
+ [name: string]: unknown;
2561
+ };
2562
+ content: {
2563
+ "application/json": components["schemas"]["ProductModelResponse"];
2564
+ };
2565
+ };
2566
+ /** @description Validation Error */
2567
+ 422: {
2568
+ headers: {
2569
+ [name: string]: unknown;
2570
+ };
2571
+ content: {
2572
+ "application/json": components["schemas"]["HTTPValidationError"];
2573
+ };
2574
+ };
2575
+ };
2576
+ };
2577
+ list_api_keys_v1_api_keys_get: {
2578
+ parameters: {
2579
+ query?: never;
2580
+ header?: never;
2581
+ path?: never;
2582
+ cookie?: never;
2583
+ };
2584
+ requestBody?: never;
2585
+ responses: {
2586
+ /** @description Successful Response */
2587
+ 200: {
2588
+ headers: {
2589
+ [name: string]: unknown;
2590
+ };
2591
+ content: {
2592
+ "application/json": components["schemas"]["ApiKeyListResponse"];
2593
+ };
2594
+ };
2595
+ };
2596
+ };
2597
+ create_api_key_v1_api_keys_post: {
2598
+ parameters: {
2599
+ query?: never;
2600
+ header?: never;
2601
+ path?: never;
2602
+ cookie?: never;
2603
+ };
2604
+ requestBody: {
2605
+ content: {
2606
+ "application/json": components["schemas"]["ApiKeyCreateRequest"];
2607
+ };
2608
+ };
2609
+ responses: {
2610
+ /** @description Successful Response */
2611
+ 201: {
2612
+ headers: {
2613
+ [name: string]: unknown;
2614
+ };
2615
+ content: {
2616
+ "application/json": components["schemas"]["ApiKeyCreateResponse"];
2617
+ };
2618
+ };
2619
+ /** @description Validation Error */
2620
+ 422: {
2621
+ headers: {
2622
+ [name: string]: unknown;
2623
+ };
2624
+ content: {
2625
+ "application/json": components["schemas"]["HTTPValidationError"];
2626
+ };
2627
+ };
2628
+ };
2629
+ };
2630
+ revoke_api_key_v1_api_keys__id__delete: {
2631
+ parameters: {
2632
+ query?: never;
2633
+ header?: never;
2634
+ path: {
2635
+ id: string;
2636
+ };
2637
+ cookie?: never;
2638
+ };
2639
+ requestBody?: never;
2640
+ responses: {
2641
+ /** @description Successful Response */
2642
+ 204: {
2643
+ headers: {
2644
+ [name: string]: unknown;
2645
+ };
2646
+ content?: never;
2647
+ };
2648
+ /** @description Validation Error */
2649
+ 422: {
2650
+ headers: {
2651
+ [name: string]: unknown;
2652
+ };
2653
+ content: {
2654
+ "application/json": components["schemas"]["HTTPValidationError"];
2655
+ };
2656
+ };
2657
+ };
2658
+ };
2659
+ get_usage_v1_usage_get: {
2660
+ parameters: {
2661
+ query?: {
2662
+ start?: string | null;
2663
+ end?: string | null;
2664
+ org_id?: string | null;
2665
+ scope?: components["schemas"]["ListScope"];
2666
+ product_id?: string | null;
2667
+ project_id?: string | null;
2668
+ model_id?: string | null;
2669
+ event_type?: components["schemas"]["UsageEventType"] | null;
2670
+ granularity?: "hour" | "day";
2671
+ include_internal?: boolean;
2672
+ group_by?: "product" | null;
2673
+ };
2674
+ header?: never;
2675
+ path?: never;
2676
+ cookie?: never;
2677
+ };
2678
+ requestBody?: never;
2679
+ responses: {
2680
+ /** @description Successful Response */
2681
+ 200: {
2682
+ headers: {
2683
+ [name: string]: unknown;
2684
+ };
2685
+ content: {
2686
+ "application/json": components["schemas"]["UsageResponse"];
2687
+ };
2688
+ };
2689
+ /** @description Validation Error */
2690
+ 422: {
2691
+ headers: {
2692
+ [name: string]: unknown;
2693
+ };
2694
+ content: {
2695
+ "application/json": components["schemas"]["HTTPValidationError"];
2696
+ };
2697
+ };
2698
+ };
2699
+ };
2700
+ ingest_beacon_v1_beacon_post: {
2701
+ parameters: {
2702
+ query?: never;
2703
+ header?: never;
2704
+ path?: never;
2705
+ cookie?: never;
2706
+ };
2707
+ requestBody: {
2708
+ content: {
2709
+ "application/json": components["schemas"]["BeaconRequest"];
2710
+ };
2711
+ };
2712
+ responses: {
2713
+ /** @description Successful Response */
2714
+ 204: {
2715
+ headers: {
2716
+ [name: string]: unknown;
2717
+ };
2718
+ content?: never;
2719
+ };
2720
+ /** @description Validation Error */
2721
+ 422: {
2722
+ headers: {
2723
+ [name: string]: unknown;
2724
+ };
2725
+ content: {
2726
+ "application/json": components["schemas"]["HTTPValidationError"];
2727
+ };
2728
+ };
2729
+ };
2730
+ };
2731
+ list_webhook_endpoints_v1_webhooks_get: {
2732
+ parameters: {
2733
+ query?: never;
2734
+ header?: never;
2735
+ path?: never;
2736
+ cookie?: never;
2737
+ };
2738
+ requestBody?: never;
2739
+ responses: {
2740
+ /** @description Successful Response */
2741
+ 200: {
2742
+ headers: {
2743
+ [name: string]: unknown;
2744
+ };
2745
+ content: {
2746
+ "application/json": components["schemas"]["WebhookEndpointListResponse"];
2747
+ };
2748
+ };
2749
+ };
2750
+ };
2751
+ create_webhook_endpoint_v1_webhooks_post: {
2752
+ parameters: {
2753
+ query?: never;
2754
+ header?: never;
2755
+ path?: never;
2756
+ cookie?: never;
2757
+ };
2758
+ requestBody: {
2759
+ content: {
2760
+ "application/json": components["schemas"]["WebhookEndpointCreateRequest"];
2761
+ };
2762
+ };
2763
+ responses: {
2764
+ /** @description Successful Response */
2765
+ 201: {
2766
+ headers: {
2767
+ [name: string]: unknown;
2768
+ };
2769
+ content: {
2770
+ "application/json": components["schemas"]["WebhookEndpointCreateResponse"];
2771
+ };
2772
+ };
2773
+ /** @description Validation Error */
2774
+ 422: {
2775
+ headers: {
2776
+ [name: string]: unknown;
2777
+ };
2778
+ content: {
2779
+ "application/json": components["schemas"]["HTTPValidationError"];
2780
+ };
2781
+ };
2782
+ };
2783
+ };
2784
+ get_webhook_endpoint_v1_webhooks__id__get: {
2785
+ parameters: {
2786
+ query?: never;
2787
+ header?: never;
2788
+ path: {
2789
+ id: string;
2790
+ };
2791
+ cookie?: never;
2792
+ };
2793
+ requestBody?: never;
2794
+ responses: {
2795
+ /** @description Successful Response */
2796
+ 200: {
2797
+ headers: {
2798
+ [name: string]: unknown;
2799
+ };
2800
+ content: {
2801
+ "application/json": components["schemas"]["WebhookEndpointResponse"];
2802
+ };
2803
+ };
2804
+ /** @description Validation Error */
2805
+ 422: {
2806
+ headers: {
2807
+ [name: string]: unknown;
2808
+ };
2809
+ content: {
2810
+ "application/json": components["schemas"]["HTTPValidationError"];
2811
+ };
2812
+ };
2813
+ };
2814
+ };
2815
+ delete_webhook_endpoint_v1_webhooks__id__delete: {
2816
+ parameters: {
2817
+ query?: never;
2818
+ header?: never;
2819
+ path: {
2820
+ id: string;
2821
+ };
2822
+ cookie?: never;
2823
+ };
2824
+ requestBody?: never;
2825
+ responses: {
2826
+ /** @description Successful Response */
2827
+ 204: {
2828
+ headers: {
2829
+ [name: string]: unknown;
2830
+ };
2831
+ content?: never;
2832
+ };
2833
+ /** @description Validation Error */
2834
+ 422: {
2835
+ headers: {
2836
+ [name: string]: unknown;
2837
+ };
2838
+ content: {
2839
+ "application/json": components["schemas"]["HTTPValidationError"];
2840
+ };
2841
+ };
2842
+ };
2843
+ };
2844
+ update_webhook_endpoint_v1_webhooks__id__patch: {
2845
+ parameters: {
2846
+ query?: never;
2847
+ header?: never;
2848
+ path: {
2849
+ id: string;
2850
+ };
2851
+ cookie?: never;
2852
+ };
2853
+ requestBody: {
2854
+ content: {
2855
+ "application/json": components["schemas"]["WebhookEndpointUpdateRequest"];
2856
+ };
2857
+ };
2858
+ responses: {
2859
+ /** @description Successful Response */
2860
+ 200: {
2861
+ headers: {
2862
+ [name: string]: unknown;
2863
+ };
2864
+ content: {
2865
+ "application/json": components["schemas"]["WebhookEndpointResponse"];
2866
+ };
2867
+ };
2868
+ /** @description Validation Error */
2869
+ 422: {
2870
+ headers: {
2871
+ [name: string]: unknown;
2872
+ };
2873
+ content: {
2874
+ "application/json": components["schemas"]["HTTPValidationError"];
2875
+ };
2876
+ };
2877
+ };
2878
+ };
2879
+ list_webhook_deliveries_v1_webhooks__id__deliveries_get: {
2880
+ parameters: {
2881
+ query?: {
2882
+ limit?: number;
2883
+ offset?: number;
2884
+ };
2885
+ header?: never;
2886
+ path: {
2887
+ id: string;
2888
+ };
2889
+ cookie?: never;
2890
+ };
2891
+ requestBody?: never;
2892
+ responses: {
2893
+ /** @description Successful Response */
2894
+ 200: {
2895
+ headers: {
2896
+ [name: string]: unknown;
2897
+ };
2898
+ content: {
2899
+ "application/json": components["schemas"]["WebhookDeliveryListResponse"];
2900
+ };
2901
+ };
2902
+ /** @description Validation Error */
2903
+ 422: {
2904
+ headers: {
2905
+ [name: string]: unknown;
2906
+ };
2907
+ content: {
2908
+ "application/json": components["schemas"]["HTTPValidationError"];
2909
+ };
2910
+ };
2911
+ };
2912
+ };
2913
+ list_projects_v1_projects_get: {
2914
+ parameters: {
2915
+ query?: never;
2916
+ header?: never;
2917
+ path?: never;
2918
+ cookie?: never;
2919
+ };
2920
+ requestBody?: never;
2921
+ responses: {
2922
+ /** @description Successful Response */
2923
+ 200: {
2924
+ headers: {
2925
+ [name: string]: unknown;
2926
+ };
2927
+ content: {
2928
+ "application/json": components["schemas"]["ProjectListResponse"];
2929
+ };
2930
+ };
2931
+ };
2932
+ };
2933
+ get_project_v1_projects__id__get: {
2934
+ parameters: {
2935
+ query?: never;
2936
+ header?: never;
2937
+ path: {
2938
+ id: string;
2939
+ };
2940
+ cookie?: never;
2941
+ };
2942
+ requestBody?: never;
2943
+ responses: {
2944
+ /** @description Successful Response */
2945
+ 200: {
2946
+ headers: {
2947
+ [name: string]: unknown;
2948
+ };
2949
+ content: {
2950
+ "application/json": components["schemas"]["ProjectResponse"];
2951
+ };
2952
+ };
2953
+ /** @description Validation Error */
2954
+ 422: {
2955
+ headers: {
2956
+ [name: string]: unknown;
2957
+ };
2958
+ content: {
2959
+ "application/json": components["schemas"]["HTTPValidationError"];
2960
+ };
2961
+ };
2962
+ };
2963
+ };
2964
+ health_v1_health_get: {
2965
+ parameters: {
2966
+ query?: never;
2967
+ header?: never;
2968
+ path?: never;
2969
+ cookie?: never;
2970
+ };
2971
+ requestBody?: never;
2972
+ responses: {
2973
+ /** @description Successful Response */
2974
+ 200: {
2975
+ headers: {
2976
+ [name: string]: unknown;
2977
+ };
2978
+ content: {
2979
+ "application/json": components["schemas"]["HealthResponse"];
2980
+ };
2981
+ };
2982
+ };
2983
+ };
47
2984
  }
48
2985
 
49
2986
  /**
50
- * Public types for the Viewrium SDK.
2987
+ * Typed errors for the Viewrium SDK.
51
2988
  *
52
- * Response shapes mirror the backend JSON contract (snake_case). Request
53
- * param interfaces use camelCase; the SDK maps camelCase → snake_case on
54
- * the wire.
2989
+ * The API returns one error envelope: `{ "error": { code, message, details } }`.
2990
+ * Non-2xx responses are parsed into a `ViewriumError` subclass keyed by HTTP status;
2991
+ * consumers branch with `instanceof`.
55
2992
  */
56
- interface ViewriumOptions {
57
- /** Override the API key. Defaults to the value passed to `new Viewrium(...)`. */
58
- apiKey?: string;
59
- /** Base URL. Defaults to `process.env.VIEWRIUM_API_BASE` or `https://api.viewrium.com`. */
60
- apiBase?: string;
61
- /** Per-request timeout in milliseconds. Default 60_000. */
62
- timeoutMs?: number;
63
- /** Retries on 429 / 5xx. Default 3. */
64
- maxRetries?: number;
65
- /** Override `globalThis.fetch` (test seams / custom transports). */
66
- fetch?: typeof fetch;
67
- }
68
- type SizeUnit = "cm" | "in";
69
- type ModelStatus = "uploading" | "processing" | "queueing" | "successful" | "failed" | "expired";
70
- type SourceType = "scan" | "upload" | "image";
71
- type UsageEventType = "generation.created" | "generation.completed" | "generation.failed" | "view" | "ar_enter" | "ar_session_ended";
72
- interface Model {
73
- id: string;
74
- project_id: string | null;
75
- custom_id: string | null;
76
- title: string | null;
77
- description: string | null;
78
- price: number | null;
79
- currency: string | null;
80
- status: ModelStatus;
81
- source_type: SourceType | null;
82
- model_url: string | null;
83
- thumbnail_url: string | null;
84
- height: number | null;
85
- width: number | null;
86
- depth: number | null;
87
- scale_factor: number | null;
88
- tags: string[];
89
- metadata: Record<string, unknown>;
90
- display_enabled: boolean;
91
- created_at: string;
92
- completed_at: string | null;
93
- [key: string]: unknown;
94
- }
95
- interface ModelListResponse {
96
- data: Model[];
97
- limit: number;
98
- offset: number;
2993
+ interface ViewriumErrorOptions {
2994
+ status?: number | null;
2995
+ code?: string;
2996
+ details?: unknown;
2997
+ cause?: unknown;
99
2998
  }
100
- interface ModelEvent {
101
- id: string;
102
- event_type: UsageEventType;
103
- timestamp: string;
104
- metadata: Record<string, unknown>;
105
- }
106
- interface ModelEventListResponse {
107
- data: ModelEvent[];
108
- limit: number;
109
- offset: number;
110
- }
111
- interface DeletedResponse {
112
- id: string;
113
- deleted: true;
2999
+ declare class ViewriumError extends Error {
3000
+ /** HTTP status, or `null` for transport/connection failures. */
3001
+ readonly status: number | null;
3002
+ /** Machine-readable code from the error envelope. */
3003
+ readonly code: string;
3004
+ /** Optional structured details from the error envelope. */
3005
+ readonly details: unknown;
3006
+ constructor(message: string, options?: ViewriumErrorOptions);
114
3007
  }
115
- interface ApiKey {
116
- id: string;
117
- name: string | null;
118
- key_type: "secret" | "publishable";
119
- key_prefix: string;
120
- last_used_at: string | null;
121
- revoked_at: string | null;
122
- created_at: string;
3008
+ /** 400 - malformed request. */
3009
+ declare class BadRequestError extends ViewriumError {
123
3010
  }
124
- /** Returned by `apiKeys.create` - `key` is plaintext, shown once. */
125
- interface ApiKeyWithSecret extends Omit<ApiKey, "last_used_at" | "revoked_at"> {
126
- key: string;
3011
+ /** 401 - missing or invalid API key. */
3012
+ declare class AuthenticationError extends ViewriumError {
127
3013
  }
128
- interface ApiKeyListResponse {
129
- data: ApiKey[];
3014
+ /**
3015
+ * 402 - the organization's plan does not allow this: no plan, a used free trial, a failed payment,
3016
+ * or past the plan's active-product cap. `details.reason` says which.
3017
+ */
3018
+ declare class PaymentRequiredError extends ViewriumError {
130
3019
  }
131
- interface RevokedResponse {
132
- id: string;
133
- revoked: true;
3020
+ /** 403 - the key is valid but not allowed (scope, origin, or role). */
3021
+ declare class PermissionError extends ViewriumError {
134
3022
  }
135
- interface UsageSummary {
136
- org_id: string;
137
- plan_tier: "free" | "pro" | "enterprise";
138
- since: string | null;
139
- until: string | null;
140
- counts: Partial<Record<UsageEventType, number>>;
3023
+ /** 404 - no such resource. */
3024
+ declare class NotFoundError extends ViewriumError {
141
3025
  }
142
- interface TagSummary {
143
- tag: string;
144
- count: number;
3026
+ /** 409 - conflict (e.g. duplicate `custom_id`, model not in a rescalable state). */
3027
+ declare class ConflictError extends ViewriumError {
145
3028
  }
146
- interface TagListResponse {
147
- data: TagSummary[];
3029
+ /** 422 - request failed validation. */
3030
+ declare class UnprocessableEntityError extends ViewriumError {
148
3031
  }
149
- interface ModelCreateParams {
150
- customId?: string;
151
- title?: string;
152
- description?: string;
153
- /** Provide one of `images` (URL list) or `sourceUrl` - not both. */
154
- images?: string[];
155
- /** Product page URL. Server extracts candidate images. */
156
- sourceUrl?: string;
157
- height?: number;
158
- sizeUnit?: SizeUnit;
159
- tags?: string[];
160
- price?: number;
161
- currency?: string;
162
- metadata?: Record<string, unknown>;
163
- displayEnabled?: boolean;
3032
+ /** 429 - rate limited, or not enough credits (`code: "quota_exceeded"`, `details.shortfall_credits`). */
3033
+ declare class RateLimitError extends ViewriumError {
164
3034
  }
165
- interface ModelCreateFromImagesParams {
166
- title?: string;
167
- customId?: string;
168
- description?: string;
169
- height?: number;
170
- sizeUnit?: SizeUnit;
171
- tags?: string[];
172
- displayEnabled?: boolean;
3035
+ /** 5xx - the API failed to handle the request. */
3036
+ declare class ServerError extends ViewriumError {
173
3037
  }
174
- interface ModelCreateFromVideoParams extends ModelCreateFromImagesParams {
3038
+ /** The request never reached the API (DNS/TLS/offline/abort). */
3039
+ declare class ConnectionError extends ViewriumError {
175
3040
  }
176
- interface ModelUpdateParams {
177
- customId?: string;
178
- title?: string;
179
- description?: string;
180
- price?: number;
181
- currency?: string;
182
- height?: number;
183
- sizeUnit?: SizeUnit;
184
- tags?: string[];
185
- metadata?: Record<string, unknown>;
186
- displayEnabled?: boolean;
3041
+ interface ApiErrorPayload {
3042
+ code: string;
3043
+ message: string;
3044
+ details?: unknown;
187
3045
  }
188
- interface ModelListParams {
189
- tag?: string;
190
- tags?: string[] | string;
191
- customId?: string;
192
- status?: ModelStatus;
193
- limit?: number;
194
- offset?: number;
3046
+ /** Build the right `ViewriumError` subclass for an HTTP status + parsed envelope. */
3047
+ declare function createApiError(status: number, payload: ApiErrorPayload): ViewriumError;
3048
+
3049
+ type JsonContent<T> = T extends {
3050
+ content: {
3051
+ "application/json": infer B;
3052
+ };
3053
+ } ? B : never;
3054
+ /** GET /v1/products/{id} resolves to one of two shapes by principal: the full product for a
3055
+ * session or `sk_` key, the allow-listed public projection for a `pk_` key. */
3056
+ type ProductGetResult = JsonContent<paths["/v1/products/{id}"]["get"]["responses"][200]>;
3057
+ /** A product with its assets (`sk_` view). */
3058
+ type Product = Extract<ProductGetResult, {
3059
+ org_id: string;
3060
+ }>;
3061
+ /** The `pk_` view of a published product: id, title, thumbnail_url, model_status, wall_mounted. The model
3062
+ * file itself is reached through `products.createTicket`. */
3063
+ type PublicProduct = Exclude<ProductGetResult, {
3064
+ org_id: string;
3065
+ }>;
3066
+ type ProductList = JsonContent<paths["/v1/products"]["get"]["responses"][200]>;
3067
+ /** A catalog row - the product plus what its card needs, with no nested assets. */
3068
+ type ProductSummary = ProductList["data"][number];
3069
+ type ProductListParams = NonNullable<paths["/v1/products"]["get"]["parameters"]["query"]>;
3070
+ type ProductCreateParams = JsonContent<paths["/v1/products"]["post"]["requestBody"]>;
3071
+ /** POST /v1/products 200 - the gate parked; resume by POSTing `resume_token`. */
3072
+ type ProductParked = JsonContent<paths["/v1/products"]["post"]["responses"][200]>;
3073
+ /** One page position of a parked plan. Both park shapes carry the same row type. */
3074
+ type PlannedView = NonNullable<ProductParked["plan"]>[number];
3075
+ /** describe's structured read of the product (D25), with its verbatim reasons. */
3076
+ type GateFlags = ProductParked["flags"];
3077
+ /** The models layer's verdict: whether a model is allowed, what blocks it, and the views it
3078
+ * would be built from - including `unseen_views`, the invented ones. */
3079
+ type ModelPlan = ProductParked["model"];
3080
+ /** The priced bundle, in credits (1 credit = $0.50): 1 per deliverable image, a flat 10 for a model. */
3081
+ type ProductCost = ProductParked["cost"];
3082
+ /** POST /v1/products 202 - a committed product whose run has started. */
3083
+ type ProductCreated = JsonContent<paths["/v1/products"]["post"]["responses"][202]>;
3084
+ /** POST /v1/products resolves to one of the two (discriminate on `status === "parked"`). */
3085
+ type ProductCreateResult = ProductParked | ProductCreated;
3086
+ type ProductUpdateParams = JsonContent<NonNullable<paths["/v1/products/{id}"]["patch"]["requestBody"]>>;
3087
+ type ProductBatchResult = JsonContent<paths["/v1/products"]["delete"]["responses"][200]>;
3088
+ type ProductPublishParams = JsonContent<paths["/v1/products/publish"]["post"]["requestBody"]>;
3089
+ type Tags = JsonContent<paths["/v1/products/tags"]["get"]["responses"][200]>;
3090
+ type TagsParams = NonNullable<paths["/v1/products/tags"]["get"]["parameters"]["query"]>;
3091
+ /** POST /v1/products/{id}/review - the write-behind flush (image + model decisions, the
3092
+ * product's user-set status). It records decisions only. */
3093
+ type ProductReviewParams = JsonContent<paths["/v1/products/{id}/review"]["post"]["requestBody"]>;
3094
+ type ProductReviewResult = JsonContent<paths["/v1/products/{id}/review"]["post"]["responses"][200]>;
3095
+ type ProductImagePatchParams = JsonContent<NonNullable<paths["/v1/products/{id}/images/{image_id}"]["patch"]["requestBody"]>>;
3096
+ type ProductImage = JsonContent<paths["/v1/products/{id}/images/{image_id}"]["patch"]["responses"][200]>;
3097
+ type ProductModelPatchParams = JsonContent<NonNullable<paths["/v1/products/{id}/model"]["patch"]["requestBody"]>>;
3098
+ type ProductModel = JsonContent<paths["/v1/products/{id}/model"]["patch"]["responses"][200]>;
3099
+ type ProductRescaleParams = JsonContent<paths["/v1/products/{id}/model/rescale"]["post"]["requestBody"]>;
3100
+ /** POST /v1/products/{id}/tickets - `{ kind: "view" | "ar", origin? }`. */
3101
+ type TicketParams = JsonContent<paths["/v1/products/{id}/tickets"]["post"]["requestBody"]>;
3102
+ /** A single-use model URL: `{ url, kind, expires_at }`. */
3103
+ type Ticket = JsonContent<paths["/v1/products/{id}/tickets"]["post"]["responses"][200]>;
3104
+ /** POST /v1/products/{id}/order - the missing half; parks like a create, commits through
3105
+ * `products.create({ resume_token })`. */
3106
+ type ProductOrderParams = JsonContent<paths["/v1/products/{id}/order"]["post"]["requestBody"]>;
3107
+ type ProductOrderParked = JsonContent<paths["/v1/products/{id}/order"]["post"]["responses"][200]>;
3108
+ type ProductExportParams = NonNullable<paths["/v1/products/export"]["get"]["parameters"]["query"]>;
3109
+ /** 202 from the export: the images are being finished in the background and a download link
3110
+ * is emailed; the same request streams the ZIP once they are done. */
3111
+ type ProductExportQueued = JsonContent<paths["/v1/products/export"]["get"]["responses"][202]>;
3112
+ type ApiKeyList = JsonContent<paths["/v1/api_keys"]["get"]["responses"][200]>;
3113
+ type ApiKeyCreateParams = JsonContent<paths["/v1/api_keys"]["post"]["requestBody"]>;
3114
+ type ApiKeyCreated = JsonContent<paths["/v1/api_keys"]["post"]["responses"][201]>;
3115
+ type Usage = JsonContent<paths["/v1/usage"]["get"]["responses"][200]>;
3116
+ type UsageParams = NonNullable<paths["/v1/usage"]["get"]["parameters"]["query"]>;
3117
+ /** One `group_by: "product"` row: a product's counts over the window, with its title. */
3118
+ type UsageProductTotals = NonNullable<Usage["by_product"]>[number];
3119
+ type WebhookEndpoint = JsonContent<paths["/v1/webhooks/{id}"]["get"]["responses"][200]>;
3120
+ type WebhookEndpointList = JsonContent<paths["/v1/webhooks"]["get"]["responses"][200]>;
3121
+ type WebhookEndpointCreateParams = JsonContent<paths["/v1/webhooks"]["post"]["requestBody"]>;
3122
+ type WebhookEndpointCreated = JsonContent<paths["/v1/webhooks"]["post"]["responses"][201]>;
3123
+ type WebhookEndpointUpdateParams = JsonContent<NonNullable<paths["/v1/webhooks/{id}"]["patch"]["requestBody"]>>;
3124
+ type WebhookDeliveryList = JsonContent<paths["/v1/webhooks/{id}/deliveries"]["get"]["responses"][200]>;
3125
+ type WebhookDeliveriesParams = NonNullable<paths["/v1/webhooks/{id}/deliveries"]["get"]["parameters"]["query"]>;
3126
+ type Project = JsonContent<paths["/v1/projects/{id}"]["get"]["responses"][200]>;
3127
+ type ProjectList = JsonContent<paths["/v1/projects"]["get"]["responses"][200]>;
3128
+ type BeaconParams = JsonContent<paths["/v1/beacon"]["post"]["requestBody"]>;
3129
+ type Health = JsonContent<paths["/v1/health"]["get"]["responses"][200]>;
3130
+ type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
3131
+ interface ViewriumOptions {
3132
+ /** `sk_` secret key (server) or `pk_` publishable key (browser). */
3133
+ apiKey: string;
3134
+ /** API origin; defaults to `https://api.viewrium.com`. Trailing slash is stripped. */
3135
+ baseUrl?: string;
3136
+ /** Injectable fetch (tests, custom agents). Defaults to `globalThis.fetch`. */
3137
+ fetch?: FetchLike;
195
3138
  }
196
- interface ModelListEventsParams {
197
- limit?: number;
198
- offset?: number;
3139
+ type QueryValue = string | number | boolean | readonly string[] | null | undefined;
3140
+ type QueryParams = Record<string, QueryValue>;
3141
+ interface RequestOptions {
3142
+ query?: QueryParams;
3143
+ body?: unknown;
199
3144
  }
200
- interface ApiKeyCreateParams {
201
- name?: string;
3145
+ type RequestFn = <T>(method: string, path: string, options?: RequestOptions) => Promise<T>;
3146
+ /** The escape hatch for the one route that answers bytes rather than JSON (the export ZIP) -
3147
+ * or, on a 202, JSON after all. */
3148
+ type BlobRequestFn = (method: string, path: string, options?: RequestOptions) => Promise<Blob | ProductExportQueued>;
3149
+ declare function createProducts(request: RequestFn, requestBlob: BlobRequestFn): {
202
3150
  /**
203
- * Type of key to create. Defaults to `"secret"`.
204
- * - `"secret"` (sk_*): server-only, authenticates /v1/* calls.
205
- * - `"publishable"` (pk_*): client-safe, used by the embed tag. Origin
206
- * restrictions inherit from the project's allowed_domains.
3151
+ * POST /v1/products - the single generation entrypoint. Supply exactly one source
3152
+ * (`image_paths` | `image_urls` | `video_url` | `source_url` | `model_url` |
3153
+ * `resume_token`). A fresh request ALWAYS parks (200, `status === "parked"`, nothing
3154
+ * written): the plan, the model verdict and the price come back inside `resume_token`,
3155
+ * which you POST back to commit (202, `ProductCreated`). A `model_url` commits at once.
207
3156
  */
208
- keyType?: "secret" | "publishable";
209
- }
210
- interface UsageRetrieveParams {
211
- /** ISO 8601 lower bound (inclusive). */
212
- since?: string;
213
- /** ISO 8601 upper bound (inclusive). */
214
- until?: string;
215
- }
216
- /**
217
- * A file passed to multipart endpoints.
218
- *
219
- * - In Node: a path string (SDK reads it via `fs.readFile`) or a `Blob`/`File`.
220
- * - In browsers / edge runtimes: `Blob` / `File` (native).
221
- * - Anywhere: a `{ data, filename, contentType? }` record with raw bytes.
222
- */
223
- type FileInput = string | Blob | {
224
- data: Uint8Array | ArrayBuffer | Blob;
225
- filename?: string;
226
- contentType?: string;
3157
+ create: (params: ProductCreateParams) => Promise<ProductCreateResult>;
3158
+ /**
3159
+ * GET /v1/products - the catalog: one org (`org_id`, or the caller's only org), or
3160
+ * `scope: "all"` for every org an agency member or staff reaches. Filters AND together.
3161
+ */
3162
+ list: (params?: ProductListParams) => Promise<{
3163
+ data: components["schemas"]["ProductSummary"][];
3164
+ total: number;
3165
+ limit: number;
3166
+ offset: number;
3167
+ }>;
3168
+ /** GET /v1/products/{id} - the product with its assets (a `pk_` key gets `PublicProduct`). */
3169
+ retrieve: (id: string) => Promise<{
3170
+ id: string;
3171
+ org_id: string;
3172
+ title: string;
3173
+ custom_id?: string | null;
3174
+ tags?: string[];
3175
+ status: components["schemas"]["ProductStatus"];
3176
+ display_status: components["schemas"]["DisplayStatus"];
3177
+ published: boolean;
3178
+ form?: string | null;
3179
+ source_type?: components["schemas"]["SourceType"] | null;
3180
+ price?: number | null;
3181
+ currency?: string | null;
3182
+ height?: number | null;
3183
+ width?: number | null;
3184
+ depth?: number | null;
3185
+ display_unit?: components["schemas"]["DimensionUnit"] | null;
3186
+ images_ordered: boolean;
3187
+ thumbnail_url?: string | null;
3188
+ has_warnings: boolean;
3189
+ warning_count: number;
3190
+ comment_count: number;
3191
+ image_count: number;
3192
+ model_status?: components["schemas"]["AssetStatus"] | null;
3193
+ owner?: components["schemas"]["ProductOwner"] | null;
3194
+ created_at: string;
3195
+ updated_at?: string | null;
3196
+ description?: string | null;
3197
+ wall_mounted: boolean;
3198
+ product_type?: string | null;
3199
+ material_words?: string | null;
3200
+ transparent: boolean;
3201
+ metadata?: {
3202
+ [key: string]: unknown;
3203
+ };
3204
+ sources?: components["schemas"]["ProductSourceResponse"][];
3205
+ images?: components["schemas"]["ProductImageResponse"][];
3206
+ model?: components["schemas"]["ProductModelResponse"] | null;
3207
+ warnings?: components["schemas"]["ProductWarning"][];
3208
+ open_request_count: number;
3209
+ }>;
3210
+ /**
3211
+ * PATCH /v1/products/{id} - the customer's fields, the user-set status and the publish
3212
+ * toggle. 409 on a `custom_id` another product in the org already holds.
3213
+ */
3214
+ update: (id: string, params: ProductUpdateParams) => Promise<{
3215
+ id: string;
3216
+ org_id: string;
3217
+ title: string;
3218
+ custom_id?: string | null;
3219
+ tags?: string[];
3220
+ status: components["schemas"]["ProductStatus"];
3221
+ display_status: components["schemas"]["DisplayStatus"];
3222
+ published: boolean;
3223
+ form?: string | null;
3224
+ source_type?: components["schemas"]["SourceType"] | null;
3225
+ price?: number | null;
3226
+ currency?: string | null;
3227
+ height?: number | null;
3228
+ width?: number | null;
3229
+ depth?: number | null;
3230
+ display_unit?: components["schemas"]["DimensionUnit"] | null;
3231
+ images_ordered: boolean;
3232
+ thumbnail_url?: string | null;
3233
+ has_warnings: boolean;
3234
+ warning_count: number;
3235
+ comment_count: number;
3236
+ image_count: number;
3237
+ model_status?: components["schemas"]["AssetStatus"] | null;
3238
+ owner?: components["schemas"]["ProductOwner"] | null;
3239
+ created_at: string;
3240
+ updated_at?: string | null;
3241
+ description?: string | null;
3242
+ wall_mounted: boolean;
3243
+ product_type?: string | null;
3244
+ material_words?: string | null;
3245
+ transparent: boolean;
3246
+ metadata?: {
3247
+ [key: string]: unknown;
3248
+ };
3249
+ sources?: components["schemas"]["ProductSourceResponse"][];
3250
+ images?: components["schemas"]["ProductImageResponse"][];
3251
+ model?: components["schemas"]["ProductModelResponse"] | null;
3252
+ warnings?: components["schemas"]["ProductWarning"][];
3253
+ open_request_count: number;
3254
+ }>;
3255
+ /** DELETE /v1/products/{id} */
3256
+ delete: (id: string) => Promise<void>;
3257
+ /** DELETE /v1/products?ids=... - per-id affected/not_found/forbidden buckets. */
3258
+ batchDelete: (ids: readonly string[]) => Promise<{
3259
+ affected: string[];
3260
+ not_found: string[];
3261
+ forbidden: string[];
3262
+ }>;
3263
+ /** POST /v1/products/publish - the bulk publish toggle; one product toggles through `update`. */
3264
+ publish: (params: ProductPublishParams) => Promise<{
3265
+ affected: string[];
3266
+ not_found: string[];
3267
+ forbidden: string[];
3268
+ }>;
3269
+ /** GET /v1/products/tags - distinct tags across the same scope the list takes. */
3270
+ tags: (params?: TagsParams) => Promise<{
3271
+ data: components["schemas"]["TagCount"][];
3272
+ }>;
3273
+ /** POST /v1/products/{id}/review - the review flush: image and model decisions plus the
3274
+ * product's user-set status, validated together and applied in order. */
3275
+ review: (id: string, params: ProductReviewParams) => Promise<{
3276
+ product_id: string;
3277
+ applied: number;
3278
+ display_status: components["schemas"]["DisplayStatus"];
3279
+ }>;
3280
+ /** PATCH /v1/products/{id}/images/{image_id} - one image's decision and overrides. */
3281
+ updateImage: (id: string, imageId: string, params: ProductImagePatchParams) => Promise<{
3282
+ id: string;
3283
+ view: string;
3284
+ kind: "wanted" | "extra";
3285
+ stands_for: string;
3286
+ status: components["schemas"]["AssetStatus"];
3287
+ skip_reason?: string | null;
3288
+ route?: ("reuse" | "edit" | "generate") | null;
3289
+ source?: ("photograph" | "edited" | "generated") | null;
3290
+ evidence?: string | null;
3291
+ azimuth?: string | null;
3292
+ tilt?: string | null;
3293
+ source_photo_id?: string | null;
3294
+ attempts: number;
3295
+ flagged: boolean;
3296
+ cut_flagged: boolean;
3297
+ cut_problems?: string | null;
3298
+ review_status: components["schemas"]["ReviewStatus"];
3299
+ filename: string;
3300
+ alt_text: string;
3301
+ filename_override?: string | null;
3302
+ alt_override?: string | null;
3303
+ shadow_override?: components["schemas"]["ShadowOverride"] | null;
3304
+ background_override?: number[] | null;
3305
+ frame_scale?: number | null;
3306
+ contact_regions?: number[][];
3307
+ raw_url?: string | null;
3308
+ cutout_url?: string | null;
3309
+ warnings?: components["schemas"]["ProductWarning"][];
3310
+ created_at: string;
3311
+ updated_at?: string | null;
3312
+ }>;
3313
+ /** PATCH /v1/products/{id}/model - the model's review decision. */
3314
+ updateModel: (id: string, params: ProductModelPatchParams) => Promise<{
3315
+ id: string;
3316
+ status: components["schemas"]["AssetStatus"];
3317
+ review_status: components["schemas"]["ReviewStatus"];
3318
+ thumbnail_url?: string | null;
3319
+ scale_factor?: number | null;
3320
+ width_axis?: ("x" | "z") | null;
3321
+ flags?: components["schemas"]["GateFlags"];
3322
+ warnings?: components["schemas"]["ProductWarning"][];
3323
+ created_at: string;
3324
+ completed_at?: string | null;
3325
+ }>;
3326
+ /**
3327
+ * POST /v1/products/{id}/model/rescale - re-apply real-world scale to the GLB in place.
3328
+ * Every supplied axis is applied to the geometry; `unit` covers them (omitted = cm) and is
3329
+ * remembered as the product's `display_unit`. The result carries the ACHIEVED dimensions.
3330
+ */
3331
+ rescale: (id: string, params: ProductRescaleParams) => Promise<{
3332
+ id: string;
3333
+ org_id: string;
3334
+ title: string;
3335
+ custom_id?: string | null;
3336
+ tags?: string[];
3337
+ status: components["schemas"]["ProductStatus"];
3338
+ display_status: components["schemas"]["DisplayStatus"];
3339
+ published: boolean;
3340
+ form?: string | null;
3341
+ source_type?: components["schemas"]["SourceType"] | null;
3342
+ price?: number | null;
3343
+ currency?: string | null;
3344
+ height?: number | null;
3345
+ width?: number | null;
3346
+ depth?: number | null;
3347
+ display_unit?: components["schemas"]["DimensionUnit"] | null;
3348
+ images_ordered: boolean;
3349
+ thumbnail_url?: string | null;
3350
+ has_warnings: boolean;
3351
+ warning_count: number;
3352
+ comment_count: number;
3353
+ image_count: number;
3354
+ model_status?: components["schemas"]["AssetStatus"] | null;
3355
+ owner?: components["schemas"]["ProductOwner"] | null;
3356
+ created_at: string;
3357
+ updated_at?: string | null;
3358
+ description?: string | null;
3359
+ wall_mounted: boolean;
3360
+ product_type?: string | null;
3361
+ material_words?: string | null;
3362
+ transparent: boolean;
3363
+ metadata?: {
3364
+ [key: string]: unknown;
3365
+ };
3366
+ sources?: components["schemas"]["ProductSourceResponse"][];
3367
+ images?: components["schemas"]["ProductImageResponse"][];
3368
+ model?: components["schemas"]["ProductModelResponse"] | null;
3369
+ warnings?: components["schemas"]["ProductWarning"][];
3370
+ open_request_count: number;
3371
+ }>;
3372
+ /**
3373
+ * POST /v1/products/{id}/tickets - a single-use URL for the product's 3D file, the ONLY way
3374
+ * to its bytes (no response carries a model file URL). It works once, until `expires_at`
3375
+ * (60 s for `view`, 30 s for `ar`); a `view` ticket only from its bound origin. With a `pk_`
3376
+ * key the product must be published and the ticket is bound to the page's Origin; with an
3377
+ * `sk_` key pass `origin` (the page that will load the model, one of your allowed domains).
3378
+ */
3379
+ createTicket: (id: string, params: TicketParams) => Promise<{
3380
+ url: string;
3381
+ kind: components["schemas"]["TicketKind"];
3382
+ expires_at: string;
3383
+ }>;
3384
+ /** POST /v1/products/{id}/order - park the missing half (images or a model); commit the
3385
+ * returned `resume_token` with `create`. */
3386
+ order: (id: string, params: ProductOrderParams) => Promise<{
3387
+ status: "parked";
3388
+ resume_token: string;
3389
+ expires_at: string;
3390
+ order: components["schemas"]["ProductOrder"];
3391
+ flags: components["schemas"]["GateFlags"];
3392
+ plan?: components["schemas"]["PlannedView"][];
3393
+ model: components["schemas"]["ModelPlanResponse"];
3394
+ cost: components["schemas"]["ProductCost"];
3395
+ warnings?: string[];
3396
+ generate_unseen: boolean;
3397
+ force_model: boolean;
3398
+ }>;
3399
+ /** GET /v1/products/export - a ZIP of finished images (never the 3D model), resolved as a
3400
+ * `Blob`; or `ProductExportQueued` (202) when the images are being finished in the
3401
+ * background and a download link is emailed - repeat the request later to stream it. */
3402
+ export: (params?: ProductExportParams) => Promise<{
3403
+ status: "queued";
3404
+ products: number;
3405
+ images: number;
3406
+ to_finish: number;
3407
+ notify_email?: string | null;
3408
+ } | Blob>;
3409
+ };
3410
+ declare function createApiKeys(request: RequestFn): {
3411
+ /** GET /v1/api_keys */
3412
+ list: () => Promise<{
3413
+ data: components["schemas"]["ApiKeyResponse"][];
3414
+ }>;
3415
+ /** POST /v1/api_keys - the full key is returned exactly once. */
3416
+ create: (params: ApiKeyCreateParams) => Promise<{
3417
+ id: string;
3418
+ org_id?: string | null;
3419
+ project_id?: string | null;
3420
+ key_type: components["schemas"] /** PATCH /v1/webhooks/{id} */["KeyType"];
3421
+ key_prefix: string;
3422
+ name?: string | null;
3423
+ scopes: string[];
3424
+ last_used_at?: string | null;
3425
+ revoked_at?: string | null;
3426
+ created_at: string;
3427
+ key: string;
3428
+ }>;
3429
+ /** DELETE /v1/api_keys/{id} - soft revoke. */
3430
+ revoke: (id: string) => Promise<void>;
3431
+ };
3432
+ declare function createUsage(request: RequestFn): {
3433
+ /** GET /v1/usage - buckets and totals over the window; `group_by: "product"` adds the
3434
+ * window's best-performing products in `by_product`. */
3435
+ get: (params?: UsageParams) => Promise<{
3436
+ start: string;
3437
+ end: string;
3438
+ granularity: "hour" | "day";
3439
+ buckets: components["schemas"]["UsageBucket"][];
3440
+ totals: {
3441
+ [key: string]: number;
3442
+ };
3443
+ durations?: {
3444
+ [key: string]: components["schemas"]["UsageDuration"];
3445
+ };
3446
+ by_product?: components["schemas"]["UsageProductTotals"][];
3447
+ }>;
3448
+ };
3449
+ declare function createWebhooks(request: RequestFn): {
3450
+ /** GET /v1/webhooks */
3451
+ list: () => Promise<{
3452
+ data: components["schemas"]["WebhookEndpointResponse"][];
3453
+ }>;
3454
+ /** POST /v1/webhooks - includes the signing secret. */
3455
+ create: (params: WebhookEndpointCreateParams) => Promise<{
3456
+ id: string;
3457
+ org_id?: string | null;
3458
+ project_id?: string | null;
3459
+ url: string;
3460
+ description?: string | null;
3461
+ events: components["schemas"]["WebhookEventType"][];
3462
+ enabled: boolean;
3463
+ created_at: string;
3464
+ updated_at: string;
3465
+ signing_secret: string;
3466
+ }>;
3467
+ /** GET /v1/webhooks/{id} */
3468
+ retrieve: (id: string) => Promise<{
3469
+ id: string;
3470
+ org_id?: string | null;
3471
+ project_id?: string | null;
3472
+ url: string;
3473
+ description?: string | null;
3474
+ events: components["schemas"]["WebhookEventType"][];
3475
+ enabled: boolean;
3476
+ created_at: string;
3477
+ updated_at: string;
3478
+ }>;
3479
+ /** PATCH /v1/webhooks/{id} */
3480
+ update: (id: string, params: WebhookEndpointUpdateParams) => Promise<{
3481
+ id: string;
3482
+ org_id?: string | null;
3483
+ project_id?: string | null;
3484
+ url: string;
3485
+ description?: string | null;
3486
+ events: components["schemas"]["WebhookEventType"][];
3487
+ enabled: boolean;
3488
+ created_at: string;
3489
+ updated_at: string;
3490
+ }>;
3491
+ /** DELETE /v1/webhooks/{id} */
3492
+ delete: (id: string) => Promise<void>;
3493
+ /** GET /v1/webhooks/{id}/deliveries */
3494
+ listDeliveries: (id: string, params?: WebhookDeliveriesParams) => Promise<{
3495
+ data: components["schemas"]["WebhookDeliveryResponse"][];
3496
+ limit: number;
3497
+ offset: number;
3498
+ }>;
3499
+ };
3500
+ declare function createProjects(request: RequestFn): {
3501
+ /** GET /v1/projects */
3502
+ list: () => Promise<{
3503
+ data: components["schemas"]["ProjectResponse"][];
3504
+ }>;
3505
+ /** GET /v1/projects/{id} */
3506
+ retrieve: (id: string) => Promise<{
3507
+ id: string;
3508
+ org_id: string;
3509
+ name: string;
3510
+ allowed_domains: string[];
3511
+ always_generate: boolean;
3512
+ created_at: string;
3513
+ }>;
3514
+ };
3515
+ declare function createBeacon(request: RequestFn): {
3516
+ /** POST /v1/beacon - ingest a view/AR analytics event (204). */
3517
+ send: (params: BeaconParams) => Promise<void>;
227
3518
  };
228
-
229
- /**
230
- * Models resource - 3D models (backed by the `scans` table).
231
- *
232
- * Mirrors the 8 `/v1/models*` endpoints. camelCase param names are mapped
233
- * to the snake_case wire contract on the way out; response shapes pass
234
- * through as-is.
235
- */
236
-
237
- declare class ModelsResource {
238
- private readonly client;
239
- constructor(client: Viewrium);
240
- create(params: ModelCreateParams): Promise<Model>;
241
- createFromImages(images: FileInput[], params?: ModelCreateFromImagesParams): Promise<Model>;
242
- createFromVideo(video: FileInput, params?: ModelCreateFromVideoParams): Promise<Model>;
243
- retrieve(modelId: string): Promise<Model>;
244
- list(params?: ModelListParams): Promise<ModelListResponse>;
245
- modify(modelId: string, params: ModelUpdateParams): Promise<Model>;
246
- delete(modelId: string): Promise<DeletedResponse>;
247
- listEvents(modelId: string, params?: ModelListEventsParams): Promise<ModelEventListResponse>;
248
- }
249
-
250
- /**
251
- * Api keys resource.
252
- *
253
- * Creates secret (`sk_*`) or publishable (`pk_*`) keys. pk keys inherit
254
- * origin restrictions from their project's `allowed_domains`. The plaintext
255
- * key is returned ONCE from `create()`; store it securely on your side.
256
- */
257
-
258
- declare class ApiKeysResource {
259
- private readonly client;
260
- constructor(client: Viewrium);
261
- create(params?: ApiKeyCreateParams): Promise<ApiKeyWithSecret>;
262
- list(): Promise<ApiKeyListResponse>;
263
- delete(keyId: string): Promise<RevokedResponse>;
264
- }
265
-
266
- /**
267
- * Usage resource.
268
- *
269
- * Returns aggregated event counts for the caller's organization. Internal
270
- * service events (rodin / gemini / scrape / convert / store) are never
271
- * exposed here.
272
- */
273
-
274
- declare class UsageResource {
275
- private readonly client;
276
- constructor(client: Viewrium);
277
- retrieve(params?: UsageRetrieveParams): Promise<UsageSummary>;
278
- }
279
-
280
- /**
281
- * Tags resource.
282
- *
283
- * Lists unique tags across the caller's organization with per-tag model
284
- * counts. Tags are created implicitly when assigned to a model; there is
285
- * no POST /v1/tags endpoint.
286
- */
287
-
288
- declare class TagsResource {
289
- private readonly client;
290
- constructor(client: Viewrium);
291
- list(): Promise<TagListResponse>;
292
- }
293
-
294
- /**
295
- * Viewrium client.
296
- *
297
- * Instantiate once per api key:
298
- *
299
- * const viewrium = new Viewrium(process.env.VIEWRIUM_API_KEY!);
300
- * const model = await viewrium.models.create({ images: [...] });
301
- *
302
- * The client uses `globalThis.fetch` by default (Node 18+, browsers, edge
303
- * runtimes all provide it). Pass `fetch` in options for custom transports
304
- * or testing.
305
- */
306
-
307
- interface RequestOptions {
308
- method: string;
309
- path: string;
310
- query?: Record<string, unknown>;
311
- json?: unknown;
312
- body?: BodyInit;
313
- headers?: Record<string, string>;
314
- /** Override per-request timeout in ms. */
315
- timeoutMs?: number;
316
- }
317
3519
  declare class Viewrium {
318
- readonly models: ModelsResource;
319
- readonly apiKeys: ApiKeysResource;
320
- readonly usage: UsageResource;
321
- readonly tags: TagsResource;
322
- private readonly apiKey;
323
- private readonly apiBase;
324
- private readonly timeoutMs;
325
- private readonly maxRetries;
326
- private readonly fetchImpl;
327
- constructor(apiKey?: string, options?: ViewriumOptions);
328
- /** Low-level request. Resources delegate here. */
329
- request<T = unknown>(options: RequestOptions): Promise<T>;
330
- private buildUrl;
331
- private buildHeaders;
332
- private buildBody;
3520
+ #private;
3521
+ readonly baseUrl: string;
3522
+ readonly products: ReturnType<typeof createProducts>;
3523
+ readonly apiKeys: ReturnType<typeof createApiKeys>;
3524
+ readonly usage: ReturnType<typeof createUsage>;
3525
+ readonly webhooks: ReturnType<typeof createWebhooks>;
3526
+ readonly projects: ReturnType<typeof createProjects>;
3527
+ readonly beacon: ReturnType<typeof createBeacon>;
3528
+ constructor(options: ViewriumOptions);
3529
+ /** GET /v1/health */
3530
+ health(): Promise<Health>;
333
3531
  }
3532
+ /** Convenience factory: `createViewrium({ apiKey })` is `new Viewrium({ apiKey })`. */
3533
+ declare function createViewrium(options: ViewriumOptions): Viewrium;
334
3534
 
335
- /**
336
- * Official JavaScript / TypeScript SDK for the Viewrium API.
337
- *
338
- * import Viewrium from "@viewrium/sdk";
339
- *
340
- * const viewrium = new Viewrium(process.env.VIEWRIUM_API_KEY!);
341
- *
342
- * const model = await viewrium.models.create({
343
- * customId: "sku-1",
344
- * images: ["https://example.com/img1.jpg"],
345
- * height: 90,
346
- * tags: ["chair", "summer-2026"],
347
- * });
348
- */
349
-
350
- export { APIError, type ApiKey, type ApiKeyCreateParams, type ApiKeyListResponse, type ApiKeyWithSecret, ApiKeysResource, AuthError, type DeletedResponse, type FileInput, type Model, type ModelCreateFromImagesParams, type ModelCreateFromVideoParams, type ModelCreateParams, type ModelEvent, type ModelEventListResponse, type ModelListEventsParams, type ModelListParams, type ModelListResponse, type ModelStatus, type ModelUpdateParams, ModelsResource, NotFoundError, RateLimitError, type RequestOptions, type RevokedResponse, type SizeUnit, type SourceType, type TagListResponse, type TagSummary, TagsResource, type UsageEventType, UsageResource, type UsageRetrieveParams, type UsageSummary, ValidationError, Viewrium, ViewriumError, type ViewriumOptions, Viewrium as default };
3535
+ export { type ApiErrorPayload, type ApiKeyCreateParams, type ApiKeyCreated, type ApiKeyList, AuthenticationError, BadRequestError, type BeaconParams, ConflictError, ConnectionError, type FetchLike, type GateFlags, type Health, type ModelPlan, NotFoundError, PaymentRequiredError, PermissionError, type PlannedView, type Product, type ProductBatchResult, type ProductCost, type ProductCreateParams, type ProductCreateResult, type ProductCreated, type ProductExportParams, type ProductExportQueued, type ProductImage, type ProductImagePatchParams, type ProductList, type ProductListParams, type ProductModel, type ProductModelPatchParams, type ProductOrderParams, type ProductOrderParked, type ProductParked, type ProductPublishParams, type ProductRescaleParams, type ProductReviewParams, type ProductReviewResult, type ProductSummary, type ProductUpdateParams, type Project, type ProjectList, type PublicProduct, RateLimitError, ServerError, type Tags, type TagsParams, type Ticket, type TicketParams, UnprocessableEntityError, type Usage, type UsageParams, type UsageProductTotals, Viewrium, ViewriumError, type ViewriumErrorOptions, type ViewriumOptions, type WebhookDeliveriesParams, type WebhookDeliveryList, type WebhookEndpoint, type WebhookEndpointCreateParams, type WebhookEndpointCreated, type WebhookEndpointList, type WebhookEndpointUpdateParams, createApiError, createViewrium };