> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hooked.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Complete Workflow

> End-to-end guide from video creation to deployment

## Overview

This guide walks through the complete process of creating and managing AI videos with Hooked's API, from initial setup to production deployment.

## Step-by-Step Workflow

### 1. Authentication Setup

First, get your API key from the dashboard:

<Steps>
  <Step title="Get API Key">
    Go to [https://hooked.so/settings/api](https://hooked.so/settings/api)
  </Step>

  <Step title="Store Securely">
    Save your API key in environment variables

    ```bash theme={null}
    # .env
    HOOKED_API_KEY=your_api_key_here
    ```
  </Step>

  <Step title="Test Authentication">
    ```bash theme={null}
    curl -H "x-api-key: $HOOKED_API_KEY" \
      https://api.hooked.so/v1/avatar/list
    ```
  </Step>
</Steps>

### 2. Choose Your Path

<CardGroup cols={2}>
  <Card title="Create from Scratch" icon="wand-magic-sparkles" href="#workflow-from-scratch">
    Full control over every aspect

    **Best for:** Unique, one-off videos
  </Card>

  <Card title="Use Templates" icon="layer-group" href="#workflow-with-templates">
    Fast, scalable personalization

    **Best for:** Bulk generation, personalized content
  </Card>
</CardGroup>

***

## Workflow: From Scratch

### Step 1: Fetch Available Resources

```javascript theme={null}
const HOOKED_API_KEY = process.env.HOOKED_API_KEY;
const BASE_URL = 'https://api.hooked.so/v1';

async function fetchResources() {
  // Get avatars
  const avatarsRes = await fetch(`${BASE_URL}/avatar/list`, {
    headers: { 'x-api-key': HOOKED_API_KEY }
  });
  const { data: { avatars } } = await avatarsRes.json();
  
  // Get voices
  const voicesRes = await fetch(`${BASE_URL}/voice/list`, {
    headers: { 'x-api-key': HOOKED_API_KEY }
  });
  const { data: { voices } } = await voicesRes.json();
  
  // Get music (optional)
  const musicRes = await fetch(`${BASE_URL}/music/list`, {
    headers: { 'x-api-key': HOOKED_API_KEY }
  });
  const { data: { music } } = await musicRes.json();
  
  return { avatars, voices, music };
}

const resources = await fetchResources();
console.log(`Found ${resources.avatars.length} avatars`);
console.log(`Found ${resources.voices.length} voices`);
```

### Step 2: Select Resources

```javascript theme={null}
// Filter for English female voices
const englishFemaleVoices = resources.voices.filter(v => 
  v.language === 'English' && v.gender === 'Female'
);

// Pick a professional-looking avatar
const professionalAvatars = resources.avatars.filter(a =>
  a.situation === 'professional'
);

const selectedAvatar = professionalAvatars[0];
const selectedVoice = englishFemaleVoices[0];

console.log(`Selected: ${selectedAvatar.name} (${selectedVoice.name})`);
```

### Step 3: Create Video

```javascript theme={null}
async function createVideoFromScratch() {
  const videoData = {
    type: 'class',
    title: 'Product Demo Video',
    script: `Hi! I'm excited to show you our amazing product. 
             It's designed to make your life easier and more productive.
             Let me walk you through the key features.`,
    avatarId: selectedAvatar.id,
    voiceId: selectedVoice.id,
    aspectRatio: 'ratio_16_9',
    caption: {
      enabled: true,
      preset: 'wrap1',
      alignment: 'bottom'
    },
    webhook: 'https://yoursite.com/api/webhook'
  };
  
  const response = await fetch(`${BASE_URL}/project/create`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': HOOKED_API_KEY
    },
    body: JSON.stringify(videoData)
  });
  
  const result = await response.json();
  
  if (result.success) {
    console.log('Video created:', result.data.projectId);
    return result.data.projectId;
  } else {
    throw new Error(result.message);
  }
}

const projectId = await createVideoFromScratch();
```

### Step 4: Monitor Progress

**Option A: Using Webhooks (Recommended)**

```javascript theme={null}
// Set up webhook endpoint (Express.js example)
app.post('/api/webhook', async (req, res) => {
  const { event, projectId, status, video } = req.body;
  
  if (event === 'project.completed' && status === 'completed') {
    console.log('✅ Video ready:', video.url);
    
    // Save to database
    await saveVideo({
      projectId,
      url: video.url,
      thumbnail: video.thumbnail,
      duration: video.duration
    });
    
    // Notify user
    await notifyUser(projectId, video.url);
  }
  
  res.status(200).send('OK');
});
```

**Option B: Polling (Not Recommended)**

```javascript theme={null}
async function pollVideoStatus(projectId) {
  const maxAttempts = 60; // 5 minutes (60 * 5 seconds)
  
  for (let i = 0; i < maxAttempts; i++) {
    const response = await fetch(`${BASE_URL}/video/list`, {
      headers: { 'x-api-key': HOOKED_API_KEY }
    });
    
    const { data: { videos } } = await response.json();
    const video = videos.find(v => v.id === projectId);
    
    if (video.status === 'completed') {
      console.log('✅ Video ready!');
      return video;
    } else if (video.status === 'failed') {
      throw new Error('Video generation failed');
    }
    
    console.log(`Status: ${video.status} (${video.progress}%)`);
    await new Promise(r => setTimeout(r, 5000)); // Wait 5 seconds
  }
  
  throw new Error('Timeout waiting for video');
}
```

***

## Workflow: With Templates

### Step 1: List Templates

```javascript theme={null}
async function listTemplates() {
  const response = await fetch(`${BASE_URL}/template/list`, {
    headers: { 'x-api-key': HOOKED_API_KEY }
  });
  
  const { data: { templates } } = await response.json();
  
  console.log('Available templates:');
  templates.forEach(t => {
    console.log(`- ${t.name} (${t.type}) - ${t.variables.length} variables`);
  });
  
  return templates;
}

const templates = await listTemplates();
```

### Step 2: Get Template Details

```javascript theme={null}
async function getTemplateDetails(templateId) {
  const response = await fetch(`${BASE_URL}/template/${templateId}`, {
    headers: { 'x-api-key': HOOKED_API_KEY }
  });
  
  const { data: { template } } = await response.json();
  
  console.log(`Template: ${template.name}`);
  console.log('Scenes:', template.scenes.length);
  console.log('Variables required:', template.variables);
  
  return template;
}

const selectedTemplate = templates[0];
const templateDetails = await getTemplateDetails(selectedTemplate.id);
```

### Step 3: Prepare Variables

```javascript theme={null}
// Extract variables from template
const requiredVariables = templateDetails.variables;

// Prepare personalized data
const personalizationData = {
  name: 'Sarah Johnson',
  company: 'TechCorp Inc.',
  product: 'AI Assistant Pro',
  benefit: 'save 10 hours per week'
};

// Validate all variables are provided
const missingVars = requiredVariables.filter(v => !personalizationData[v]);
if (missingVars.length > 0) {
  throw new Error(`Missing variables: ${missingVars.join(', ')}`);
}
```

### Step 4: Generate from Template

```javascript theme={null}
async function generateFromTemplate(templateId, data) {
  const videoData = {
    type: 'class',
    templateId: templateId,
    title: `Personalized video for ${data.name}`,
    aspectRatio: 'ratio_16_9',
    caption: {
      enabled: true,
      preset: 'wrap1',
      alignment: 'bottom'
    },
    scenes: templateDetails.scenes.map(scene => ({
      script: scene.script,
      variables: Object.entries(data).map(([key, value]) => ({
        key,
        value
      }))
    })),
    webhook: 'https://yoursite.com/api/webhook'
  };
  
  const response = await fetch(`${BASE_URL}/project/create`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': HOOKED_API_KEY
    },
    body: JSON.stringify(videoData)
  });
  
  const result = await response.json();
  return result.data.projectId;
}

const projectId = await generateFromTemplate(selectedTemplate.id, personalizationData);
```

### Step 5: Bulk Generation

```javascript theme={null}
async function bulkGenerate(templateId, recipients) {
  const projectIds = [];
  
  for (const recipient of recipients) {
    try {
      const projectId = await generateFromTemplate(templateId, recipient);
      projectIds.push({ recipient: recipient.name, projectId });
      
      console.log(`✅ Created video for ${recipient.name}`);
      
      // Rate limiting: wait between requests
      await new Promise(r => setTimeout(r, 1000));
      
    } catch (error) {
      console.error(`❌ Failed for ${recipient.name}:`, error.message);
    }
  }
  
  return projectIds;
}

// Generate personalized videos for multiple recipients
const recipients = [
  { name: 'Sarah Johnson', company: 'TechCorp', product: 'AI Assistant' },
  { name: 'Mike Chen', company: 'StartupXYZ', product: 'Analytics Tool' },
  { name: 'Emma Davis', company: 'BigCorp', product: 'Cloud Platform' },
];

const projects = await bulkGenerate(selectedTemplate.id, recipients);
console.log(`Generated ${projects.length} videos`);
```

***

## Complete Example: Production-Ready

Here's a complete, production-ready implementation:

```javascript theme={null}
class HookedVideoAPI {
  constructor(apiKey, baseUrl = 'https://api.hooked.so/v1') {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
  }
  
  async request(endpoint, options = {}) {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': this.apiKey,
        ...options.headers
      }
    });
    
    const data = await response.json();
    
    if (!response.ok) {
      throw new Error(`API Error: ${data.message}`);
    }
    
    return data;
  }
  
  // Resources
  async getAvatars(type = 'all') {
    const { data } = await this.request(`/avatar/list?type=${type}`);
    return data.avatars;
  }
  
  async getVoices(filters = {}) {
    const params = new URLSearchParams(filters);
    const { data } = await this.request(`/voice/list?${params}`);
    return data.voices;
  }
  
  async getMusic(category = null) {
    const params = category ? `?category=${category}` : '';
    const { data } = await this.request(`/music/list${params}`);
    return data.music;
  }
  
  // Templates
  async listTemplates(type = null) {
    const params = type ? `?type=${type}` : '';
    const { data } = await this.request(`/template/list${params}`);
    return data.templates;
  }
  
  async getTemplate(templateId) {
    const { data } = await this.request(`/template/${templateId}`);
    return data.template;
  }
  
  // Video Creation
  async createVideo(videoData) {
    const { data } = await this.request('/project/create', {
      method: 'POST',
      body: JSON.stringify(videoData)
    });
    return data.projectId;
  }
  
  async listVideos(filters = {}) {
    const params = new URLSearchParams(filters);
    const { data } = await this.request(`/video/list?${params}`);
    return data.videos;
  }
  
  // High-level methods
  async createFromScratch(script, options = {}) {
    const videoData = {
      type: options.type || 'class',
      title: options.title || 'My Video',
      script,
      avatarId: options.avatarId,
      voiceId: options.voiceId,
      aspectRatio: options.aspectRatio || 'ratio_9_16',
      caption: options.caption || { enabled: true },
      webhook: options.webhook
    };
    
    return await this.createVideo(videoData);
  }
  
  async generateFromTemplate(templateId, variables, options = {}) {
    const template = await this.getTemplate(templateId);
    
    const videoData = {
      type: template.type,
      templateId,
      title: options.title || `Video from ${template.name}`,
      aspectRatio: options.aspectRatio || template.videoSettings?.aspectRatio,
      caption: options.caption,
      scenes: template.scenes.map(scene => ({
        script: scene.script,
        variables: Object.entries(variables).map(([key, value]) => ({
          key,
          value: String(value)
        }))
      })),
      webhook: options.webhook
    };
    
    return await this.createVideo(videoData);
  }
}

// Usage
const api = new HookedVideoAPI(process.env.HOOKED_API_KEY);

// Create from scratch
const projectId1 = await api.createFromScratch(
  'Welcome to our platform! Let me show you around.',
  {
    avatarId: 'avatar_123',
    voiceId: 'voice_456',
    aspectRatio: 'ratio_16_9',
    webhook: 'https://mysite.com/webhook'
  }
);

// Generate from template
const projectId2 = await api.generateFromTemplate(
  'template_789',
  {
    name: 'John Doe',
    company: 'Acme Corp'
  },
  {
    webhook: 'https://mysite.com/webhook'
  }
);

console.log('Videos created:', projectId1, projectId2);
```

## Best Practices Summary

<CardGroup cols={2}>
  <Card title="Use Webhooks" icon="webhook">
    Always use webhooks instead of polling for better efficiency
  </Card>

  <Card title="Error Handling" icon="shield">
    Implement comprehensive error handling and retries
  </Card>

  <Card title="Rate Limiting" icon="gauge">
    Respect rate limits and implement backoff strategies
  </Card>

  <Card title="Caching" icon="database">
    Cache resources (avatars, voices) to reduce API calls
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={3}>
  <Card title="Bulk Generation" icon="layer-group" href="/guides/bulk-generation">
    Learn to generate videos at scale
  </Card>

  <Card title="Personalization" icon="sparkles" href="/guides/personalization">
    Master video personalization techniques
  </Card>

  <Card title="Best Practices" icon="star" href="/guides/best-practices">
    Production-ready patterns
  </Card>
</CardGroup>
