@epilot/file-client 1.21.0 → 1.23.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/openapi.json CHANGED
@@ -2,29 +2,29 @@
2
2
  "openapi": "3.0.3",
3
3
  "info": {
4
4
  "title": "File API",
5
- "version": "1.7.0",
6
- "description": "Upload and manage epilot Files\n\n## Changelog\n<a href=\"changelog\">View API Changelog</a>\n"
5
+ "version": "1.10.0",
6
+ "description": "The File API enables you to upload, store, manage, and share files within the epilot platform.\n\n## Key Features\n- **Upload files** to temporary storage and save them permanently as File entities\n- **Generate previews** (thumbnails) for images and documents\n- **Create public links** to share private files externally\n- **Organize files** into collections for better management\n- **Version control** with automatic file versioning on updates\n\n## File Upload Workflow\n1. Call `uploadFileV2` to get a pre-signed S3 URL\n2. Upload your file directly to S3 using the pre-signed URL (PUT request)\n3. Call `saveFileV2` with the S3 reference to create a permanent File entity\n\n## Changelog\n<a href=\"changelog\">View API Changelog</a>\n"
7
7
  },
8
8
  "tags": [
9
9
  {
10
10
  "name": "File",
11
- "description": "Upload and Manage File Entities"
11
+ "description": "Core file operations for uploading, saving, retrieving, and deleting files.\n\nFiles are stored as epilot entities with the `file` schema and support:\n- Multiple versions (each save creates a new version)\n- Custom metadata and tags\n- Relations to other entities (contacts, orders, etc.)\n- Access control (private or public-read)\n"
12
12
  },
13
13
  {
14
14
  "name": "Preview",
15
- "description": "Preview APIs"
15
+ "description": "Generate thumbnail previews for files. Supports images, PDFs, and common document formats.\n\nPreview images are generated on-demand and cached for performance.\nYou can specify custom dimensions using the `w` (width) and `h` (height) parameters.\n"
16
16
  },
17
17
  {
18
18
  "name": "Public Links",
19
- "description": "Create and Manage Public Links for Files"
19
+ "description": "Create shareable public links for private files.\n\nPublic links allow external users to access files without authentication.\nLinks are permanent until revoked and include the filename for user-friendly URLs.\n"
20
20
  },
21
21
  {
22
22
  "name": "Session",
23
- "description": "Session API for cookie authentication"
23
+ "description": "Browser session management for cookie-based authentication.\n\nUse `getSession` to convert a Bearer token into a session cookie. This enables:\n- Direct use of preview URLs in `<img>` tags\n- File downloads without manual token handling\n\n**Typical flow:**\n1. Authenticate and obtain a Bearer token\n2. Call `GET /v1/files/session` with the Bearer token\n3. Subsequent requests use the session cookie automatically\n"
24
24
  },
25
25
  {
26
26
  "name": "Deprecated",
27
- "description": "Deprecated APIs"
27
+ "description": "Legacy API endpoints scheduled for removal.\n\n**Important:** These endpoints will be removed on **2025-06-30**.\nPlease migrate to the v2 equivalents before this date.\n\n| Deprecated Endpoint | Replacement |\n|---------------------|-------------|\n| `POST /v1/files/upload` | `POST /v2/files/upload` |\n| `POST /v1/files` | `POST /v2/files` |\n"
28
28
  },
29
29
  {
30
30
  "name": "file_schema",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  {
35
35
  "name": "File Collections",
36
- "description": "Collection management for organizing files within entities"
36
+ "description": "Organize files into collections (folders) for better management.\n\nCollections can be:\n- **User-scoped**: Personal collections visible only to the creating user\n- **Global**: Shared collections available to all users for a schema\n\nCollections support hierarchical organization with parent-child relationships.\n"
37
37
  }
38
38
  ],
39
39
  "x-tagGroups": [
@@ -117,6 +117,15 @@
117
117
  }
118
118
  }
119
119
  }
120
+ },
121
+ "400": {
122
+ "$ref": "#/components/responses/BadRequestError"
123
+ },
124
+ "401": {
125
+ "$ref": "#/components/responses/UnauthorizedError"
126
+ },
127
+ "500": {
128
+ "$ref": "#/components/responses/InternalServerError"
120
129
  }
121
130
  }
122
131
  }
@@ -144,13 +153,29 @@
144
153
  },
145
154
  {
146
155
  "$ref": "#/components/parameters/DeleteTempFileQueryParam"
156
+ },
157
+ {
158
+ "$ref": "#/components/parameters/VersionOnlyQueryParam"
147
159
  }
148
160
  ],
149
161
  "requestBody": {
150
162
  "content": {
151
163
  "application/json": {
152
164
  "schema": {
153
- "$ref": "#/components/schemas/SaveFilePayloadV2"
165
+ "oneOf": [
166
+ {
167
+ "$ref": "#/components/schemas/SaveFilePayloadV2"
168
+ },
169
+ {
170
+ "type": "array",
171
+ "description": "Batch version mode: array of s3ref payloads to add multiple versions to a single file entity.\nAll payloads must target the same file entity (_id or file_entity_id).\nRequires version_only=true query parameter.\nS3 operations run in parallel, with a single entity update at the end.\n",
172
+ "items": {
173
+ "$ref": "#/components/schemas/BatchSaveFileVersionPayload"
174
+ },
175
+ "minItems": 1,
176
+ "maxItems": 20
177
+ }
178
+ ]
154
179
  },
155
180
  "examples": {
156
181
  "New file from s3ref": {
@@ -208,6 +233,29 @@
208
233
  "custom_download_url": "https://some-api-url.com/download?file_id=123",
209
234
  "shared_with_end_customer": true
210
235
  }
236
+ },
237
+ "Batch save multiple versions": {
238
+ "description": "Save multiple file versions in a single request (parallel S3 processing)",
239
+ "value": [
240
+ {
241
+ "_id": "ef7d985c-2385-44f4-9c71-ae06a52264f8",
242
+ "filename": "photo1.jpg",
243
+ "access_control": "private",
244
+ "s3ref": {
245
+ "bucket": "epilot-prod-user-content",
246
+ "key": "123/temp/abc/photo1.jpg"
247
+ }
248
+ },
249
+ {
250
+ "_id": "ef7d985c-2385-44f4-9c71-ae06a52264f8",
251
+ "filename": "photo2.jpg",
252
+ "access_control": "private",
253
+ "s3ref": {
254
+ "bucket": "epilot-prod-user-content",
255
+ "key": "123/temp/def/photo2.jpg"
256
+ }
257
+ }
258
+ ]
211
259
  }
212
260
  }
213
261
  }
@@ -215,7 +263,7 @@
215
263
  },
216
264
  "responses": {
217
265
  "200": {
218
- "description": "Created File Entity",
266
+ "description": "Created or updated File Entity",
219
267
  "content": {
220
268
  "application/json": {
221
269
  "schema": {
@@ -223,6 +271,18 @@
223
271
  }
224
272
  }
225
273
  }
274
+ },
275
+ "400": {
276
+ "$ref": "#/components/responses/BadRequestError"
277
+ },
278
+ "401": {
279
+ "$ref": "#/components/responses/UnauthorizedError"
280
+ },
281
+ "404": {
282
+ "$ref": "#/components/responses/NotFoundError"
283
+ },
284
+ "500": {
285
+ "$ref": "#/components/responses/InternalServerError"
226
286
  }
227
287
  }
228
288
  }
@@ -232,7 +292,7 @@
232
292
  "operationId": "uploadFile",
233
293
  "summary": "uploadFile",
234
294
  "deprecated": true,
235
- "description": "Create pre-signed S3 URL to upload a file to keep temporarily (one week).\n\nUse the saveFile operation to store file file permanently.\n",
295
+ "description": "**DEPRECATED** - Will be removed on **2025-06-30**. Use `POST /v2/files/upload` instead.\n\n## Migration Guide\nReplace calls to this endpoint with `uploadFileV2`:\n\n| v1 Parameter | v2 Parameter | Notes |\n|--------------|--------------|-------|\n| `file_entity_id` | `file_entity_id` | No change |\n\nThe v2 response includes the same fields with improved structure.\n\n---\n\nCreate pre-signed S3 URL to upload a file to keep temporarily (one week).\n\nUse the saveFile operation to store file file permanently.\n",
236
296
  "tags": [
237
297
  "Deprecated"
238
298
  ],
@@ -251,6 +311,14 @@
251
311
  "application/json": {
252
312
  "schema": {
253
313
  "$ref": "#/components/schemas/UploadFilePayload"
314
+ },
315
+ "examples": {
316
+ "Upload a document": {
317
+ "value": {
318
+ "filename": "document.pdf",
319
+ "mime_type": "application/pdf"
320
+ }
321
+ }
254
322
  }
255
323
  }
256
324
  }
@@ -291,6 +359,15 @@
291
359
  }
292
360
  }
293
361
  }
362
+ },
363
+ "400": {
364
+ "$ref": "#/components/responses/BadRequestError"
365
+ },
366
+ "401": {
367
+ "$ref": "#/components/responses/UnauthorizedError"
368
+ },
369
+ "500": {
370
+ "$ref": "#/components/responses/InternalServerError"
294
371
  }
295
372
  }
296
373
  }
@@ -300,7 +377,7 @@
300
377
  "operationId": "saveFile",
301
378
  "summary": "saveFile",
302
379
  "deprecated": true,
303
- "description": "Create / Update a permanent File entity\n\nMakes file object permanent\n\nSaves metadata to file entity\n",
380
+ "description": "**DEPRECATED** - Will be removed on **2025-06-30**. Use `POST /v2/files` instead.\n\n## Migration Guide\nReplace calls to this endpoint with `saveFileV2`:\n\n| v1 Feature | v2 Feature | Notes |\n|------------|------------|-------|\n| `activity_id` param | `activity_id` param | No change |\n| `async` param | `async` param | No change |\n| - | `fill_activity` param | New in v2 |\n| - | `strict` param | New in v2 |\n| - | `delete_temp_file` param | New in v2, defaults to true |\n\nThe v2 endpoint supports additional parameters for better control over file saving behavior.\n\n---\n\nCreate / Update a permanent File entity.\n\nMakes file object permanent and saves metadata to file entity.\n",
304
381
  "tags": [
305
382
  "Deprecated"
306
383
  ],
@@ -310,6 +387,9 @@
310
387
  },
311
388
  {
312
389
  "$ref": "#/components/parameters/AsyncOperationQueryParam"
390
+ },
391
+ {
392
+ "$ref": "#/components/parameters/VersionOnlyQueryParam"
313
393
  }
314
394
  ],
315
395
  "requestBody": {
@@ -317,6 +397,19 @@
317
397
  "application/json": {
318
398
  "schema": {
319
399
  "$ref": "#/components/schemas/SaveFilePayload"
400
+ },
401
+ "examples": {
402
+ "Save file with S3 reference": {
403
+ "value": {
404
+ "filename": "document.pdf",
405
+ "type": "document",
406
+ "access_control": "private",
407
+ "s3ref": {
408
+ "bucket": "epilot-prod-user-content",
409
+ "key": "123/temp/4d689aeb-1497-4410-a9fe-b36ca9ac4389/document.pdf"
410
+ }
411
+ }
412
+ }
320
413
  }
321
414
  }
322
415
  }
@@ -331,6 +424,15 @@
331
424
  }
332
425
  }
333
426
  }
427
+ },
428
+ "400": {
429
+ "$ref": "#/components/responses/BadRequestError"
430
+ },
431
+ "401": {
432
+ "$ref": "#/components/responses/UnauthorizedError"
433
+ },
434
+ "500": {
435
+ "$ref": "#/components/responses/InternalServerError"
334
436
  }
335
437
  }
336
438
  }
@@ -378,6 +480,18 @@
378
480
  }
379
481
  }
380
482
  }
483
+ },
484
+ "401": {
485
+ "$ref": "#/components/responses/UnauthorizedError"
486
+ },
487
+ "403": {
488
+ "$ref": "#/components/responses/ForbiddenError"
489
+ },
490
+ "404": {
491
+ "$ref": "#/components/responses/NotFoundError"
492
+ },
493
+ "500": {
494
+ "$ref": "#/components/responses/InternalServerError"
381
495
  }
382
496
  }
383
497
  },
@@ -423,6 +537,18 @@
423
537
  }
424
538
  }
425
539
  }
540
+ },
541
+ "401": {
542
+ "$ref": "#/components/responses/UnauthorizedError"
543
+ },
544
+ "403": {
545
+ "$ref": "#/components/responses/ForbiddenError"
546
+ },
547
+ "404": {
548
+ "$ref": "#/components/responses/NotFoundError"
549
+ },
550
+ "500": {
551
+ "$ref": "#/components/responses/InternalServerError"
426
552
  }
427
553
  }
428
554
  }
@@ -431,7 +557,7 @@
431
557
  "get": {
432
558
  "operationId": "downloadFile",
433
559
  "summary": "downloadFile",
434
- "description": "Generate pre-signed download S3 url for a file",
560
+ "description": "Generate a pre-signed download URL for a file.\n\nThe returned URL is valid for a limited time (typically 15 minutes) and can be used to download the file directly.\n",
435
561
  "tags": [
436
562
  "File"
437
563
  ],
@@ -440,6 +566,7 @@
440
566
  "name": "id",
441
567
  "in": "path",
442
568
  "required": true,
569
+ "description": "The UUID of the file entity",
443
570
  "schema": {
444
571
  "$ref": "#/components/schemas/FileEntityId"
445
572
  }
@@ -447,7 +574,7 @@
447
574
  {
448
575
  "name": "version",
449
576
  "in": "query",
450
- "description": "index of file version",
577
+ "description": "Index of the file version to download (0 = latest)",
451
578
  "schema": {
452
579
  "type": "integer",
453
580
  "default": 0
@@ -456,7 +583,7 @@
456
583
  {
457
584
  "name": "attachment",
458
585
  "in": "query",
459
- "description": "Controls the Content-Disposition header to control browser behaviour. Set to true to trigger download.",
586
+ "description": "Controls the Content-Disposition header. Set to `true` to trigger browser download dialog, `false` to display inline.",
460
587
  "schema": {
461
588
  "type": "boolean",
462
589
  "default": true
@@ -465,7 +592,7 @@
465
592
  ],
466
593
  "responses": {
467
594
  "200": {
468
- "description": "Generated thumbnail image",
595
+ "description": "Pre-signed download URL",
469
596
  "content": {
470
597
  "application/json": {
471
598
  "schema": {
@@ -474,12 +601,28 @@
474
601
  "download_url": {
475
602
  "type": "string",
476
603
  "format": "uri",
604
+ "description": "Pre-signed S3 URL valid for downloading the file",
477
605
  "example": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/temp/4d689aeb-1497-4410-a9fe-b36ca9ac4389/document.pdf?AWSParams=123"
478
606
  }
479
607
  }
608
+ },
609
+ "example": {
610
+ "download_url": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/4d689aeb-1497-4410-a9fe-b36ca9ac4389/document.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&..."
480
611
  }
481
612
  }
482
613
  }
614
+ },
615
+ "401": {
616
+ "$ref": "#/components/responses/UnauthorizedError"
617
+ },
618
+ "403": {
619
+ "$ref": "#/components/responses/ForbiddenError"
620
+ },
621
+ "404": {
622
+ "$ref": "#/components/responses/NotFoundError"
623
+ },
624
+ "500": {
625
+ "$ref": "#/components/responses/InternalServerError"
483
626
  }
484
627
  }
485
628
  }
@@ -488,7 +631,7 @@
488
631
  "post": {
489
632
  "operationId": "downloadS3File",
490
633
  "summary": "downloadS3File",
491
- "description": "Generate pre-signed download S3 url for a file",
634
+ "description": "Generate a pre-signed download URL for a file using its S3 reference.\n\nUse this endpoint when you have the S3 bucket and key but not the file entity ID.\n",
492
635
  "tags": [
493
636
  "File"
494
637
  ],
@@ -497,22 +640,26 @@
497
640
  "name": "s3_key",
498
641
  "in": "query",
499
642
  "required": true,
643
+ "description": "The S3 object key",
500
644
  "schema": {
501
645
  "type": "string"
502
- }
646
+ },
647
+ "example": "123/4d689aeb-1497-4410-a9fe-b36ca9ac4389/document.pdf"
503
648
  },
504
649
  {
505
650
  "name": "s3_bucket",
506
651
  "in": "query",
507
652
  "required": true,
653
+ "description": "The S3 bucket name",
508
654
  "schema": {
509
655
  "type": "string"
510
- }
656
+ },
657
+ "example": "epilot-prod-user-content"
511
658
  },
512
659
  {
513
660
  "name": "attachment",
514
661
  "in": "query",
515
- "description": "Controls the Content-Disposition header to control browser behaviour. Set to true to trigger download.",
662
+ "description": "Controls the Content-Disposition header. Set to `true` to trigger browser download dialog, `false` to display inline.",
516
663
  "schema": {
517
664
  "type": "boolean",
518
665
  "default": true
@@ -521,7 +668,7 @@
521
668
  ],
522
669
  "responses": {
523
670
  "200": {
524
- "description": "Generated thumbnail image",
671
+ "description": "Pre-signed download URL",
525
672
  "content": {
526
673
  "application/json": {
527
674
  "schema": {
@@ -530,12 +677,25 @@
530
677
  "download_url": {
531
678
  "type": "string",
532
679
  "format": "uri",
680
+ "description": "Pre-signed S3 URL valid for downloading the file",
533
681
  "example": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/temp/4d689aeb-1497-4410-a9fe-b36ca9ac4389/document.pdf?AWSParams=123"
534
682
  }
535
683
  }
536
684
  }
537
685
  }
538
686
  }
687
+ },
688
+ "400": {
689
+ "$ref": "#/components/responses/BadRequestError"
690
+ },
691
+ "401": {
692
+ "$ref": "#/components/responses/UnauthorizedError"
693
+ },
694
+ "404": {
695
+ "$ref": "#/components/responses/NotFoundError"
696
+ },
697
+ "500": {
698
+ "$ref": "#/components/responses/InternalServerError"
539
699
  }
540
700
  }
541
701
  }
@@ -544,7 +704,7 @@
544
704
  "post": {
545
705
  "operationId": "downloadFiles",
546
706
  "summary": "downloadFiles",
547
- "description": "Bulk generate pre-signed download S3 urls for multiple files",
707
+ "description": "Bulk generate pre-signed download URLs for multiple files in a single request.\n\nThis is more efficient than calling `downloadFile` multiple times when you need to download several files.\n",
548
708
  "tags": [
549
709
  "File"
550
710
  ],
@@ -553,13 +713,27 @@
553
713
  "application/json": {
554
714
  "schema": {
555
715
  "$ref": "#/components/schemas/DownloadFilesPayload"
716
+ },
717
+ "examples": {
718
+ "Download multiple files": {
719
+ "value": [
720
+ {
721
+ "id": "ef7d985c-2385-44f4-9c71-ae06a52264f8",
722
+ "version": 0
723
+ },
724
+ {
725
+ "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
726
+ "version": 0
727
+ }
728
+ ]
729
+ }
556
730
  }
557
731
  }
558
732
  }
559
733
  },
560
734
  "responses": {
561
735
  "200": {
562
- "description": "Generated download urls",
736
+ "description": "Generated download URLs for each requested file",
563
737
  "content": {
564
738
  "application/json": {
565
739
  "schema": {
@@ -570,17 +744,38 @@
570
744
  "download_url": {
571
745
  "type": "string",
572
746
  "format": "uri",
747
+ "description": "Pre-signed S3 URL for downloading the file",
573
748
  "example": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/temp/4d689aeb-1497-4410-a9fe-b36ca9ac4389/document.pdf?AWSParams=123"
574
749
  },
575
750
  "file_entity_id": {
576
751
  "type": "string",
577
- "format": "uuid"
752
+ "format": "uuid",
753
+ "description": "The file entity ID (matches the requested ID)"
578
754
  }
579
755
  }
580
756
  }
581
- }
757
+ },
758
+ "example": [
759
+ {
760
+ "download_url": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/document.pdf?X-Amz-...",
761
+ "file_entity_id": "ef7d985c-2385-44f4-9c71-ae06a52264f8"
762
+ },
763
+ {
764
+ "download_url": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/image.png?X-Amz-...",
765
+ "file_entity_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
766
+ }
767
+ ]
582
768
  }
583
769
  }
770
+ },
771
+ "400": {
772
+ "$ref": "#/components/responses/BadRequestError"
773
+ },
774
+ "401": {
775
+ "$ref": "#/components/responses/UnauthorizedError"
776
+ },
777
+ "500": {
778
+ "$ref": "#/components/responses/InternalServerError"
584
779
  }
585
780
  }
586
781
  }
@@ -589,7 +784,7 @@
589
784
  "get": {
590
785
  "operationId": "previewFile",
591
786
  "summary": "previewFile",
592
- "description": "Generate thumbnail preview for a file entity",
787
+ "description": "Generate a thumbnail preview for a file entity.\n\nSupported file types include images (PNG, JPEG, GIF, WebP), PDFs, and common document formats.\nThe preview is returned as an image (PNG or JPEG).\n\n**Tip:** Use with CookieAuth to embed previews directly in `<img>` tags.\n",
593
788
  "tags": [
594
789
  "Preview"
595
790
  ],
@@ -598,6 +793,7 @@
598
793
  "name": "id",
599
794
  "in": "path",
600
795
  "required": true,
796
+ "description": "The UUID of the file entity",
601
797
  "schema": {
602
798
  "$ref": "#/components/schemas/FileEntityId"
603
799
  }
@@ -605,7 +801,7 @@
605
801
  {
606
802
  "name": "version",
607
803
  "in": "query",
608
- "description": "index of file version",
804
+ "description": "Index of the file version to preview (0 = latest)",
609
805
  "schema": {
610
806
  "type": "integer",
611
807
  "default": 0
@@ -614,27 +810,48 @@
614
810
  {
615
811
  "name": "w",
616
812
  "in": "query",
617
- "description": "width",
813
+ "description": "Desired width in pixels (maintains aspect ratio if only width is specified)",
618
814
  "schema": {
619
815
  "type": "integer"
620
- }
816
+ },
817
+ "example": 200
621
818
  },
622
819
  {
623
820
  "name": "h",
624
821
  "in": "query",
625
- "description": "height",
822
+ "description": "Desired height in pixels (maintains aspect ratio if only height is specified)",
626
823
  "schema": {
627
824
  "type": "integer"
628
- }
825
+ },
826
+ "example": 200
629
827
  }
630
828
  ],
631
829
  "responses": {
632
830
  "200": {
633
831
  "description": "Generated thumbnail image",
634
832
  "content": {
635
- "image/png": {},
636
- "image/jpeg": {}
833
+ "image/png": {
834
+ "schema": {
835
+ "type": "string",
836
+ "format": "binary"
837
+ }
838
+ },
839
+ "image/jpeg": {
840
+ "schema": {
841
+ "type": "string",
842
+ "format": "binary"
843
+ }
844
+ }
637
845
  }
846
+ },
847
+ "401": {
848
+ "$ref": "#/components/responses/UnauthorizedError"
849
+ },
850
+ "404": {
851
+ "$ref": "#/components/responses/NotFoundError"
852
+ },
853
+ "500": {
854
+ "$ref": "#/components/responses/InternalServerError"
638
855
  }
639
856
  }
640
857
  }
@@ -643,7 +860,7 @@
643
860
  "post": {
644
861
  "operationId": "previewS3File",
645
862
  "summary": "previewS3File",
646
- "description": "Generate thumbnail preview from an s3 reference for a file entity",
863
+ "description": "Generate a thumbnail preview from an S3 reference.\n\nUse this endpoint when you have the S3 bucket and key but not the file entity ID.\n",
647
864
  "tags": [
648
865
  "Preview"
649
866
  ],
@@ -651,18 +868,20 @@
651
868
  {
652
869
  "name": "w",
653
870
  "in": "query",
654
- "description": "width",
871
+ "description": "Desired width in pixels",
655
872
  "schema": {
656
873
  "type": "integer"
657
- }
874
+ },
875
+ "example": 200
658
876
  },
659
877
  {
660
878
  "name": "h",
661
879
  "in": "query",
662
- "description": "height",
880
+ "description": "Desired height in pixels",
663
881
  "schema": {
664
882
  "type": "integer"
665
- }
883
+ },
884
+ "example": 200
666
885
  }
667
886
  ],
668
887
  "requestBody": {
@@ -670,6 +889,14 @@
670
889
  "application/json": {
671
890
  "schema": {
672
891
  "$ref": "#/components/schemas/S3Ref"
892
+ },
893
+ "examples": {
894
+ "Preview from S3": {
895
+ "value": {
896
+ "bucket": "epilot-prod-user-content",
897
+ "key": "123/4d689aeb-1497-4410-a9fe-b36ca9ac4389/image.png"
898
+ }
899
+ }
673
900
  }
674
901
  }
675
902
  }
@@ -678,16 +905,38 @@
678
905
  "200": {
679
906
  "description": "Generated thumbnail image",
680
907
  "content": {
681
- "image/png": {},
682
- "image/jpeg": {}
908
+ "image/png": {
909
+ "schema": {
910
+ "type": "string",
911
+ "format": "binary"
912
+ }
913
+ },
914
+ "image/jpeg": {
915
+ "schema": {
916
+ "type": "string",
917
+ "format": "binary"
918
+ }
919
+ }
683
920
  }
921
+ },
922
+ "400": {
923
+ "$ref": "#/components/responses/BadRequestError"
924
+ },
925
+ "401": {
926
+ "$ref": "#/components/responses/UnauthorizedError"
927
+ },
928
+ "404": {
929
+ "$ref": "#/components/responses/NotFoundError"
930
+ },
931
+ "500": {
932
+ "$ref": "#/components/responses/InternalServerError"
684
933
  }
685
934
  }
686
935
  },
687
936
  "get": {
688
937
  "operationId": "previewS3FileGet",
689
938
  "summary": "previewS3FileGet",
690
- "description": "Get thumbnail preview from an s3 reference for a file entity",
939
+ "description": "Get a thumbnail preview from an S3 reference using query parameters.\n\nThis GET variant is useful for embedding previews directly in `<img>` tags.\n",
691
940
  "tags": [
692
941
  "Preview"
693
942
  ],
@@ -695,45 +944,71 @@
695
944
  {
696
945
  "name": "key",
697
946
  "in": "query",
698
- "description": "s3 key",
947
+ "description": "The S3 object key",
699
948
  "required": true,
700
949
  "schema": {
701
950
  "type": "string"
702
- }
951
+ },
952
+ "example": "123/4d689aeb-1497-4410-a9fe-b36ca9ac4389/image.png"
703
953
  },
704
954
  {
705
955
  "name": "bucket",
706
956
  "in": "query",
707
- "description": "s3 bucket",
957
+ "description": "The S3 bucket name",
708
958
  "required": true,
709
959
  "schema": {
710
960
  "type": "string"
711
- }
961
+ },
962
+ "example": "epilot-prod-user-content"
712
963
  },
713
964
  {
714
965
  "name": "w",
715
966
  "in": "query",
716
- "description": "width",
967
+ "description": "Desired width in pixels",
717
968
  "schema": {
718
969
  "type": "integer"
719
- }
970
+ },
971
+ "example": 200
720
972
  },
721
973
  {
722
974
  "name": "h",
723
975
  "in": "query",
724
- "description": "height",
976
+ "description": "Desired height in pixels",
725
977
  "schema": {
726
978
  "type": "integer"
727
- }
979
+ },
980
+ "example": 200
728
981
  }
729
982
  ],
730
983
  "responses": {
731
984
  "200": {
732
985
  "description": "Generated thumbnail image",
733
986
  "content": {
734
- "image/png": {},
735
- "image/jpeg": {}
987
+ "image/png": {
988
+ "schema": {
989
+ "type": "string",
990
+ "format": "binary"
991
+ }
992
+ },
993
+ "image/jpeg": {
994
+ "schema": {
995
+ "type": "string",
996
+ "format": "binary"
997
+ }
998
+ }
736
999
  }
1000
+ },
1001
+ "400": {
1002
+ "$ref": "#/components/responses/BadRequestError"
1003
+ },
1004
+ "401": {
1005
+ "$ref": "#/components/responses/UnauthorizedError"
1006
+ },
1007
+ "404": {
1008
+ "$ref": "#/components/responses/NotFoundError"
1009
+ },
1010
+ "500": {
1011
+ "$ref": "#/components/responses/InternalServerError"
737
1012
  }
738
1013
  }
739
1014
  }
@@ -742,7 +1017,7 @@
742
1017
  "get": {
743
1018
  "operationId": "previewPublicFile",
744
1019
  "summary": "previewPublicFile",
745
- "description": "Generate thumbnail preview for a public file entity",
1020
+ "description": "Generate a thumbnail preview for a public file entity.\n\n**No authentication required.** This endpoint only works for files with `access_control: public-read`.\n",
746
1021
  "security": [],
747
1022
  "tags": [
748
1023
  "Preview"
@@ -752,6 +1027,7 @@
752
1027
  "name": "id",
753
1028
  "in": "path",
754
1029
  "required": true,
1030
+ "description": "The UUID of the public file entity",
755
1031
  "schema": {
756
1032
  "$ref": "#/components/schemas/FileEntityId"
757
1033
  }
@@ -759,7 +1035,7 @@
759
1035
  {
760
1036
  "name": "version",
761
1037
  "in": "query",
762
- "description": "index of file version",
1038
+ "description": "Index of the file version to preview (0 = latest)",
763
1039
  "schema": {
764
1040
  "type": "integer",
765
1041
  "default": 0
@@ -768,35 +1044,68 @@
768
1044
  {
769
1045
  "name": "w",
770
1046
  "in": "query",
771
- "description": "width",
1047
+ "description": "Desired width in pixels",
772
1048
  "schema": {
773
1049
  "type": "integer"
774
- }
1050
+ },
1051
+ "example": 200
775
1052
  },
776
1053
  {
777
1054
  "name": "h",
778
1055
  "in": "query",
779
- "description": "height",
1056
+ "description": "Desired height in pixels",
780
1057
  "schema": {
781
1058
  "type": "integer"
782
- }
1059
+ },
1060
+ "example": 200
783
1061
  },
784
1062
  {
785
1063
  "name": "org_id",
786
1064
  "in": "query",
787
- "description": "Org id",
1065
+ "description": "Organization ID that owns the file",
788
1066
  "schema": {
789
1067
  "type": "string"
790
- }
1068
+ },
1069
+ "example": "123"
791
1070
  }
792
1071
  ],
793
1072
  "responses": {
794
1073
  "200": {
795
1074
  "description": "Generated thumbnail image for a public file",
796
1075
  "content": {
797
- "image/png": {},
798
- "image/jpeg": {}
1076
+ "image/png": {
1077
+ "schema": {
1078
+ "type": "string",
1079
+ "format": "binary"
1080
+ }
1081
+ },
1082
+ "image/jpeg": {
1083
+ "schema": {
1084
+ "type": "string",
1085
+ "format": "binary"
1086
+ }
1087
+ }
1088
+ }
1089
+ },
1090
+ "403": {
1091
+ "description": "File is not public",
1092
+ "content": {
1093
+ "application/json": {
1094
+ "schema": {
1095
+ "$ref": "#/components/schemas/ErrorObject"
1096
+ },
1097
+ "example": {
1098
+ "status": 403,
1099
+ "error": "File is not publicly accessible"
1100
+ }
1101
+ }
799
1102
  }
1103
+ },
1104
+ "404": {
1105
+ "$ref": "#/components/responses/NotFoundError"
1106
+ },
1107
+ "500": {
1108
+ "$ref": "#/components/responses/InternalServerError"
800
1109
  }
801
1110
  }
802
1111
  }
@@ -805,26 +1114,38 @@
805
1114
  "get": {
806
1115
  "operationId": "getSession",
807
1116
  "summary": "getSession",
808
- "description": "Start a browser session by setting passed Authorization token in a server side cookie.\n\nAllows using preview urls directly in img src for private files using cookie authentication.\n",
1117
+ "description": "Start a browser session by converting a Bearer token into a server-side cookie.\n\n**Use case:** After calling this endpoint, you can use preview URLs directly in `<img>` tags\nwithout needing to set the Authorization header manually.\n\n**Example flow:**\n1. Call this endpoint with your Bearer token: `GET /v1/files/session` with `Authorization: Bearer <token>`\n2. The server sets an HTTP-only cookie named `token`\n3. Use preview URLs directly: `<img src=\"https://file.sls.epilot.io/v1/files/{id}/preview\" />`\n",
809
1118
  "tags": [
810
1119
  "Session"
811
1120
  ],
812
1121
  "responses": {
813
1122
  "200": {
814
- "description": "Session started successfully"
1123
+ "description": "Session started successfully. A session cookie has been set.",
1124
+ "headers": {
1125
+ "Set-Cookie": {
1126
+ "description": "HTTP-only session cookie containing the authentication token",
1127
+ "schema": {
1128
+ "type": "string",
1129
+ "example": "token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...; HttpOnly; Secure; Path=/"
1130
+ }
1131
+ }
1132
+ }
1133
+ },
1134
+ "401": {
1135
+ "$ref": "#/components/responses/UnauthorizedError"
815
1136
  }
816
1137
  }
817
1138
  },
818
1139
  "delete": {
819
1140
  "operationId": "deleteSession",
820
1141
  "summary": "deleteSession",
821
- "description": "End browser session by deleting token cookie",
1142
+ "description": "End a browser session by deleting the token cookie.\n\nCall this endpoint to log out and clear the session cookie.\n",
822
1143
  "tags": [
823
1144
  "Session"
824
1145
  ],
825
1146
  "responses": {
826
1147
  "200": {
827
- "description": "Session deleted successfully"
1148
+ "description": "Session deleted successfully. The session cookie has been cleared."
828
1149
  }
829
1150
  }
830
1151
  }
@@ -833,7 +1154,7 @@
833
1154
  "post": {
834
1155
  "operationId": "generatePublicLink",
835
1156
  "summary": "generatePublicLink",
836
- "description": "Generates a public link to access a private file\n",
1157
+ "description": "Generate a public link to share a private file externally.\n\nThe generated link:\n- Is permanent until explicitly revoked\n- Includes the filename for user-friendly URLs\n- Does not require authentication to access\n- Redirects to a signed download URL when accessed\n\n**Use case:** Share invoices, contracts, or documents with external parties who don't have epilot accounts.\n",
837
1158
  "tags": [
838
1159
  "Public Links"
839
1160
  ],
@@ -842,6 +1163,7 @@
842
1163
  "name": "id",
843
1164
  "in": "path",
844
1165
  "required": true,
1166
+ "description": "The UUID of the file entity to share",
845
1167
  "schema": {
846
1168
  "$ref": "#/components/schemas/FileEntityId"
847
1169
  }
@@ -849,33 +1171,46 @@
849
1171
  ],
850
1172
  "responses": {
851
1173
  "201": {
852
- "description": "Returns the public link which can be used to access the file later",
1174
+ "description": "Public link generated successfully",
853
1175
  "content": {
854
1176
  "application/json": {
855
1177
  "schema": {
856
1178
  "type": "string",
857
- "example": "https://file.sls.epilot.io/v1/files/public/links/3ef5c6d9-818d-45e6-8efb-b1de59079a1c/invoice-2023-12.pdf"
858
- }
1179
+ "description": "The public URL that can be shared externally"
1180
+ },
1181
+ "example": "https://file.sls.epilot.io/v1/files/public/links/3ef5c6d9-818d-45e6-8efb-b1de59079a1c/invoice-2023-12.pdf"
859
1182
  }
860
1183
  }
1184
+ },
1185
+ "401": {
1186
+ "$ref": "#/components/responses/UnauthorizedError"
1187
+ },
1188
+ "403": {
1189
+ "$ref": "#/components/responses/ForbiddenError"
1190
+ },
1191
+ "404": {
1192
+ "$ref": "#/components/responses/NotFoundError"
1193
+ },
1194
+ "500": {
1195
+ "$ref": "#/components/responses/InternalServerError"
861
1196
  }
862
1197
  }
863
1198
  },
864
1199
  "get": {
865
1200
  "operationId": "listPublicLinksForFile",
866
1201
  "summary": "listPublicLinksForFile",
867
- "description": "Not yet implemented; This API would fetch all the public links that are previously generated for a file",
1202
+ "description": "**Not yet implemented.**\n\nThis endpoint will fetch all public links previously generated for a file.\n",
868
1203
  "x-not-implemented": true,
869
1204
  "parameters": [
870
1205
  {
871
1206
  "name": "id",
872
1207
  "in": "path",
873
1208
  "required": true,
1209
+ "description": "The UUID of the file entity",
874
1210
  "schema": {
875
- "type": "string",
876
- "description": "ID of the file entity",
877
- "example": "13d22918-36bd-4227-9ad4-2cb978788c8d"
878
- }
1211
+ "type": "string"
1212
+ },
1213
+ "example": "13d22918-36bd-4227-9ad4-2cb978788c8d"
879
1214
  }
880
1215
  ],
881
1216
  "tags": [
@@ -883,7 +1218,7 @@
883
1218
  ],
884
1219
  "responses": {
885
1220
  "200": {
886
- "description": "Public links of a file retrieved successfully",
1221
+ "description": "Public links retrieved successfully",
887
1222
  "content": {
888
1223
  "application/json": {
889
1224
  "schema": {
@@ -896,6 +1231,29 @@
896
1231
  }
897
1232
  }
898
1233
  }
1234
+ },
1235
+ "example": {
1236
+ "results": [
1237
+ {
1238
+ "id": "3ef5c6d9-818d-45e6-8efb-b1de59079a1c",
1239
+ "link": "https://file.sls.epilot.io/v1/files/public/links/3ef5c6d9-818d-45e6-8efb-b1de59079a1c/invoice.pdf",
1240
+ "last_accessed_at": "2024-01-15T10:30:00Z"
1241
+ }
1242
+ ]
1243
+ }
1244
+ }
1245
+ }
1246
+ },
1247
+ "501": {
1248
+ "description": "Not implemented",
1249
+ "content": {
1250
+ "application/json": {
1251
+ "schema": {
1252
+ "$ref": "#/components/schemas/ErrorObject"
1253
+ },
1254
+ "example": {
1255
+ "status": 501,
1256
+ "error": "Not Implemented"
899
1257
  }
900
1258
  }
901
1259
  }
@@ -911,41 +1269,69 @@
911
1269
  "tags": [
912
1270
  "Public Links"
913
1271
  ],
914
- "description": "Redirects to a accessible signed url for the respective file associated to the public link",
1272
+ "description": "Access a file via its public link.\n\n**No authentication required.** This endpoint redirects to a signed S3 URL for downloading the file.\n\nThe filename in the URL is for user-friendliness and SEO; the actual file is identified by the link ID.\n",
915
1273
  "parameters": [
916
1274
  {
917
1275
  "name": "id",
918
1276
  "in": "path",
919
1277
  "required": true,
1278
+ "description": "The UUID of the public link (not the file entity ID)",
920
1279
  "schema": {
921
- "type": "string",
922
- "description": "Id of the publicly generated link",
923
- "example": "13d22918-36bd-4227-9ad4-2cb978788c8d"
924
- }
1280
+ "type": "string"
1281
+ },
1282
+ "example": "13d22918-36bd-4227-9ad4-2cb978788c8d"
925
1283
  },
926
1284
  {
927
1285
  "name": "filename",
928
1286
  "in": "path",
929
1287
  "required": true,
1288
+ "description": "The filename (for user-friendly URLs)",
930
1289
  "schema": {
931
- "type": "string",
932
- "description": "Name of the file",
933
- "example": "invoice-2023-12.pdf"
934
- }
1290
+ "type": "string"
1291
+ },
1292
+ "example": "invoice-2023-12.pdf"
935
1293
  },
936
1294
  {
937
1295
  "name": "hash",
938
1296
  "in": "query",
939
1297
  "required": false,
1298
+ "description": "Optional cache-busting hash to force re-download",
940
1299
  "schema": {
941
- "type": "string",
942
- "description": "An optional cache-busting hash for the file"
943
- }
1300
+ "type": "string"
1301
+ },
1302
+ "example": "abc123"
944
1303
  }
945
1304
  ],
946
1305
  "responses": {
947
1306
  "302": {
948
- "description": "Redirect to signed URL where the caller can access the file"
1307
+ "description": "Redirect to a signed S3 URL for downloading the file",
1308
+ "headers": {
1309
+ "Location": {
1310
+ "description": "The signed S3 URL to download the file",
1311
+ "schema": {
1312
+ "type": "string",
1313
+ "format": "uri"
1314
+ },
1315
+ "example": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/document.pdf?X-Amz-..."
1316
+ }
1317
+ }
1318
+ },
1319
+ "404": {
1320
+ "description": "Public link not found or has been revoked",
1321
+ "content": {
1322
+ "application/json": {
1323
+ "schema": {
1324
+ "$ref": "#/components/schemas/ErrorObject"
1325
+ },
1326
+ "example": {
1327
+ "status": 404,
1328
+ "error": "Public link not found"
1329
+ }
1330
+ }
1331
+ }
1332
+ },
1333
+ "500": {
1334
+ "$ref": "#/components/responses/InternalServerError"
949
1335
  }
950
1336
  }
951
1337
  }
@@ -954,18 +1340,18 @@
954
1340
  "delete": {
955
1341
  "operationId": "revokePublicLink",
956
1342
  "summary": "revokePublicLink",
957
- "description": "Not yet implemented; This operation would revoke a given public link by ID",
1343
+ "description": "**Not yet implemented.**\n\nThis endpoint will revoke a public link, making the file inaccessible via that link.\n",
958
1344
  "x-not-implemented": true,
959
1345
  "parameters": [
960
1346
  {
961
1347
  "name": "id",
962
1348
  "in": "path",
963
1349
  "required": true,
1350
+ "description": "The UUID of the public link to revoke",
964
1351
  "schema": {
965
- "type": "string",
966
- "description": "Id of the publicly generated link",
967
- "example": "13d22918-36bd-4227-9ad4-2cb978788c8d"
968
- }
1352
+ "type": "string"
1353
+ },
1354
+ "example": "13d22918-36bd-4227-9ad4-2cb978788c8d"
969
1355
  }
970
1356
  ],
971
1357
  "tags": [
@@ -973,12 +1359,18 @@
973
1359
  ],
974
1360
  "responses": {
975
1361
  "204": {
976
- "description": "Revokes a public link successfully.",
1362
+ "description": "Public link revoked successfully"
1363
+ },
1364
+ "501": {
1365
+ "description": "Not implemented",
977
1366
  "content": {
978
1367
  "application/json": {
979
1368
  "schema": {
980
- "type": "string",
981
- "example": "https://file.sls.epilot.io/v1/files/public/links/3ef5c6d9-818d-45e6-8efb-b1de59079a1c"
1369
+ "$ref": "#/components/schemas/ErrorObject"
1370
+ },
1371
+ "example": {
1372
+ "status": 501,
1373
+ "error": "Not Implemented"
982
1374
  }
983
1375
  }
984
1376
  }
@@ -990,7 +1382,7 @@
990
1382
  "post": {
991
1383
  "operationId": "verifyCustomDownloadUrl",
992
1384
  "summary": "verifyCustomDownloadUrl",
993
- "description": "Verify a pre-signed custom download url for a file",
1385
+ "description": "Verify that a custom download URL is valid and has not expired.\n\nUse this endpoint to validate custom download URLs before redirecting users.\nCustom download URLs include a signature and expiration time for security.\n",
994
1386
  "tags": [
995
1387
  "File"
996
1388
  ],
@@ -999,25 +1391,54 @@
999
1391
  "application/json": {
1000
1392
  "schema": {
1001
1393
  "$ref": "#/components/schemas/VerifyCustomDownloadUrlPayload"
1394
+ },
1395
+ "examples": {
1396
+ "Verify URL": {
1397
+ "value": {
1398
+ "custom_download_url": "https://some-api-url.com?file_id=123&expires_at=1699273500029&signature=abcdefg"
1399
+ }
1400
+ }
1002
1401
  }
1003
1402
  }
1004
1403
  }
1005
1404
  },
1006
1405
  "responses": {
1007
1406
  "200": {
1008
- "description": "Download Url matches signature and has not expired",
1407
+ "description": "Verification result",
1009
1408
  "content": {
1010
1409
  "application/json": {
1011
1410
  "schema": {
1012
1411
  "type": "object",
1013
1412
  "properties": {
1014
1413
  "valid": {
1015
- "type": "boolean"
1414
+ "type": "boolean",
1415
+ "description": "Whether the URL is valid and not expired"
1416
+ }
1417
+ }
1418
+ },
1419
+ "examples": {
1420
+ "Valid URL": {
1421
+ "value": {
1422
+ "valid": true
1423
+ }
1424
+ },
1425
+ "Invalid URL": {
1426
+ "value": {
1427
+ "valid": false
1016
1428
  }
1017
1429
  }
1018
1430
  }
1019
1431
  }
1020
1432
  }
1433
+ },
1434
+ "400": {
1435
+ "$ref": "#/components/responses/BadRequestError"
1436
+ },
1437
+ "401": {
1438
+ "$ref": "#/components/responses/UnauthorizedError"
1439
+ },
1440
+ "500": {
1441
+ "$ref": "#/components/responses/InternalServerError"
1021
1442
  }
1022
1443
  }
1023
1444
  }
@@ -1027,7 +1448,7 @@
1027
1448
  "operationId": "uploadFilePublic",
1028
1449
  "summary": "uploadFilePublic",
1029
1450
  "security": [],
1030
- "description": "Create pre-signed S3 URL to upload a file to keep temporarily (one week).\n\nUse the saveFileV2 operation to store file file permanently.\n",
1451
+ "description": "Create a pre-signed S3 URL for uploading a file without authentication.\n\n**No authentication required.** This endpoint is intended for public-facing forms and journeys\nwhere end-users need to upload files without logging in.\n\nThe uploaded file is stored temporarily (one week). Use `saveFileV2` with proper authentication\nto store the file permanently.\n\n**Security note:** Files uploaded via this endpoint are temporary and require authenticated\naccess to be saved permanently.\n",
1031
1452
  "tags": [
1032
1453
  "File"
1033
1454
  ],
@@ -1038,7 +1459,7 @@
1038
1459
  "$ref": "#/components/schemas/UploadFilePayload"
1039
1460
  },
1040
1461
  "examples": {
1041
- "Upload an image file": {
1462
+ "Upload an image": {
1042
1463
  "description": "Upload an image file",
1043
1464
  "value": {
1044
1465
  "filename": "image.png",
@@ -1046,7 +1467,7 @@
1046
1467
  }
1047
1468
  },
1048
1469
  "Upload a document": {
1049
- "description": "Upload an image file",
1470
+ "description": "Upload a PDF document",
1050
1471
  "value": {
1051
1472
  "filename": "document.pdf",
1052
1473
  "mime_type": "application/pdf"
@@ -1058,7 +1479,7 @@
1058
1479
  },
1059
1480
  "responses": {
1060
1481
  "201": {
1061
- "description": "Pre-signed URL for POST / PUT upload",
1482
+ "description": "Pre-signed URL for uploading the file",
1062
1483
  "content": {
1063
1484
  "application/json": {
1064
1485
  "schema": {
@@ -1069,6 +1490,9 @@
1069
1490
  {
1070
1491
  "$ref": "#/components/schemas/S3Ref"
1071
1492
  },
1493
+ {
1494
+ "description": "S3 reference to use when saving the file permanently"
1495
+ },
1072
1496
  {
1073
1497
  "example": {
1074
1498
  "bucket": "epilot-prod-user-content",
@@ -1080,16 +1504,24 @@
1080
1504
  "upload_url": {
1081
1505
  "type": "string",
1082
1506
  "format": "url",
1507
+ "description": "Pre-signed URL for uploading the file via PUT request",
1083
1508
  "example": "https://epilot-prod-user-content.s3.eu-central-1.amazonaws.com/123/temp/4d689aeb-1497-4410-a9fe-b36ca9ac4389/document.pdf?AWSParams=123"
1084
1509
  },
1085
1510
  "error": {
1086
1511
  "type": "string",
1512
+ "description": "Error message if the upload preparation failed",
1087
1513
  "example": "File entity not found"
1088
1514
  }
1089
1515
  }
1090
1516
  }
1091
1517
  }
1092
1518
  }
1519
+ },
1520
+ "400": {
1521
+ "$ref": "#/components/responses/BadRequestError"
1522
+ },
1523
+ "500": {
1524
+ "$ref": "#/components/responses/InternalServerError"
1093
1525
  }
1094
1526
  }
1095
1527
  }
@@ -1098,7 +1530,7 @@
1098
1530
  "get": {
1099
1531
  "operationId": "getUserSchemaFileCollections",
1100
1532
  "summary": "getUserSchemaFileCollections",
1101
- "description": "Gets a list of file collections for the current user and schema",
1533
+ "description": "Get all file collections for the current user within a specific schema.\n\nCollections help organize files into logical groups (e.g., \"Contracts\", \"Invoices\").\nUser collections are private to the creating user.\n",
1102
1534
  "tags": [
1103
1535
  "File Collections"
1104
1536
  ],
@@ -1107,11 +1539,11 @@
1107
1539
  "name": "slug",
1108
1540
  "in": "path",
1109
1541
  "required": true,
1110
- "description": "The schema slug (e.g., order, opportunity)",
1542
+ "description": "The entity schema slug (e.g., order, opportunity, contact)",
1111
1543
  "schema": {
1112
- "type": "string",
1113
- "example": "opportunity"
1114
- }
1544
+ "type": "string"
1545
+ },
1546
+ "example": "opportunity"
1115
1547
  }
1116
1548
  ],
1117
1549
  "responses": {
@@ -1124,16 +1556,34 @@
1124
1556
  "items": {
1125
1557
  "$ref": "#/components/schemas/FileCollectionItem"
1126
1558
  }
1127
- }
1559
+ },
1560
+ "example": [
1561
+ {
1562
+ "slug": "_system_files_collection_3fa85f64-5717-4562-b3fc-2c963f66afa6_10234:documents",
1563
+ "name": "Documents",
1564
+ "id": "ef7d985c-2385-44f4-9c71-ae06a52264f8",
1565
+ "parents": [],
1566
+ "starred": false,
1567
+ "order": 0,
1568
+ "created_at": "2024-01-01T12:00:00Z",
1569
+ "updated_at": "2024-01-02T12:00:00Z"
1570
+ }
1571
+ ]
1128
1572
  }
1129
1573
  }
1574
+ },
1575
+ "401": {
1576
+ "$ref": "#/components/responses/UnauthorizedError"
1577
+ },
1578
+ "500": {
1579
+ "$ref": "#/components/responses/InternalServerError"
1130
1580
  }
1131
1581
  }
1132
1582
  },
1133
1583
  "post": {
1134
1584
  "operationId": "createUserSchemaFileCollection",
1135
1585
  "summary": "createUserSchemaFileCollection",
1136
- "description": "Creates a new file collection for the current user and schema",
1586
+ "description": "Create a new file collection for the current user within a specific schema.\n\nThe collection will be private to the creating user and associated with the specified schema.\n",
1137
1587
  "tags": [
1138
1588
  "File Collections"
1139
1589
  ],
@@ -1142,11 +1592,11 @@
1142
1592
  "name": "slug",
1143
1593
  "in": "path",
1144
1594
  "required": true,
1145
- "description": "The schema slug (e.g., order, opportunity)",
1595
+ "description": "The entity schema slug (e.g., order, opportunity, contact)",
1146
1596
  "schema": {
1147
- "type": "string",
1148
- "example": "opportunity"
1149
- }
1597
+ "type": "string"
1598
+ },
1599
+ "example": "opportunity"
1150
1600
  }
1151
1601
  ],
1152
1602
  "requestBody": {
@@ -1155,6 +1605,22 @@
1155
1605
  "application/json": {
1156
1606
  "schema": {
1157
1607
  "$ref": "#/components/schemas/FileCollectionCreateRequest"
1608
+ },
1609
+ "examples": {
1610
+ "Create collection": {
1611
+ "value": {
1612
+ "name": "Contracts",
1613
+ "starred": false
1614
+ }
1615
+ },
1616
+ "Create nested collection": {
1617
+ "value": {
1618
+ "name": "2024 Contracts",
1619
+ "parents": [
1620
+ "_system_files_collection_3fa85f64-5717-4562-b3fc-2c963f66afa6_10234:contracts"
1621
+ ]
1622
+ }
1623
+ }
1158
1624
  }
1159
1625
  }
1160
1626
  }
@@ -1169,6 +1635,15 @@
1169
1635
  }
1170
1636
  }
1171
1637
  }
1638
+ },
1639
+ "400": {
1640
+ "$ref": "#/components/responses/BadRequestError"
1641
+ },
1642
+ "401": {
1643
+ "$ref": "#/components/responses/UnauthorizedError"
1644
+ },
1645
+ "500": {
1646
+ "$ref": "#/components/responses/InternalServerError"
1172
1647
  }
1173
1648
  }
1174
1649
  }
@@ -1177,7 +1652,7 @@
1177
1652
  "put": {
1178
1653
  "operationId": "updateUserSchemaFileCollection",
1179
1654
  "summary": "updateUserSchemaFileCollection",
1180
- "description": "Updates a file collection for the current user and schema",
1655
+ "description": "Update an existing file collection.\n\nYou can update the name, parent relationships, starred status, and enabled locations/purposes.\n",
1181
1656
  "tags": [
1182
1657
  "File Collections"
1183
1658
  ],
@@ -1186,21 +1661,21 @@
1186
1661
  "name": "slug",
1187
1662
  "in": "path",
1188
1663
  "required": true,
1189
- "description": "The schema slug (e.g., order, opportunity)",
1664
+ "description": "The entity schema slug (e.g., order, opportunity)",
1190
1665
  "schema": {
1191
- "type": "string",
1192
- "example": "opportunity"
1193
- }
1666
+ "type": "string"
1667
+ },
1668
+ "example": "opportunity"
1194
1669
  },
1195
1670
  {
1196
1671
  "name": "collectionSlug",
1197
1672
  "in": "path",
1198
1673
  "required": true,
1199
- "description": "The slug identifier for the collection",
1674
+ "description": "The collection slug identifier",
1200
1675
  "schema": {
1201
- "type": "string",
1202
- "example": "documents"
1203
- }
1676
+ "type": "string"
1677
+ },
1678
+ "example": "documents"
1204
1679
  }
1205
1680
  ],
1206
1681
  "requestBody": {
@@ -1209,6 +1684,18 @@
1209
1684
  "application/json": {
1210
1685
  "schema": {
1211
1686
  "$ref": "#/components/schemas/FileCollectionAttributes"
1687
+ },
1688
+ "examples": {
1689
+ "Rename collection": {
1690
+ "value": {
1691
+ "name": "Important Documents"
1692
+ }
1693
+ },
1694
+ "Star collection": {
1695
+ "value": {
1696
+ "starred": true
1697
+ }
1698
+ }
1212
1699
  }
1213
1700
  }
1214
1701
  }
@@ -1224,15 +1711,24 @@
1224
1711
  }
1225
1712
  }
1226
1713
  },
1714
+ "400": {
1715
+ "$ref": "#/components/responses/BadRequestError"
1716
+ },
1717
+ "401": {
1718
+ "$ref": "#/components/responses/UnauthorizedError"
1719
+ },
1227
1720
  "404": {
1228
1721
  "$ref": "#/components/responses/NotFoundError"
1722
+ },
1723
+ "500": {
1724
+ "$ref": "#/components/responses/InternalServerError"
1229
1725
  }
1230
1726
  }
1231
1727
  },
1232
1728
  "delete": {
1233
1729
  "operationId": "deleteUserSchemaFileCollection",
1234
1730
  "summary": "deleteUserSchemaFileCollection",
1235
- "description": "Deletes a file collection for the current user and schema",
1731
+ "description": "Delete a file collection.\n\n**Note:** Deleting a collection does not delete the files within it.\nFiles will remain but will no longer be associated with this collection.\n",
1236
1732
  "tags": [
1237
1733
  "File Collections"
1238
1734
  ],
@@ -1241,29 +1737,35 @@
1241
1737
  "name": "slug",
1242
1738
  "in": "path",
1243
1739
  "required": true,
1244
- "description": "The schema slug (e.g., order, opportunity)",
1740
+ "description": "The entity schema slug (e.g., order, opportunity)",
1245
1741
  "schema": {
1246
- "type": "string",
1247
- "example": "opportunity"
1248
- }
1742
+ "type": "string"
1743
+ },
1744
+ "example": "opportunity"
1249
1745
  },
1250
1746
  {
1251
1747
  "name": "collectionSlug",
1252
1748
  "in": "path",
1253
1749
  "required": true,
1254
- "description": "The slug identifier for the collection",
1750
+ "description": "The collection slug identifier",
1255
1751
  "schema": {
1256
- "type": "string",
1257
- "example": "documents"
1258
- }
1752
+ "type": "string"
1753
+ },
1754
+ "example": "documents"
1259
1755
  }
1260
1756
  ],
1261
1757
  "responses": {
1262
1758
  "200": {
1263
1759
  "description": "File collection deleted successfully"
1264
1760
  },
1761
+ "401": {
1762
+ "$ref": "#/components/responses/UnauthorizedError"
1763
+ },
1265
1764
  "404": {
1266
1765
  "$ref": "#/components/responses/NotFoundError"
1766
+ },
1767
+ "500": {
1768
+ "$ref": "#/components/responses/InternalServerError"
1267
1769
  }
1268
1770
  }
1269
1771
  }
@@ -1272,7 +1774,7 @@
1272
1774
  "get": {
1273
1775
  "operationId": "getFilesInCollection",
1274
1776
  "summary": "getFilesInCollection",
1275
- "description": "Gets all files within a specific collection for an entity (uses schema-based taxonomy derived from entity)",
1777
+ "description": "Get all files within a specific collection for an entity.\n\nThe schema is automatically derived from the entity. This endpoint requires\nview permission on the parent entity to access its files.\n",
1276
1778
  "tags": [
1277
1779
  "File Collections"
1278
1780
  ],
@@ -1284,11 +1786,11 @@
1284
1786
  "name": "collectionSlug",
1285
1787
  "in": "path",
1286
1788
  "required": true,
1287
- "description": "The slug identifier for the collection",
1789
+ "description": "The collection slug identifier",
1288
1790
  "schema": {
1289
- "type": "string",
1290
- "example": "documents"
1291
- }
1791
+ "type": "string"
1792
+ },
1793
+ "example": "documents"
1292
1794
  }
1293
1795
  ],
1294
1796
  "responses": {
@@ -1305,18 +1807,19 @@
1305
1807
  }
1306
1808
  }
1307
1809
  },
1810
+ "401": {
1811
+ "$ref": "#/components/responses/UnauthorizedError"
1812
+ },
1308
1813
  "403": {
1309
- "description": "User must have permission to view this entity to access its files",
1814
+ "description": "Insufficient permissions to view the entity's files",
1310
1815
  "content": {
1311
1816
  "application/json": {
1312
1817
  "schema": {
1313
- "type": "object",
1314
- "properties": {
1315
- "error": {
1316
- "type": "string",
1317
- "example": "User must have permission to view this entity to access its files"
1318
- }
1319
- }
1818
+ "$ref": "#/components/schemas/ErrorObject"
1819
+ },
1820
+ "example": {
1821
+ "status": 403,
1822
+ "error": "User must have permission to view this entity to access its files"
1320
1823
  }
1321
1824
  }
1322
1825
  }
@@ -1326,16 +1829,17 @@
1326
1829
  "content": {
1327
1830
  "application/json": {
1328
1831
  "schema": {
1329
- "type": "object",
1330
- "properties": {
1331
- "error": {
1332
- "type": "string",
1333
- "example": "Entity not found"
1334
- }
1335
- }
1832
+ "$ref": "#/components/schemas/ErrorObject"
1833
+ },
1834
+ "example": {
1835
+ "status": 404,
1836
+ "error": "Entity not found"
1336
1837
  }
1337
1838
  }
1338
1839
  }
1840
+ },
1841
+ "500": {
1842
+ "$ref": "#/components/responses/InternalServerError"
1339
1843
  }
1340
1844
  }
1341
1845
  }
@@ -1344,7 +1848,7 @@
1344
1848
  "get": {
1345
1849
  "operationId": "getGlobalFileCollections",
1346
1850
  "summary": "getGlobalFileCollections",
1347
- "description": "Gets all global file collections for a specific schema",
1851
+ "description": "Get all global file collections for a specific schema.\n\nGlobal collections are shared across all users in the organization for the specified schema.\nUnlike user collections, these are visible to everyone with access to entities of that schema.\n",
1348
1852
  "tags": [
1349
1853
  "File Collections"
1350
1854
  ],
@@ -1353,11 +1857,11 @@
1353
1857
  "name": "schemaSlug",
1354
1858
  "in": "path",
1355
1859
  "required": true,
1356
- "description": "The schema slug (e.g., order, opportunity)",
1860
+ "description": "The entity schema slug (e.g., order, opportunity, contact)",
1357
1861
  "schema": {
1358
- "type": "string",
1359
- "example": "order"
1360
- }
1862
+ "type": "string"
1863
+ },
1864
+ "example": "order"
1361
1865
  }
1362
1866
  ],
1363
1867
  "responses": {
@@ -1370,9 +1874,27 @@
1370
1874
  "items": {
1371
1875
  "$ref": "#/components/schemas/FileCollectionItem"
1372
1876
  }
1373
- }
1877
+ },
1878
+ "example": [
1879
+ {
1880
+ "slug": "_system_files_collection_schema_order:templates",
1881
+ "name": "Templates",
1882
+ "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
1883
+ "parents": [],
1884
+ "starred": false,
1885
+ "order": 0,
1886
+ "created_at": "2024-01-01T12:00:00Z",
1887
+ "updated_at": "2024-01-01T12:00:00Z"
1888
+ }
1889
+ ]
1374
1890
  }
1375
1891
  }
1892
+ },
1893
+ "401": {
1894
+ "$ref": "#/components/responses/UnauthorizedError"
1895
+ },
1896
+ "500": {
1897
+ "$ref": "#/components/responses/InternalServerError"
1376
1898
  }
1377
1899
  }
1378
1900
  }
@@ -1383,14 +1905,14 @@
1383
1905
  "EpilotAuth": {
1384
1906
  "type": "http",
1385
1907
  "scheme": "bearer",
1386
- "description": "Authorization header with epilot OAuth2 bearer token",
1387
- "bearerFormat": "JWT"
1908
+ "bearerFormat": "JWT",
1909
+ "description": "Bearer token authentication using epilot OAuth2 JWT tokens.\n\n**When to use:** Server-to-server integrations, API clients, and programmatic access.\n\n**How to obtain a token:**\n1. Use the epilot Auth API to authenticate\n2. Include the token in the `Authorization` header: `Authorization: Bearer <token>`\n\n**Example:**\n```\nAuthorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\n```\n\n**Token contents:** The JWT contains user identity, organization ID, and permissions.\n"
1388
1910
  },
1389
1911
  "CookieAuth": {
1390
1912
  "type": "apiKey",
1391
1913
  "in": "cookie",
1392
1914
  "name": "token",
1393
- "description": "Cookie with epilot OAuth2 token"
1915
+ "description": "Cookie-based session authentication for browser applications.\n\n**When to use:** Browser-based applications that need to:\n- Embed file previews directly in `<img>` tags\n- Download files without JavaScript token handling\n- Access files from HTML elements that cannot set custom headers\n\n**How to establish a session:**\n1. Obtain a Bearer token via EpilotAuth\n2. Call `GET /v1/files/session` with the Bearer token\n3. The server sets an HTTP-only cookie named `token`\n4. Subsequent requests automatically include the cookie\n\n**Security note:** The cookie is HTTP-only and secure, protecting against XSS attacks.\n"
1394
1916
  }
1395
1917
  },
1396
1918
  "schemas": {
@@ -1726,6 +2248,50 @@
1726
2248
  }
1727
2249
  ]
1728
2250
  },
2251
+ "BatchSaveFileVersionPayload": {
2252
+ "type": "object",
2253
+ "description": "Payload for batch version save. Only s3ref payloads are supported.",
2254
+ "properties": {
2255
+ "_id": {
2256
+ "allOf": [
2257
+ {
2258
+ "$ref": "#/components/schemas/FileEntityId"
2259
+ },
2260
+ {
2261
+ "description": "Target file entity to add version to"
2262
+ }
2263
+ ]
2264
+ },
2265
+ "file_entity_id": {
2266
+ "type": "string",
2267
+ "description": "Deprecated, use _id instead",
2268
+ "deprecated": true
2269
+ },
2270
+ "filename": {
2271
+ "type": "string",
2272
+ "example": "document.pdf"
2273
+ },
2274
+ "mime_type": {
2275
+ "type": "string",
2276
+ "example": "application/pdf"
2277
+ },
2278
+ "access_control": {
2279
+ "type": "string",
2280
+ "default": "private",
2281
+ "enum": [
2282
+ "private",
2283
+ "public-read"
2284
+ ]
2285
+ },
2286
+ "s3ref": {
2287
+ "$ref": "#/components/schemas/S3Ref"
2288
+ }
2289
+ },
2290
+ "required": [
2291
+ "s3ref"
2292
+ ],
2293
+ "additionalProperties": false
2294
+ },
1729
2295
  "UploadFilePayload": {
1730
2296
  "type": "object",
1731
2297
  "properties": {
@@ -2024,8 +2590,8 @@
2024
2590
  "type": "string"
2025
2591
  },
2026
2592
  "example": [
2027
- "purpose:9eefcb98-93cf-4c5b-a040-f1d26d57c177",
2028
- "purpose:5c544c09-a691-43ed-a7fa-0a8b44b5b161"
2593
+ "9eefcb98-93cf-4c5b-a040-f1d26d57c177",
2594
+ "5c544c09-a691-43ed-a7fa-0a8b44b5b161"
2029
2595
  ]
2030
2596
  },
2031
2597
  "created_at": {
@@ -2153,9 +2719,79 @@
2153
2719
  "type": "boolean",
2154
2720
  "default": true
2155
2721
  }
2722
+ },
2723
+ "VersionOnlyQueryParam": {
2724
+ "name": "version_only",
2725
+ "in": "query",
2726
+ "description": "When true, only adds a new file version and updates the entity's\ns3ref to point to the new version, without overwriting the entity's\nexisting top-level metadata. The entity's filename, type, and other\nfields are preserved as-is. The new version entry in the versions\narray will contain the file-level metadata (filename, mime_type, etc).\nOnly applies when updating an existing entity (_id or file_entity_id is set).\n",
2727
+ "required": false,
2728
+ "schema": {
2729
+ "type": "boolean",
2730
+ "default": false
2731
+ }
2156
2732
  }
2157
2733
  },
2158
2734
  "responses": {
2735
+ "BadRequestError": {
2736
+ "description": "Invalid request parameters or payload",
2737
+ "content": {
2738
+ "application/json": {
2739
+ "schema": {
2740
+ "allOf": [
2741
+ {
2742
+ "$ref": "#/components/schemas/ErrorObject"
2743
+ },
2744
+ {
2745
+ "example": {
2746
+ "status": 400,
2747
+ "error": "Bad Request: filename is required"
2748
+ }
2749
+ }
2750
+ ]
2751
+ }
2752
+ }
2753
+ }
2754
+ },
2755
+ "UnauthorizedError": {
2756
+ "description": "Authentication required or invalid credentials",
2757
+ "content": {
2758
+ "application/json": {
2759
+ "schema": {
2760
+ "allOf": [
2761
+ {
2762
+ "$ref": "#/components/schemas/ErrorObject"
2763
+ },
2764
+ {
2765
+ "example": {
2766
+ "status": 401,
2767
+ "error": "Unauthorized: Invalid or expired token"
2768
+ }
2769
+ }
2770
+ ]
2771
+ }
2772
+ }
2773
+ }
2774
+ },
2775
+ "ForbiddenError": {
2776
+ "description": "Insufficient permissions to access the resource",
2777
+ "content": {
2778
+ "application/json": {
2779
+ "schema": {
2780
+ "allOf": [
2781
+ {
2782
+ "$ref": "#/components/schemas/ErrorObject"
2783
+ },
2784
+ {
2785
+ "example": {
2786
+ "status": 403,
2787
+ "error": "Forbidden: You do not have permission to access this file"
2788
+ }
2789
+ }
2790
+ ]
2791
+ }
2792
+ }
2793
+ }
2794
+ },
2159
2795
  "NotFoundError": {
2160
2796
  "description": "The requested resource was not found",
2161
2797
  "content": {
@@ -2168,7 +2804,27 @@
2168
2804
  {
2169
2805
  "example": {
2170
2806
  "status": 404,
2171
- "error": "Not Found"
2807
+ "error": "Not Found: File entity not found"
2808
+ }
2809
+ }
2810
+ ]
2811
+ }
2812
+ }
2813
+ }
2814
+ },
2815
+ "InternalServerError": {
2816
+ "description": "An unexpected error occurred on the server",
2817
+ "content": {
2818
+ "application/json": {
2819
+ "schema": {
2820
+ "allOf": [
2821
+ {
2822
+ "$ref": "#/components/schemas/ErrorObject"
2823
+ },
2824
+ {
2825
+ "example": {
2826
+ "status": 500,
2827
+ "error": "Internal Server Error"
2172
2828
  }
2173
2829
  }
2174
2830
  ]