Developing with APIs that charge per request requires careful testing strategies. This guide shows you how to build and test your Magic Hour integration effectively while minimizing costs and avoiding production issues.
The Magic Hour SDKs include a mock server that returns realistic sample data without processing jobs or charging credits:
from magic_hour import Clientfrom magic_hour.environment import Environment# Use mock server for developmentclient = Client( token="YOUR_API_KEY", # Can use any value for mock mode environment=Environment.MOCK_SERVER)# All API calls return mock data instantlyresult = client.v1.ai_image_generator.create( image_count=1, aspect_ratio="16:9", resolution="1k", style={"prompt": "Test image", "tool": "ai-anime-generator"})print(f"Job ID: {result.id}") # Returns mock ID# No credits charged, no actual processing
import Client, { Environment } from "magic-hour";// Use mock server for developmentconst client = new Client({ token: "YOUR_API_KEY", // Can use any value for mock mode environment: Environment.MockServer,});// All API calls return mock data instantlyconst result = await client.v1.aiImageGenerator.create({ imageCount: 1, aspectRatio: "16:9", resolution: "1k", style: { prompt: "Test image", tool: "ai-anime-generator" },});console.log(`Job ID: ${result.id}`); // Returns mock ID// No credits charged, no actual processing
style.tool is optional. It selects an art-style preset; ai-anime-generator requests an
anime look. Omit it to use the default general style.
import timedownload_url = Nonejob_id = "your_job_id" # Change this to your job IDwhile True: status = client.v1.image_projects.get(id=job_id) if status.status == "complete": download_url = status.downloads[0].url break if status.status == "error": err = status.error or {} error_code = err.get("code", "unknown") error_msg = err.get("message", "Unknown error") if error_code == "no_source_face": print("❌ No face detected. Use an image with a visible face.") elif error_code == "invalid_file_format": print("❌ Unsupported file format. Check supported formats.") elif error_code == "file_too_large": print("❌ File too large. Reduce file size or upgrade tier.") elif error_code == "insufficient_credits": print("❌ Not enough credits. Add credits to your account.") else: print(f"❌ Error ({error_code}): {error_msg}") break time.sleep(3)if not download_url: raise RuntimeError("Job did not complete successfully; no download URL available.")
// Poll for completion with error handlingwhile (true) { const status = await client.v1.imageProjects.get({ id: jobId }); if (status.status === "complete") { // Success - download result const downloadUrl = status.downloads[0].url; break; } else if (status.status === "error") { // Job failed during processing const errorCode = status.error?.code || "unknown"; const errorMsg = status.error?.message || "Unknown error"; // Handle specific error codes switch (errorCode) { case "no_source_face": console.log("❌ No face detected. Use an image with a visible face."); break; case "invalid_file_format": console.log("❌ Unsupported file format. Check supported formats."); break; case "file_too_large": console.log("❌ File too large. Reduce file size or upgrade tier."); break; case "insufficient_credits": console.log("❌ Not enough credits. Add credits to your account."); break; default: console.log(`❌ Error (${errorCode}): ${errorMsg}`); } return null; } await new Promise((resolve) => setTimeout(resolve, 3000));}
from magic_hour import Clientfrom magic_hour.environment import Environmentdef test_with_mock_server(): client = Client( token="test-key", environment=Environment.MOCK_SERVER ) # Test the full workflow result = client.v1.ai_image_generator.create(...) assert result.id is not None assert result.credits_charged > 0 # Test status checking status = client.v1.image_projects.get(id=result.id) assert status.status in ["queued", "rendering", "complete"]