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

# Magic Hour API Quickstart

> Create a Magic Hour API key and generate your first image or video with Python, Node.js, Go, Rust, or cURL.

Magic Hour is an AI video and image generation platform. You submit a job, we render it, and you download the result. This guide gets you to your first output in a few minutes.

Compare [API pricing and payment options](/billing/overview) and
[per-model credit costs](/api-reference/models) before running a generation. You can use the
[account endpoint](/api-reference/account/get-account-details) to check your balance.

## Choose your path

<CardGroup cols={3}>
  <Card title="Build with an SDK" icon="key" href="https://magichour.ai/developer?tab=api-keys&ref=docs-quickstart-path&utm_source=docs&utm_medium=referral&utm_campaign=quick-start">
    Create an API key, then follow the runnable example below.
  </Card>

  <Card title="Connect an AI agent" icon="wand-magic-sparkles" href="/integration/model-context-protocol">
    Use Magic Hour from Claude, ChatGPT, Claude Code, or Codex through MCP.
  </Card>

  <Card title="Run in Google Colab" icon="code" href="https://colab.research.google.com/drive/1NTHL_lr_s-qBJ-mSecSXPzRLi9_V5JiU?usp=sharing" openInNewTab>
    Try the APIs in your browser without setting up a local project.
  </Card>
</CardGroup>

**What you'll accomplish:**

1. **Create an API key** - Get credentials to authenticate with our API
2. **Set up your development environment** - Install SDK and create project files
3. **Generate your first output** - Make an API call and download the result

<Note>
  **Credit Cost:** Pick the example that matches your goal. The image tab costs about 5 credits; the
  face swap video tab costs about 200 credits for the sample clip. New accounts may receive starter
  credits and account-specific rewards; check your balance in the web app.
</Note>

## 1. Create your API key

**Why:** API keys authenticate your requests and track your usage.

1. Open the [API Keys section of the Developer Hub](https://magichour.ai/developer?tab=api-keys\&ref=docs-quickstart\&utm_source=docs\&utm_medium=referral\&utm_campaign=quick-start) and sign in.
2. Click **Create key**, give it a name (e.g., "My First Project"), and create it.
3. **Copy the API key immediately** — you won't be able to see it again.

<Card title="Need the full walkthrough?" icon="key" href="/get-started/authentication#creating-your-first-api-key">
  See screenshots and key-management guidance in the Authentication guide.
</Card>

Store your API key as an environment variable:

<CodeGroup>
  ```bash macOS/Linux theme={null}
  export MAGIC_HOUR_API_KEY="your_api_key_here"
  ```

  ```cmd Windows theme={null}
  set MAGIC_HOUR_API_KEY=your_api_key_here
  ```

  ```powershell PowerShell theme={null}
  $env:MAGIC_HOUR_API_KEY = "your_api_key_here"
  ```
</CodeGroup>

<Warning>
  **Never commit API keys to version control.** Always use environment variables or secure
  credential management.
</Warning>

## 2. Set up your development environment

**Why:** SDKs handle authentication, polling, and file downloads automatically, reducing boilerplate code.

### Create your project directory

<CodeGroup>
  ```bash Python theme={null}
  # Create and navigate to project directory
  mkdir magic-hour-quickstart
  cd magic-hour-quickstart

  # Create your Python file
  touch main.py
  ```

  ```bash Node.js theme={null}
  # Create and navigate to project directory
  mkdir magic-hour-quickstart
  cd magic-hour-quickstart

  # Initialize npm project
  npm init -y

  # Enable ES module support for this example
  npm pkg set type=module

  # Create your JavaScript file
  touch main.js
  ```

  ```bash Go theme={null}
  # Create and navigate to project directory
  mkdir magic-hour-quickstart
  cd magic-hour-quickstart

  # Initialize Go module
  go mod init magic-hour-quickstart

  # Create your Go file
  touch main.go
  ```

  ```bash Rust theme={null}
  # Create new Rust project
  cargo new magic-hour-quickstart
  cd magic-hour-quickstart
  ```
</CodeGroup>

### Install the SDK

<CodeGroup>
  ```sh Python SDK theme={null}
  pip install magic_hour
  ```

  ```sh Node SDK theme={null}
  npm install magic-hour
  ```

  ```sh Go SDK theme={null}
  go get -u github.com/magichourhq/magic-hour-go
  ```

  ```sh Rust SDK theme={null}
  cargo add magic_hour
  ```
</CodeGroup>

<Tip>
  Want to test your integration without spending credits? The SDKs include a [mock
  server](/integration/development-and-testing#mock-server-recommended-for-development) that returns
  sample responses instantly.
</Tip>

## 3. Generate your first output

**What we're doing:** Submit a generation job, wait for Magic Hour to render it, then download the
result. Choose the example that matches what you want to build:

| Example             | Best for                  | Typical cost                      | Typical wait |
| :------------------ | :------------------------ | :-------------------------------- | :----------- |
| **Generate image**  | Cheapest first success    | 5 credits                         | 5-30 seconds |
| **Face swap video** | Our most popular API path | \~200 credits for the sample clip | 2-5 minutes  |

### Copy the code and run it

<Note>
  **SDK version required for `generate()`:** Use Python SDK v0.36.0+ or Node SDK v0.37.0+. Older
  versions do not include this helper. Go and Rust use the manual create/poll/download pattern shown
  below.
</Note>

1. **Choose an example tab**, then copy the code from your preferred language tab below.

<Tabs>
  <Tab title="Generate image (~5 credits)">
    Create an image from a text prompt. This is the cheapest way to verify your setup end to end.

    See the [image generation guide](/tools/image/image-generator) for prompt examples and the
    [Image Generator API reference](/api-reference/image-projects/ai-image-generator) for every request field.

    **Why these parameters:**

    * `image_count: 1` - Generate one image (costs 5 credits)
    * `aspect_ratio: "16:9"` - Widescreen (landscape) output; also supports `1:1` and `9:16`
    * `resolution: "1k"` - Request an explicit supported resolution instead of deprecated `auto`
    * `wait_for_completion: true` - SDK polls until done
    * `download_outputs: true` - Automatically download to local disk
    * `download_directory: "."` - Save to the current directory

    <CodeGroup>
      ```python Python SDK theme={null}
      from magic_hour import Client
      import os

      # Use environment variable for security
      client = Client(token=os.getenv("MAGIC_HOUR_API_KEY"))

      result = client.v1.ai_image_generator.generate(
          image_count=1,
          aspect_ratio="16:9",
          resolution="1k",
          style={
              "prompt": "Epic anime art of wizard casting a cosmic spell in the sky that says 'Magic Hour'"
          },
          wait_for_completion=True, # wait for the render to complete
          download_outputs=True, # download the outputs to local disk
          download_directory=".", # save the outputs to the current directory
      )

      print(f"created image with id {result.id}, spent {result.credits_charged} credits. Outputs are saved at {result.downloaded_paths}")
      ```

      ```typescript Node SDK theme={null}
      import { Client } from "magic-hour";

      // Use environment variable for security
      const client = new Client({ token: process.env.MAGIC_HOUR_API_KEY });

      async function main() {
        const createRes = await client.v1.aiImageGenerator.generate(
          {
            imageCount: 1,
            aspectRatio: "16:9",
            resolution: "1k",
            style: {
              prompt: "Epic anime art of wizard casting a cosmic spell in the sky that says 'Magic Hour'",
            },
          },
          {
            waitForCompletion: true, // wait for the render to complete
            downloadOutputs: true, // download the outputs to local disk
            downloadDirectory: ".", // save the outputs to the current directory
          }
        );

        console.log(
          `created image with id ${createRes.id}, spent ${createRes.creditsCharged} credits. Outputs are saved at ${createRes.downloadedPaths}`
        );
      }

      main();
      ```

      ```go Go SDK theme={null}
      package main

      import (
      	"fmt"
      	"io"
      	"net/http"
      	"os"
      	"time"

      	sdk "github.com/magichourhq/magic-hour-go/client"
      	nullable "github.com/magichourhq/magic-hour-go/nullable"
      	"github.com/magichourhq/magic-hour-go/resources/v1/ai_image_generator"
      	"github.com/magichourhq/magic-hour-go/resources/v1/image_projects"
      	"github.com/magichourhq/magic-hour-go/types"
      )

      func main() {
      	// Use environment variable for security
      	client := sdk.NewClient(sdk.WithBearerAuth(os.Getenv("MAGIC_HOUR_API_KEY")))
      	createRes, err := client.V1.AiImageGenerator.Create(ai_image_generator.CreateRequest{
      		ImageCount:  1,
      		AspectRatio: nullable.NewValue(types.V1AiImageGeneratorCreateBodyAspectRatioEnum169),
      		Resolution:  nullable.NewValue(types.V1AiImageGeneratorCreateBodyResolutionEnum1k),
      		Style: types.V1AiImageGeneratorCreateBodyStyle{
      			Prompt: "Epic anime art of wizard casting a cosmic spell in the sky that says 'Magic Hour'",
      		},
      	})

      	if err != nil {
      		fmt.Println(err)
      		return
      	}

      	fmt.Printf("queued image with id %s, spent %d credits\n", createRes.Id, createRes.CreditsCharged)

      	for {
      		res, err := client.V1.ImageProjects.Get(image_projects.GetRequest{Id: createRes.Id})
      		if err != nil {
      			fmt.Println(err)
      			return
      		}
              if res.Status == "complete" {
      			println("render complete!")
      			url := res.Downloads[0].Url
      			outputFile := "output.png"

      			resp, err := http.Get(url)
      			if err != nil {
      				fmt.Println(err)
      				return
      			}
      			defer resp.Body.Close()

      			out, err := os.Create(outputFile)
      			if err != nil {
      				fmt.Println(err)
      				return
      			}
      			defer out.Close()

      			_, err = io.Copy(out, resp.Body)
      			if err != nil {
      				fmt.Println(err)
      				return
      			}
      			fmt.Printf("file downloaded successfully to %s\n", outputFile)
      			break
      		} else if res.Status == "error" || res.Status == "canceled" {
      			println("render failed")
      			break
      		} else {
      			fmt.Printf("render in progress: %s\n", res.Status)
      			time.Sleep(1 * time.Second)
      		}
      	}
      }
      ```

      ```rust Rust SDK theme={null}
      use magic_hour;
      use reqwest;
      use std::io::Read;

      #[tokio::main]
      async fn main() {
          // Use environment variable for security
          let api_key = std::env::var("MAGIC_HOUR_API_KEY")
              .expect("MAGIC_HOUR_API_KEY environment variable not set");
          let mut client = magic_hour::Client::default().with_bearer_auth(&api_key);

          let create_res = client
              .v1()
              .ai_image_generator()
              .create(magic_hour::resources::v1::ai_image_generator::CreateRequest {
                  image_count: 1,
                  aspect_ratio: Some(magic_hour::models::V1AiImageGeneratorCreateBodyAspectRatioEnum::Enum169),
                  resolution: Some(magic_hour::models::V1AiImageGeneratorCreateBodyResolutionEnum::Enum1k),
                  style: magic_hour::models::V1AiImageGeneratorCreateBodyStyle {
                      prompt: "Epic anime art of wizard casting a cosmic spell in the sky that says 'Magic Hour'".to_string(),
                      ..Default::default()
                  },
                  ..Default::default()
              })
              .await
              .unwrap();
          let project_id = create_res.id;
          let credits_charged = create_res.credits_charged;
          println!("queued image with id {project_id}, spent {credits_charged} credits");
          loop {
              let res = client
                  .v1()
                  .image_projects()
                  .get(magic_hour::resources::v1::image_projects::GetRequest {
                      id: project_id.clone(),
                  })
                  .await
                  .unwrap();
              match res.status {
                  magic_hour::models::V1ImageProjectsGetResponseStatusEnum::Complete => {
                      println!("render complete!");
                      let url = res.downloads[0].url.clone();

                      tokio::task::block_in_place(move || {
                          let mut response = reqwest::blocking::get(url).unwrap();
                          let output_path = "output.png";
                          if response.status().is_success() {
                              let mut output_file = std::fs::File::create(output_path).unwrap();
                              std::io::copy(&mut response, &mut output_file).unwrap();
                              println!("file downloaded successfully to {}", output_path);
                          } else {
                              println!("failed to download file: {}", response.status());
                          }
                      });

                      return;
                  }
                  magic_hour::models::V1ImageProjectsGetResponseStatusEnum::Error
                  | magic_hour::models::V1ImageProjectsGetResponseStatusEnum::Canceled => {
                      println!("render failed");
                      return;
                  }
                  _ => {
                      println!("render in progress: {}", res.status);
                      std::thread::sleep(std::time::Duration::from_secs(1));
                  }
              }
          }
      }
      ```

      ```sh cURL theme={null}
      #!/bin/bash
      set -e

      URL="https://api.magichour.ai/v1/ai-image-generator"
      STATUS_URL="https://api.magichour.ai/v1/image-projects"
      # Use environment variable for security
      API_KEY="$MAGIC_HOUR_API_KEY"
      OUTPUT_PATH="output.png"

      create_response=$(curl -fsS "$URL" \
        --request POST \
        --header "Content-Type: application/json" \
        --header "Authorization: Bearer $API_KEY" \
        --data '{
          "image_count": 1,
          "aspect_ratio": "16:9",
          "resolution": "1k",
          "style": {
            "prompt": "Epic anime art of wizard casting a cosmic spell in the sky that says \"Magic Hour\""
          }
        }')

      project_id=$(echo "$create_response" | jq -er '.id')
      credits_charged=$(echo "$create_response" | jq -r '.credits_charged')

      echo "queued image with id $project_id, spent $credits_charged credits"
      while true; do
          status_response=$(curl -fsS "$STATUS_URL/$project_id" --header "Authorization: Bearer $API_KEY")

          status=$(echo "$status_response" | jq -r '.status')

          if [ "$status" == "complete" ]; then
              echo "render complete!"
              download_url=$(echo "$status_response" | jq -r '.downloads[0].url')

              echo "downloading image from $download_url..."
              curl -fsS "$download_url" -o "$OUTPUT_PATH"

              echo "file downloaded successfully to $OUTPUT_PATH"
              break
          elif [ "$status" == "error" ] || [ "$status" == "canceled" ]; then
              echo "render failed"
              break
          else
              echo "render in progress"
              sleep 1
          fi
      done
      ```
    </CodeGroup>

    **Expected output for Python and Node.js:**

    ```
    created image with id clx1234567890, spent 5 credits. Outputs are saved at ['./output-0.png']
    ```

    **Expected output for Go, Rust, and cURL:**

    ```
    queued image with id clx1234567890, spent 5 credits
    render complete!
    file downloaded successfully to output.png
    ```
  </Tab>

  <Tab title="Face swap video (~200 credits)">
    Swap a face into a video clip. This is our most popular API path. The sample uses a 6.2-second
    segment (`start_seconds` to `end_seconds`). Video pricing is duration-based, so longer clips cost
    more.

    <CodeGroup>
      ```python Python SDK theme={null}
      from magic_hour import Client
      import os

      # Use environment variable for security
      client = Client(token=os.getenv("MAGIC_HOUR_API_KEY"))

      result = client.v1.face_swap.generate(
          name="Swap Tom Cruise into Iron Man scene",
          assets={
              "image_file_path": "https://videos.magichour.ai/api-assets/sample/tom-cruise.png",
              "video_file_path": "https://videos.magichour.ai/api-assets/sample/iron-man.mp4",
              "video_source": "file",
          },
          start_seconds=2.3,
          end_seconds=8.5,
          wait_for_completion=True, # wait for the render to complete
          download_outputs=True, # download the outputs to local disk
          download_directory=".", # save the outputs to the current directory
      )

      print(f"created face swap video with id {result.id}, spent {result.credits_charged} credits. Outputs are saved at {result.downloaded_paths}")
      ```

      ```typescript Node SDK theme={null}
      import { Client } from "magic-hour";

      // Use environment variable for security
      const client = new Client({ token: process.env.MAGIC_HOUR_API_KEY });

      async function main() {
        const createRes = await client.v1.faceSwap.generate(
          {
            name: "Swap Tom Cruise into Iron Man scene",
            assets: {
              imageFilePath: "https://videos.magichour.ai/api-assets/sample/tom-cruise.png",
              videoFilePath: "https://videos.magichour.ai/api-assets/sample/iron-man.mp4",
              videoSource: "file",
            },
            startSeconds: 2.3,
            endSeconds: 8.5,
          },
          {
            waitForCompletion: true, // wait for the render to complete
            downloadOutputs: true, // download the outputs to local disk
            downloadDirectory: ".", // save the outputs to the current directory
          }
        );

        console.log(
          `created face swap video with id ${createRes.id}, spent ${createRes.creditsCharged} credits. Outputs are saved at ${createRes.downloadedPaths}`
        );
      }

      main();
      ```

      ```go Go SDK theme={null}
      package main

      import (
      	"fmt"
      	"io"
      	"net/http"
      	"os"
      	"time"

      	sdk "github.com/magichourhq/magic-hour-go/client"
      	nullable "github.com/magichourhq/magic-hour-go/nullable"
      	"github.com/magichourhq/magic-hour-go/resources/v1/face_swap"
      	"github.com/magichourhq/magic-hour-go/resources/v1/video_projects"
      	"github.com/magichourhq/magic-hour-go/types"
      )

      func main() {
      	// Use environment variable for security
      	client := sdk.NewClient(sdk.WithBearerAuth(os.Getenv("MAGIC_HOUR_API_KEY")))
      	createRes, err := client.V1.FaceSwap.Create(face_swap.CreateRequest{
      		Name: nullable.NewValue("Swap Tom Cruise into Iron Man scene"),
      		Assets: types.V1FaceSwapCreateBodyAssets{
      			ImageFilePath: "https://videos.magichour.ai/api-assets/sample/tom-cruise.png",
      			VideoFilePath: nullable.NewValue("https://videos.magichour.ai/api-assets/sample/iron-man.mp4"),
      			VideoSource:   types.V1FaceSwapCreateBodyAssetsVideoSourceEnumFile,
      		},
      		StartSeconds: 2.3,
      		EndSeconds:   8.5,
      	})
      	if err != nil {
      		fmt.Println(err)
      		return
      	}

      	fmt.Printf("queued video with id %s, spent %d estimated credits. The final charge is available after rendering.\n", createRes.Id, createRes.CreditsCharged)

      	for {
      		res, err := client.V1.VideoProjects.Get(video_projects.GetRequest{Id: createRes.Id})
      		if err != nil {
      			fmt.Println(err)
      			return
      		}
      		if res.Status == "complete" {
      			fmt.Printf("render complete! Final credits charged is %d, actual fps is %f.\n", res.CreditsCharged, res.Fps)
      			url := res.Downloads[0].Url
      			outputFile := "output.mp4"

      			resp, err := http.Get(url)
      			if err != nil {
      				fmt.Println(err)
      				return
      			}
      			defer resp.Body.Close()

      			out, err := os.Create(outputFile)
      			if err != nil {
      				fmt.Println(err)
      				return
      			}
      			defer out.Close()

      			_, err = io.Copy(out, resp.Body)
      			if err != nil {
      				fmt.Println(err)
      				return
      			}
      			fmt.Printf("file downloaded successfully to %s\n", outputFile)
      			break
      		} else if res.Status == "error" || res.Status == "canceled" {
      			println("render failed")
      			break
      		} else {
      			fmt.Printf("render in progress: %s\n", res.Status)
      			time.Sleep(1 * time.Second)
      		}
      	}
      }
      ```

      ```rust Rust SDK theme={null}
      use magic_hour;
      use reqwest;

      #[tokio::main]
      async fn main() {
          // Use environment variable for security
          let api_key = std::env::var("MAGIC_HOUR_API_KEY")
              .expect("MAGIC_HOUR_API_KEY environment variable not set");
          let mut client = magic_hour::Client::default().with_bearer_auth(&api_key);

          let create_res = client
              .v1()
              .face_swap()
              .create(magic_hour::resources::v1::face_swap::CreateRequest {
                  name: Some("Swap Tom Cruise into Iron Man scene".to_string()),
                  assets: magic_hour::models::V1FaceSwapCreateBodyAssets {
                      image_file_path: "https://videos.magichour.ai/api-assets/sample/tom-cruise.png"
                          .to_string(),
                      video_file_path: Some(
                          "https://videos.magichour.ai/api-assets/sample/iron-man.mp4".to_string(),
                      ),
                      video_source: magic_hour::models::V1FaceSwapCreateBodyAssetsVideoSourceEnum::File,
                      ..Default::default()
                  },
                  start_seconds: 2.3,
                  end_seconds: 8.5,
                  ..Default::default()
              })
              .await
              .unwrap();
          let project_id = create_res.id;
          let credits_charged = create_res.credits_charged;
          println!("queued face swap video with id {project_id}, spent {credits_charged} estimated credits. The final charge is available after rendering.");

          loop {
              let res = client
                  .v1()
                  .video_projects()
                  .get(magic_hour::resources::v1::video_projects::GetRequest {
                      id: project_id.clone(),
                  })
                  .await
                  .unwrap();
              match res.status {
                  magic_hour::models::V1VideoProjectsGetResponseStatusEnum::Complete => {
                      println!(
                          "render complete! Final credit charged is {}, actual fps is {}",
                          res.credits_charged, res.fps
                      );
                      let url = res.downloads[0].url.clone();

                      tokio::task::block_in_place(move || {
                          let mut response = reqwest::blocking::get(url).unwrap();
                          let output_path = "output.mp4";
                          if response.status().is_success() {
                              let mut output_file = std::fs::File::create(output_path).unwrap();
                              std::io::copy(&mut response, &mut output_file).unwrap();
                              println!("file downloaded successfully to {}", output_path);
                          } else {
                              println!("failed to download file: {}", response.status());
                          }
                      });

                      return;
                  }
                  magic_hour::models::V1VideoProjectsGetResponseStatusEnum::Error
                  | magic_hour::models::V1VideoProjectsGetResponseStatusEnum::Canceled => {
                      println!("render failed");
                      return;
                  }
                  _ => {
                      println!("render in progress: {}", res.status);
                      std::thread::sleep(std::time::Duration::from_secs(1));
                  }
              }
          }
      }
      ```

      ```sh cURL theme={null}
      #!/bin/bash
      set -e

      URL="https://api.magichour.ai/v1/face-swap"
      STATUS_URL="https://api.magichour.ai/v1/video-projects"
      # Use environment variable for security
      API_KEY="$MAGIC_HOUR_API_KEY"
      OUTPUT_PATH="output.mp4"

      create_response=$(curl -fsS "$URL" \
        --request POST \
        --header "Content-Type: application/json" \
        --header "Authorization: Bearer $API_KEY" \
        --data '{
          "name": "Swap Tom Cruise into Iron Man scene",
          "assets": {
              "image_file_path": "https://videos.magichour.ai/api-assets/sample/tom-cruise.png",
              "video_file_path": "https://videos.magichour.ai/api-assets/sample/iron-man.mp4",
              "video_source": "file"
          },
          "start_seconds": 2.3,
          "end_seconds": 8.5
        }')

      project_id=$(echo "$create_response" | jq -er '.id')
      credits_charged=$(echo "$create_response" | jq -r '.credits_charged')

      echo "queued face swap video with id $project_id, spent $credits_charged estimated credits. The final charge is available after rendering."
      while true; do
          status_response=$(curl -fsS "$STATUS_URL/$project_id" --header "Authorization: Bearer $API_KEY")

          status=$(echo "$status_response" | jq -r '.status')

          if [ "$status" == "complete" ]; then
              credits_charged=$(echo "$status_response" | jq -r '.credits_charged')
              fps=$(echo "$status_response" | jq -r '.fps')
              download_url=$(echo "$status_response" | jq -r '.downloads[0].url')
              echo "render complete! Final credit charged is $credits_charged, actual fps is $fps."

              echo "downloading video from $download_url..."
              curl -fsS "$download_url" -o "$OUTPUT_PATH"

              echo "file downloaded successfully to $OUTPUT_PATH"
              break
          elif [ "$status" == "error" ] || [ "$status" == "canceled" ]; then
              echo "render failed"
              break
          else
              echo "render in progress: $status"
              sleep 3
          fi
      done
      ```
    </CodeGroup>

    **Expected output for Python and Node.js:**

    ```
    created face swap video with id clx1234567890, spent 186 credits. Outputs are saved at ['./output.mp4']
    ```
  </Tab>
</Tabs>

2. **Paste it into your file** (`main.py`, `main.js`, `main.go`, etc.)
3. **Run the code:**

<CodeGroup>
  ```bash Python theme={null}
  # Make sure you're in your project directory
  cd magic-hour-quickstart

  # Run the script
  python main.py
  ```

  ```bash Node.js theme={null}
  # Make sure you're in your project directory
  cd magic-hour-quickstart

  # Run the script
  node main.js
  ```

  ```bash Go theme={null}
  # Make sure you're in your project directory
  cd magic-hour-quickstart

  # Run the program
  go run main.go
  ```

  ```bash Rust theme={null}
  # Make sure you're in your project directory
  cd magic-hour-quickstart

  # Run the program
  cargo run
  ```
</CodeGroup>

## Troubleshooting

### Common Issues

**FileNotFoundError when using a custom `download_directory`**

The SDK saves outputs into `download_directory` but does **not** create the folder for you. The default (`"."`) always works. If you point it at a folder that doesn't exist yet (e.g. `"outputs"`), create it first:

```bash theme={null}
mkdir outputs
```

**Error: MAGIC\_HOUR\_API\_KEY environment variable not set**

**Solution:** Set your API key as an environment variable. See
[Environment Variables](/get-started/authentication#environment-variables) in the
Authentication guide for platform-specific setup steps.

### HTTP Error Codes

If you encounter HTTP errors, here's what they mean:

| Error Code | Meaning               | Solution                                                                          |
| :--------- | :-------------------- | :-------------------------------------------------------------------------------- |
| `400`      | Bad Request           | The response `message` names the invalid or missing field - fix it and resubmit   |
| `401`      | Unauthorized          | Verify your API key is correct and sent as `Authorization: Bearer <key>`          |
| `402`      | Payment Required      | Use the response `code` to add credits, start a subscription, or upgrade the plan |
| `404`      | Not Found             | Check the route and project ID                                                    |
| `422`      | Unprocessable Entity  | Change the request values before retrying                                         |
| `500`      | Internal Server Error | Retry later; contact support if the error continues                               |

**For persistent errors:** Contact [support@magichour.ai](mailto:support@magichour.ai) with your project ID.

<Check>🎉 Congratulations! You have successfully created your first Magic Hour project.</Check>

## Next Steps

* **Explore the API Reference:** Learn how to generate and edit videos and images programmatically. [API Reference →](/api-reference/overview)

* **Explore Face Swap Video:** See parameter details, pricing, and production patterns in the
  [Face Swap Video guide](/tools/video/face-swap-video).

* **Try All APIs in Google Colab:** [Run our complete cookbook](https://colab.research.google.com/drive/1NTHL_lr_s-qBJ-mSecSXPzRLi9_V5JiU?usp=sharing) with ready-to-run sample code. Just add your API key and start experimenting.

* **Use the Web App:** Try more tools and experiment interactively at [magichour.ai](https://magichour.ai/?utm_source=docs\&utm_medium=referral\&utm_campaign=quick-start).

* **Handle Results at Scale:** Set up [webhooks](https://docs.magichour.ai/integration/webhook/overview) to process results async and avoid polling.

* **Join the Community:** Get help, share projects, and see what others are building in [Discord](https://discord.gg/JX5rgsZaJp).

* **Stay Updated:** Check out the [Changelog](https://docs.magichour.ai/changelog) for new products and API updates.

<Tip>
  Prefer fast iteration inside your editor? Install this documentation as an MCP server to get
  contextual help while integrating the Magic Hour API. [Learn more](/integration/api-docs-mcp).
</Tip>
