# easyCDN Documentation > easyCDN is a modern content delivery network designed for developers who need fast, reliable, and scalable asset delivery with asset transformations and asset expiration functionality. ## Quick Start Integrate easyCDN into your application in minutes. The Quick Start Guide is adjusted for a Next.js application. Your Public and Secret Keys are accessible in the Developers section of your dashboard. Keep your Secret Key secure and never expose it in client-side code. --- ## React SDK ### Installation Prerequisites: - React 19+ - easyCDN Account (sign up at easycdn.co) ```bash npm install @easycdn/react ``` Peer Dependencies: react@^19, react-dom@^19 TypeScript support is included — no additional @types packages needed. ### Auth & Basic Usage easyCDN uses two types of API keys: - **Public Key:** Safe for client-side use, used in React components - **Secret Key:** Server-side only, never expose in client code Getting Your API Keys: 1. Log in to your easyCDN dashboard 2. Navigate to your project settings 3. Go to the "Developers" section 4. Copy your Public Key for client-side use Basic usage: ```typescript 'use client' import { Dropzone } from '@easycdn/react' export default function MyUploadPage() { return ( { console.log('Upload complete:', { tempId, previewUrl }) // make sure to persist this asset in the backend, see Node.js SDK }} /> ) } ``` Environment Variables: Next.js (.env.local): ```bash NEXT_PUBLIC_EASYCDN_PUBLIC_KEY=pk-your-public-key-here ``` Create React App: ```bash REACT_APP_EASYCDN_PUBLIC_KEY=pk-your-public-key-here ``` Vite: ```bash VITE_EASYCDN_PUBLIC_KEY=pk-your-public-key-here ``` File size and type restrictions: ```typescript ``` Visual customization: ```typescript ``` Full-featured example: ```typescript 'use client' import { Dropzone } from '@easycdn/react' import { useState } from 'react' import { toast } from 'sonner' export default function FileUploadComponent() { const [uploadedFiles, setUploadedFiles] = useState([]) const handleUploadComplete = ({ tempId, previewUrl, expiresAt }, file) => { setUploadedFiles(prev => [...prev, { id: tempId, name: file.name, url: previewUrl, expiresAt }]) toast.success(`${file.name} uploaded successfully!`) } const handleUploadError = (error, file) => { toast.error('Upload failed. Please try again or contact support.') } return (

Upload Your Files

) } ``` Security Best Practices: - Always use environment variables for API keys - Add .env* files to your .gitignore - Only use your public key in client-side code - Always use HTTPS in production ### API Reference — Dropzone Component The main file upload component with drag-and-drop functionality. Handles file validation, upload progress, retry logic, and provides callbacks for upload events. ```typescript import { Dropzone } from '@easycdn/react' { // Handle completion }} /> ``` Properties: | Name | Type | Default | Description | |------|------|---------|-------------| | publicKey | string | required | Your easyCDN public API key | | onUploadComplete | (uploadResult: UploadResult, file?: File) => void | — | Called when a single file upload completes successfully | | acceptedFileTypes | string[] | undefined | Array of accepted MIME types or extensions | | maxSize | number | 15GB | Maximum file size in bytes | | maxFiles | number | 10 | Maximum number of files allowed | | showPreview | boolean | false | Show image previews in file list | | theme | 'light' | 'dark' | 'auto' | 'auto' | Force light/dark theme or respect parent | | compact | boolean | false | Use compact file list layout | | clearAfter | number | 5000 | Auto-clear completed uploads after milliseconds | | maxRetries | number | 3 | Maximum retry attempts for failed uploads | | className | string | undefined | Additional CSS classes | | onAllUploadsComplete | () => void | — | Called when all queued uploads have finished | | baseUrl | string | — | Custom API endpoint URL (usually not needed) | | projectId | string | optional | Optional project ID for multi-project setups (usually not needed) | Example with backend persistence: ```typescript import { Dropzone } from '@easycdn/react' export default function App() { async function handleUploadComplete({ tempId }: UploadResult) { const response = await fetch('/api/persist-file', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tempId }) }) const { asset } = await response.json() console.log('Persisted asset URL:', asset.url) } return ( ) } ``` --- ## Node.js SDK ### Installation Prerequisites: - Node.js 18+ - easyCDN Account (sign up at easycdn.co) ```bash npm install @easycdn/server ``` Also available via yarn and pnpm. TypeScript support is included. Verification: ```typescript import { createClient } from '@easycdn/server' const client = createClient({ secretKey: process.env.EASYCDN_SECRET_KEY! }) console.log('easyCDN Node.js SDK installed successfully!') ``` ### Auth & Basic Usage The Node.js SDK uses secret API keys for server-side authentication. Getting Your Secret Key: 1. Log in to your easyCDN dashboard 2. Navigate to your project settings 3. Go to the "Developers" section 4. Copy your Secret Key for server-side use Client initialization: ```typescript import { createClient } from '@easycdn/server' const client = createClient({ secretKey: process.env.EASYCDN_SECRET_KEY }) ``` Persist files from Dropzone / React SDK: ```typescript export async function POST(request: Request) { const { tempAssetId } = await request.json() try { const persistedAsset = await client.persist({ tempAssetId }) return Response.json({ success: true, asset: persistedAsset }) } catch (error) { return Response.json({ success: false, error: error.message }, { status: 500 }) } } ``` Simple file upload: ```typescript // Upload from file path const result = await client.upload('./image.jpg') // Upload from Buffer const buffer = Buffer.from('file content') const result = await client.upload(buffer, { fileName: 'data.txt' }) // Upload from stream import { createReadStream } from 'fs' const stream = createReadStream('./video.mp4') const result = await client.upload(stream, { fileName: 'video.mp4' }) ``` Security Best Practices: - Always use environment variables for secret keys - Add .env* files to your .gitignore - Never expose secret keys in client-side code or logs - Rotate API keys regularly - Use different keys for different environments (dev, staging, prod) - Always use HTTPS in production - Implement proper error handling to avoid leaking sensitive information ### OpenAI Integration Upload images from OpenAI Image API and Chat Completions with Image Generation directly to easyCDN. ```bash npm install @easycdn/server openai ``` Usage with Image API: ```typescript import { createClient } from '@easycdn/server' import OpenAI from 'openai' const easyCdnClient = createClient({ secretKey: process.env.EASYCDN_SECRET_KEY!, }) const openAiClient = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }) const response = await openAiClient.images.generate({ model: 'gpt-image-1', prompt: 'A beautiful sunset over a calm ocean', n: 1, size: '1024x1024', }) const uploadedAssets = await easyCdnClient.uploadFromOpenAi(response) for (const asset of uploadedAssets) { console.log(`- ${asset.asset.name}: ${asset.asset.url}`) } ``` Usage with Chat Completions API: ```typescript const response = await openAiClient.responses.create({ model: 'gpt-5', input: 'Generate an image of gray tabby cat hugging an otter with an orange scarf', tools: [{ type: 'image_generation' }], }) const uploadedAssets = await easyCdnClient.uploadFromOpenAi(response) ``` Extended usage with transformation and expiration: ```typescript const uploadedAssets = await easyCdnClient.uploadFromOpenAi(response, { fileNamePrefix: 'openai-sunset', expiresAt: dayjs().add(1, 'day').toISOString(), transform: { image: { width: 642, format: 'webp', }, }, }) ``` ### xAI Integration Upload images from xAI Grok image generation directly to easyCDN. Uses the Vercel AI SDK with the xAI provider. ```bash npm install @easycdn/server ai @ai-sdk/xai ``` ```typescript import { createClient } from '@easycdn/server' import { xai } from '@ai-sdk/xai' import { generateImage } from 'ai' const easyCdnClient = createClient({ secretKey: process.env.EASYCDN_SECRET_KEY!, }) const { image } = await generateImage({ model: xai.image('grok-imagine-image'), prompt: 'A lake with a mountain in the background', aspectRatio: '16:9', }) const uploadedAsset = await easyCdnClient.upload( Buffer.from(image.base64, 'base64'), { fileName: 'xai-lake.png' }, ) console.log(`Uploaded: ${uploadedAsset.asset.url}`) ``` ### Google AI Integration Upload images from Google Gemini image generation directly to easyCDN. ```bash npm install @easycdn/server @google/genai ``` ```typescript import { createClient } from '@easycdn/server' import { GoogleGenAI } from '@google/genai' const easyCdnClient = createClient({ secretKey: process.env.EASYCDN_SECRET_KEY!, }) const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY! }) const response = await ai.models.generateContent({ model: 'gemini-2.5-flash-image', contents: 'Generate an image of a tiny banana wearing sunglasses', config: { responseModalities: ['Text', 'Image'], }, }) const uploadedAssets = await easyCdnClient.uploadFromGoogleAi(response) for (const asset of uploadedAssets) { console.log(`- ${asset.asset.name}: ${asset.asset.url}`) } ``` ### API Reference #### createClient() Initialize a new easyCDN API client for Node.js applications. ```typescript import { createClient } from '@easycdn/server' createClient(options: { secretKey: string baseUrl?: string }): ApiClient ``` Parameters: - secretKey (string, required) — Your easyCDN API secret key - baseUrl (string, optional) — Custom API base URL (defaults to production) Returns an ApiClient instance with methods: upload(), persist(), uploadFromOpenAi(), uploadFromGoogleAi(), healthCheck() #### persist() Persist a temporary asset to permanent storage. Optionally apply transformations. ```typescript persist(input: { tempAssetId: string transform?: TransformOptions expiresAt?: string fileName?: string }): Promise<{ asset: Asset }> ``` Parameters: - tempAssetId (string, required) — The ID of the temporary asset to persist - transform (TransformOptions, optional) — Transformations to apply - expiresAt (string, optional) — Expiration date (ISO datetime format) - fileName (string, optional) — Custom filename for the asset Example: ```typescript const result = await client.persist({ tempAssetId: 'temp-asset-id-123', transform: { image: { width: 800, height: 600, quality: 85, format: 'webp' } } }) console.log(result.asset.url) ``` #### upload() Upload a file from a file path, Buffer, or stream. Handles multipart uploads automatically. ```typescript upload( source: string | Buffer | ReadableStream, options?: { fileName?: string onProgress?: (progress: UploadProgress) => void transform?: TransformOptions expiresAt?: string chunkSize?: number } ): Promise<{ asset: Asset }> ``` Parameters: - source (string | Buffer | ReadableStream, required) — File path, Buffer, or stream to upload - fileName (string, optional) — Custom filename - onProgress (function, optional) — Upload progress callback - transform (TransformOptions, optional) — Transformations to apply - expiresAt (string, optional) — Expiration date (ISO datetime format) - chunkSize (number, optional) — Chunk size for multipart uploads (in bytes) Examples: ```typescript // Upload from file path const result = await client.upload('/path/to/file.jpg') // Upload with progress tracking const result = await client.upload('/path/to/large-file.mp4', { onProgress: (progress) => { console.log(`Progress: ${progress.percentage}%`) } }) // Upload Buffer with transformation const buffer = fs.readFileSync('/path/to/image.png') const result = await client.upload(buffer, { fileName: 'my-image.webp', transform: { image: { width: 1200, format: 'webp', quality: 90 } } }) ``` #### uploadFromOpenAi() Upload images generated by OpenAI or xAI directly to easyCDN. ```typescript uploadFromOpenAi( response: ImagesResponse | OpenAI.Responses.Response | any, options?: { fileNames?: string[] fileNamePrefix?: string onProgress?: (progress: UploadProgress) => void transform?: TransformOptions expiresAt?: string } ): Promise> ``` Parameters: - response (required) — OpenAI or xAI image generation response - fileNames (string[], optional) — Custom filenames for each generated image - fileNamePrefix (string, optional) — Prefix for auto-generated filenames - onProgress (function, optional) — Upload progress callback - transform (TransformOptions, optional) — Transformations to apply - expiresAt (string, optional) — Expiration date (ISO datetime format) Returns array of uploaded assets with CDN URLs. #### uploadFromGoogleAi() Upload images generated by Google Gemini directly to easyCDN. ```typescript uploadFromGoogleAi( response: GenerateContentResponse | any, options?: { fileNames?: string[] fileNamePrefix?: string onProgress?: (progress: UploadProgress) => void transform?: TransformOptions expiresAt?: string } ): Promise> ``` Parameters: - response (required) — Google GenAI image generation response - fileNames (string[], optional) — Custom filenames for each generated image - fileNamePrefix (string, optional) — Prefix for auto-generated filenames - onProgress (function, optional) — Upload progress callback - transform (TransformOptions, optional) — Transformations to apply - expiresAt (string, optional) — Expiration date (ISO datetime format) Returns array of uploaded assets with CDN URLs. --- ## HTTP API ### Setup Prerequisites: - Any HTTP client (curl, Postman, or built into your application) - easyCDN Account (sign up at easycdn.co) - API Secret Key (available in your easyCDN dashboard) ### Auth & Basic Usage The easyCDN HTTP API uses Bearer token authentication. Base URL: ``` https://api.easycdn.co ``` Authentication header: ``` Authorization: Bearer YOUR_SECRET_KEY ``` Content-Type: ``` Content-Type: application/json ``` Example request: ```bash curl -X POST https://api.easycdn.co/asset/upload/persist \ -H "Authorization: Bearer ${EASYCDN_SECRET_KEY}" \ -H "Content-Type: application/json" \ -d '{"tempAssetId": "temp_abc123"}' ``` ### API Reference #### POST /asset/upload/persist Persist a temporary asset uploaded from the client-side Dropzone, converting it to a permanent asset with a permanent CDN URL. ```http POST https://api.easycdn.co/asset/upload/persist Authorization: Bearer YOUR_SECRET_KEY Content-Type: application/json ``` Request body: ```json { "tempAssetId": "temp_abc123" } ``` Parameters: - tempAssetId (string, required) — The temporary asset ID from client-side upload Response: ```json { "asset": { "_id": "507f1f77bcf86cd799439011", "bucket": "easycdn-assets", "key": "uploads/2024/01/15/image.jpg", "name": "image.jpg", "size": 1024000, "type": "image/jpeg", "createdAt": "2024-01-15T10:30:00.000Z", "updatedAt": "2024-01-15T10:30:00.000Z", "projectId": "507f1f77bcf86cd799439012", "url": "https://cdn.easycdn.co/uploads/2024/01/15/image.jpg", "expiresAt": null, "userId": "507f1f77bcf86cd799439013" } } ``` curl example: ```bash curl -X POST https://api.easycdn.co/asset/upload/persist \ -H "Authorization: Bearer ${EASYCDN_SECRET_KEY}" \ -H "Content-Type: application/json" \ -d '{ "tempAssetId": "temp_abc123" }' ``` Python example: ```python import requests import os response = requests.post( 'https://api.easycdn.co/asset/upload/persist', json={'tempAssetId': temp_asset_id}, headers={ 'Authorization': f"Bearer {os.environ.get('EASYCDN_SECRET_KEY')}", 'Content-Type': 'application/json' } ) ``` Ruby example: ```ruby response = HTTParty.post( 'https://api.easycdn.co/asset/upload/persist', body: { tempAssetId: temp_asset_id }.to_json, headers: { 'Authorization' => "Bearer #{ENV['EASYCDN_SECRET_KEY']}", 'Content-Type' => 'application/json' } ) ``` --- ## Schemas ### Asset | Field | Type | Description | |-------|------|-------------| | _id | string | Unique identifier for the asset | | url | string | Public CDN URL for accessing the asset | | name | string | Filename of the asset | | size | number | File size in bytes | | type | string | MIME type of the asset | | expiresAt | string or null | Optional expiration date (ISO datetime) | | projectId | string | ID of the project this asset belongs to | | createdAt | string | When the asset was created (ISO datetime) | | updatedAt | string | When the asset was last updated (ISO datetime) | | bucket | string | Storage bucket where the asset is stored | | key | string | Storage key/path for the asset | | userId | string | ID of the user who uploaded the asset | ### UploadResult | Field | Type | Description | |-------|------|-------------| | tempId | string | Temporary file ID for the uploaded file | | previewUrl | string | Preview URL to uploaded file (not persisted yet) | | expiresAt | Date | When the temporary file expires | ### TransformOptions Options for transforming assets during upload or persist operations. ```typescript { image?: { width?: number // Target width in pixels height?: number // Target height in pixels quality?: number // Image quality (1-100) format?: 'webp' | 'jpeg' | 'png' // Output format } } ```