This guide walks through building a full-featured Eden application using our hello-eden starter repository.
Overview
The hello-eden repository is a production-ready Next.js application that demonstrates best practices for integrating with the Eden API. It showcases all major Eden features including AI-powered creation, agent interactions, and content browsing.
Hello Eden Repository Clone the starter repository to follow along with this guide
What You’ll Build
By following this guide, you’ll learn how to:
Generate AI content - Submit creation tasks for images and videos
Build chat interfaces - Create interactive sessions with Eden agents
Browse creations - Implement galleries with filtering and pagination
Handle authentication - Properly manage API keys and credentials
Poll for results - Implement efficient polling patterns for async operations
Prerequisites
Before starting, ensure you have:
Node.js 18+ and pnpm installed
Basic familiarity with React and Next.js
Eden API credentials (request in Discord )
Quick Start
1. Clone and Setup
# Clone the repository
git clone https://github.com/edenartlab/hello-eden.git
cd hello-eden
# Install dependencies
pnpm install
# Copy environment template
cp .env.local.example .env.local
Edit .env.local with your credentials:
EDEN_API_KEY=your_api_key_here
NEXT_PUBLIC_EDEN_AGENT_ID=your_agent_id_here
NEXT_PUBLIC_EDEN_API_BASE=https://api.eden.art # Optional
Keep your EDEN_API_KEY private! Never commit it to version control or expose it in client-side code.
3. Run the Application
Visit http://localhost:3000 to see your app running.
Core Concepts
API Client Structure
The hello-eden app uses a centralized API client (src/lib/eden.ts) that wraps all Eden API interactions. This pattern provides:
Type-safe interfaces for all API responses
Centralized error handling
Consistent authentication headers
Clean separation between API logic and UI components
API Client Setup
Type Definitions
const EDEN_API_BASE =
process . env . NEXT_PUBLIC_EDEN_API_BASE || "https://api.eden.art" ;
// Always include API key in server-side requests
const headers = {
"Content-Type" : "application/json" ,
"X-Api-Key" : process . env . EDEN_API_KEY || ""
};
Authentication Pattern
The app uses Next.js API routes as a backend-for-frontend (BFF) pattern to keep API keys secure:
Client makes requests to Next.js API routes
API Route adds authentication headers
API Route forwards request to Eden API
Response flows back through the same chain
This ensures your API key never reaches the client browser.
Feature Implementation
Creating Images and Videos
The creation flow involves submitting a task and polling for completion:
Submit Creation Task
Send a POST request to /v2/tasks/create with your prompt and configuration export async function createTask ( prompt : string , type : "image" | "video" ) {
const response = await fetch ( ` ${ EDEN_API_BASE } /v2/tasks/create` , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
"X-Api-Key" : process . env . EDEN_API_KEY || "" ,
},
body: JSON . stringify ({
tool: "create" ,
args: {
prompt: prompt ,
output: type === "video" ? "video" : undefined
},
makePublic: true
})
});
const data = await response . json ();
return { taskId: data . task . _id };
}
Poll for Completion
Check task status every few seconds until completed export async function pollTask ( taskId : string ) : Promise < Task > {
const response = await fetch ( ` ${ EDEN_API_BASE } /v2/tasks/ ${ taskId } ` , {
method: "GET" ,
headers: {
"X-Api-Key" : process . env . EDEN_API_KEY || "" ,
}
});
const data = await response . json ();
return {
taskId: data . task . _id ,
status: data . task . status ,
creation: data . task . result ?.[ 0 ]?. output ?.[ 0 ]
};
}
Display Result
Show the generated content once the task completes // In your React component
const [ polling , setPolling ] = useState ( false );
const [ result , setResult ] = useState < string | null >( null );
useEffect (() => {
if ( ! polling ) return ;
const interval = setInterval ( async () => {
const task = await pollTask ( taskId );
if ( task . status === "completed" ) {
setResult ( task . creation ?. uri || null );
setPolling ( false );
} else if ( task . status === "failed" ) {
setPolling ( false );
// Handle error
}
}, 3000 );
return () => clearInterval ( interval );
}, [ polling , taskId ]);
Building Agent Chat Interfaces
Eden agents support interactive conversations through sessions:
Create Session
Send Message
Poll for Updates
export async function createSession ( agentIds : string []) {
const response = await fetch ( ` ${ EDEN_API_BASE } /v2/sessions` , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
"X-Api-Key" : process . env . EDEN_API_KEY || "" ,
},
body: JSON . stringify ({
agent_ids: agentIds ,
autonomy_settings: {
auto_reply: true ,
reply_interval: 1000 ,
actor_selection_method: "random"
}
})
});
const data = await response . json ();
return { session_id: data . session_id };
}
Browsing and Filtering Creations
Implement galleries with advanced filtering:
export async function getCreations ( filters ?: {
cursor ?: string ;
limit ?: number ;
type ?: "image" | "video" ;
onlyMine ?: boolean ;
onlyAgents ?: boolean ;
}) {
const params = new URLSearchParams ();
// Pagination
if ( filters ?. cursor ) params . append ( "cursor" , filters . cursor );
params . append ( "limit" , ( filters ?. limit || 20 ). toString ());
// Type filtering
if ( filters ?. type ) {
params . append ( "filter" , `output_type; ${ filters . type } ` );
}
// Agent filtering
if ( filters ?. onlyAgents && process . env . NEXT_PUBLIC_EDEN_AGENT_ID ) {
params . append ( "filter" , `agent; ${ process . env . NEXT_PUBLIC_EDEN_AGENT_ID } ` );
}
const response = await fetch (
` ${ EDEN_API_BASE } /v2/feed-cursor/creations? ${ params } ` ,
{
headers: {
"Content-Type" : "application/json" ,
// Include API key for private content
... ( filters ?. onlyMine && {
"X-Api-Key" : process . env . EDEN_API_KEY || ""
})
}
}
);
const data = await response . json ();
return {
docs: data . docs ,
nextCursor: data . nextCursor ,
hasMore: data . docs ?. length === filters ?. limit
};
}
Best Practices
Error Handling
Always implement robust error handling for API calls:
try {
const response = await fetch ( endpoint , options );
if ( ! response . ok ) {
const errorText = await response . text ();
console . error ( `Eden API Error ${ response . status } :` , errorText );
throw new Error ( `Eden API ${ response . status } : ${ errorText } ` );
}
return await response . json ();
} catch ( error ) {
console . error ( "Failed to make API call:" , error );
// Show user-friendly error message
throw error ;
}
Rate Limiting
Be mindful of API rate limits:
Implement exponential backoff for retries
Cache responses when appropriate
Batch requests where possible
Use reasonable polling intervals (3-5 seconds)
Security
Never expose API keys in client-side code
Use environment variables for all credentials
Implement proper CORS headers in production
Validate and sanitize all user inputs
Use HTTPS for all API communications
Implement loading states for better UX
Use React hooks for efficient state management
Lazy load images and videos
Implement pagination for large datasets
Cache API responses when appropriate
Common Patterns
Polling Pattern
const usePollTask = ( taskId : string | null ) => {
const [ task , setTask ] = useState < Task | null >( null );
const [ error , setError ] = useState < string | null >( null );
useEffect (() => {
if ( ! taskId ) return ;
let cancelled = false ;
const poll = async () => {
try {
const result = await pollTask ( taskId );
if ( ! cancelled ) {
setTask ( result );
if ( result . status === "pending" || result . status === "processing" ) {
setTimeout ( poll , 3000 );
}
}
} catch ( err ) {
if ( ! cancelled ) {
setError ( err . message );
}
}
};
poll ();
return () => {
cancelled = true ;
};
}, [ taskId ]);
return { task , error };
};
API Route Pattern
// pages/api/tasks/create.ts
export async function POST ( req : Request ) {
try {
const body = await req . json ();
const response = await fetch ( ` ${ EDEN_API_BASE } /v2/tasks/create` , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
"X-Api-Key" : process . env . EDEN_API_KEY || "" ,
},
body: JSON . stringify ( body )
});
if ( ! response . ok ) {
return Response . json (
{ error: "Failed to create task" },
{ status: response . status }
);
}
const data = await response . json ();
return Response . json ( data );
} catch ( error ) {
return Response . json (
{ error: "Internal server error" },
{ status: 500 }
);
}
}
Deployment
Environment Variables
When deploying to production, ensure all environment variables are properly configured:
Variable Required Description EDEN_API_KEYYes Your Eden API key for authentication NEXT_PUBLIC_EDEN_AGENT_IDYes Default agent ID for chat features NEXT_PUBLIC_EDEN_API_BASENo API endpoint (defaults to production)
Troubleshooting
Common Issues
Task creation returns 401 Unauthorized
Solution : Verify your API key is correct and included in the request headers. Check that the environment variable is properly loaded.
Solution : Some tasks may take longer to process. Increase your polling timeout or implement a maximum retry count to prevent infinite polling.
Solution : Make sure you’re calling your Next.js API routes, not the Eden API directly from the browser. The API routes should proxy requests to Eden.
Agent not responding in chat
Solution : Verify the agent ID exists and is active. Check that autonomy settings are properly configured for auto-reply.
Next Steps
Now that you have a working Eden application, explore these advanced features:
Resources
Support
Need help? Join our Discord community where you can:
Request API keys
Get implementation help
Report bugs and issues
Share your creations
Connect with other developers