Build Your First App
Learn to integrate the CyberPod SDK into your app with practical examples. This tutorial focuses on SDK usage patterns with minimal UI components.
What You'll Learn
- Initialize and configure the SDK
- Authenticate users and manage sessions
- Fetch and display user data
- Work with projects and files
- Use AI chat completions with streaming
- Handle notifications
Prerequisites
- Node.js 18+
- Basic React/TypeScript knowledge
- CyberPod API access (or use mock mode for learning)
Part 1: Setup
Create Your Project
npx @cpod/cli create my-app
cd my-app
npm install
Install the SDK
npm install @cpod/sdk @cpod/react
Initialize the SDK
Create lib/sdk.ts:
import { CyberPod } from "@cpod/sdk";
// Create SDK instance
export const sdk = new CyberPod({
baseUrl: process.env.NEXT_PUBLIC_CPOD_BASE_URL!,
});
// Helper to set auth token after login
export function setAuthToken(token: string) {
sdk.setAccessToken(token);
}
Setup Provider
In your app/layout.tsx:
import "@cpod/react/styles.css";
import { ThemeProvider } from "@cpod/react";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
);
}
Part 2: Authentication
SDK Functions
import { sdk } from "@/lib/sdk";
// Login with credentials
async function login(email: string, password: string) {
const tokens = await sdk.auth.authenticateUser({
username: email,
password: password,
});
// Store tokens
localStorage.setItem("access_token", tokens.access_token);
localStorage.setItem("refresh_token", tokens.refresh_token);
// Set for API calls
sdk.setAccessToken(tokens.access_token);
return tokens;
}
// Check current session
async function getSession() {
const session = await sdk.auth.getSession();
return session;
}
// Logout
async function logout() {
await sdk.auth.signOutUser();
localStorage.removeItem("access_token");
localStorage.removeItem("refresh_token");
}
// Refresh expired token
async function refreshToken() {
const refreshToken = localStorage.getItem("refresh_token");
const tokens = await sdk.auth.refreshToken({ refresh_token: refreshToken });
sdk.setAccessToken(tokens.access_token);
return tokens;
}
Simple Login Form
Live Editor
function LoginExample() { const [email, setEmail] = React.useState(''); const [password, setPassword] = React.useState(''); const [status, setStatus] = React.useState(''); const handleLogin = async () => { setStatus('Logging in...'); // In real app: const tokens = await sdk.auth.authenticateUser({...}) await new Promise(r => setTimeout(r, 1000)); // Simulate API setStatus('✅ Logged in! Token stored.'); }; return ( <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', maxWidth: '300px' }}> <input type="email" placeholder="Email" value={email} onChange={e => setEmail(e.target.value)} style={{ padding: '8px 12px', border: '1px solid #e2e8f0', borderRadius: '6px' }} /> <input type="password" placeholder="Password" value={password} onChange={e => setPassword(e.target.value)} style={{ padding: '8px 12px', border: '1px solid #e2e8f0', borderRadius: '6px' }} /> <button onClick={handleLogin} style={{ padding: '10px', background: '#8b5cf6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }} > Login </button> {status && <p style={{ margin: 0, fontSize: '14px', color: '#64748b' }}>{status}</p>} </div> ); }
Result
Loading...
Response Types
interface AuthTokens {
access_token: string;
refresh_token: string;
token_type: string;
expires_in: number;
}
interface Session {
user_id: string;
email: string;
name: string;
role: string;
permissions: string[];
}
Part 3: Users API
SDK Functions
import { sdk } from "@/lib/sdk";
// Get current user profile
async function getCurrentUser() {
const user = await sdk.users.getUser();
return user;
}
// Update user profile
async function updateProfile(data: { name?: string; avatar_url?: string }) {
const updated = await sdk.users.updateUser(data);
return updated;
}
// Get user activity logs
async function getUserActivity(startDate: string, endDate: string) {
const activity = await sdk.users.getUserActivity({
start_date: startDate,
end_date: endDate,
});
return activity;
}
Display User Profile
Live Editor
function UserProfileExample() { const [user, setUser] = React.useState(null); const [loading, setLoading] = React.useState(false); const fetchUser = async () => { setLoading(true); // In real app: const user = await sdk.users.getUser(); await new Promise(r => setTimeout(r, 500)); setUser({ id: 'usr_abc123', name: 'John Doe', email: 'john@example.com', role: 'Developer', created_at: '2024-01-15', }); setLoading(false); }; return ( <div style={{ maxWidth: '400px' }}> <button onClick={fetchUser} disabled={loading} style={{ padding: '8px 16px', background: '#8b5cf6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', marginBottom: '16px' }} > {loading ? 'Loading...' : 'Fetch User (sdk.users.getUser)'} </button> {user && ( <div style={{ padding: '16px', border: '1px solid #e2e8f0', borderRadius: '8px', background: '#f8fafc' }}> <p style={{ margin: '0 0 8px', fontWeight: 600 }}>{user.name}</p> <p style={{ margin: '0 0 4px', fontSize: '14px', color: '#64748b' }}>{user.email}</p> <p style={{ margin: '0 0 4px', fontSize: '14px', color: '#64748b' }}>Role: {user.role}</p> <p style={{ margin: 0, fontSize: '12px', color: '#94a3b8' }}>ID: {user.id}</p> </div> )} </div> ); }
Result
Loading...
Response Types
interface User {
id: string;
name: string;
email: string;
role: string;
avatar_url?: string;
created_at: string;
updated_at: string;
}
Part 4: Projects API
SDK Functions
import { sdk } from "@/lib/sdk";
// List all projects
async function listProjects(page = 1, limit = 20) {
const result = await sdk.projects.listProjects({ page, limit });
return result; // { projects: Project[], total: number }
}
// Create a project
async function createProject(name: string, description?: string) {
const project = await sdk.projects.createProject({
name,
description,
});
return project;
}
// Get project details
async function getProject(projectId: string) {
const project = await sdk.projects.getProject(projectId);
return project;
}
// Update project
async function updateProject(projectId: string, data: { name?: string; description?: string }) {
const updated = await sdk.projects.updateProject(projectId, data);
return updated;
}
// Delete project
async function deleteProject(projectId: string) {
await sdk.projects.deleteProject(projectId);
}
// Add files to project
async function addFilesToProject(projectId: string, fileIds: string[]) {
await sdk.projects.addFilesToProject(projectId, { file_ids: fileIds });
}
Projects List Example
Live Editor
function ProjectsExample() { const [projects, setProjects] = React.useState([]); const [loading, setLoading] = React.useState(false); const [newName, setNewName] = React.useState(''); const fetchProjects = async () => { setLoading(true); // In real app: const { projects } = await sdk.projects.listProjects(); await new Promise(r => setTimeout(r, 500)); setProjects([ { id: 'proj_1', name: 'Marketing Campaign', files_count: 12 }, { id: 'proj_2', name: 'Q4 Report', files_count: 8 }, ]); setLoading(false); }; const createProject = async () => { if (!newName.trim()) return; // In real app: const project = await sdk.projects.createProject({ name: newName }); setProjects([...projects, { id: `proj_${Date.now()}`, name: newName, files_count: 0 }]); setNewName(''); }; return ( <div style={{ maxWidth: '400px' }}> <button onClick={fetchProjects} disabled={loading} style={{ padding: '8px 16px', background: '#8b5cf6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', marginBottom: '16px' }} > {loading ? 'Loading...' : 'Fetch Projects (sdk.projects.listProjects)'} </button> <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}> <input value={newName} onChange={e => setNewName(e.target.value)} placeholder="New project name" style={{ flex: 1, padding: '8px', border: '1px solid #e2e8f0', borderRadius: '6px' }} /> <button onClick={createProject} style={{ padding: '8px 12px', background: '#22c55e', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }} > Create </button> </div> {projects.length > 0 && ( <div style={{ border: '1px solid #e2e8f0', borderRadius: '8px', overflow: 'hidden' }}> {projects.map((p, i) => ( <div key={p.id} style={{ padding: '12px', borderBottom: i < projects.length - 1 ? '1px solid #e2e8f0' : 'none', background: '#fff' }}> <p style={{ margin: 0, fontWeight: 500 }}>{p.name}</p> <p style={{ margin: '4px 0 0', fontSize: '12px', color: '#64748b' }}>{p.files_count} files • {p.id}</p> </div> ))} </div> )} </div> ); }
Result
Loading...
Response Types
interface Project {
id: string;
name: string;
description?: string;
status: "active" | "archived";
files_count: number;
created_at: string;
updated_at: string;
}
interface ListProjectsResponse {
projects: Project[];
total: number;
page: number;
limit: number;
}
Part 5: Chat Completions
The Chat API is the core of AI-powered features.
SDK Functions
import { sdk } from "@/lib/sdk";
// Simple chat completion
async function chat(message: string) {
const response = await sdk.chat.complete({
message,
});
return response.content;
}
// Chat with options
async function chatWithOptions(message: string, options?: {
temperature?: number;
maxTokens?: number;
expertId?: string;
projectId?: string;
}) {
const response = await sdk.chat.complete({
message,
temperature: options?.temperature ?? 0.7,
maxTokens: options?.maxTokens ?? 500,
expertId: options?.expertId,
projectId: options?.projectId,
});
return response;
}
// Streaming chat (for real-time responses)
async function* streamChat(message: string) {
const stream = sdk.chat.stream({ message });
for await (const chunk of stream) {
yield chunk.content;
}
}
// Multi-turn conversation
async function chatWithHistory(messages: Array<{ role: string; content: string }>) {
const response = await sdk.chat.complete({
messages,
});
return response;
}
Chat Example
Live Editor
function ChatExample() { const [message, setMessage] = React.useState(''); const [response, setResponse] = React.useState(''); const [loading, setLoading] = React.useState(false); const sendMessage = async () => { if (!message.trim()) return; setLoading(true); setResponse(''); // In real app: const result = await sdk.chat.complete({ message }); await new Promise(r => setTimeout(r, 1000)); // Simulated response const replies = [ "I'd be happy to help with that! Here's what I found...", "Great question! Let me explain...", "Based on my analysis, here are the key points...", ]; setResponse(replies[Math.floor(Math.random() * replies.length)]); setLoading(false); }; return ( <div style={{ maxWidth: '500px' }}> <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}> <input value={message} onChange={e => setMessage(e.target.value)} placeholder="Ask something..." onKeyDown={e => e.key === 'Enter' && sendMessage()} style={{ flex: 1, padding: '10px', border: '1px solid #e2e8f0', borderRadius: '6px' }} /> <button onClick={sendMessage} disabled={loading} style={{ padding: '10px 16px', background: '#8b5cf6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' }} > {loading ? '...' : 'Send'} </button> </div> {response && ( <div style={{ padding: '16px', background: '#f8fafc', border: '1px solid #e2e8f0', borderRadius: '8px' }}> <p style={{ margin: 0, fontSize: '12px', color: '#64748b', marginBottom: '8px' }}>sdk.chat.complete() response:</p> <p style={{ margin: 0 }}>{response}</p> </div> )} </div> ); }
Result
Loading...
Streaming Example
// Using streaming in a React component
function StreamingChat() {
const [content, setContent] = useState('');
async function handleStream(message: string) {
setContent('');
const stream = sdk.chat.stream({ message });
for await (const chunk of stream) {
setContent(prev => prev + chunk.content);
}
}
}
Response Types
interface ChatRequest {
message?: string;
messages?: ChatMessage[];
expertId?: string;
projectId?: string;
temperature?: number;
maxTokens?: number;
}
interface ChatMessage {
role: "system" | "user" | "assistant";
content: string;
}
interface ChatResponse {
id: string;
content: string;
role: "assistant";
model: string;
usage?: {
promptTokens: number;
completionTokens: number;
totalTokens: number;
};
}
Part 6: Files API
SDK Functions
import { sdk } from "@/lib/sdk";
// List files
async function listFiles(folderId?: string) {
const files = await sdk.files.listFiles({ folder_id: folderId });
return files;
}
// Upload a file
async function uploadFile(file: File, folderId?: string) {
const result = await sdk.files.uploadFile({
file,
folder_id: folderId,
});
return result;
}
// Download a file
async function downloadFile(fileId: string) {
const blob = await sdk.files.downloadFile(fileId);
return blob;
}
// Search files
async function searchFiles(query: string) {
const results = await sdk.files.searchFiles({ query });
return results;
}
// Delete a file
async function deleteFile(fileId: string) {
await sdk.files.deleteFile(fileId);
}
// Share a file
async function shareFile(fileId: string, userIds: string[]) {
await sdk.files.shareFile(fileId, { user_ids: userIds });
}
Files List Example
Live Editor
function FilesExample() { const [files, setFiles] = React.useState([]); const [loading, setLoading] = React.useState(false); const fetchFiles = async () => { setLoading(true); // In real app: const files = await sdk.files.listFiles(); await new Promise(r => setTimeout(r, 500)); setFiles([ { id: 'file_1', name: 'report.pdf', size: '2.4 MB', type: 'application/pdf' }, { id: 'file_2', name: 'data.csv', size: '156 KB', type: 'text/csv' }, { id: 'file_3', name: 'presentation.pptx', size: '5.1 MB', type: 'application/vnd.ms-powerpoint' }, ]); setLoading(false); }; return ( <div style={{ maxWidth: '400px' }}> <button onClick={fetchFiles} disabled={loading} style={{ padding: '8px 16px', background: '#8b5cf6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', marginBottom: '16px' }} > {loading ? 'Loading...' : 'Fetch Files (sdk.files.listFiles)'} </button> {files.length > 0 && ( <div style={{ border: '1px solid #e2e8f0', borderRadius: '8px', overflow: 'hidden' }}> {files.map((f, i) => ( <div key={f.id} style={{ padding: '12px', borderBottom: i < files.length - 1 ? '1px solid #e2e8f0' : 'none', background: '#fff', display: 'flex', justifyContent: 'space-between' }}> <div> <p style={{ margin: 0, fontWeight: 500 }}>{f.name}</p> <p style={{ margin: '2px 0 0', fontSize: '12px', color: '#64748b' }}>{f.size}</p> </div> <button style={{ padding: '4px 8px', fontSize: '12px', border: '1px solid #e2e8f0', borderRadius: '4px', background: '#fff', cursor: 'pointer' }}> Download </button> </div> ))} </div> )} </div> ); }
Result
Loading...
Response Types
interface File {
id: string;
name: string;
size: number;
mime_type: string;
folder_id?: string;
created_at: string;
updated_at: string;
}
Part 7: Notifications API
SDK Functions
import { sdk } from "@/lib/sdk";
// Get notifications
async function getNotifications(page = 1, limit = 20) {
const result = await sdk.notifications.getNotifications({ page, limit });
return result;
}
// Mark as read
async function markAsRead(notificationId: string) {
await sdk.notifications.markNotificationRead(notificationId, true);
}
// Archive notifications
async function archiveNotifications(ids: string[]) {
await sdk.notifications.archiveNotifications(ids);
}
// Delete notification
async function deleteNotification(notificationId: string) {
await sdk.notifications.deleteNotification(notificationId);
}
// Clear all notifications
async function clearAll() {
await sdk.notifications.clearAllNotifications({ scope: "all" });
}
Notifications Example
Live Editor
function NotificationsExample() { const [notifications, setNotifications] = React.useState([]); const [loading, setLoading] = React.useState(false); const fetchNotifications = async () => { setLoading(true); // In real app: const { notifications } = await sdk.notifications.getNotifications(); await new Promise(r => setTimeout(r, 500)); setNotifications([ { id: '1', title: 'New comment', message: 'Alex commented on your file', is_read: false }, { id: '2', title: 'Project shared', message: 'Sarah shared "Q4 Report"', is_read: false }, { id: '3', title: 'Task completed', message: 'Review task marked done', is_read: true }, ]); setLoading(false); }; const markRead = (id) => { // In real app: await sdk.notifications.markNotificationRead(id, true); setNotifications(notifications.map(n => n.id === id ? { ...n, is_read: true } : n)); }; return ( <div style={{ maxWidth: '400px' }}> <button onClick={fetchNotifications} disabled={loading} style={{ padding: '8px 16px', background: '#8b5cf6', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', marginBottom: '16px' }} > {loading ? 'Loading...' : 'Fetch Notifications'} </button> {notifications.length > 0 && ( <div style={{ border: '1px solid #e2e8f0', borderRadius: '8px', overflow: 'hidden' }}> {notifications.map((n, i) => ( <div key={n.id} onClick={() => markRead(n.id)} style={{ padding: '12px', borderBottom: i < notifications.length - 1 ? '1px solid #e2e8f0' : 'none', background: n.is_read ? '#fff' : '#faf5ff', cursor: 'pointer', }} > <p style={{ margin: 0, fontWeight: n.is_read ? 400 : 600, fontSize: '14px' }}>{n.title}</p> <p style={{ margin: '4px 0 0', fontSize: '13px', color: '#64748b' }}>{n.message}</p> </div> ))} </div> )} </div> ); }
Result
Loading...
Response Types
interface Notification {
id: string;
title: string;
message: string;
type: string;
is_read: boolean;
created_at: string;
}
interface GetNotificationsResponse {
notifications: Notification[];
total: number;
page: number;
limit: number;
}
Part 8: Error Handling
Best Practices
import { sdk } from "@/lib/sdk";
// Wrap API calls with error handling
async function safeApiCall<T>(fn: () => Promise<T>): Promise<{ data?: T; error?: string }> {
try {
const data = await fn();
return { data };
} catch (error) {
if (error.status === 401) {
// Token expired, try refresh
await refreshToken();
const data = await fn();
return { data };
}
if (error.status === 403) {
return { error: "You don't have permission for this action" };
}
if (error.status === 404) {
return { error: "Resource not found" };
}
return { error: error.message || "Something went wrong" };
}
}
// Usage
const { data: user, error } = await safeApiCall(() => sdk.users.getUser());
if (error) {
console.error(error);
} else {
console.log(user);
}
React Hook Pattern
function useApi<T>(fetcher: () => Promise<T>) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const execute = async () => {
setLoading(true);
setError(null);
try {
const result = await fetcher();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return { data, loading, error, execute };
}
// Usage
function MyComponent() {
const { data: user, loading, error, execute } = useApi(() => sdk.users.getUser());
useEffect(() => {
execute();
}, []);
}
Quick Reference
All SDK Modules
| Module | Common Functions |
|---|---|
sdk.auth | authenticateUser, getSession, signOutUser, refreshToken |
sdk.users | getUser, updateUser, getUserActivity |
sdk.projects | listProjects, createProject, getProject, deleteProject |
sdk.files | listFiles, uploadFile, downloadFile, searchFiles |
sdk.folders | listFolders, createFolder, deleteFolder |
sdk.chat | complete, stream |
sdk.notifications | getNotifications, markNotificationRead, archiveNotifications |
sdk.storage | get, set, delete, list |
sdk.experts | listExperts, getExpert |
sdk.tasks | listTasks, getTask, cancelTask |
Import Pattern
// Option 1: Class-based (recommended for most cases)
import { CyberPod } from "@cpod/sdk";
const sdk = new CyberPod({ baseUrl: "..." });
// Option 2: Global functions (simpler syntax)
import { initSDK, chat, users, projects } from "@cpod/sdk";
initSDK({ baseUrl: "..." });
const user = await users.getUser();
const response = await chat.complete({ message: "Hello" });
Next Steps
- Authentication Guide — Advanced auth patterns
- Chat Completions Guide — Streaming, experts, context
- File Management Guide — Upload, search, share
- API Reference — Complete function documentation
- UI Components — Pre-built React components