Upload files to Whop for use in courses, forums, profiles, and more. The SDK provides a simple upload method that handles the entire process for you.
import fs from 'fs';
const file = await client.files.upload({
file: fs.readFileSync('./photo.jpg'),
filename: 'photo.jpg',
});
console.log(file.id); // file_xxxxxxxxxxxxx
console.log(file.url); // URL to access the file
The upload method:
- Creates a file record with a presigned URL
- Uploads your file to storage
- Polls until processing is complete
- Returns the ready file with its final URL
Public vs private files
Every file you upload has a visibility that controls how it can be accessed. You choose visibility at upload time — it cannot be changed after.
| Visibility | URL type | Who can access | Use for |
|---|
public (default) | Permanent, unsigned CDN URL | Anyone with the link | Product images, thumbnails, branding, marketing assets |
private | Signed URL that expires | Only your app, via the API | User-uploaded documents, sensitive content, AI-generated files |
Choose carefully. Public files are cached on our CDN and accessible to anyone with the URL — there is no way to revoke access. If the content is user-specific or sensitive, use private.
Uploading a private file
Pass visibility: "private" when creating the file:
const file = await client.files.upload({
file: fs.readFileSync('./user-document.pdf'),
filename: 'user-document.pdf',
visibility: 'private',
});
// file.url is a signed URL that expires — fetch it fresh via
// client.files.retrieve(file.id) whenever you need a new one
Accessing private files
Private file URLs expire. To get a fresh URL, retrieve the file by ID:
const file = await client.files.retrieve(fileId);
console.log(file.url); // fresh signed URL
Using uploaded files
Once uploaded, use the file ID in any API call that accepts file attachments:
await client.courses.update({
id: "course_xxx",
thumbnail: { id: file.id },
});
File properties
| Property | Description |
|---|
id | Unique identifier (e.g., file_xxxxxxxxxxxxx) |
filename | Original filename |
content_type | MIME type (e.g., image/jpeg) |
byte_size | File size in bytes |
url | URL to access the file (signed and expiring for private files) |
upload_status | Status: pending, processing, ready, or failed |
visibility | public or private |