Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nayalsaurav/Storx/llms.txt

Use this file to discover all available pages before exploring further.

Accepts a multipart/form-data request containing the file binary and ownership metadata. The endpoint validates the Clerk session, checks the file type, optionally verifies the target parent folder, uploads the file to ImageKit under /storex/{userId}/, and persists a metadata record in the database.

Request

Method: POST
Path: /api/files/upload
Content-Type: multipart/form-data
Auth: Clerk session cookie required. The userId form field must match the session’s user ID.

Form Fields

file
File
required
The binary file to upload. Accepted MIME types are:
  • image/* — any image format (JPEG, PNG, WebP, GIF, etc.)
  • application/pdf — PDF documents
Any other MIME type returns a 400 error.
userId
string
required
The Clerk user ID of the authenticated user. Must match the session’s userId exactly; mismatches return 401 without touching storage.
parentId
string
UUID of an existing folder to upload into. When provided the endpoint queries the database to confirm the folder exists, is a folder (isFolder = true), and belongs to the authenticated user — returning 404 if any check fails. Omit to upload to the user’s root directory.

ImageKit Storage Path

The file is stored under one of these paths depending on whether parentId is supplied:
ScenarioImageKit folder path
No parentId (root)/storex/{userId}/
With parentId (folder)/storex/{userId}/folder/{parentId}/
The stored filename is a UUID v4 with the original extension preserved (e.g. 3f7a1b2c-....jpg). useUniqueFileName is set to false so the UUID filename is used as-is. The original filename is kept in the database name field for display.

Response

200 — Success

Returns a JSON object confirming success and the full persisted FileItem record.
{
  "success": true,
  "file": {
    "id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "name": "photo.jpg",
    "path": "/storex/user_abc123/3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c.jpg",
    "size": 2048576,
    "type": "image/jpeg",
    "fileUrl": "https://ik.imagekit.io/your_id/storex/user_abc123/3f7a1b2c.jpg",
    "thumbnailUrl": "https://ik.imagekit.io/your_id/tr:n-ik_ml_thumbnail/storex/user_abc123/3f7a1b2c.jpg",
    "imagekitFileId": "ik_abc123xyz",
    "userId": "user_abc123",
    "parentId": null,
    "isFolder": false,
    "isStarred": false,
    "isTrash": false,
    "createdAt": "2024-11-01T10:30:00.000Z",
    "updatedAt": "2024-11-01T10:30:00.000Z"
  }
}
success
boolean
required
Always true on a successful upload.
file
FileItem
required
The full database record created for the uploaded file.

Error Responses

StatusError messageCause
400"File is required"The file field is missing from the form data.
400"Only images and PDF files are supported"The uploaded file’s MIME type is not image/* or application/pdf.
401"Unauthorized"No active Clerk session, or userId form field doesn’t match the session user.
404"Parent folder not found"The provided parentId doesn’t exist, isn’t a folder, or isn’t owned by user.
503"File upload service error"ImageKit threw an error during the upload operation.
500"Failed to upload file"Unexpected server or database error.

Examples

curl -X POST https://your-app.vercel.app/api/files/upload \
  -H "Cookie: __session=<clerk_session_token>" \
  -F "file=@photo.jpg" \
  -F "userId=user_abc123"
Do not set the Content-Type header manually when using FormData in the browser or Node.js — the runtime sets the correct multipart/form-data boundary automatically.

Build docs developers (and LLMs) love