huhu.ai

API Documentation

The Huhu Studio Public API lets you programmatically access virtual try-on, model generation, video creation, and more using long-lived API keys.

Overview

All endpoints are served under https://api.huhu.ai/public/v1. Create an API key from Studio → API → API Keys to get started.

Data Model

Understanding the entity hierarchy:

Team
├── Program (workspace / brand)
│   ├── Model (AI fashion model identity)
│   ├── Project (batch of work)
│   │   └── SKU (single product/garment)
│   │       └── Task (generation job → output images)
└── Credits (shared pool for all operations)
  • Team — top-level billing unit. API key is bound to one team.
  • Program — workspace (brand/product line). Contains models, projects. Can be shared across teams.
  • Project — batch of work (collection/campaign). Contains SKUs. Status: Creating → Created → In process → Completed.
  • SKU — single product. Has garment images, category (13 types), and generation tasks.
  • Task — generation job. Lifecycle: Created → Submitted → Generation → Editing → Review → Approved.
  • Credits — shared pool. Each operation deducts credits. API and UI share the same pool.

Credit Costs

OperationCredits
Image Generation (SD)1
Image Generation (HD) / Same-ID2
Multipose Generation2
Image Editing / Inpainting2
Face Swap / Upscale2
Background Change / Removal2
Hand Fix / Foot Fix2
Logo Transfer / Accessory Try-On2
Ghost Mannequin2
Prompt Generation2
Video Generation (5s)25
Video Generation (10s)40

New teams receive 50 free credits and 10 concurrent request slots.

Authentication

Create an API key from the API Keys page. Include it in every request:

curl https://api.huhu.ai/public/v1/metering/plan \
  -H "Authorization: Bearer sk-<your-api-key>"

Keys are scoped to a team. Requests to resources outside your team return 403. Revoked or invalid keys return 401.

Base URL

Production:  https://api.huhu.ai/public/v1
Gamma:       https://api-gamma.huhu.ai/public/v1

Metering

GET/metering/plan

Check your team's credit balance, plan status, and concurrent request limit. Call this before generation requests.

ParameterTypeRequiredDescription
program_idstringNoResolves owner team for shared programs
# Response
{
  "credits": 99999,
  "plan_status": "free",
  "concurrent_requests": 10,
  "plan_name": null,
  "subscription_id": null
}
GET/metering/credit-history

Get paginated credit usage history for a program.

ParameterTypeRequiredDescription
program_idstringNoProgram ID (uses key default if omitted)
pagination_tokenstringNoToken for next page
fetch_allbooleanNoFetch all records (max 10,000)
# Response
{
  "items": [
    { "program_id": "xxx", "request_id": "xxx", "credits": 1, "timestamp": 1773702421471, "operation": "model_gen" }
  ],
  "pagination_token": null
}

Programs

GET/program

List programs accessible to your team.

ParameterTypeRequiredDescription
ownedboolNoIf true, only programs you own (default: false)
pagination_tokenstringNoToken for next page
# Response
{ "programs": [{ "program_id": "xxx", "program_name": "My Brand", "create_time": 1773702421471 }], "pagination_token": null }
POST/program

Create a new program (workspace) within your team.

ParameterTypeRequiredDescription
program_namestringYesName for the program
# Response
{
  "program_name": "My New Brand",
  "user_id": "xxx", "create_time": 1773702421471
}

Projects

GET/project

List projects, or get a single project detail by adding project_id.

ParameterTypeRequiredDescription
project_idstringNoIf provided, returns single project detail
pagination_tokenstringNoToken for next page (list only)
# List response (no project_id)
{ "projects": [{ "project_id": "xxx", "project_name": "Spring", "project_status": "Created" }], "pagination_token": null }

# Detail response (with project_id)
{ "project_id": "xxx", "project_name": "Spring", "project_status": "Created", "create_time": 1773702421471 }
POST/project

Create a new project within a program.

ParameterTypeRequiredDescription
project_namestringYesName for the project
program_idstringNoProgram ID (uses key default if omitted)
POST/project/upload

Upload garment images (base64) or initiate multipart zip upload for SKU archives.

ParameterTypeRequiredDescription
project_idstringYesProject ID
file_typestringYes"garment_image", "sku_zip", "model_image", "reference_image"
program_idstringNoProgram ID (uses key default if omitted)
file_datastringNoBase64 image data (for image types)
file_sizenumberNoFile size in bytes (for sku_zip)
# For garment_image → { "success": true, "image_id": "xxx" }
# For sku_zip → { "message": "success", "key": "...", "upload_id": "...", "upload_urls": ["..."] }
POST/project/complete_multipart_upload

Complete a multipart zip upload after all parts are uploaded to presigned URLs.

ParameterTypeRequiredDescription
project_idstringYesProject ID
keystringYesS3 key from upload response
upload_idstringYesUpload ID from upload response
partsobject[]Yes[{PartNumber, ETag}] for each part
program_idstringNoProgram ID (uses key default if omitted)
# Response: { "message": "success" }

Models

POST/model

Create a new AI model in the gallery with searchable attributes. Add images after with /model/image.

ParameterTypeRequiredDescription
model_namestringYesDisplay name
model_typestringNo"Men", "Women", "Baby", "Toddler", "Kid", "Maternity"
model_sizestringNo"Petit", "Regular", "Plus size"
attributesobjectNoDescriptive attributes for filtering: ethnicity, age_range, hair_color, hair_style, skin_tone, eye_color
program_idstringNoProgram ID (uses key default if omitted)
# Request with attributes
{ "model_name": "Caucasian Plus-Size Woman",
  "model_type": "Women", "model_size": "Plus size",
  "attributes": { "ethnicity": "Caucasian", "age_range": "Middle-aged",
    "hair_color": "Blonde", "hair_style": "Long", "skin_tone": "Fair" } }
# Response: {"success": true, "model_id": "xxx"}
GET/model

List models with attribute filters, or get a model's images by adding model_id. LLM agents: use filters to match user descriptions.

ParameterTypeRequiredDescription
model_idstringNoIf provided, returns model images instead of model list
model_typestringNoFilter: "Men", "Women", "Baby", "Toddler", "Kid", "Maternity"
model_sizestringNoFilter: "Petit", "Regular", "Plus size"
ethnicitystringNoFilter: Caucasian, East Asian, Black, Hispanic, etc.
age_rangestringNoFilter: Young, Young Adult, Middle-aged, Mature, Senior
hair_colorstringNoFilter: Blonde, Brown, Black, Red, etc.
skin_tonestringNoFilter: Fair, Light, Medium, Olive, Tan, Brown, Dark
# List response — with attributes for LLM selection
{ "models": [{ "model_id": "xxx", "model_name": "Dae Nakamura", "model_type": "Women",
  "attributes": { "ethnicity": "East Asian", "age_range": "Young Adult",
    "hair_color": "Black", "skin_tone": "Light" } }] }

# Images response (with model_id)
{ "model_images": [
  { "model_image_id": "...", "model_image_url": "https://...",
    "model_id": "xxx", "style_id": "yyy",
    "view_type": "front_facing", "crop_type": "fullbody" }
] }
# view_type: front_facing, back_facing (or null)
# crop_type: fullbody, head_half_cropped, top, bottom (or null)
POST/model/face

Generate AI face images. Supports variety (diverse) and fidelity (precise) modes.

ParameterTypeRequiredDescription
promptstringYesFace description with attributes
mode"variety" | "fidelity"Novariety = diverse, fidelity = precise (default: variety)
num_output_imagesintNo1-4 images (default: 1)
program_idstringNoProgram ID (uses key default if omitted)
# Response
{ "request_id": "xxx", "status": "Request Submitted", "images_generated": [], "num_output_images": 2 }

# Poll via GET /model/image?request_id=xxx until status = "Generation Completed"
# Then save to model via POST /model/image with model_id + image_url from result

Prompt template: Headshot front facing portrait of a {Age} {Race} {BodySize} {Gender} with {HairColor} {HairStyle} hair with {EyeColor} eye with {SkinColor} skin tone in the {Background} setting with {Expression}. {Pose} pose, professional lighting, high detail.

POST/model/image

Two modes: generate a new image (with prompt) or upload/save an existing image to a model (with model_id).

Mode 1 — Generate (provide prompt):

ParameterTypeRequiredDescription
promptstringYesText prompt for image generation
reference_imagestringNoGallery image ID, HTTP URL, or base64
num_output_imagesintNo1-8 images (default: 1)
program_idstringNoProgram ID (uses key default if omitted)
# Generate request
{ "prompt": "professional photo of model wearing garment" }

# Generate response — poll GET /model/image?request_id=xxx for results
{ "request_id": "xxx", "status": "Request Submitted", "images_generated": [], "num_output_images": 1 }

Mode 2 — Upload/Save to model (provide model_id):

ParameterTypeRequiredDescription
model_idstringYesModel ID to save image to
style_idstringYesStyle ID
image_urlstringNoImage URL to save (e.g. from generation result)
file_datastringNoBase64 image to upload
program_idstringNoProgram ID (uses key default if omitted)
# Upload request — save a generated image to a model
{ "model_id": "xxx", "style_id": "yyy", "image_url": "https://s3.../generated.png?signed..." }

# Upload response
{ "success": true, "image_id": "...", "image_url": "https://...", "view_type": "front_facing", "crop_type": "fullbody" }
# view_type/crop_type are auto-detected by AI: front_facing/back_facing, fullbody/head_half_cropped
GET/model/image

Poll generation status for POST /model/face, POST /model/image (generate), or POST /model/pose.

ParameterTypeRequiredDescription
request_idstringYesRequest ID from any generation response
program_idstringNoProgram ID (uses key default if omitted)
# Response (completed)
{
  "status": "Generation Completed",
  "images_generated": [
    { "model_image_id": "path/to/output.png", "model_image_url": "https://s3.../output.png?signed..." }
  ]
}
POST/model/pose

Generate model images in specific poses using a reference image. Costs credits.

ParameterTypeRequiredDescription
promptstringYesPrompt describing the desired pose
reference_imagestringYesModel image ID from gallery (e.g. from GET /model?model_id=)
program_idstringNoProgram ID (uses key default if omitted)
# Response
{ "request_id": "xxx" }

# Poll: GET /model/image?request_id=xxx → same polling as face/image generation
# Save results: POST /model/image with model_id + style_id + image_url from result
# The reference_image's model_id and style_id can be found via GET /model?model_id=

Poses

GET/pose/library

Browse 143 preset poses. Filter by model_category and prompt_type. Use pose reference images with POST /model/pose.

ParameterTypeRequiredDescription
model_categorystringNoFilter: Women, Men, Child, Infant
prompt_typestringNoFilter: fullbody, head_half_cropped, top, bottom, close_up_upper_body, close_up_lower_body
# Response
{ "poses": [{ "pose_id": "f00cb596...", "pose_name": "Full body upright",
  "model_category": "Women", "prompt_type": "fullbody",
  "reference_image_url": "https://cdn.huhu.ai/poses/xxx.png",
  "sketch_url": "https://cdn.huhu.ai/poses/yyy.png" }], "total": 14 }

# LLM agent tips: "front view" → fullbody + pose_name with "front"
# "back view" → pose_name with "back", "close-up" → close_up_upper_body
# Use reference_image_url as reference_image in POST /model/pose
GET/pose

List your custom poses, or get detail by adding pose_id. For preset poses, use GET /pose/library.

ParameterTypeRequiredDescription
pose_idstringNoIf provided, returns single pose detail
program_idstringNoProgram ID (uses key default if omitted)
# List response
{ "poses": [{ "pose_id": "xxx", "title": "Standing Front", "prompt": "standing pose, front facing...",
  "reference_image_presigned_url": "https://...", "prompt_type": "fullbody" }] }

# Detail response (with pose_id)
{ "pose_id": "xxx", "title": "...", "prompt": "...", "reference_image_presigned_url": "https://..." }
POST/pose

Create a new pose from a reference image. AI extracts the pose prompt automatically.

ParameterTypeRequiredDescription
reference_imagestringYesBase64 image or HTTP URL of a person in the desired pose
pose_titlestringYesName for this pose
program_idstringNoProgram ID (uses key default if omitted)
# Response
{ "status": "success", "pose_id": "xxx", "pose_prompt": "standing pose, front facing, arms at sides...", "pose_title": "My Pose" }

# Use the pose_prompt in POST /model/pose to generate images in this pose

SKUs

GET/sku

List SKUs in a project, or get detail by adding sku_id. Detail includes AI-classified garment images.

ParameterTypeRequiredDescription
project_idstringYesProject ID
sku_idstringNoIf provided, returns single SKU detail with garment classification
pagination_tokenstringNoToken for next page (list only)
# Detail response (with sku_id) — includes AI garment classification
{
  "skus": [{
    "sku_id": "xxx", "sku_name": "sku1", "garment_type": "Full body",
    "garment_images": [
      { "garment_id": "abc", "image_id": "assets/sku_images/xxx.png", "image_url": "https://...",
        "garment_type": "Top", "view": "front", "presentation": "flatlay_clean" },
      { "garment_id": "def", "image_id": "assets/sku_images/yyy.png", "image_url": "https://...",
        "garment_type": "Bottom", "view": "front", "presentation": "flatlay_clean" },
      { "garment_id": "ghi", "image_id": "assets/sku_images/zzz.png", "image_url": "https://...",
        "garment_type": "Shoes", "view": "front", "presentation": "flatlay_clean" }
    ]
  }]
}

Garment classification: After zip upload, images are automatically classified by AI into garment_type (Top, Bottom, Shoes, Accessory) and view (front, back). This classification is used when creating tasks.

PUT/sku

Update SKUs — assign model, style, garment type.

# Body: { "sku_ids": ["sku-001"], "model_id": "...", "style_id": "...", "garment_type": "Full body" }

Tasks & Try-On

POST/task

Create generation tasks for SKUs. Tasks are auto-created based on garment image classification (front/back views).

ParameterTypeRequiredDescription
project_idstringYesProject ID
sku_idsstring[]YesSKU IDs to create tasks for
program_idstringNoProgram ID (uses key default if omitted)
# Response: {"message": "success"}
# Tasks are created based on garment pairing (front view task + back view task)
# Then GET /task to find new task IDs with status "Task created"
PUT/task

Update a task — set model_image before generation. REQUIRED for try-on.

ParameterTypeRequiredDescription
project_idstringYesProject ID
task_idstringYesTask ID to update
sku_idstringYesSKU ID the task belongs to
program_idstringNoProgram ID (uses key default if omitted)
model_idstringNoModel ID to assign
model_imagestringNoModel image ID (from GET /model/.../images). Required before generation.
POST/task/generate

Submit try-on generation. Each task must have model_image set first.

ParameterTypeRequiredDescription
project_idstringYesProject ID
task_idsstring[]YesTask IDs to generate (must have model_image set)
program_idstringNoProgram ID (uses key default if omitted)
num_output_imagesintNoImages per task, 1-4 (default: 1)
promptstringNoOptional text prompt
# Response: {"message": "success"}
# Errors: 429 (concurrent limit exceeded)
# Poll: GET /task → ~90s to complete
GET/task

List tasks (poll status), or get task detail with output images by adding project_id + sku_id + task_id.

ParameterTypeRequiredDescription
project_idstringNoFor task detail
sku_idstringNoFor task detail
task_idstringNoFor task detail
program_idstringNoProgram ID (uses key default if omitted)
# List response (no detail params) — poll for generation progress
{ "skus": [{ "sku_name": "Blue Dress", "tasks": [{ "task_id": "xxx", "task_status": "Generation completed" }] }] }

# Detail response (with project_id + sku_id + task_id) — get output images
{ "task_id": "xxx", "task_status": "Generation completed", "output": [{ "image_id": "xxx", "image_url": "https://..." }] }

Video

POST/video

Generate a video from a try-on output image. Costs 25 credits (5s) or 40 credits (10s).

ParameterTypeRequiredDescription
project_idstringYesProject ID
sku_idstringYesSKU ID
video_lengthstringYes"5" (5 seconds) or "10" (10 seconds)
promptstringYesVideo motion prompt
first_frame_imageobjectYes{image_base64: "..."} or {image_id: "..."}
program_idstringNoProgram ID (uses key default if omitted)
source_task_idstringNoSource task ID
GET/video/requests

Poll video generation status. Returns video_url when completed.

ParameterTypeRequiredDescription
program_idstringNoProgram ID (uses key default if omitted)
limitintNoMax results (default: 10)
pagination_tokenstringNoFor pagination
# Response
{
  "requests": [{
    "request_status": "Generation completed",
    "video_url": "https://s3.../video.mp4?signed...",
    "duration": "5"
  }]
}

Upscale

POST/upscale

Upscale an image to 2x-4x resolution (max 18M output pixels). Costs 2 credits per image.

ParameterTypeRequiredDescription
imagestringYesBase64-encoded image or HTTP URL
upscale_factorfloatNoScale factor: 1-4 (default: 2)
num_imagesintNoOutput variations: 1-4 (default: 1)
program_idstringNoProgram ID (uses key default if omitted)
# Response
{ "status": "success", "request_id": "req-upscale-123", "cost": 2 }

# Resolution limits: input_pixels × factor² ≤ 18,000,000
# 1024×1024 → 4x = 16.8M ✓   |   2048×2048 → 4x = 67M ✗
GET/upscale

Poll upscale status. Returns result URLs when completed.

ParameterTypeRequiredDescription
request_idstringYesRequest ID from POST /upscale
program_idstringNoProgram ID (uses key default if omitted)
# Response (completed)
{ "request_id": "...", "status": "success", "result_urls": ["https://...upscaled.png"] }

Error Codes

CodeMeaningAction
401Invalid, missing, or revoked API keyCheck your API key
402Insufficient creditsTop up credits or wait for renewal
403API key not authorized for this teamCheck API key team binding
404Resource not foundVerify IDs exist
422Validation errorCheck request body and params
429Rate limitedBack off and retry
500Internal server errorRetry after a delay

Common Workflows

Generate Images

# 1. Check credits
curl https://api.huhu.ai/public/v1/metering/plan \
  -H "Authorization: Bearer sk-..."

# 2. Submit generation
curl -X POST https://api.huhu.ai/public/v1/model/image \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json"

# 3. Poll task status (every 5-10 seconds)
curl https://api.huhu.ai/public/v1/task \
  -H "Authorization: Bearer sk-..."
# → Check task_status until "Generation completed"
# → Retrieve output_image_url from completed tasks

Explore Resources

# List programs → pick program_id
curl https://api.huhu.ai/public/v1/program -H "Authorization: Bearer sk-..."

# List projects → pick project_id
curl https://api.huhu.ai/public/v1/project -H "Authorization: Bearer sk-..."

# Create a new project
curl -X POST "https://api.huhu.ai/public/v1/project" \
  -H "Content-Type: application/json" \
  -d '{"project_name":"New Project"}' \
  -H "Authorization: Bearer sk-..."

Best Practices

  • Check credits first — Always call /metering/plan before generation.
  • Respect concurrency — The concurrent_requests field limits parallel jobs.
  • Poll gently — Check /task every 5-10 seconds, not faster.
  • Handle 402 — Stop submitting if credits run out.
  • Pagination — If pagination_token is non-null, pass it to get more results.
  • Timestamps — All timestamps are Unix epoch in milliseconds.
  • IDs — All IDs are UUID or hex strings. Store as strings.

LLM Agent Integration

Two integration options for AI agents and automation tools:

  • OpenAPI Spec — Machine-readable JSON schema for auto-generating tool definitions, importing into Postman/Swagger, or building client SDKs. Best for agents with function-calling/tool-use capabilities.
  • SKILL.md — Complete human-readable reference with decision trees, workflows, best practices, and prompt templates. Best for loading into LLM context windows.

Quick Reference

BASE: https://api.huhu.ai/public/v1
AUTH: Authorization: Bearer sk-<key>

GET  /metering/plan                       → credits & plan
GET  /metering/credit-history             → spending log
GET  /program                             → list programs (add ?owned=true for owned only)
POST /program                             → create program
GET  /project                             → list projects (add ?project_id= for detail)
POST /project                             → create project
POST /model                               → create model in gallery
GET  /model                               → list models
GET  /model?model_id=                     → model images (omit for list)
POST /model/face                          → generate face (variety/fidelity)
POST /model/image                         → generate or upload model image
GET  /model/image?request_id=             → poll generation status
POST /model/pose                          → generate with poses
GET  /pose/library                        → browse 143 preset poses (filter by category, type)
GET  /pose                                → list custom poses (add ?pose_id= for detail)
POST /pose                                → create pose from reference image
GET  /sku?project_id=                     → list SKUs (add &sku_id= for detail)
PUT  /sku                                 → update SKU (model, style)
POST /project/upload                      → upload garment image or init zip
POST /project/complete_multipart_upload   → finalize zip upload
POST /task                                → create tasks for SKUs
PUT  /task                                → set model_image on task
POST /task/generate                       → try-on generation
GET  /task                                → list tasks (add ?project_id=&sku_id=&task_id= for detail)
POST /video                               → create video
GET  /video/requests                      → poll video status
POST /upscale                             → upscale image (2x-4x, max 18M px)
GET  /upscale?request_id=                 → poll upscale status