> For the complete documentation index, see [llms.txt](https://docs.osmosworks.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.osmosworks.com/business-modules/files-and-storage.md).

# Files and storage

This module covers file uploads, metadata, delivery URLs, and deletion.

## Storage provider

Osmos uses Cloudinary as the default storage provider. Files are uploaded directly from the client to Cloudinary using a signed upload authorization issued by the backend. This keeps large files out of the application server.

## Upload flow

```mermaid
sequenceDiagram
    autonumber
    participant Client as Frontend / Client
    participant Osmos as Osmos Backend
    participant Cloud as Cloudinary
    participant DB as PostgreSQL

    Client->>Osmos: POST /api/v1/files (filename, mimeType, size)
    Osmos->>Osmos: Check MIME whitelist & size <= 20MB
    Osmos->>DB: Create FileObject (status: PENDING)
    Osmos->>Osmos: Compute HMAC upload signature with API Secret
    Osmos-->>Client: 201 Created {uploadUrl, apiKey, timestamp, signature, publicId}
    
    Client->>Cloud: POST direct multipart/form-data
    Cloud-->>Client: 200 OK (Upload stored in Cloudinary)
    
    Cloud->>Osmos: POST /api/v1/files/webhooks/cloudinary (X-Cld-Signature)
    Osmos->>Osmos: Verify HMAC signature & timestamp age (<= 300s)
    Osmos->>DB: Update FileObject status -> UPLOADED
    Osmos-->>Cloud: 200 OK Webhook received
```

1. Client calls `POST /api/v1/files` with file metadata (filename, MIME type, size).
2. Backend validates the file type and size, creates a pending `FileObject`, and returns an upload URL and signed parameters.
3. Client uploads the file directly to Cloudinary.
4. Cloudinary calls `POST /api/v1/files/webhooks/cloudinary` with the upload result.
5. Backend verifies the webhook signature and updates the `FileObject` to `UPLOADED`.

If the upload parameters expire, the client can request a fresh signature:

`POST /api/v1/files/{fileId}/upload-signature`

## File status

* `PENDING` — upload authorized but not yet confirmed.
* `UPLOADED` — confirmed by the provider.
* `DELETED` — marked as deleted in Osmos; removed from Cloudinary if it was uploaded.

## File metadata

`GET /api/v1/files/{fileId}` returns metadata including:

* Original filename, MIME type, size, format.
* Storage provider, public ID, resource type.
* Status and uploaded timestamp.
* View and download URLs (only when status is `UPLOADED`).

## Deletion

`DELETE /api/v1/files/{fileId}` deletes the file from Cloudinary and marks the `FileObject` as `DELETED`. It also evicts the file from the Redis cache.

## Configuration

| Setting                    | Default      | Description                              |
| -------------------------- | ------------ | ---------------------------------------- |
| `CLOUDINARY_URL`           | —            | Connection URL for Cloudinary.           |
| `CLOUDINARY_FOLDER`        | `kleankoder` | Folder path for uploaded assets.         |
| `CLOUDINARY_UPLOAD_PRESET` | —            | Optional upload preset.                  |
| `FILE_UPLOAD_TTL_MINUTES`  | 30           | How long upload signatures remain valid. |
| `FILE_MAX_SIZE_BYTES`      | 20971520     | Maximum file size (20 MB).               |

## Permissions

* `file:upload` — authorize and re-sign uploads.
* `file:view` — read file metadata.
* `file:delete` — delete files.

## Webhook security

Cloudinary webhook requests include `X-Cld-Timestamp` and `X-Cld-Signature` headers. The backend verifies the signature against the configured secret and rejects requests older than `CLOUDINARY_WEBHOOK_MAX_AGE_SECONDS` (default 300 seconds).


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.osmosworks.com/business-modules/files-and-storage.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
