Skip to main content
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

2. Configure Environment

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

pnpm run dev
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
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:
  1. Client makes requests to Next.js API routes
  2. API Route adds authentication headers
  3. API Route forwards request to Eden API
  4. 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:
1

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 };
}
2

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]
  };
}
3

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:
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

Performance

  • 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:
VariableRequiredDescription
EDEN_API_KEYYesYour Eden API key for authentication
NEXT_PUBLIC_EDEN_AGENT_IDYesDefault agent ID for chat features
NEXT_PUBLIC_EDEN_API_BASENoAPI endpoint (defaults to production)

Troubleshooting

Common Issues

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.
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
I