Skip to content

SDK Examples ​

Real-world, production-ready examples for common FOTOhub SDK workflows. This guide covers all major capabilities from basic image generation to advanced cloud compute provisioning.

PRO TIP

Always monitor your wallet balance programmatically. All FOTOhub billing is purely in USD. NEVER use deprecated 'credits' or other legacy currencies. Use wallet.available_usd.

MULTI-LANGUAGE SUPPORT

FOTOhub natively supports Python, TypeScript, and Go. All endpoints are also accessible via standard cURL requests using Authorization: Bearer fh_live_your_api_key.

Architecture Overview ​

SYSTEM FLOW

Most heavy operations like Video, 3D, and Compute use an asynchronous polling or webhook pattern. The diagram below illustrates the typical event-driven architecture used in production.

mermaid
sequenceDiagram
    participant App as Client Application
    participant SDK as FOTOhub SDK
    participant API as FOTOhub API
    participant Worker as FOTOhub GPU Worker
    participant Webhook as Your Webhook Server

    App->>SDK: generate_video(kling-v2.1)
    SDK->>API: POST /v1/ai/generate/video
    API-->>SDK: 202 Accepted (job_id)
    SDK-->>App: Job Object (status: processing)
    
    Note over API, Worker: GPU Worker picks up job
    Worker->>Worker: Processing (2-5 mins)
    Worker-->>API: Completion / Result URL / USD Cost
    
    API->>Webhook: POST https://yourapp.com/webhook (HMAC-SHA256 signed)
    Webhook-->>API: 200 OK
    Webhook->>App: Notify completion

1. Batch Product Photography ​

Process a list of prompts concurrently with progress tracking and USD cost tracking.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
promptStringYes-Text description of the image.
modelStringYesseedream-5-0-260128The model to use.
aspect_ratioStringNo1:1Aspect ratio, e.g., 16:9, 4:3.
webhook_urlStringNonullOptional callback.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Batch Product Photography...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Batch Product Photography...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "Studio product photo on a white background",
		"model": "seedream-5-0-260128",
	}

	raw, err := client.Post(ctx, "/ai/generate/image", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Batch Product Photography
curl -X POST https://apis.fotohub.app/v1/ai/generate/image \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Studio product photo on a white background",
    "model": "seedream-5-0-260128"
  }'

2. Brand-consistent Image Generation ​

Inject brand DNA into every prompt automatically to maintain cohesive identity.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
promptStringYes-Base description.
brand_dnaStringYes-Brand identity string.
negative_promptStringNo-Things to avoid.
style_referenceStringNo-URL to style image.
style_strengthFloatNo0.5Strength of the reference style.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Brand-consistent Image Generation...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Brand-consistent Image Generation...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "A pair of running shoes, in the style of our minimalist brand identity",
		"model": "seedream-5-0-260128",
	}

	raw, err := client.Post(ctx, "/ai/generate/image", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Brand-consistent Image Generation
curl -X POST https://apis.fotohub.app/v1/ai/generate/image \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A pair of running shoes, in the style of our minimalist brand identity",
    "model": "seedream-5-0-260128"
  }'

3. Multi-model Comparison ​

Generate same prompt with FLUX.1, Seedream, GPT-Image-1, compare results.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
promptStringYes-The prompt.
modelStringYes-E.g. flux-1-pro, seedream-5-0-260128, gpt-image-1

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Multi-model Comparison...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Multi-model Comparison...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "A cup of coffee on a wooden table",
		"model": "seedream-5-0-260128",
	}

	raw, err := client.Post(ctx, "/ai/generate/image", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Multi-model Comparison
curl -X POST https://apis.fotohub.app/v1/ai/generate/image \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A cup of coffee on a wooden table",
    "model": "seedream-5-0-260128"
  }'

4. Image-to-image Style Transfer ​

Apply artistic styles from reference images.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
image_urlStringYes-Base image to transform.
promptStringYes-New style description.
strengthFloatNo0.7How much to mutate the original (0-1).

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Image-to-image Style Transfer...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Image-to-image Style Transfer...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient.
// FotoHubClient.BaseURL hardcodes /v1; /stability/* sits outside that prefix,
// so this builds the request directly instead of going through client.Post.
func main() {
	apiKey := os.Getenv("FOTOHUB_API_KEY")

	payload, _ := json.Marshal(map[string]any{
		"image": "<base64-encoded-source-image>",
		"reference": "<base64-encoded-style-reference>",
		"output_format": "png",
	})

	req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "https://apis.fotohub.app/stability/style-transfer", bytes.NewReader(payload))
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}
	defer resp.Body.Close()

	result, _ := io.ReadAll(resp.Body)
	fmt.Printf("Result: %s\n", result)
}
bash
# Example request for Image-to-image Style Transfer
curl -X POST https://apis.fotohub.app/stability/style-transfer \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "<base64-encoded-source-image>",
    "reference": "<base64-encoded-style-reference>",
    "output_format": "png"
  }'

5. Automatic Prompt Enhancement with Gabriel AI ​

Route and enhance prompts before generation.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
raw_promptStringYes-Your basic prompt.
enhanceBooleanNofalseSet to true to use Gabriel AI.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Automatic Prompt Enhancement with Gabriel AI...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Automatic Prompt Enhancement with Gabriel AI...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "a red sports car",
	}

	raw, err := client.Post(ctx, "/ai/enhance-prompt", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Automatic Prompt Enhancement with Gabriel AI
curl -X POST https://apis.fotohub.app/v1/ai/enhance-prompt \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a red sports car"
  }'

6. I2V (Image-to-Video) Animation Pipeline ​

Animate product photos with Kling v2.1.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
image_urlStringYes-Starting frame for video.
promptStringYes-Motion description.
modelStringYeskling-v2.1Video model.
durationIntegerNo5Length in seconds (5 or 10).

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting I2V (Image-to-Video) Animation Pipeline...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting I2V (Image-to-Video) Animation Pipeline...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"image_url": "https://cdn.brand.com/product.jpg",
		"prompt": "Slow rotation, studio lighting",
		"model": "kling-v2.1",
		"duration": 5,
	}

	raw, err := client.Post(ctx, "/ai/generate/video", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for I2V (Image-to-Video) Animation Pipeline
curl -X POST https://apis.fotohub.app/v1/ai/generate/video \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "image_url": "https://cdn.brand.com/product.jpg",
    "prompt": "Slow rotation, studio lighting",
    "model": "kling-v2.1",
    "duration": 5
  }'

7. Long-form Video Assembly ​

Combine 5 clips into a 25s final video.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
clipsArray[String]Yes-URLs of the videos to stitch.
transitionStringNocrossfadeTransition type.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Long-form Video Assembly...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Long-form Video Assembly...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"clips": []any{"https://cdn.brand.com/clip1.mp4", "https://cdn.brand.com/clip2.mp4"},
		"transition": "crossfade",
	}

	raw, err := client.Post(ctx, "/video/merge", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Long-form Video Assembly
curl -X POST https://apis.fotohub.app/v1/video/merge \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "clips": ["https://cdn.brand.com/clip1.mp4", "https://cdn.brand.com/clip2.mp4"],
    "transition": "crossfade"
  }'

8. Multi-language Ad Video Factory ​

Generate same ad in EN/ES/FR/DE/JP with dubbed audio.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
video_urlStringYes-Original video with spoken track.
target_languagesArray[String]Yes-ISO codes of target languages.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Multi-language Ad Video Factory...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Multi-language Ad Video Factory...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"video_url": "https://cdn.brand.com/ad.mp4",
		"target_language": "es",
	}

	raw, err := client.Post(ctx, "/video/lip-sync", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Multi-language Ad Video Factory
curl -X POST https://apis.fotohub.app/v1/video/lip-sync \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://cdn.brand.com/ad.mp4",
    "target_language": "es"
  }'

9. Video with Synchronized Music ​

Generate video + matching music score simultaneously.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
video_promptStringYes-Video description.
music_promptStringYes-Audio description.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Video with Synchronized Music...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Video with Synchronized Music...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "Product hero shot, cinematic pan",
		"model": "kling-v2.1",
	}

	raw, err := client.Post(ctx, "/ai/generate/video", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Video with Synchronized Music
curl -X POST https://apis.fotohub.app/v1/ai/generate/video \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Product hero shot, cinematic pan",
    "model": "kling-v2.1"
  }'

10. Podcast Voice Cloning ​

NOT AVAILABLE

There is no voice-cloning endpoint on the public API — you cannot train a new voice from an audio sample. The example below uses standard TTS with one of the built-in preset voices instead.

Generate a full podcast episode with a preset TTS voice.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
textStringYes-Script to read.
voice_idStringYes-Preset voice ID (see GET /v1/ai/tts/polly/voices).

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Podcast Voice Cloning...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Podcast Voice Cloning...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"text": "Welcome back to the show.",
		"voice_id": "en-US-Matthew",
	}

	raw, err := client.Post(ctx, "/ai/tts/polly/synthesize", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Podcast Voice Cloning
curl -X POST https://apis.fotohub.app/v1/ai/tts/polly/synthesize \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Welcome back to the show.",
    "voice_id": "en-US-Matthew"
  }'

11. Multilingual TTS Batch ​

Same script in 10 languages for international campaign.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
script_mapObjectYes-Dictionary of lang_code to text.
base_voice_idStringYes-Voice to use across languages.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Multilingual TTS Batch...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Multilingual TTS Batch...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"text": "Bienvenido a FOTOhub",
		"voice_id": "es-ES-Lucia",
	}

	raw, err := client.Post(ctx, "/ai/tts/polly/synthesize", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Multilingual TTS Batch
curl -X POST https://apis.fotohub.app/v1/ai/tts/polly/synthesize \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Bienvenido a FOTOhub",
    "voice_id": "es-ES-Lucia"
  }'

12. Music Bed Generation ​

60s instrumental loop for video background, perfectly loopable.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
promptStringYes-Music description.
loopableBooleanNofalseEnsure ends match for seamless looping.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Music Bed Generation...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Music Bed Generation...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "Upbeat corporate background loop",
		"duration": 60,
	}

	raw, err := client.Post(ctx, "/ai/generate/music", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Music Bed Generation
curl -X POST https://apis.fotohub.app/v1/ai/generate/music \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Upbeat corporate background loop",
    "duration": 60
  }'

13. Sound Effect Library Builder ​

Generate 100 categorized SFX for a game.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
promptStringYes-Sound effect description.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Sound Effect Library Builder...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Sound Effect Library Builder...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "Footsteps on gravel, single step",
	}

	raw, err := client.Post(ctx, "/ai/generate/sfx", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Sound Effect Library Builder
curl -X POST https://apis.fotohub.app/v1/ai/generate/sfx \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Footsteps on gravel, single step"
  }'

14. E-commerce 3D Model Pipeline ​

Image → 3D → USDZ → Shopify AR quick look. 3D generation runs on dedicated FOTOhub GPU workers.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
image_urlStringYes-Base product image.
formatStringNoglbExport format (glb, usdz, obj).

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting E-commerce 3D Model Pipeline...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting E-commerce 3D Model Pipeline...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"image_url": "https://cdn.brand.com/product.jpg",
		"format": "glb",
	}

	raw, err := client.Post(ctx, "/ai/generate/3d", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for E-commerce 3D Model Pipeline
curl -X POST https://apis.fotohub.app/v1/ai/generate/3d \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "image_url": "https://cdn.brand.com/product.jpg",
    "format": "glb"
  }'

15. Batch 3D from Product Catalog ​

20 SKUs → 20 GLTF meshes for web viewer.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
imagesArray[String]Yes-Batch of images.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Batch 3D from Product Catalog...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Batch 3D from Product Catalog...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"image_url": "https://cdn.brand.com/sku-001.jpg",
		"format": "glb",
	}

	raw, err := client.Post(ctx, "/ai/generate/3d", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Batch 3D from Product Catalog
curl -X POST https://apis.fotohub.app/v1/ai/generate/3d \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "image_url": "https://cdn.brand.com/sku-001.jpg",
    "format": "glb"
  }'

16. Invoice Automation ​

Extract → validate → post to QuickBooks via JSON.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
document_urlStringYes-PDF or Image of invoice.
schemaObjectYes-JSON schema for extraction.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Invoice Automation...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Invoice Automation...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"document_base64": "JVBERi0xLjcK...",
	}

	raw, err := client.Post(ctx, "/ai/document/analyze-expense", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Invoice Automation
curl -X POST https://apis.fotohub.app/v1/ai/document/analyze-expense \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "document_base64": "JVBERi0xLjcK..."
  }'

17. Contract Risk Analysis ​

Extract clauses → Claude analysis → risk score.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
document_urlStringYes-Contract PDF.
analysis_typeStringYesrisk_scoreType of analysis.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Contract Risk Analysis...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Contract Risk Analysis...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"document_base64": "JVBERi0xLjcK...",
		"features": []any{"TABLES", "FORMS"},
	}

	raw, err := client.Post(ctx, "/ai/document/analyze", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Contract Risk Analysis
curl -X POST https://apis.fotohub.app/v1/ai/document/analyze \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "document_base64": "JVBERi0xLjcK...",
    "features": ["TABLES", "FORMS"]
  }'

18. Receipt Batch Processor ​

100 receipts → structured CSV for expense tracking.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
batch_urlsArray[String]Yes-List of receipt images.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Receipt Batch Processor...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Receipt Batch Processor...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"document_base64": "JVBERi0xLjcK...",
	}

	raw, err := client.Post(ctx, "/ai/document/analyze-expense", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Receipt Batch Processor
curl -X POST https://apis.fotohub.app/v1/ai/document/analyze-expense \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "document_base64": "JVBERi0xLjcK..."
  }'

19. Fashion Catalog Generator ​

100 garments × 3 model personas = 300 on-model images.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
garment_urlStringYes-The clothing item.
model_personaStringYes-ID of the virtual model.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Fashion Catalog Generator...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Fashion Catalog Generator...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"person_image_url": "https://cdn.brand.com/models/persona-1.jpg",
		"garment_image_url": "https://cdn.brand.com/catalog/garment.png",
		"category": "tops",
	}

	raw, err := client.Post(ctx, "/ai/tryon", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Fashion Catalog Generator
curl -X POST https://apis.fotohub.app/v1/ai/tryon \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "person_image_url": "https://cdn.brand.com/models/persona-1.jpg",
    "garment_image_url": "https://cdn.brand.com/catalog/garment.png",
    "category": "tops"
  }'

20. Size Recommendation from Body Scan ​

Extract measurements from tryon job metadata.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
scan_urlStringYes-User uploaded photo.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Size Recommendation from Body Scan...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Size Recommendation from Body Scan...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"person_image_url": "https://cdn.brand.com/uploads/scan.jpg",
		"garment_image_url": "https://cdn.brand.com/catalog/reference-garment.png",
		"category": "tops",
	}

	raw, err := client.Post(ctx, "/ai/tryon", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Size Recommendation from Body Scan
curl -X POST https://apis.fotohub.app/v1/ai/tryon \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "person_image_url": "https://cdn.brand.com/uploads/scan.jpg",
    "garment_image_url": "https://cdn.brand.com/catalog/reference-garment.png",
    "category": "tops"
  }'

21. Rent an A10G GPU and run your own training script ​

Dedicated GPU rental is real and lives under /compute/v1/*. GET /compute/v1/catalog lists the 22 instance types with their hourly and spot rates, POST /compute/v1/instances provisions one, and you reach it over SSH like any other machine. That is the path for running your own code on a GPU.

There is no public code-execution endpoint

FOTOhub runs a Firecracker microVM sandbox internally, but it is not exposed as a customer-callable API: the route is gated by an internal proxy secret and is only reached by the code.python node inside an Agent Engine workflow. Neither /sandbox/exec-python nor a code parameter on any public endpoint exists.

If you want arbitrary Python executed by FOTOhub, the two supported routes are a code.python node in a workflow (Agents) or your own script on a rented instance. See Compute.

bash
# 1. See what is available and what it costs
curl -s https://apis.fotohub.app/compute/v1/catalog \
  -H "Authorization: Bearer $FOTOHUB_API_KEY"

# 2. Provision one
curl -X POST https://apis.fotohub.app/compute/v1/instances \
  -H "Authorization: Bearer $FOTOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"instance_type": "g5.xlarge", "spot_instance": true}'

Spot pricing is real and roughly a third of on-demand — g5.xlarge is $1.0123/hr on-demand against $0.3827/hr spot. For a training run you can checkpoint and resume, spot is usually the right call.


22. Test an integration without being charged ​

POST /v1/console/sandbox/execute is a dry-run tester for FOTOhub's own API, not a code sandbox. You give it an endpoint and a body, and it returns a realistic mock response — or, with billing_mode set to wallet or credits, actually runs the call — so you can build and assert against your integration before spending anything.

FieldNotes
endpointRequired. The FOTOhub endpoint you are testing, e.g. /image/generate
methodDefault POST
bodyThe request body you would send
billing_modedry_run (default, free), wallet, or credits
assertionsChecks on status_code, latency_ms or a json_field
simulate_statusForce a particular status code, to exercise your error paths
project_id / module_idOptional; the module is inferred from endpoint otherwise
bash
curl -X POST https://apis.fotohub.app/v1/console/sandbox/execute \
  -H "Authorization: Bearer $FOTOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "/image/generate",
    "method": "POST",
    "billing_mode": "dry_run",
    "body": {"model": "seedream-5-0-260128", "prompt": "a green apple"},
    "assertions": [{"type": "status_code", "expected": 200}]
  }'

Forcing a failure with simulate_status is the cheapest way to prove your 402 and 429 handling works before a real one arrives at 3am.


23. Fan out work across rented instances ​

There is no server-side batch queue and no fan-out primitive. Provision several instances from the catalogue, dispatch to them yourself, and terminate them when the run finishes. For generation work specifically, prefer calling the generation endpoints concurrently from your own client and rate-limiting to the per-endpoint cap in Rate Limits — that needs no instances at all.


24. Complete Webhook Receiver ​

FastAPI app verifying HMAC-SHA256, handling all event types.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
webhook_secretStringYes-Your webhook secret key.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Complete Webhook Receiver...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Complete Webhook Receiver...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"url": "https://yourapp.com/webhook",
		"events": []any{"job.completed", "job.failed"},
	}

	raw, err := client.Post(ctx, "/console/webhooks", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Complete Webhook Receiver
curl -X POST https://apis.fotohub.app/v1/console/webhooks \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhook",
    "events": ["job.completed", "job.failed"]
  }'

25. Event-driven Pipeline ​

Webhook triggers next step automatically (image done → start video).

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
event_typeStringYes-The event to trigger on.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Event-driven Pipeline...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Event-driven Pipeline...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"url": "https://yourapp.com/webhook",
		"events": []any{"job.completed"},
	}

	raw, err := client.Post(ctx, "/console/webhooks", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Event-driven Pipeline
curl -X POST https://apis.fotohub.app/v1/console/webhooks \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhook",
    "events": ["job.completed"]
  }'

26. Webhook Retry Simulation ​

Test idempotency by replaying events.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
event_idStringYes-The ID of the event to replay.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Webhook Retry Simulation...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Webhook Retry Simulation...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"webhook_id": "wh_your_webhook_id",
	}

	raw, err := client.Post(ctx, "/console/sandbox/webhook-test", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Webhook Retry Simulation
curl -X POST https://apis.fotohub.app/v1/console/sandbox/webhook-test \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_id": "wh_your_webhook_id"
  }'

27. Rate Limiter with Token Bucket ​

Handle 429s gracefully with exponential backoff.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
max_retriesIntegerNo5Maximum number of retries.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Rate Limiter with Token Bucket...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Rate Limiter with Token Bucket...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient.
// GET isn't in the shared Post() helper, so this reuses the client's exported fields directly.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))

	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, client.BaseURL+"/tiers/wallet", nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Authorization", "Bearer "+client.APIKey)

	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Printf("Result: %s\n", body)
}
bash
# Example request for Rate Limiter with Token Bucket
curl -X GET https://apis.fotohub.app/v1/tiers/wallet \
  -H "Authorization: Bearer fh_live_your_api_key"

28. Wallet Balance Guard ​

Check balance before every expensive operation.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
alert_threshold_usdFloatNo5.0Minimum USD before alert.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Wallet Balance Guard...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Wallet Balance Guard...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient.
// GET isn't in the shared Post() helper, so this reuses the client's exported fields directly.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))

	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, client.BaseURL+"/tiers/wallet", nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Authorization", "Bearer "+client.APIKey)

	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Printf("Result: %s\n", body)
}
bash
# Example request for Wallet Balance Guard
curl -X GET https://apis.fotohub.app/v1/tiers/wallet \
  -H "Authorization: Bearer fh_live_your_api_key"

29. Cost Tracking Dashboard ​

Aggregate daily spend by model and endpoint.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
timeframeStringNotodayTimeframe for stats.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Cost Tracking Dashboard...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Cost Tracking Dashboard...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient.
// GET isn't in the shared Post() helper, so this reuses the client's exported fields directly.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))

	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, client.BaseURL+"/billing/transactions", nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Authorization", "Bearer "+client.APIKey)

	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Printf("Result: %s\n", body)
}
bash
# Example request for Cost Tracking Dashboard
curl -X GET https://apis.fotohub.app/v1/billing/transactions \
  -H "Authorization: Bearer fh_live_your_api_key"

30. Full Multi-step Creative Pipeline ​

1 product URL → brief → script → voice → video → social publish.

ERROR HANDLING

Always catch standard exceptions and check for RateLimitError or InsufficientFundsError. See API documentation for specifics.

Parameters ​

FieldTypeRequiredDefaultDescription
product_urlStringYes-Product to market.

PRO OPTIMIZATION

For batch operations, use concurrency to dramatically reduce wall-clock time. Check wallet.available_usd first to avoid mid-batch failure.

python
import asyncio
import logging
from fotohub import FotoHub, APIError

logging.basicConfig(level=logging.INFO)
client = FotoHub() # Uses FOTOHUB_API_KEY

async def run_example():
    try:
        logging.info('Starting Full Multi-step Creative Pipeline...')
        # Balance check pattern
        balance = client.get_balance()
        logging.info(f'Available USD: ${balance.wallet.available_usd:.2f}')

        # Main API call
        logging.info('Executing main operation...')
        # Example specific logic
        # result = client.some_action(...)
        
        # Simulate success
        cost = round(random.uniform(0.01, 0.50), 4) # Mock cost
        logging.info(f'Operation successful. Charged: ${cost} USD')
        
    except APIError as e:
        logging.error(f'API Error: {e.status_code} - {e.message}')
    except Exception as e:
        logging.error(f'Unexpected error: {str(e)}')

if __name__ == '__main__':
    asyncio.run(run_example())
typescript
import { FotoHub } from 'fotohub';

const client = new FotoHub({ apiKey: process.env.FOTOHUB_API_KEY! });

async function runExample(): Promise<void> {
  try {
    console.log('Starting Full Multi-step Creative Pipeline...');
    
    const balance = await client.getBalance();
    console.log(`Available USD: $${balance.wallet.availableUsd.toFixed(2)}`);

    // Main API call
    console.log('Executing main operation...');
    // const result = await client.someAction(...);
    
    const cost = (Math.random() * 0.5).toFixed(4);
    console.log(`Operation successful. Charged: $${cost} USD`);

  } catch (error: any) {
    console.error(`Error: ${error.message}`);
    if (error.status) {
      console.error(`Status code: ${error.status}`);
    }
  }
}

runExample();
go
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
)

// See https://docs.fotohub.app/sdk/go for FotoHubClient / NewFotoHubClient / Post.
func main() {
	client := NewFotoHubClient(os.Getenv("FOTOHUB_API_KEY"))
	ctx := context.Background()

	body := map[string]any{
		"prompt": "30s product ad, cinematic",
		"model": "kling-v2.1",
	}

	raw, err := client.Post(ctx, "/ai/generate/video", body)
	if err != nil {
		log.Fatalf("request failed: %v", err)
	}

	var result map[string]any
	if err := json.Unmarshal(raw, &result); err != nil {
		log.Fatalf("decode failed: %v", err)
	}
	fmt.Printf("Result: %+v\n", result)
}
bash
# Example request for Full Multi-step Creative Pipeline
curl -X POST https://apis.fotohub.app/v1/ai/generate/video \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "30s product ad, cinematic",
    "model": "kling-v2.1"
  }'

Dead Letter Queue (DLQ) & Webhook Retry Patterns ​

When relying on webhooks in a production environment, missing a webhook event means losing track of a completed job. Implement a robust Dead Letter Queue (DLQ) and retry pattern to gracefully handle service interruptions.

DLQ BEST PRACTICES

Ensure your webhook endpoint acknowledges the event (returns 200 OK) as quickly as possible. Offload processing to a background worker to prevent FOTOhub from timing out the webhook request and assuming it failed.

python
import json
import boto3

sqs = boto3.client('sqs')
DLQ_URL = 'https://sqs.us-east-1.amazonaws.com/12345/fotohub-dlq'

def route_to_dlq(payload, error_msg):
    sqs.send_message(
        QueueUrl=DLQ_URL,
        MessageBody=json.dumps({
            'payload': payload,
            'error': error_msg
        })
    )
    print(f'Routed failed webhook to DLQ.')

Unit Economics Table ​

OperationBase Cost (USD)Additional Options
Image Generation (Seedream)$0.002 per image+$0.001 High Res
Video Generation (Kling)$0.050 per 5s+$0.020 1080p
Audio TTS$0.010 per min-
3D Mesh$0.150 per model-
A10G Compute$1.250 per hourProrated by second

Next Steps ​