{
  "openapi": "3.0.0",
  "info": {
    "title": "AI Hair Extension Virtual Try-On",
    "description": "# Overview\nDiscover Your Perfect Hair Extension Match with AI​\nExperiment with a variety of lengths—from long to extra-long—styles, colors, and bangs, all from the comfort of your device. No more guessing games—see exactly how each hair extension style looks on you with the advanced Generative AI. Make informed styling decisions before committing to a new look.​\nWith the advanced Hair Extension Try-On, which naturally blends with your current hair length, it’s the perfect time to experiment with super-long styles.\n\nUse case:\n![AI Hair Extension](https://bcw-media.s3.ap-northeast-1.amazonaws.com/YCE_web_Hair_Extension_Filter_S2_img_07_098b6e08c4.jpg \"AI Hair Extension\")\n\n![AI Hair Extension](https://bcw-media.s3.ap-northeast-1.amazonaws.com/YCE_web_Hair_Extension_Filter_S1_img_01_eab88fe3e2.jpg \"AI Hair Extension\")\n\nSuggestions for How to Shoot:\n![Suggestions for How to Shoot](https://bcw-media.s3.ap-northeast-1.amazonaws.com/AI_Hair_Extension_recommendation_ba24bd5d92.png \"Suggestions for How to Shoot\")\n\n---\n\n## File Specs & Errors\n\n* Supported Formats & Dimensions\n\n|AI Feature|Supported Dimensions|Supported File Size|Supported Formats|\n|  ----  | ----  | ----  | ----  |\n|AI Hair Extension|long side <= 1024, face width >= 128, face pose: -10 < pitch < +10, -45 < yaw < +45, -15 < roll < +15, single face only, need to show full face|< 10MB|jpg/jpeg|\n\n* Error Codes\n\n|Error Code|Description|\n|  ----  | ----  |\n|error_no_shoulder\t|Shoulders are not visible in the source image\n|error_large_face_angle\t|The face angle in the uploaded image is too large\n|error_insufficient_landmarks\t|Cannot detect sufficient face or body landmarks in the source image\n|error_hair_too_short\t|Input hair is too short\n|error_face_pose\t|The face pose of source image is unsupported\n|error_bald_image\t|Input hairstyle is bald\n\n---\n\n## Unit Consumption\n\n| AI Feature | Unit Consumed |\n|---|---|\n| AI Hair Extension Virtual Try-On V1.0 | 1 |\n\n---\n",
    "version": "",
    "termsOfService": "https://www.makeupar.com/perfectbeauty/youcam/terms-of-service-api",
    "contact": {
      "email": "YouCamOnlineEditor_API@perfectcorp.com"
    },
    "license": {
      "name": "Privacy policy",
      "url": "https://www.makeupar.com/perfectbeauty/youcam/privacy-policy-api"
    }
  },
  "servers": [
    {
      "url": "https://yce-api-01.makeupar.com"
    }
  ],
  "tags": [
    {
      "name": "V1.0",
      "description": "Generate hair extension effects from uploaded images using AI processing, supporting templates and source references."
    }
  ],
  "paths": {
    "/s2s/v2.0/task/template/hair-ext": {
      "get": {
        "summary": "List predefined templates.",
        "tags": [
          "V1.0"
        ],
        "security": [
          {
            "BearerAuthenticationV2": []
          }
        ],
        "parameters": [
          {
            "name": "page_size",
            "in": "query",
            "schema": {
              "type": "integer",
              "example": 20
            },
            "description": "Number of results to return in this page. Valid value should be between 1 and 20. Default 20."
          },
          {
            "name": "starting_token",
            "in": "query",
            "schema": {
              "type": "string",
              "example": "73a3c9e69b89"
            },
            "description": "Token for current page. Start with `null` for the first page, and use `next_token` from the previous response to start next page"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/TemplateResponse"
          },
          "400": {
            "$ref": "#/components/responses/InvalidParameters"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          }
        }
      }
    },
    "/s2s/v2.0/task/hair-ext": {
      "post": {
        "summary": "Run an AI Hair Extension task.",
        "description": "This endpoint initiates the hair extension generation process using a template and source image. The task will be processed asynchronously, and you can check its status using the task_id returned in this response.\n",
        "tags": [
          "V1.0"
        ],
        "security": [
          {
            "BearerAuthenticationV2": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunWithSingleTemplateAndSrcUrl"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful execution of the task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BasicRunTaskResponseV2"
                }
              }
            }
          },
          "400": {
            "description": "Failed execution of task",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/responses/RunError"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/s2s/v2.0/task/hair-ext/{task_id}": {
      "get": {
        "summary": "Check the status of a AI Hair Extension task.",
        "tags": [
          "V1.0"
        ],
        "security": [
          {
            "BearerAuthenticationV2": []
          }
        ],
        "parameters": [
          {
            "name": "task_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "grH0CvsgXuAIHLUzD0V1Ol34hoet3R1tvdbtiVHrDb6_UqCLKIejAIajwxrhOAfe"
            },
            "description": "ID of task to check"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful check of the task status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskStatusResponseV2"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidTaskId"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "500": {
            "$ref": "#/components/responses/TaskTimeout"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuthenticationV2": {
        "type": "http",
        "scheme": "bearer",
        "description": "Use the standard 'Bearer authentication'. Put your 'API Key' in header: `Authorization:Bearer YOUR_API_KEY`. Notice that there is ' ' a space between 'Bearer' and the 'YOUR_API_KEY'."
      }
    },
    "schemas": {
      "EngineErrorCode": {
        "type": "string",
        "nullable": true,
        "enum": [
          "exceed_max_filesize",
          "invalid_parameter",
          "error_download_image",
          "error_decode_image",
          "error_nsfw_content_detected",
          "error_inference",
          "unknown_internal_error"
        ],
        "description": "Errors:\n\n- `exceed_max_filesize` - Input file size exceeds the maximum limit\n\n- `invalid_parameter` - Invalid parameter value\n\n- `error_download_image` - Download source image error\n\n- `error_decode_image` - Decode source image error\n\n- `unknown_internal_error` - Others\n"
      },
      "FileV1.1": {
        "title": "File V1.1",
        "description": "This object represents a file.",
        "type": "object",
        "required": [
          "files"
        ],
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "content_type",
                "file_name",
                "file_size"
              ],
              "properties": {
                "content_type": {
                  "type": "string",
                  "example": "image/jpg",
                  "description": "Content MIME type for this file. Currently available values are listed in the enum."
                },
                "file_name": {
                  "type": "string",
                  "example": "my-selfie.jpg",
                  "description": "Name of this file"
                },
                "file_size": {
                  "type": "integer",
                  "example": 50000,
                  "description": "Content length for this file in bytes. Should not be larger than 10MB."
                }
              }
            }
          }
        }
      },
      "BasicFileResponse": {
        "type": "object",
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "content_type": {
                  "type": "string",
                  "example": "image/jpg",
                  "description": "Content MIME type for this file."
                },
                "file_name": {
                  "type": "string",
                  "example": "my-selfie.jpg",
                  "description": "Name of this file"
                },
                "file_id": {
                  "type": "string",
                  "example": "U8aqJbsXGT537jtGnEDFHqxdDXqh8+oTF/cSkLimzuvVwMP+Jb1XbjPsf7ZgUgLY",
                  "description": "ID of this file. Other run task API will need this `file_id`."
                },
                "requests": {
                  "type": "array",
                  "description": "Using upload `url`, `headers`, `method` below to upload file. After completion, the `file_id` is used to proceed with calling run task API.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "headers": {
                        "type": "object",
                        "example": {
                          "Content-Type": "image/jpg",
                          "Content-Length": 50000
                        },
                        "description": "Headers to include when uploading the file"
                      },
                      "url": {
                        "type": "string",
                        "example": "https://example.com/presigned-upload-url",
                        "description": "URL to upload this file"
                      },
                      "method": {
                        "type": "string",
                        "example": "PUT",
                        "description": "HTTP method to upload this file"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "FileResponseV2": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "example": 200,
            "description": "Response status"
          },
          "data": {
            "$ref": "#/components/schemas/BasicFileResponse"
          }
        }
      },
      "BasicRunTaskV2SrcFileUrl": {
        "title": "Run task with src file url",
        "type": "object",
        "required": [
          "src_file_url"
        ],
        "properties": {
          "src_file_url": {
            "type": "string",
            "description": "Url of the file to run task. The url should be publicly accessible.",
            "example": "https://example.com/selfie.jpg"
          }
        }
      },
      "BasicRunTaskV2SrcFileId": {
        "title": "Run task with src file ID",
        "type": "object",
        "required": [
          "src_file_id"
        ],
        "properties": {
          "src_file_id": {
            "type": "string",
            "description": "ID of file to run task. File ID from upload file API.",
            "example": "pfNK5PuRe0MrwLHcGA3DOmB1ahwfXTbYHjv+KoBIxbE="
          }
        }
      },
      "BasicRunTaskV2": {
        "title": "BasicRunTaskV2",
        "anyOf": [
          {
            "$ref": "#/components/schemas/BasicRunTaskV2SrcFileUrl"
          },
          {
            "$ref": "#/components/schemas/BasicRunTaskV2SrcFileId"
          }
        ]
      },
      "RunWithSingleTemplate": {
        "title": "RunWithSingleTemplate",
        "type": "object",
        "properties": {
          "template_id": {
            "type": "string",
            "description": "ID of the template. List predefined templates first, and use the id of a template.\n",
            "example": "good_template_001"
          }
        },
        "required": [
          "template_id"
        ]
      },
      "RunWithSingleTemplateAndSrcUrl": {
        "title": "RunWithSingleTemplateAndSrcUrl",
        "allOf": [
          {
            "$ref": "#/components/schemas/RunWithSingleTemplate"
          },
          {
            "$ref": "#/components/schemas/BasicRunTaskV2"
          }
        ]
      },
      "BasicRunTaskResponseV2": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "description": "Response status",
            "example": 200
          },
          "data": {
            "type": "object",
            "properties": {
              "task_id": {
                "type": "string",
                "description": "ID of this task. Task result is valid to query by this ID for 24 hours.",
                "example": "grH0CvsgXuAIHLUzD0V1Ol34hoet3R1tvdbtiVHrDb6_UqCLKIejAIajwxrhOAfe"
              }
            }
          }
        }
      },
      "TaskStatusResponseBodySingleUrlResultsV2": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "URL to download this result. Valid for 2 hours",
            "example": "https://example.com/sample-result-url"
          }
        }
      },
      "TaskStatusResponseV2": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "description": "Response status",
            "example": 200
          },
          "data": {
            "type": "object",
            "properties": {
              "task_status": {
                "type": "string",
                "enum": [
                  "running",
                  "success",
                  "error"
                ],
                "description": "Status of this task"
              },
              "error": {
                "$ref": "#/components/schemas/EngineErrorCode"
              },
              "error_message": {
                "type": "string",
                "description": "Detailed description of error"
              },
              "results": {
                "$ref": "#/components/schemas/TaskStatusResponseBodySingleUrlResultsV2"
              }
            }
          }
        }
      },
      "Template": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The ID of the template. Use this as `template_id` when run task.",
            "example": "good_template_001"
          },
          "thumb": {
            "type": "string",
            "description": "The thumbnail of style."
          },
          "title": {
            "type": "string",
            "description": "The title of the template."
          },
          "category_name": {
            "type": "string",
            "description": "The category name of the template."
          }
        }
      },
      "Style": {
        "type": "object",
        "properties": {
          "style_group_id": {
            "type": "integer",
            "description": "The id of style group. Use this as `style_group_id` when run task."
          },
          "style_id": {
            "type": "integer",
            "description": "The id of style. Use this as `style_ids` when run task."
          },
          "info": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "description": "The style name"
              },
              "thumb": {
                "type": "string",
                "description": "The thumbnail of style"
              }
            },
            "required": [
              "title",
              "thumb"
            ]
          }
        },
        "required": [
          "style_group_id",
          "style_id",
          "info"
        ]
      },
      "Category": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "The id of category."
          },
          "name": {
            "type": "string",
            "description": "The name of category."
          },
          "styles": {
            "type": "array",
            "description": "The styles belong to this category.",
            "items": {
              "$ref": "#/components/schemas/Style"
            }
          },
          "sub_categories": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "The id of sub-category. Use this id to query for its content."
                },
                "name": {
                  "type": "string",
                  "description": "The name of sub-category."
                }
              },
              "required": [
                "id",
                "name"
              ]
            }
          }
        },
        "required": [
          "id",
          "name",
          "styles",
          "sub_categories"
        ]
      },
      "TemplateResponseSchema": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "description": "Response status",
            "example": 200
          },
          "data": {
            "type": "object",
            "properties": {
              "templates": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Template"
                }
              },
              "next_token": {
                "type": "string",
                "example": "73a3c9e69b89",
                "description": "Token to query next page."
              }
            }
          }
        }
      }
    },
    "responses": {
      "InvalidParameters": {
        "description": "Invalid request parameters",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "example": 400,
                  "description": "Response status"
                },
                "error": {
                  "type": "string",
                  "description": "Error message",
                  "example": "The operation could not be completed"
                },
                "error_code": {
                  "type": "string",
                  "enum": [
                    "InvalidParameters"
                  ]
                }
              }
            }
          }
        }
      },
      "InvalidApiKey": {
        "description": "Invalid API Key or Inactive API Key or Expired API Key",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "example": 401,
                  "description": "Response status"
                },
                "error_code": {
                  "type": "string",
                  "enum": [
                    "InvalidApiKey",
                    "InactiveApiKey",
                    "ExpiredApiKey"
                  ]
                }
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Too many requests within a given amount of time"
      },
      "RunError": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer",
            "description": "Response status",
            "example": 400
          },
          "error": {
            "type": "string",
            "description": "Error message",
            "example": "The operation could not be completed"
          },
          "error_code": {
            "type": "string",
            "enum": [
              "CreditInsufficiency",
              "InvalidStyleGroup",
              "InvalidStyle",
              "BadRequest",
              "InvalidParameters"
            ]
          }
        }
      },
      "TaskTimeout": {
        "description": "The task has no response in the expected time",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "description": "Response status",
                  "example": 500
                },
                "error_code": {
                  "type": "string",
                  "enum": [
                    "TaskTimeout"
                  ]
                }
              }
            }
          }
        }
      },
      "InvalidTaskId": {
        "description": "Invalid task id",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "integer",
                  "description": "Response status",
                  "example": 400
                },
                "error_code": {
                  "type": "string",
                  "enum": [
                    "InvalidTaskId"
                  ]
                }
              }
            }
          }
        }
      },
      "TemplateResponse": {
        "description": "Successful retrieval of styles",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TemplateResponseSchema"
            }
          }
        }
      }
    }
  }
}