> For the complete documentation index, see [llms.txt](https://developer.celigo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.celigo.com/api/api-reference/file-storage.md).

# File Storage

Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.

### Storage item schema

## The StorageItem object

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"components":{"schemas":{"StorageItem":{"type":"object","description":"A file or folder stored in Celigo Storage.","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the item. Pass it to download, move, copy,\nreplace, rename, or delete the item; folders and files share one\nID space."},"type":{"type":"string","enum":["file","folder"],"readOnly":true,"description":"Distinguishes a content-bearing file from an organizational folder.\nFixed when the item is created and never changes."},"name":{"type":"string","maxLength":256,"description":"Display name, including the extension for files (for example\n`orders.csv`). Two items with the same name can coexist in one\nfolder — the name is not a unique key."},"_parentId":{"type":["string","null"],"format":"objectId","readOnly":true,"description":"Folder that contains this item. Null when the item sits at the\naccount root."},"__ancestorIds":{"type":"array","readOnly":true,"description":"Folder IDs from the root down to the immediate parent, in order.\nEmpty for root-level items. Rewritten automatically when the item\nor any ancestor folder is moved.","items":{"type":"string","format":"objectId"}},"size":{"type":"integer","format":"int64","readOnly":true,"description":"File size in bytes. Present when type is file; folders carry no\nsize. While an upload is pending this reflects the reserved quota,\nand is reconciled to the actual byte count once the upload finalizes."},"mimeType":{"type":"string","maxLength":256,"readOnly":true,"description":"Media type recorded at upload time, used to set the download\nContent-Type. Present when type is file; absent for folders and for\nfiles uploaded without a declared type."},"description":{"type":"string","maxLength":1000,"description":"Optional caller-supplied note describing the item."},"status":{"type":"string","enum":["pending","active"],"readOnly":true,"description":"Upload lifecycle state. A file is created pending at initiate-upload\nand flips to active once S3 confirms the bytes; folders are created\nactive."},"isSystem":{"type":"boolean","readOnly":true,"description":"When true, the platform created the item (for example a system or\nintegration folder) and protects it — move, content replace, copy,\ndelete, and purge are rejected with `STORAGE_SYSTEM_ITEM_PROTECTED`."},"deletedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was soft-deleted to the recycle bin. Present\nonly for recycle-bin items; the item is permanently purged 30 days\nafter this time unless restored."},"deletedBy":{"type":"string","readOnly":true,"description":"Who soft-deleted the item — a user ID for a direct delete, or\n`cascadeDelete` for a descendant removed when its parent folder was\ndeleted. Present only for recycle-bin items. Cascade-deleted items\ncan be recovered only by restoring the folder that was deleted\ndirectly."},"location":{"type":"object","readOnly":true,"description":"Folder that contains this search hit. Present only in search-mode\nresults from `GET /v1/storage/items` (when the `search` query\nparameter is set).","properties":{"_id":{"type":"string","format":"objectId","description":"ID of the containing folder."},"name":{"type":"string","description":"Name of the containing folder."}}},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the most recent metadata change. Updated on rename,\nmove, and content replace, and when the folder's direct children\nchange."}},"required":["_id","type","name","status","isSystem","createdAt","lastModified"]}}}}
```

## Initiate file upload

> Starts one or more file uploads. For each file, reserves quota, creates a\
> pending item, and returns presigned S3 URLs to transfer the bytes to:\
> a single PUT URL for files up to 5 GB, or a multipart \`uploadId\`,\
> \`partUrls\`, and \`completeUrl\` for larger files. Upload the bytes directly\
> to those URLs, then the item flips to active once S3 confirms it — no\
> further API call is needed. URLs expire after one hour; reissue them with\
> \`POST /v1/storage/files/refresh-urls\`. Each file is validated\
> independently, so the response can mix per-file successes and failures\
> while the request itself returns 200.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"InitiateUploadRequest":{"type":"object","description":"Reserves quota and requests presigned upload URLs for one or more files.","required":["files"],"properties":{"_parentId":{"type":["string","null"],"format":"objectId","description":"Folder to create the files in. Omit or pass null to upload to the\naccount root. Must reference an existing active folder."},"files":{"type":"array","minItems":1,"description":"Files to initiate. Each entry is validated and reserved independently.","items":{"$ref":"#/components/schemas/UploadRequestFile"}}}},"UploadRequestFile":{"type":"object","description":"One file to upload within an initiate-upload request.","required":["name","uploadType"],"properties":{"_id":{"type":"string","format":"objectId","description":"Existing pending item to continue. Set it only to request the next\nbatch of part URLs for an in-progress multipart upload, alongside\n`uploadId` and `issuedPartsCount`. Omit for a new upload."},"name":{"type":"string","maxLength":256,"description":"File name, including extension. Duplicate names in a folder are allowed."},"mimeType":{"type":"string","maxLength":256,"description":"Media type to record for the file and serve as its download\nContent-Type. Optional; sniffed by callers from the file extension\nwhen omitted."},"size":{"type":"integer","format":"int64","minimum":0,"description":"Declared size in bytes. Used to reserve quota up front. When omitted,\nthe backend reserves a worst-case estimate (1 GB for single,\n`numParts` × 5 GB for multipart) and reconciles to the real size when\nthe upload finalizes."},"uploadType":{"type":"string","enum":["single","multipart"],"description":"How the file will be transferred. Use single for files up to 5 GB;\nuse multipart for larger files, which returns per-part URLs plus a\ncomplete URL."},"numParts":{"type":"integer","minimum":1,"description":"Total number of parts the file will be split into. Required when\nuploadType is multipart; the response returns presigned URLs for as\nmany parts as the part budget allows."},"uploadId":{"type":"string","description":"S3 multipart upload ID from a prior initiate response. Provide with\n`issuedPartsCount` (and `_id`) to resume and request the next batch\nof part URLs."},"issuedPartsCount":{"type":"integer","minimum":0,"description":"Number of part URLs already issued for this upload. Provide together\nwith `uploadId` to resume; the response continues numbering after\nthis value."}}},"InitiateUploadResponse":{"type":"object","description":"Per-file upload instructions, in the same order as the request.","required":["files"],"properties":{"files":{"type":"array","items":{"$ref":"#/components/schemas/UploadResult"}}}},"UploadResult":{"type":"object","description":"Outcome for one file in an upload response. On success, `statusCode` is\n200 and `body` carries the presigned-URL instructions; on failure,\n`statusCode` is a 4xx and `errors` explains why. Each file in a batch is\nvalidated independently, so a single response can mix successes and\nfailures.","required":["name","statusCode"],"properties":{"_id":{"type":"string","format":"objectId","description":"ID of the pending item this result refers to. Present once the item\nis created; absent when the file failed validation before creation.\nUse it to upload, refresh URLs, cancel, or download once active."},"name":{"type":"string","description":"File name echoed back from the request, to correlate results."},"statusCode":{"type":"integer","description":"Per-file result status, mirroring HTTP status semantics."},"body":{"$ref":"#/components/schemas/UploadBody"},"errors":{"type":"array","description":"Reasons the file was rejected. Present when statusCode is a 4xx.","items":{"$ref":"#/components/schemas/UploadError"}}}},"UploadBody":{"type":"object","description":"Presigned-URL instructions for one file. The fields present depend on\n`uploadType`: a single PUT returns one `uploadUrl`; a multipart upload\nreturns an `uploadId`, a batch of `partUrls`, and a `completeUrl`.","required":["uploadType"],"properties":{"uploadType":{"type":"string","enum":["single","multipart"],"description":"Transfer mechanism the caller must use for this file."},"uploadUrl":{"type":"string","format":"uri","description":"Presigned S3 URL to PUT the file's bytes to in a single request.\nPresent when uploadType is single. Expires after one hour; use\n`POST /v1/storage/files/refresh-urls` to reissue."},"uploadId":{"type":"string","description":"S3 multipart upload identifier. Present when uploadType is\nmultipart. Pass it to refresh-urls to fetch later part batches and\nto cancel the upload."},"partUrls":{"type":"array","description":"Presigned URLs for the next batch of parts. Present when uploadType\nis multipart. A request may return fewer parts than requested when\nthe account-wide part budget is constrained; fetch the remaining\nparts with refresh-urls.","items":{"$ref":"#/components/schemas/PartUrl"}},"completeUrl":{"type":"string","format":"uri","description":"Presigned URL to POST the ordered list of part numbers and ETags to,\nfinalizing the multipart upload. Present when uploadType is multipart."}}},"PartUrl":{"type":"object","description":"A presigned URL for uploading one part of a multipart upload.","required":["partNumber","url"],"properties":{"partNumber":{"type":"integer","minimum":1,"description":"1-based index of this part. Send it back as the S3 `partNumber`\nwhen uploading, and keep each part's returned `ETag` to finalize\nthe upload."},"url":{"type":"string","format":"uri","description":"Presigned S3 URL to PUT this part's bytes to."}}},"UploadError":{"type":"object","description":"A per-file failure within a batch upload response.","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable storage error code."},"message":{"type":"string","description":"Human-readable explanation of the failure."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/files/initiateUpload":{"post":{"summary":"Initiate file upload","description":"Starts one or more file uploads. For each file, reserves quota, creates a\npending item, and returns presigned S3 URLs to transfer the bytes to:\na single PUT URL for files up to 5 GB, or a multipart `uploadId`,\n`partUrls`, and `completeUrl` for larger files. Upload the bytes directly\nto those URLs, then the item flips to active once S3 confirms it — no\nfurther API call is needed. URLs expire after one hour; reissue them with\n`POST /v1/storage/files/refresh-urls`. Each file is validated\nindependently, so the response can mix per-file successes and failures\nwhile the request itself returns 200.","operationId":"initiateStorageUpload","tags":["File Storage"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadRequest"}}}},"responses":{"200":{"description":"Per-file upload instructions, in request order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateUploadResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Refresh upload URLs

> Reissues presigned upload URLs for pending uploads whose URLs have\
> expired (URLs last one hour). For a single PUT, returns a fresh upload\
> URL; for multipart, returns fresh URLs for the requested part numbers plus\
> the complete URL. Already-uploaded parts are preserved. Each item is\
> processed independently.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"RefreshUrlsRequest":{"type":"object","description":"Reissues presigned URLs for pending uploads whose URLs have expired.","required":["items"],"properties":{"items":{"type":"array","minItems":1,"description":"Pending uploads to refresh. Each is processed independently.","items":{"type":"object","required":["_id","uploadType"],"properties":{"_id":{"type":"string","format":"objectId","description":"Pending item to reissue URLs for."},"uploadType":{"type":"string","enum":["single","multipart"],"description":"Must match the upload type the item was initiated with."},"uploadId":{"type":"string","description":"S3 multipart upload ID. Required when uploadType is multipart."},"partNumbers":{"type":"array","description":"Part numbers to reissue URLs for. Required when uploadType is\nmultipart. Must continue sequentially after the last issued\nbatch. Already-uploaded parts are preserved.","items":{"type":"integer","minimum":1}}}}}}},"RefreshUrlsResponse":{"type":"object","description":"Per-item refreshed upload instructions.","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/UploadResult"}}}},"UploadResult":{"type":"object","description":"Outcome for one file in an upload response. On success, `statusCode` is\n200 and `body` carries the presigned-URL instructions; on failure,\n`statusCode` is a 4xx and `errors` explains why. Each file in a batch is\nvalidated independently, so a single response can mix successes and\nfailures.","required":["name","statusCode"],"properties":{"_id":{"type":"string","format":"objectId","description":"ID of the pending item this result refers to. Present once the item\nis created; absent when the file failed validation before creation.\nUse it to upload, refresh URLs, cancel, or download once active."},"name":{"type":"string","description":"File name echoed back from the request, to correlate results."},"statusCode":{"type":"integer","description":"Per-file result status, mirroring HTTP status semantics."},"body":{"$ref":"#/components/schemas/UploadBody"},"errors":{"type":"array","description":"Reasons the file was rejected. Present when statusCode is a 4xx.","items":{"$ref":"#/components/schemas/UploadError"}}}},"UploadBody":{"type":"object","description":"Presigned-URL instructions for one file. The fields present depend on\n`uploadType`: a single PUT returns one `uploadUrl`; a multipart upload\nreturns an `uploadId`, a batch of `partUrls`, and a `completeUrl`.","required":["uploadType"],"properties":{"uploadType":{"type":"string","enum":["single","multipart"],"description":"Transfer mechanism the caller must use for this file."},"uploadUrl":{"type":"string","format":"uri","description":"Presigned S3 URL to PUT the file's bytes to in a single request.\nPresent when uploadType is single. Expires after one hour; use\n`POST /v1/storage/files/refresh-urls` to reissue."},"uploadId":{"type":"string","description":"S3 multipart upload identifier. Present when uploadType is\nmultipart. Pass it to refresh-urls to fetch later part batches and\nto cancel the upload."},"partUrls":{"type":"array","description":"Presigned URLs for the next batch of parts. Present when uploadType\nis multipart. A request may return fewer parts than requested when\nthe account-wide part budget is constrained; fetch the remaining\nparts with refresh-urls.","items":{"$ref":"#/components/schemas/PartUrl"}},"completeUrl":{"type":"string","format":"uri","description":"Presigned URL to POST the ordered list of part numbers and ETags to,\nfinalizing the multipart upload. Present when uploadType is multipart."}}},"PartUrl":{"type":"object","description":"A presigned URL for uploading one part of a multipart upload.","required":["partNumber","url"],"properties":{"partNumber":{"type":"integer","minimum":1,"description":"1-based index of this part. Send it back as the S3 `partNumber`\nwhen uploading, and keep each part's returned `ETag` to finalize\nthe upload."},"url":{"type":"string","format":"uri","description":"Presigned S3 URL to PUT this part's bytes to."}}},"UploadError":{"type":"object","description":"A per-file failure within a batch upload response.","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable storage error code."},"message":{"type":"string","description":"Human-readable explanation of the failure."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/files/refresh-urls":{"post":{"summary":"Refresh upload URLs","description":"Reissues presigned upload URLs for pending uploads whose URLs have\nexpired (URLs last one hour). For a single PUT, returns a fresh upload\nURL; for multipart, returns fresh URLs for the requested part numbers plus\nthe complete URL. Already-uploaded parts are preserved. Each item is\nprocessed independently.","operationId":"refreshStorageUploadUrls","tags":["File Storage"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshUrlsRequest"}}}},"responses":{"200":{"description":"Per-item refreshed upload instructions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshUrlsResponse"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Cancel a multipart upload

> Aborts an in-progress multipart upload, discarding any uploaded parts and\
> releasing the reserved quota. Use this to abandon a multipart upload\
> started with \`POST /v1/storage/files/initiateUpload\`; single PUT uploads\
> do not need canceling. If the upload has in fact already completed in S3,\
> the item is activated instead and the request is rejected as not pending.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/storage/files/{_id}/cancel":{"post":{"summary":"Cancel a multipart upload","description":"Aborts an in-progress multipart upload, discarding any uploaded parts and\nreleasing the reserved quota. Use this to abandon a multipart upload\nstarted with `POST /v1/storage/files/initiateUpload`; single PUT uploads\ndo not need canceling. If the upload has in fact already completed in S3,\nthe item is activated instead and the request is rejected as not pending.","operationId":"cancelStorageUpload","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the pending multipart item to cancel.","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Multipart upload aborted and the pending item removed."},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get a file download URL

> Returns a short-lived presigned S3 URL for downloading a file's content,\
> along with how many seconds it stays valid. Fetch the bytes directly from\
> that URL — the content does not pass through this API. Files only; folders\
> have no content to download.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/storage/files/{_id}/download":{"get":{"summary":"Get a file download URL","description":"Returns a short-lived presigned S3 URL for downloading a file's content,\nalong with how many seconds it stays valid. Fetch the bytes directly from\nthat URL — the content does not pass through this API. Files only; folders\nhave no content to download.","operationId":"getStorageFileDownloadUrl","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the file to download.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"A presigned download URL and its lifetime.","content":{"application/json":{"schema":{"type":"object","required":["downloadUrl","expiresIn"],"properties":{"downloadUrl":{"type":"string","format":"uri","description":"Presigned S3 URL to GET the file's bytes from."},"expiresIn":{"type":"integer","description":"Seconds the URL stays valid from the time of this response."}}}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## List or search items

> Browse or search Celigo Storage. In list mode (no \`search\`), returns the\
> direct children of a folder — omit \`\_parentId\` for the account root — and\
> includes a \`breadcrumb\` of the path to that folder. In search mode (with\
> \`search\`), recursively matches item names across the whole account and\
> returns each hit's \`location\`. Results are paginated with the \`Link\`\
> response header.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"StorageItem":{"type":"object","description":"A file or folder stored in Celigo Storage.","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the item. Pass it to download, move, copy,\nreplace, rename, or delete the item; folders and files share one\nID space."},"type":{"type":"string","enum":["file","folder"],"readOnly":true,"description":"Distinguishes a content-bearing file from an organizational folder.\nFixed when the item is created and never changes."},"name":{"type":"string","maxLength":256,"description":"Display name, including the extension for files (for example\n`orders.csv`). Two items with the same name can coexist in one\nfolder — the name is not a unique key."},"_parentId":{"type":["string","null"],"format":"objectId","readOnly":true,"description":"Folder that contains this item. Null when the item sits at the\naccount root."},"__ancestorIds":{"type":"array","readOnly":true,"description":"Folder IDs from the root down to the immediate parent, in order.\nEmpty for root-level items. Rewritten automatically when the item\nor any ancestor folder is moved.","items":{"type":"string","format":"objectId"}},"size":{"type":"integer","format":"int64","readOnly":true,"description":"File size in bytes. Present when type is file; folders carry no\nsize. While an upload is pending this reflects the reserved quota,\nand is reconciled to the actual byte count once the upload finalizes."},"mimeType":{"type":"string","maxLength":256,"readOnly":true,"description":"Media type recorded at upload time, used to set the download\nContent-Type. Present when type is file; absent for folders and for\nfiles uploaded without a declared type."},"description":{"type":"string","maxLength":1000,"description":"Optional caller-supplied note describing the item."},"status":{"type":"string","enum":["pending","active"],"readOnly":true,"description":"Upload lifecycle state. A file is created pending at initiate-upload\nand flips to active once S3 confirms the bytes; folders are created\nactive."},"isSystem":{"type":"boolean","readOnly":true,"description":"When true, the platform created the item (for example a system or\nintegration folder) and protects it — move, content replace, copy,\ndelete, and purge are rejected with `STORAGE_SYSTEM_ITEM_PROTECTED`."},"deletedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was soft-deleted to the recycle bin. Present\nonly for recycle-bin items; the item is permanently purged 30 days\nafter this time unless restored."},"deletedBy":{"type":"string","readOnly":true,"description":"Who soft-deleted the item — a user ID for a direct delete, or\n`cascadeDelete` for a descendant removed when its parent folder was\ndeleted. Present only for recycle-bin items. Cascade-deleted items\ncan be recovered only by restoring the folder that was deleted\ndirectly."},"location":{"type":"object","readOnly":true,"description":"Folder that contains this search hit. Present only in search-mode\nresults from `GET /v1/storage/items` (when the `search` query\nparameter is set).","properties":{"_id":{"type":"string","format":"objectId","description":"ID of the containing folder."},"name":{"type":"string","description":"Name of the containing folder."}}},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the most recent metadata change. Updated on rename,\nmove, and content replace, and when the folder's direct children\nchange."}},"required":["_id","type","name","status","isSystem","createdAt","lastModified"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items":{"get":{"summary":"List or search items","description":"Browse or search Celigo Storage. In list mode (no `search`), returns the\ndirect children of a folder — omit `_parentId` for the account root — and\nincludes a `breadcrumb` of the path to that folder. In search mode (with\n`search`), recursively matches item names across the whole account and\nreturns each hit's `location`. Results are paginated with the `Link`\nresponse header.","operationId":"listStorageItems","tags":["File Storage"],"parameters":[{"name":"_parentId","in":"query","required":false,"description":"Folder whose direct children to list. Omit for the account root.\nIgnored in search mode.","schema":{"type":"string","format":"objectId"}},{"name":"search","in":"query","required":false,"description":"Recursive, case-insensitive substring match on item names across the\nwhole account. Switches the endpoint to search mode, where\n`_parentId` is ignored and each item carries its `location`. Matches\nnames only, not contents or descriptions.","schema":{"type":"string","minLength":2}},{"name":"type","in":"query","required":false,"description":"Restrict results to one item type.","schema":{"type":"string","enum":["file","folder"]}},{"name":"mimeType","in":"query","required":false,"description":"Restrict results to files of a single media type.","schema":{"type":"string"}},{"name":"sort_by","in":"query","required":false,"description":"Field to sort by.","schema":{"type":"string","enum":["name","lastModified"],"default":"name"}},{"name":"sort_order","in":"query","required":false,"description":"Sort direction.","schema":{"type":"string","enum":["asc","desc"],"default":"asc"}},{"name":"lastModified_gte","in":"query","required":false,"description":"Return only items modified at or after this time.","schema":{"type":"string","format":"date-time"}},{"name":"lastModified_lte","in":"query","required":false,"description":"Return only items modified at or before this time.","schema":{"type":"string","format":"date-time"}},{"name":"pageSize","in":"query","required":false,"description":"Maximum number of items to return per page.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1000}},{"name":"after","in":"query","required":false,"description":"Opaque cursor for the next page. Take it from the `Link` response\nheader's `rel=\"next\"` URL rather than constructing it. Cannot be\ncombined with `before`.","schema":{"type":"string"}},{"name":"before","in":"query","required":false,"description":"Opaque cursor for the previous page, taken from the `Link` header's\n`rel=\"prev\"` URL. Cannot be combined with `after`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Matching items. Includes `breadcrumb` in list mode and per-item\n`location` in search mode.","headers":{"Link":{"description":"RFC 5988 pagination links. Includes `<...>; rel=\"next\"` (and\n`rel=\"prev\"` when paging backward) with cursor params; the\n`rel=\"next\"` entry is absent on the final page.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StorageItem"}},"breadcrumb":{"type":"array","description":"Path from the root to the listed folder, nearest the root\nfirst. Present in list mode when `_parentId` is set.","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Folder ID."},"name":{"type":"string","description":"Folder name."}}}}}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Create a folder

> Creates an empty folder. Folders are organizational only — they hold no\
> content and do not count against storage quota. To create files, use\
> \`POST /v1/storage/files/initiateUpload\`.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"CreateFolderRequest":{"type":"object","description":"Request body for creating a folder.","required":["name"],"properties":{"name":{"type":"string","maxLength":256,"description":"Folder name. Duplicate names within the same parent are allowed."},"_parentId":{"type":["string","null"],"format":"objectId","description":"Parent folder to create this folder in. Omit or pass null to create\nit at the account root. Must reference an existing active folder."},"description":{"type":"string","maxLength":1000,"description":"Optional note describing the folder."}}},"StorageItem":{"type":"object","description":"A file or folder stored in Celigo Storage.","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the item. Pass it to download, move, copy,\nreplace, rename, or delete the item; folders and files share one\nID space."},"type":{"type":"string","enum":["file","folder"],"readOnly":true,"description":"Distinguishes a content-bearing file from an organizational folder.\nFixed when the item is created and never changes."},"name":{"type":"string","maxLength":256,"description":"Display name, including the extension for files (for example\n`orders.csv`). Two items with the same name can coexist in one\nfolder — the name is not a unique key."},"_parentId":{"type":["string","null"],"format":"objectId","readOnly":true,"description":"Folder that contains this item. Null when the item sits at the\naccount root."},"__ancestorIds":{"type":"array","readOnly":true,"description":"Folder IDs from the root down to the immediate parent, in order.\nEmpty for root-level items. Rewritten automatically when the item\nor any ancestor folder is moved.","items":{"type":"string","format":"objectId"}},"size":{"type":"integer","format":"int64","readOnly":true,"description":"File size in bytes. Present when type is file; folders carry no\nsize. While an upload is pending this reflects the reserved quota,\nand is reconciled to the actual byte count once the upload finalizes."},"mimeType":{"type":"string","maxLength":256,"readOnly":true,"description":"Media type recorded at upload time, used to set the download\nContent-Type. Present when type is file; absent for folders and for\nfiles uploaded without a declared type."},"description":{"type":"string","maxLength":1000,"description":"Optional caller-supplied note describing the item."},"status":{"type":"string","enum":["pending","active"],"readOnly":true,"description":"Upload lifecycle state. A file is created pending at initiate-upload\nand flips to active once S3 confirms the bytes; folders are created\nactive."},"isSystem":{"type":"boolean","readOnly":true,"description":"When true, the platform created the item (for example a system or\nintegration folder) and protects it — move, content replace, copy,\ndelete, and purge are rejected with `STORAGE_SYSTEM_ITEM_PROTECTED`."},"deletedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was soft-deleted to the recycle bin. Present\nonly for recycle-bin items; the item is permanently purged 30 days\nafter this time unless restored."},"deletedBy":{"type":"string","readOnly":true,"description":"Who soft-deleted the item — a user ID for a direct delete, or\n`cascadeDelete` for a descendant removed when its parent folder was\ndeleted. Present only for recycle-bin items. Cascade-deleted items\ncan be recovered only by restoring the folder that was deleted\ndirectly."},"location":{"type":"object","readOnly":true,"description":"Folder that contains this search hit. Present only in search-mode\nresults from `GET /v1/storage/items` (when the `search` query\nparameter is set).","properties":{"_id":{"type":"string","format":"objectId","description":"ID of the containing folder."},"name":{"type":"string","description":"Name of the containing folder."}}},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the most recent metadata change. Updated on rename,\nmove, and content replace, and when the folder's direct children\nchange."}},"required":["_id","type","name","status","isSystem","createdAt","lastModified"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items":{"post":{"summary":"Create a folder","description":"Creates an empty folder. Folders are organizational only — they hold no\ncontent and do not count against storage quota. To create files, use\n`POST /v1/storage/files/initiateUpload`.","operationId":"createStorageFolder","tags":["File Storage"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFolderRequest"}}}},"responses":{"201":{"description":"Created folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageItem"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Look up items in batch

> Returns metadata for up to 100 items in one call. Send the item ids and\
> optionally a \`fields\` projection; by default each result carries only\
> \`\_id\`. Requesting \`path\` adds a breadcrumb path built from the item's\
> ancestor folder names.\
> \
> With \`failFast: true\` (the default), the first unknown id fails the whole\
> request with \`422 STORAGE\_BATCH\_ITEM\_NOT\_FOUND\`. With \`failFast: false\`,\
> unknown ids come back inline as\
> \`{\_id, notFound: true, reason: "STORAGE\_BATCH\_ITEM\_NOT\_FOUND"}\` entries\
> alongside the found items.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/storage/items/batch":{"post":{"summary":"Look up items in batch","description":"Returns metadata for up to 100 items in one call. Send the item ids and\noptionally a `fields` projection; by default each result carries only\n`_id`. Requesting `path` adds a breadcrumb path built from the item's\nancestor folder names.\n\nWith `failFast: true` (the default), the first unknown id fails the whole\nrequest with `422 STORAGE_BATCH_ITEM_NOT_FOUND`. With `failFast: false`,\nunknown ids come back inline as\n`{_id, notFound: true, reason: \"STORAGE_BATCH_ITEM_NOT_FOUND\"}` entries\nalongside the found items.","operationId":"batchGetStorageItems","tags":["File Storage"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","minItems":1,"maxItems":100,"description":"Item ids to look up. Each must be a 24-character ObjectId;\na malformed id fails the request with\n`400 STORAGE_BATCH_INVALID_REQUEST` before any lookup runs.","items":{"type":"string","format":"objectId"}},"fields":{"type":"array","minItems":1,"description":"Which fields to return per item (`_id` is always included).\nOmitted means `_id` only. An unknown field name fails with\n`400 STORAGE_BATCH_INVALID_REQUEST` naming the allowed set.","items":{"type":"string","enum":["name","description","size","mimeType","type","status","_parentId","__ancestorIds","path"]}},"failFast":{"type":"boolean","default":true,"description":"When true (the default), an unknown id fails the whole request\nwith 422. When false, unknown ids are reported inline per item\nand the request still returns 200."}}}}}},"responses":{"200":{"description":"Per-id results, in the same order as the requested `ids`.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","description":"One entry per requested id, in request order.","items":{"type":"object","required":["_id"],"properties":{"_id":{"type":"string","format":"objectId","description":"Item id this entry corresponds to."},"name":{"type":"string","description":"Present when requested via `fields`."},"size":{"type":"integer","description":"File size in bytes. Present when requested via `fields`."},"path":{"type":"string","description":"Breadcrumb path from the root, built from ancestor\nfolder names. Present when requested via `fields`."},"notFound":{"type":"boolean","description":"Present (true) only on unknown ids when\n`failFast: false`."},"reason":{"type":"string","description":"Error code for an unknown id when `failFast: false`\n(`STORAGE_BATCH_ITEM_NOT_FOUND`)."}}}}}}}}},"400":{"description":"Malformed request — `ids` missing/empty/over 100 entries, a\nnon-ObjectId id, an unknown `fields` entry, or a non-boolean\n`failFast`. Error code: `STORAGE_BATCH_INVALID_REQUEST`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"422":{"description":"An id was not found while `failFast` was true (the default). Each\nerror entry carries the offending `_id`.","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","description":"Error code (`STORAGE_BATCH_ITEM_NOT_FOUND`)."},"message":{"type":"string","description":"Human-readable error message naming the id."},"_id":{"type":"string","format":"objectId","description":"The id that was not found."}}}}}}}}}}}}}}
```

## Move items in bulk

> Moves up to 100 files or folders into one destination folder (or the\
> account root) in a single call. Metadata only — content stays in place,\
> ids are unchanged, and quota is unaffected. Folders re-parent immediately\
> and re-anchor their descendants asynchronously.\
> \
> The destination is validated once up front — a bad destination rejects the\
> whole batch. Each source id is then processed best-effort: the response is\
> \`200\` when every item moved, or \`207\` when results are mixed, with a\
> per-id \`status\` of \`success\` or \`error\`. An optional \`name\` renames the\
> item as it lands (single-id requests only) so a destination name collision\
> can be resolved without a second call.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"BulkMoveResults":{"type":"object","description":"Per-id move results, one entry per source id.","properties":{"results":{"type":"array","items":{"type":"object","required":["_id","status"],"properties":{"_id":{"type":"string","format":"objectId","description":"Source item id this entry corresponds to."},"status":{"type":"string","enum":["success","error"],"description":"Outcome for this item."},"_parentId":{"type":["string","null"],"format":"objectId","description":"New parent folder (null for the root). Present on success."},"__ancestorIds":{"type":"array","description":"New ancestor chain from the root. Present on success.","items":{"type":"string","format":"objectId"}},"type":{"type":"string","enum":["file","folder"],"description":"Type of the moved item. Present on success."},"errorCode":{"type":"string","description":"Error code for this item. Present on error."},"message":{"type":"string","description":"Human-readable failure reason. Present on error."}}}}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items/move":{"post":{"summary":"Move items in bulk","description":"Moves up to 100 files or folders into one destination folder (or the\naccount root) in a single call. Metadata only — content stays in place,\nids are unchanged, and quota is unaffected. Folders re-parent immediately\nand re-anchor their descendants asynchronously.\n\nThe destination is validated once up front — a bad destination rejects the\nwhole batch. Each source id is then processed best-effort: the response is\n`200` when every item moved, or `207` when results are mixed, with a\nper-id `status` of `success` or `error`. An optional `name` renames the\nitem as it lands (single-id requests only) so a destination name collision\ncan be resolved without a second call.","operationId":"bulkMoveStorageItems","tags":["File Storage"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["_parentFolderId","_storageItemIds"],"properties":{"_parentFolderId":{"type":["string","null"],"format":"objectId","description":"Destination folder. Send null to move the items to the account\nroot. The key must be present — omitting it fails with\n`400 STORAGE_BULK_MOVE_PARENT_REQUIRED`. Must not appear in\n`_storageItemIds` (`422 STORAGE_BULK_MOVE_DESTINATION_IN_SOURCES`)."},"_storageItemIds":{"type":"array","minItems":1,"maxItems":100,"description":"Ids of the items to move. Over 100 entries fails with\n`422 STORAGE_BULK_MOVE_TOO_MANY_ITEMS`.","items":{"type":"string","format":"objectId"}},"name":{"type":"string","description":"New name applied to the moved item in the same write as the\nre-parent. Only allowed when `_storageItemIds` has exactly one\nentry — with more, the request fails with\n`400 STORAGE_BULK_MOVE_NAME_DISALLOWED`."}}}}}},"responses":{"200":{"description":"Every item moved successfully.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkMoveResults"}}}},"207":{"description":"Mixed results — at least one item failed to move. Inspect each\nentry's `status`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkMoveResults"}}}},"400":{"description":"Malformed request — `_parentFolderId` key missing\n(`STORAGE_BULK_MOVE_PARENT_REQUIRED`), `_storageItemIds`\nmissing or empty (`STORAGE_BULK_MOVE_IDS_REQUIRED`), or `name` sent\nwith more than one id (`STORAGE_BULK_MOVE_NAME_DISALLOWED`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"description":"Batch-level rejection — too many ids\n(`STORAGE_BULK_MOVE_TOO_MANY_ITEMS`), the destination appears among\nthe source ids (`STORAGE_BULK_MOVE_DESTINATION_IN_SOURCES`), or the\ndestination is not a folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## List recycle-bin items

> Lists the items currently in the recycle bin, newest deletion first. Only\
> items deleted directly are listed — descendants removed as part of a\
> folder deletion are hidden, since they are restored or purged with their\
> parent. Each item carries \`deletedAt\` and \`deletedBy\`. Restore an item\
> with \`POST /v1/storage/items/{\_id}/restore\` or remove it for good with\
> \`DELETE /v1/storage/items/{\_id}/purge\`.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"StorageItem":{"type":"object","description":"A file or folder stored in Celigo Storage.","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the item. Pass it to download, move, copy,\nreplace, rename, or delete the item; folders and files share one\nID space."},"type":{"type":"string","enum":["file","folder"],"readOnly":true,"description":"Distinguishes a content-bearing file from an organizational folder.\nFixed when the item is created and never changes."},"name":{"type":"string","maxLength":256,"description":"Display name, including the extension for files (for example\n`orders.csv`). Two items with the same name can coexist in one\nfolder — the name is not a unique key."},"_parentId":{"type":["string","null"],"format":"objectId","readOnly":true,"description":"Folder that contains this item. Null when the item sits at the\naccount root."},"__ancestorIds":{"type":"array","readOnly":true,"description":"Folder IDs from the root down to the immediate parent, in order.\nEmpty for root-level items. Rewritten automatically when the item\nor any ancestor folder is moved.","items":{"type":"string","format":"objectId"}},"size":{"type":"integer","format":"int64","readOnly":true,"description":"File size in bytes. Present when type is file; folders carry no\nsize. While an upload is pending this reflects the reserved quota,\nand is reconciled to the actual byte count once the upload finalizes."},"mimeType":{"type":"string","maxLength":256,"readOnly":true,"description":"Media type recorded at upload time, used to set the download\nContent-Type. Present when type is file; absent for folders and for\nfiles uploaded without a declared type."},"description":{"type":"string","maxLength":1000,"description":"Optional caller-supplied note describing the item."},"status":{"type":"string","enum":["pending","active"],"readOnly":true,"description":"Upload lifecycle state. A file is created pending at initiate-upload\nand flips to active once S3 confirms the bytes; folders are created\nactive."},"isSystem":{"type":"boolean","readOnly":true,"description":"When true, the platform created the item (for example a system or\nintegration folder) and protects it — move, content replace, copy,\ndelete, and purge are rejected with `STORAGE_SYSTEM_ITEM_PROTECTED`."},"deletedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was soft-deleted to the recycle bin. Present\nonly for recycle-bin items; the item is permanently purged 30 days\nafter this time unless restored."},"deletedBy":{"type":"string","readOnly":true,"description":"Who soft-deleted the item — a user ID for a direct delete, or\n`cascadeDelete` for a descendant removed when its parent folder was\ndeleted. Present only for recycle-bin items. Cascade-deleted items\ncan be recovered only by restoring the folder that was deleted\ndirectly."},"location":{"type":"object","readOnly":true,"description":"Folder that contains this search hit. Present only in search-mode\nresults from `GET /v1/storage/items` (when the `search` query\nparameter is set).","properties":{"_id":{"type":"string","format":"objectId","description":"ID of the containing folder."},"name":{"type":"string","description":"Name of the containing folder."}}},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the most recent metadata change. Updated on rename,\nmove, and content replace, and when the folder's direct children\nchange."}},"required":["_id","type","name","status","isSystem","createdAt","lastModified"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items/recycleBinTTL":{"get":{"summary":"List recycle-bin items","description":"Lists the items currently in the recycle bin, newest deletion first. Only\nitems deleted directly are listed — descendants removed as part of a\nfolder deletion are hidden, since they are restored or purged with their\nparent. Each item carries `deletedAt` and `deletedBy`. Restore an item\nwith `POST /v1/storage/items/{_id}/restore` or remove it for good with\n`DELETE /v1/storage/items/{_id}/purge`.","operationId":"listStorageRecycleBin","tags":["File Storage"],"parameters":[{"name":"pageSize","in":"query","required":false,"description":"Maximum number of items to return per page.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":1000}},{"name":"after","in":"query","required":false,"description":"Opaque forward-paging cursor. Take it from the previous response's\n`Link` header (`rel=\"next\"`); omit for the first page. Cannot be\ncombined with `before`.","schema":{"type":"string"}},{"name":"before","in":"query","required":false,"description":"Opaque backward-paging cursor from a previous response's `Link`\nheader. Cannot be combined with `after`.","schema":{"type":"string"}}],"responses":{"200":{"description":"Recycle-bin items. Pagination is cursor-based via the `Link`\nheader — the body carries only `items`.","headers":{"Link":{"description":"RFC-5988 pagination links. When more pages remain, includes a\n`<...?after=...>; rel=\"next\"` entry; absent on the final page.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StorageItem"}}}}}}},"400":{"description":"The `after`/`before` cursor is malformed, was not issued by this\nlisting, or both were sent together. Error code:\n`STORAGE_INVALID_CURSOR`. Restart from the first page (omit the\ncursor).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"}}}}}}
```

## Rename or describe an item

> Updates an item's \`name\` and/or \`description\`. Renaming keeps the item's\
> \`\_id\` stable, so references from flows, exports, imports, and tokens\
> survive. To move an item to a different folder, use\
> \`PATCH /v1/storage/items/{\_id}/move\`; to replace a file's content, use\
> \`PATCH /v1/storage/items/{\_id}/replace\`.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"UpdateRequest":{"type":"object","description":"Request body for renaming an item or changing its description. Provide\n`name`, `description`, or both. Folder placement is changed with the move\nendpoint, not here — `_parentId` and `__ancestorIds` are rejected.","properties":{"name":{"type":"string","maxLength":256,"description":"New display name for the item."},"description":{"type":"string","maxLength":1000,"description":"New description. Pass an empty string to clear it."}}},"StorageItem":{"type":"object","description":"A file or folder stored in Celigo Storage.","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the item. Pass it to download, move, copy,\nreplace, rename, or delete the item; folders and files share one\nID space."},"type":{"type":"string","enum":["file","folder"],"readOnly":true,"description":"Distinguishes a content-bearing file from an organizational folder.\nFixed when the item is created and never changes."},"name":{"type":"string","maxLength":256,"description":"Display name, including the extension for files (for example\n`orders.csv`). Two items with the same name can coexist in one\nfolder — the name is not a unique key."},"_parentId":{"type":["string","null"],"format":"objectId","readOnly":true,"description":"Folder that contains this item. Null when the item sits at the\naccount root."},"__ancestorIds":{"type":"array","readOnly":true,"description":"Folder IDs from the root down to the immediate parent, in order.\nEmpty for root-level items. Rewritten automatically when the item\nor any ancestor folder is moved.","items":{"type":"string","format":"objectId"}},"size":{"type":"integer","format":"int64","readOnly":true,"description":"File size in bytes. Present when type is file; folders carry no\nsize. While an upload is pending this reflects the reserved quota,\nand is reconciled to the actual byte count once the upload finalizes."},"mimeType":{"type":"string","maxLength":256,"readOnly":true,"description":"Media type recorded at upload time, used to set the download\nContent-Type. Present when type is file; absent for folders and for\nfiles uploaded without a declared type."},"description":{"type":"string","maxLength":1000,"description":"Optional caller-supplied note describing the item."},"status":{"type":"string","enum":["pending","active"],"readOnly":true,"description":"Upload lifecycle state. A file is created pending at initiate-upload\nand flips to active once S3 confirms the bytes; folders are created\nactive."},"isSystem":{"type":"boolean","readOnly":true,"description":"When true, the platform created the item (for example a system or\nintegration folder) and protects it — move, content replace, copy,\ndelete, and purge are rejected with `STORAGE_SYSTEM_ITEM_PROTECTED`."},"deletedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was soft-deleted to the recycle bin. Present\nonly for recycle-bin items; the item is permanently purged 30 days\nafter this time unless restored."},"deletedBy":{"type":"string","readOnly":true,"description":"Who soft-deleted the item — a user ID for a direct delete, or\n`cascadeDelete` for a descendant removed when its parent folder was\ndeleted. Present only for recycle-bin items. Cascade-deleted items\ncan be recovered only by restoring the folder that was deleted\ndirectly."},"location":{"type":"object","readOnly":true,"description":"Folder that contains this search hit. Present only in search-mode\nresults from `GET /v1/storage/items` (when the `search` query\nparameter is set).","properties":{"_id":{"type":"string","format":"objectId","description":"ID of the containing folder."},"name":{"type":"string","description":"Name of the containing folder."}}},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the most recent metadata change. Updated on rename,\nmove, and content replace, and when the folder's direct children\nchange."}},"required":["_id","type","name","status","isSystem","createdAt","lastModified"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items/{_id}":{"put":{"summary":"Rename or describe an item","description":"Updates an item's `name` and/or `description`. Renaming keeps the item's\n`_id` stable, so references from flows, exports, imports, and tokens\nsurvive. To move an item to a different folder, use\n`PATCH /v1/storage/items/{_id}/move`; to replace a file's content, use\n`PATCH /v1/storage/items/{_id}/replace`.","operationId":"updateStorageItem","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"Item ID.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRequest"}}}},"responses":{"200":{"description":"Updated item.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageItem"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Delete an item

> Soft-deletes a file or folder to the recycle bin, where it is retained\
> for 30 days and can be restored with\
> \`POST /v1/storage/items/{\_id}/restore\`. Deleting a folder also removes\
> its entire subtree; the folder is removed immediately and its descendants\
> follow asynchronously. Delete is never blocked by references — flows,\
> exports, imports, and tokens that point at the item are left dangling and\
> fail at runtime, so check \`GET /v1/storage/items/{\_id}/dependencies\`\
> first. A pending multipart upload cannot be deleted here — cancel it with\
> \`POST /v1/storage/files/{\_id}/cancel\`.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/storage/items/{_id}":{"delete":{"summary":"Delete an item","description":"Soft-deletes a file or folder to the recycle bin, where it is retained\nfor 30 days and can be restored with\n`POST /v1/storage/items/{_id}/restore`. Deleting a folder also removes\nits entire subtree; the folder is removed immediately and its descendants\nfollow asynchronously. Delete is never blocked by references — flows,\nexports, imports, and tokens that point at the item are left dangling and\nfail at runtime, so check `GET /v1/storage/items/{_id}/dependencies`\nfirst. A pending multipart upload cannot be deleted here — cancel it with\n`POST /v1/storage/files/{_id}/cancel`.","operationId":"deleteStorageItem","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"Item ID.","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Item soft-deleted. For a folder, the root is removed and its\ndescendants are removed asynchronously."},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Replace file content

> Overwrites an existing file's content in place. Returns presigned upload\
> URLs in the same shape as one initiate-upload file entry; transfer the new\
> bytes to them just as for a new upload. The item's \`\_id\`, name, and folder\
> placement are preserved, so every reference to the file stays intact — use\
> this instead of delete-and-recreate when a file is referenced by flows or\
> exports. The previous content remains downloadable until the replacement\
> finalizes. Rename with \`PUT /v1/storage/items/{\_id}\` instead; this\
> endpoint does not accept a name.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"ReplaceRequest":{"type":"object","description":"Requests presigned URLs to overwrite an existing file's content in place.\nSame shape as one initiate-upload file entry, minus `name` — the existing\nname, `_id`, and folder placement are preserved. Rename with\n`PUT /v1/storage/items/{_id}` instead.","required":["uploadType"],"properties":{"mimeType":{"type":"string","maxLength":256,"description":"New media type for the replaced content. Optional; the existing\nmimeType is kept when omitted."},"size":{"type":"integer","format":"int64","minimum":0,"description":"Declared size in bytes of the replacement content, used to reserve\nquota. Reconciled to the real size when the upload finalizes."},"uploadType":{"type":"string","enum":["single","multipart"],"description":"How the replacement content will be transferred."},"numParts":{"type":"integer","minimum":1,"description":"Number of parts the replacement will be split into. Required when uploadType is multipart."},"uploadId":{"type":"string","description":"S3 multipart upload ID from a prior replace response. Provide with\n`issuedPartsCount` to resume and request the next batch of part URLs."},"issuedPartsCount":{"type":"integer","minimum":0,"description":"Number of part URLs already issued. Provide together with `uploadId`\nto resume an in-progress replacement."}}},"UploadResult":{"type":"object","description":"Outcome for one file in an upload response. On success, `statusCode` is\n200 and `body` carries the presigned-URL instructions; on failure,\n`statusCode` is a 4xx and `errors` explains why. Each file in a batch is\nvalidated independently, so a single response can mix successes and\nfailures.","required":["name","statusCode"],"properties":{"_id":{"type":"string","format":"objectId","description":"ID of the pending item this result refers to. Present once the item\nis created; absent when the file failed validation before creation.\nUse it to upload, refresh URLs, cancel, or download once active."},"name":{"type":"string","description":"File name echoed back from the request, to correlate results."},"statusCode":{"type":"integer","description":"Per-file result status, mirroring HTTP status semantics."},"body":{"$ref":"#/components/schemas/UploadBody"},"errors":{"type":"array","description":"Reasons the file was rejected. Present when statusCode is a 4xx.","items":{"$ref":"#/components/schemas/UploadError"}}}},"UploadBody":{"type":"object","description":"Presigned-URL instructions for one file. The fields present depend on\n`uploadType`: a single PUT returns one `uploadUrl`; a multipart upload\nreturns an `uploadId`, a batch of `partUrls`, and a `completeUrl`.","required":["uploadType"],"properties":{"uploadType":{"type":"string","enum":["single","multipart"],"description":"Transfer mechanism the caller must use for this file."},"uploadUrl":{"type":"string","format":"uri","description":"Presigned S3 URL to PUT the file's bytes to in a single request.\nPresent when uploadType is single. Expires after one hour; use\n`POST /v1/storage/files/refresh-urls` to reissue."},"uploadId":{"type":"string","description":"S3 multipart upload identifier. Present when uploadType is\nmultipart. Pass it to refresh-urls to fetch later part batches and\nto cancel the upload."},"partUrls":{"type":"array","description":"Presigned URLs for the next batch of parts. Present when uploadType\nis multipart. A request may return fewer parts than requested when\nthe account-wide part budget is constrained; fetch the remaining\nparts with refresh-urls.","items":{"$ref":"#/components/schemas/PartUrl"}},"completeUrl":{"type":"string","format":"uri","description":"Presigned URL to POST the ordered list of part numbers and ETags to,\nfinalizing the multipart upload. Present when uploadType is multipart."}}},"PartUrl":{"type":"object","description":"A presigned URL for uploading one part of a multipart upload.","required":["partNumber","url"],"properties":{"partNumber":{"type":"integer","minimum":1,"description":"1-based index of this part. Send it back as the S3 `partNumber`\nwhen uploading, and keep each part's returned `ETag` to finalize\nthe upload."},"url":{"type":"string","format":"uri","description":"Presigned S3 URL to PUT this part's bytes to."}}},"UploadError":{"type":"object","description":"A per-file failure within a batch upload response.","required":["code","message"],"properties":{"code":{"type":"string","description":"Machine-readable storage error code."},"message":{"type":"string","description":"Human-readable explanation of the failure."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items/{_id}/replace":{"patch":{"summary":"Replace file content","description":"Overwrites an existing file's content in place. Returns presigned upload\nURLs in the same shape as one initiate-upload file entry; transfer the new\nbytes to them just as for a new upload. The item's `_id`, name, and folder\nplacement are preserved, so every reference to the file stays intact — use\nthis instead of delete-and-recreate when a file is referenced by flows or\nexports. The previous content remains downloadable until the replacement\nfinalizes. Rename with `PUT /v1/storage/items/{_id}` instead; this\nendpoint does not accept a name.","operationId":"replaceStorageFileContent","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the file to replace.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceRequest"}}}},"responses":{"200":{"description":"Upload instructions for the replacement content.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadResult"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"409":{"description":"A concurrent replace is already in progress for this file\n(`STORAGE_ITEM_REPLACE_CONFLICT`). Retry once the in-flight\nreplacement finalizes or is abandoned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Merge a folder into another

> Merges the contents of a source folder into an existing destination\
> folder, then removes the source. Runs asynchronously: the request is\
> validated and queued, and the endpoint immediately returns \`202\` with a\
> job receipt — contents move in the background and the source folder\
> disappears once the merge completes. A soft-deleted source folder may be\
> merged, which restores its contents into the destination. Folders only —\
> move individual files with the move endpoint. Requires delete access on\
> the source folder and write access on the destination.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"MergeRequest":{"type":"object","description":"Request body for merging a folder into another folder.","required":["_destinationId"],"properties":{"_destinationId":{"type":"string","format":"objectId","description":"Destination folder that receives the source folder's contents. Must\nreference an existing active folder that is different from the source\nand not one of its descendants."},"trigger":{"type":"string","enum":["move","rename"],"default":"move","description":"How the merge is recorded. Unrecognized values fall back to `move`.\nIgnored when the source folder is soft-deleted — the platform then\nrecords the merge as a restore automatically."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}}}},"paths":{"/v1/storage/items/{_id}/merge":{"post":{"summary":"Merge a folder into another","description":"Merges the contents of a source folder into an existing destination\nfolder, then removes the source. Runs asynchronously: the request is\nvalidated and queued, and the endpoint immediately returns `202` with a\njob receipt — contents move in the background and the source folder\ndisappears once the merge completes. A soft-deleted source folder may be\nmerged, which restores its contents into the destination. Folders only —\nmove individual files with the move endpoint. Requires delete access on\nthe source folder and write access on the destination.","operationId":"mergeStorageFolder","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the source folder to merge and remove.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergeRequest"}}}},"responses":{"202":{"description":"Merge accepted and queued. The source folder remains visible until\nthe background job completes, then is removed.","content":{"application/json":{"schema":{"type":"object","required":["jobId","jobType","status","sourceFolderId","_destinationId"],"properties":{"jobId":{"type":"string","description":"Identifier of the queued merge job."},"jobType":{"type":"string","enum":["folderMerge"],"description":"Kind of background job that was queued."},"status":{"type":"string","enum":["accepted"],"description":"Acknowledgement state of the request."},"sourceFolderId":{"type":"string","format":"objectId","description":"The source folder being merged and removed."},"_destinationId":{"type":"string","format":"objectId","description":"The folder receiving the source folder's contents."}}}}}},"400":{"description":"`_destinationId` is missing from the request body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"description":"Caller lacks delete access on the source or write access on the\ndestination, the source is a protected system folder, or the account\nis not entitled to Celigo Storage.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The source or destination folder does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The merge is structurally invalid — the source or destination is not\na folder, the source and destination are the same folder, the\ndestination sits inside the source (circular merge), or the merged\ntree would exceed the maximum folder depth.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}
```

## Move an item

> Moves a file or folder to a different folder. Metadata only — the content\
> stays in place, the item's \`\_id\` is unchanged so references survive, and\
> quota is unaffected. Moving a folder re-parents the folder immediately and\
> re-anchors its descendants asynchronously, so the response reflects only\
> the moved item itself. A folder cannot be moved into itself or one of its\
> own descendants.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"MoveRequest":{"type":"object","description":"Request body for moving an item to a different folder.","required":["_parentId"],"properties":{"_parentId":{"type":["string","null"],"format":"objectId","description":"Destination folder. Pass null to move the item to the account root.\nThe key is required even when null. Must differ from the current\nparent, must be an active folder, and — for a folder — must not be\nthe item itself or one of its descendants."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items/{_id}/move":{"patch":{"summary":"Move an item","description":"Moves a file or folder to a different folder. Metadata only — the content\nstays in place, the item's `_id` is unchanged so references survive, and\nquota is unaffected. Moving a folder re-parents the folder immediately and\nre-anchors its descendants asynchronously, so the response reflects only\nthe moved item itself. A folder cannot be moved into itself or one of its\nown descendants.","operationId":"moveStorageItem","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the item to move.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveRequest"}}}},"responses":{"200":{"description":"The moved item's changed fields. Only the item's own re-parenting is\nreflected; for a folder, descendants re-anchor asynchronously.","content":{"application/json":{"schema":{"type":"object","required":["_id"],"properties":{"_id":{"type":"string","format":"objectId","description":"ID of the moved item."},"_parentId":{"type":["string","null"],"format":"objectId","description":"New parent folder, or null if moved to the root."},"__ancestorIds":{"type":"array","description":"New ancestor chain from the root to the parent.","items":{"type":"string","format":"objectId"}}}}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Copy a file

> Creates an independent copy of a file in a destination folder, with a new\
> \`\_id\` and its own copy of the content. Consumes quota equal to the source\
> file's size. Files only — folder copy is not supported. Names are not\
> deduplicated, so copying into the source's own folder without a new name\
> produces a second file with the same name.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"CopyRequest":{"type":"object","description":"Request body for copying a file.","properties":{"_destinationId":{"type":["string","null"],"format":"objectId","description":"Destination folder for the copy. Pass null to copy to the account\nroot. Must reference an existing active folder."},"name":{"type":"string","maxLength":256,"description":"Name for the copy. Defaults to the source file's name when omitted.\nDuplicate names are allowed, so a copy into the source's own folder\nwith no name produces a second file with the same name."}}},"StorageItem":{"type":"object","description":"A file or folder stored in Celigo Storage.","properties":{"_id":{"type":"string","format":"objectId","readOnly":true,"description":"Unique identifier for the item. Pass it to download, move, copy,\nreplace, rename, or delete the item; folders and files share one\nID space."},"type":{"type":"string","enum":["file","folder"],"readOnly":true,"description":"Distinguishes a content-bearing file from an organizational folder.\nFixed when the item is created and never changes."},"name":{"type":"string","maxLength":256,"description":"Display name, including the extension for files (for example\n`orders.csv`). Two items with the same name can coexist in one\nfolder — the name is not a unique key."},"_parentId":{"type":["string","null"],"format":"objectId","readOnly":true,"description":"Folder that contains this item. Null when the item sits at the\naccount root."},"__ancestorIds":{"type":"array","readOnly":true,"description":"Folder IDs from the root down to the immediate parent, in order.\nEmpty for root-level items. Rewritten automatically when the item\nor any ancestor folder is moved.","items":{"type":"string","format":"objectId"}},"size":{"type":"integer","format":"int64","readOnly":true,"description":"File size in bytes. Present when type is file; folders carry no\nsize. While an upload is pending this reflects the reserved quota,\nand is reconciled to the actual byte count once the upload finalizes."},"mimeType":{"type":"string","maxLength":256,"readOnly":true,"description":"Media type recorded at upload time, used to set the download\nContent-Type. Present when type is file; absent for folders and for\nfiles uploaded without a declared type."},"description":{"type":"string","maxLength":1000,"description":"Optional caller-supplied note describing the item."},"status":{"type":"string","enum":["pending","active"],"readOnly":true,"description":"Upload lifecycle state. A file is created pending at initiate-upload\nand flips to active once S3 confirms the bytes; folders are created\nactive."},"isSystem":{"type":"boolean","readOnly":true,"description":"When true, the platform created the item (for example a system or\nintegration folder) and protects it — move, content replace, copy,\ndelete, and purge are rejected with `STORAGE_SYSTEM_ITEM_PROTECTED`."},"deletedAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was soft-deleted to the recycle bin. Present\nonly for recycle-bin items; the item is permanently purged 30 days\nafter this time unless restored."},"deletedBy":{"type":"string","readOnly":true,"description":"Who soft-deleted the item — a user ID for a direct delete, or\n`cascadeDelete` for a descendant removed when its parent folder was\ndeleted. Present only for recycle-bin items. Cascade-deleted items\ncan be recovered only by restoring the folder that was deleted\ndirectly."},"location":{"type":"object","readOnly":true,"description":"Folder that contains this search hit. Present only in search-mode\nresults from `GET /v1/storage/items` (when the `search` query\nparameter is set).","properties":{"_id":{"type":"string","format":"objectId","description":"ID of the containing folder."},"name":{"type":"string","description":"Name of the containing folder."}}},"createdAt":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp when the item was created."},"lastModified":{"type":"string","format":"date-time","readOnly":true,"description":"Timestamp of the most recent metadata change. Updated on rename,\nmove, and content replace, and when the folder's direct children\nchange."}},"required":["_id","type","name","status","isSystem","createdAt","lastModified"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items/{_id}/copy":{"post":{"summary":"Copy a file","description":"Creates an independent copy of a file in a destination folder, with a new\n`_id` and its own copy of the content. Consumes quota equal to the source\nfile's size. Files only — folder copy is not supported. Names are not\ndeduplicated, so copying into the source's own folder without a new name\nproduces a second file with the same name.","operationId":"copyStorageFile","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the file to copy.","schema":{"type":"string","format":"objectId"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyRequest"}}}},"responses":{"201":{"description":"The newly created copy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageItem"}}}},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Restore an item

> Restores a soft-deleted item from the recycle bin back to its original\
> location. Restoring a folder also restores the descendants that were\
> removed with it; the folder comes back immediately and its descendants\
> follow asynchronously. Only items deleted directly can be restored — a\
> descendant removed by its parent's deletion comes back only when that\
> parent folder is restored.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/storage/items/{_id}/restore":{"post":{"summary":"Restore an item","description":"Restores a soft-deleted item from the recycle bin back to its original\nlocation. Restoring a folder also restores the descendants that were\nremoved with it; the folder comes back immediately and its descendants\nfollow asynchronously. Only items deleted directly can be restored — a\ndescendant removed by its parent's deletion comes back only when that\nparent folder is restored.","operationId":"restoreStorageItem","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the recycle-bin item to restore.","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Item restored. For a folder, the root is restored and its descendants\nfollow asynchronously."},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Purge an item

> Permanently deletes a soft-deleted item from the recycle bin and frees its\
> storage. This cannot be undone. Purging a folder also purges its\
> descendants; the folder and its subtree are removed asynchronously. Only\
> items deleted directly can be purged — a descendant removed by its\
> parent's deletion is purged together with that parent. The item must\
> already be in the recycle bin.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/storage/items/{_id}/purge":{"delete":{"summary":"Purge an item","description":"Permanently deletes a soft-deleted item from the recycle bin and frees its\nstorage. This cannot be undone. Purging a folder also purges its\ndescendants; the folder and its subtree are removed asynchronously. Only\nitems deleted directly can be purged — a descendant removed by its\nparent's deletion is purged together with that parent. The item must\nalready be in the recycle bin.","operationId":"purgeStorageItem","tags":["File Storage"],"parameters":[{"name":"_id","in":"path","required":true,"description":"ID of the recycle-bin item to purge.","schema":{"type":"string","format":"objectId"}}],"responses":{"204":{"description":"Item permanently deleted. For a folder, the subtree is purged\nasynchronously."},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## List dependencies of an item

> Returns the resources that reference this item — flows, exports, imports,\
> MCP servers, and access tokens. These references are soft: they never\
> block a delete or move, and go dangling if the item is removed. Check this\
> before deleting or moving an item to see what may break.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"DependencyResponse":{"type":"object","description":"Map of dependent-resource types to arrays of dependency entries.\nKeys are plural resource type strings (e.g. `flows`, `imports`,\n`connections`). An empty object `{}` means no dependents.\n","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/DependencyEntry"}}},"DependencyEntry":{"type":"object","description":"A single resource that depends on the queried resource.","properties":{"id":{"type":"string","description":"Unique identifier of the dependent resource."},"name":{"type":"string","description":"Display name of the dependent resource."},"paths":{"type":"array","description":"Dot-notation paths within the dependent resource that reference\nthe target resource. `[*]` denotes array elements.","items":{"type":"string"}},"accessLevel":{"type":"string","description":"The caller's access level on the dependent resource."},"dependencyIds":{"type":"object","description":"Map of resource types to arrays of IDs that this dependent\nresource references on the target. Keys are singular or plural\nresource type strings; values are arrays of ID strings.","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["id","name","paths","accessLevel","dependencyIds"]},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/items/{_id}/dependencies":{"get":{"operationId":"listStorageItemDependencies","tags":["File Storage"],"summary":"List dependencies of an item","description":"Returns the resources that reference this item — flows, exports, imports,\nMCP servers, and access tokens. These references are soft: they never\nblock a delete or move, and go dangling if the item is removed. Check this\nbefore deleting or moving an item to see what may break.","parameters":[{"name":"_id","in":"path","required":true,"description":"Item ID.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Dependency map. Keys are resource-type strings; values are arrays of\ndependency entries. Returns `{}` when nothing references the item.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DependencyResponse"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"}}}}}}
```

## Get audit log for an item

> Returns the change history for a storage item — creation, renames and\
> description edits, moves, content replacements, downloads, deletes,\
> restores, and purges — newest first. Each entry records who made the\
> change, when, and which fields were affected.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"responses":{"400-bad-request":{"description":"Bad request. The server could not understand the request because of malformed syntax or invalid parameters.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"404-not-found":{"description":"Not found. The requested resource does not exist or is not visible to the caller.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}}},"paths":{"/v1/storageitems/{_id}/audit":{"get":{"summary":"Get audit log for an item","description":"Returns the change history for a storage item — creation, renames and\ndescription edits, moves, content replacements, downloads, deletes,\nrestores, and purges — newest first. Each entry records who made the\nchange, when, and which fields were affected.","tags":["File Storage"],"operationId":"getStorageItemAudit","parameters":[{"name":"_id","in":"path","description":"Item ID.","required":true,"schema":{"type":"string","format":"objectId"}},{"name":"limit","in":"query","description":"Maximum number of audit entries to return per page.","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"default":1000}},{"name":"after","in":"query","required":false,"description":"Opaque pagination cursor for the next page. Take it from the `after`\nvalue in the `Link` response header's `rel=\"next\"` URL rather than\nconstructing it.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Only return entries at or after this timestamp.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","required":false,"description":"Only return entries at or before this timestamp.","schema":{"type":"string","format":"date-time"}},{"name":"action","in":"query","required":false,"description":"Filter by the change type. Maps to the `event` field on each entry.","schema":{"type":"string","enum":["create","update","delete","download","restore","purge"]}},{"name":"source","in":"query","required":false,"description":"Filter by how the change was initiated.","schema":{"type":"string","enum":["ui","api","system"]}},{"name":"_byUserId","in":"query","required":false,"description":"Filter to changes performed by a single user.","schema":{"type":"string","format":"objectId"}}],"responses":{"200":{"description":"Array of audit entries, newest first.","headers":{"Link":{"description":"RFC 5988 pagination link. Includes `<...>; rel=\"next\"` with an\n`after` cursor when more entries exist; absent on the final page.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","format":"objectId","description":"Unique identifier for this audit entry."},"resourceType":{"type":"string","description":"Always `storageitem` for this endpoint."},"_resourceId":{"type":"string","format":"objectId","description":"ID of the item this entry belongs to."},"event":{"type":"string","description":"Type of change that occurred.","enum":["create","update","delete","download","restore","purge"]},"source":{"type":"string","description":"How the change was initiated.","enum":["api","ui","system"]},"time":{"type":"string","format":"date-time","description":"When the change occurred."},"byUser":{"type":"object","description":"User who made the change.","properties":{"_id":{"type":"string","format":"objectId","description":"User ID."},"email":{"type":"string","format":"email","description":"User email address."},"name":{"type":"string","description":"User display name."}}},"fieldChanges":{"type":"array","description":"Fields that were modified.","items":{"type":"object","properties":{"fieldPath":{"type":"string","description":"Dot-notation path of the changed field."},"oldValue":{"description":"Previous value (absent on create)."},"newValue":{"description":"New value (absent on delete)."}}}},"deletedInfo":{"type":"object","description":"Metadata about the deleted item. Present on `delete` events.","properties":{"name":{"type":"string","description":"Name of the item at the time of deletion."}}}}}}}}},"204":{"description":"No audit entries exist for this item."},"400":{"$ref":"#/components/responses/400-bad-request"},"401":{"$ref":"#/components/responses/401-unauthorized"},"404":{"$ref":"#/components/responses/404-not-found"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get storage usage

> Returns account-wide storage usage and entitlement, aggregated across all\
> environments: bytes in use (active and recycle bin), the licensed quota,\
> the hard limit at which uploads are blocked, and whether the account is in\
> overage.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"Usage":{"type":"object","description":"Account-wide storage usage and entitlement, aggregated across all environments.","required":["activeUsage","recycleBinUsage","totalUsage","maxAllowedUsage","isOverage","hardLimit","overage"],"properties":{"activeUsage":{"type":"integer","format":"int64","description":"Bytes consumed by active and pending files."},"recycleBinUsage":{"type":"integer","format":"int64","description":"Bytes consumed by soft-deleted files still retained in the recycle bin."},"totalUsage":{"type":"integer","format":"int64","description":"Sum of activeUsage and recycleBinUsage. This is the figure checked\nagainst hardLimit when an upload is attempted."},"systemUsage":{"type":"integer","format":"int64","description":"Bytes consumed by system items (folders and files the platform\ncreated). Present only when the request sets `includeSystem=true`."},"maxAllowedUsage":{"type":"integer","format":"int64","description":"Storage quota in bytes granted by the account's license."},"isOverage":{"type":"boolean","description":"When true, totalUsage has passed maxAllowedUsage and the account is\nconsuming the overage buffer. Uploads still succeed until totalUsage\nreaches hardLimit."},"hardLimit":{"type":"integer","format":"int64","description":"Byte ceiling at which further uploads are rejected with\n`STORAGE_QUOTA_EXCEEDED`. Equals maxAllowedUsage plus the licensed\noverage buffer, or maxAllowedUsage exactly when overage is disabled."},"overage":{"type":"integer","format":"int64","description":"Bytes currently consumed beyond maxAllowedUsage. Zero when not in overage."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/usage":{"get":{"summary":"Get storage usage","description":"Returns account-wide storage usage and entitlement, aggregated across all\nenvironments: bytes in use (active and recycle bin), the licensed quota,\nthe hard limit at which uploads are blocked, and whether the account is in\noverage.","operationId":"getStorageUsage","tags":["File Storage"],"parameters":[{"name":"includeSystem","in":"query","required":false,"description":"When true, also returns `systemUsage` — the bytes consumed by system items.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Account-wide usage and entitlement.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```

## Get storage usage by environment

> Returns the same account-wide totals as \`GET /v1/storage/usage\`, broken\
> down per environment. Use it to see which environment is consuming the\
> account's shared quota.

```json
{"openapi":"3.2.0","info":{"title":"File Storage","version":"1.0.0"},"tags":[{"name":"File Storage","description":"Celigo Storage is managed file storage built into integrator.io for staging files between flows and giving integrations persistent files to work with. Organize content into files and folders, transfer bytes directly through short-lived presigned S3 URLs, and reference stored files from flows. Items are addressed by `_id` and placed by parent folder; renames and moves keep the `_id` stable, and deletes go to a 30-day recycle bin before they can be purged.\n\n## Storage item schema\n\n{% openapi-schemas spec=\"filestorage\" schemas=\"StorageItem\" grouped=\"true\" %}"}],"servers":[{"url":"https://api.integrator.io","description":"Production (US / default region)"},{"url":"https://api.eu.integrator.io","description":"Production (EU region)"},{"url":"https://api.au.integrator.io","description":"Production (AU region)"},{"url":"https://api.ca.integrator.io","description":"Production (CA region)"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer"}},"schemas":{"UsageEnvironments":{"type":"object","description":"Per-environment usage breakdown alongside the same account-wide totals\nreturned by `GET /v1/storage/usage`.","required":["environments","activeUsage","recycleBinUsage","totalUsage","maxAllowedUsage","isOverage","hardLimit","overage"],"properties":{"environments":{"type":"array","description":"One entry per environment in the account.","items":{"$ref":"#/components/schemas/EnvironmentUsage"}},"activeUsage":{"type":"integer","format":"int64","description":"Account-wide bytes consumed by active and pending files."},"recycleBinUsage":{"type":"integer","format":"int64","description":"Account-wide bytes consumed by soft-deleted files."},"totalUsage":{"type":"integer","format":"int64","description":"Account-wide sum of activeUsage and recycleBinUsage."},"systemUsage":{"type":"integer","format":"int64","description":"Account-wide bytes consumed by system items. Present only when the\nrequest sets `includeSystem=true`."},"maxAllowedUsage":{"type":"integer","format":"int64","description":"Storage quota in bytes granted by the account's license."},"isOverage":{"type":"boolean","description":"When true, totalUsage has passed maxAllowedUsage and the account is in the overage buffer."},"hardLimit":{"type":"integer","format":"int64","description":"Byte ceiling at which further uploads are rejected."},"overage":{"type":"integer","format":"int64","description":"Bytes currently consumed beyond maxAllowedUsage. Zero when not in overage."}}},"EnvironmentUsage":{"type":"object","description":"Storage usage for a single environment.","required":["_envUserId","activeUsage","recycleBinUsage","totalUsage"],"properties":{"_envUserId":{"type":"string","format":"objectId","description":"Environment user ID this breakdown belongs to."},"name":{"type":"string","description":"Environment name, such as Production or Sandbox."},"activeUsage":{"type":"integer","format":"int64","description":"Bytes consumed by active and pending files in this environment."},"recycleBinUsage":{"type":"integer","format":"int64","description":"Bytes consumed by this environment's soft-deleted files."},"totalUsage":{"type":"integer","format":"int64","description":"Sum of this environment's activeUsage and recycleBinUsage."}}},"Error":{"type":"object","description":"Standard error response envelope returned by integrator.io APIs.","properties":{"errors":{"type":"array","description":"List of errors that occurred while processing the request.","items":{"type":"object","properties":{"code":{"oneOf":[{"type":"string"},{"type":"integer"}],"description":"Machine-readable error code. Usually a string like\n`invalid_ref`, `missing_required_field`, or `unauthorized`;\nmay be an **integer** when the error mirrors an upstream HTTP\nstatus (e.g. `500`) — most commonly returned by connection-ping\nand adaptor-proxy responses."},"message":{"type":"string","description":"Human-readable description of the error."},"field":{"type":"string","description":"Optional pointer to the document field that caused the error.\nUsed by structural validation errors (`missing_required_field`,\n`invalid_ref`) to indicate which field is at fault\n(e.g. `_id`, `type`, `http.baseURI`)."},"source":{"type":"string","description":"Optional origin layer for the error — e.g. `application` when\nthe error came from the remote system the adaptor called,\n`connector` when the adaptor itself rejected the request."}},"required":["message"]}}},"required":["errors"]}},"responses":{"401-unauthorized":{"description":"Unauthorized. The request lacks a valid bearer token, or the provided token\nfailed to authenticate.\n\nNote: the 401 response is produced by the auth middleware **before** the\nrequest reaches the endpoint handler, so it does **not** follow the\nstandard `{errors: [...]}` envelope. Instead the body is a bare\n`{message: string}` object with no `code`, no `errors` array. Callers\nhandling 401s should key off the HTTP status and the `message` string,\nnot try to destructure an `errors[]`.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Human-readable description of the auth failure. Known values:\n- `\"Unauthorized\"` — no `Authorization` header on the request.\n- `\"Bearer Authentication Failed\"` — header present but token\n  is invalid, revoked, or expired."}},"required":["message"]}}}},"403-forbidden":{"description":"Forbidden. The authenticated caller does not have permission to perform this operation.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422-unprocessable-entity":{"description":"Unprocessable entity. The request was well-formed but was unable to be followed due to semantic errors.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/storage/usage/environments":{"get":{"summary":"Get storage usage by environment","description":"Returns the same account-wide totals as `GET /v1/storage/usage`, broken\ndown per environment. Use it to see which environment is consuming the\naccount's shared quota.","operationId":"getStorageUsageByEnvironment","tags":["File Storage"],"parameters":[{"name":"includeSystem","in":"query","required":false,"description":"When true, also returns `systemUsage` in the account-wide totals.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Per-environment breakdown with account-wide totals.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageEnvironments"}}}},"401":{"$ref":"#/components/responses/401-unauthorized"},"403":{"$ref":"#/components/responses/403-forbidden"},"422":{"$ref":"#/components/responses/422-unprocessable-entity"}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.celigo.com/api/api-reference/file-storage.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
