Skip to main content
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. 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
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 get 400 free credits plus 100 daily credits if you claim them in the web app.

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

Need the full walkthrough?

See screenshots, permissions, and key-management guidance in the Authentication guide.
Store your API key as an environment variable:
export MAGIC_HOUR_API_KEY="your_api_key_here"
setx MAGIC_HOUR_API_KEY "your_api_key_here"
$env:MAGIC_HOUR_API_KEY = "your_api_key_here"
Never commit API keys to version control. Always use environment variables or secure credential management.

2. Set up your development environment

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

Create your project directory

# Create and navigate to project directory
mkdir magic-hour-quickstart
cd magic-hour-quickstart

# Create your Python file
touch main.py
# Create and navigate to project directory
mkdir magic-hour-quickstart
cd magic-hour-quickstart

# Initialize npm project
npm init -y

# Enable ES module support (required for the SDK)
echo '{"type":"module"}' > package.json

# Create your JavaScript file
touch main.js
# 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
# Create new Rust project
cargo new magic-hour-quickstart
cd magic-hour-quickstart

Install the SDK

pip install magic_hour
npm install magic-hour
go get -u github.com/magichourhq/magic-hour-go
cargo add magic_hour
Want to test your integration without spending credits? The SDKs include a mock server that returns sample responses instantly.

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:
ExampleBest forTypical costTypical wait
Generate imageCheapest first success5 credits30-60 seconds
Face swap videoOur most popular API path~200 credits for the sample clip2-5 minutes

Copy the code and run it

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.
  1. Choose an example tab, then copy the code from your preferred language tab below.
Create an image from a text prompt. This is the cheapest way to verify your setup end to end.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
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}")
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();
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" {
			println("render failed")
			break
		} else {
			fmt.Printf("render in progress: %s\n", res.Status)
			time.Sleep(1 * time.Second)
		}
	}
}
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::GetV1ImageProjectsIdResponseStatusEnum::Complete => {
                println!("render complete!");
                let url = res.downloads[0].url.clone();

                tokio::task::block_in_place(move || {
                    let 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::GetV1ImageProjectsIdResponseStatusEnum::Error => {
                println!("render failed");
                return;
            }
            _ => {
                println!("render in progress: {}", res.status);
                std::thread::sleep(std::time::Duration::from_secs(1));
            }
        }
    }
}
#!/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 -s $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 -r '.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 -s $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 -s $download_url -o $OUTPUT_PATH

        echo "file downloaded successfully to $OUTPUT_PATH"
        break
    elif [ "$status" == "error" ]; then
        echo "render failed"
        break
    else
        echo "render in progress"
        sleep 1
    fi
done
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
  1. Paste it into your file (main.py, main.js, main.go, etc.)
  2. Run the code:
# Make sure you're in your project directory
cd magic-hour-quickstart

# Run the script
python main.py
# Make sure you're in your project directory
cd magic-hour-quickstart

# Run the script
node main.js
# Make sure you're in your project directory
cd magic-hour-quickstart

# Run the program
go run main.go
# Make sure you're in your project directory
cd magic-hour-quickstart

# Run the program
cargo run

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:
mkdir outputs
Error: MAGIC_HOUR_API_KEY environment variable not set Solution: Set your API key as an environment variable. See 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 CodeMeaningSolution
400Bad RequestCheck your request parameters and format
401UnauthorizedVerify your API key is correct and active
402Payment RequiredInsufficient credits - add more credits
500Internal Server ErrorTemporary server issue - retry after a few seconds
502Bad GatewayServer temporarily unavailable - retry after 30-60 seconds
503Service UnavailableServer overloaded - retry with exponential backoff
For persistent errors: Contact support@magichour.ai with your project ID.
🎉 Congratulations! You have successfully created your first Magic Hour project.

Next Steps

  • Explore the API Reference: Learn how to generate and edit videos and images programmatically. API Reference →
  • Explore Face Swap Video: See parameter details, pricing, and production patterns in the Face Swap Video guide.
  • Try All APIs in Google Colab: Run our complete cookbook with sample code for all 22 APIs. Just add your API key and start experimenting.
  • Use the Web App: Try more tools and experiment interactively at magichour.ai.
  • Handle Results at Scale: Set up webhooks to process results async and avoid polling.
  • Join the Community: Get help, share projects, and see what others are building in Discord.
  • Stay Updated: Check out the Changelog for new products and API updates.
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.