openapi: 3.0.0
info:
  title: AI Hair Density Detection
  description: >
    # Overview

    AI Hair Density Detection delivers a fast, professional, photo‑based
    assessment that accurately classifies hair density into four levels by
    evaluating scalp visibility and hair distribution patterns, providing
    trichoscopy‑inspired insights without physical tools and empowering
    businesses to offer expert‑level personalization at scale from a single
    uploaded image.


    ![](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/AI_hair_density_S3_02_b34f2db2ce.jpg)


    ## Integration Guide

    * How to Take Photos for AI Hair Density Detection

    * Take a selfie
      - Please face the camera directly with proper lighting, then lower your head to a 45‑degree angle. Keep your hair untied and ensure your entire hairline is clearly visible.

      ![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_popup_step_animated_02.aadf7a34.png)

      - Instead, use the JS Camera Kit to take a photo.

    * How to Detect Hair Density by AI

    * Using the ***/s2s/v2.0/file*** API, please upload the following assets:
      - Your selfie photo.

    * Execute AI task ***/s2s/v2.0/task/hair-density-detection*** </br>

    Run the detection task by sending one front facing 45 degree lower selfie
    image. Use it's file ID as the source input for the AI.


    * Polling to check the status of a task until it succeed or error</br>

    This ***task_id*** is used to monitor the task's status through polling GET
    'task/hair-density-detection' to retrieve the current engine status. Until
    the engine completes the task, the status will remain 'running', and no
    units will be consumed during this stage.



    ## Hair Density Classification


    |Thumbnail|Hair Density Classification|Description|

    | ----  | ----  | ----  |

    |![](https://d3ss46vukfdtpo.cloudfront.net/static/media/dt_classification_LV01.5097a6c2.png)|Level
    1<br>Extremely Low Density|Hair appears significantly sparse, with visible
    scalp across a large area. Hair fibers are thin and coverage is minimal.|

    |![](https://d3ss46vukfdtpo.cloudfront.net/static/media/dt_classification_LV02.7966983d.png)|Level
    2<br>Low Density|Noticeable thinning with clear scalp visibility, especially
    at the crown and part lines. Hair may lack volume and body.|

    |![](https://d3ss46vukfdtpo.cloudfront.net/static/media/dt_classification_LV03.c49dbfb7.png)|Level
    3<br>Medium Density|Scalp is partially visible under direct light, but hair
    still maintains moderate volume and coverage. Hair may feel finer but
    remains relatively healthy.|

    |![](https://d3ss46vukfdtpo.cloudfront.net/static/media/dt_classification_LV04.e467f2aa.png)|Level
    4<br>High Density|Hair looks full and thick, with minimal to no scalp
    visibility. Hair strands are closely packed, providing rich volume and
    natural coverage.|



    * Suggestions for How to Shoot


    ![Suggestions for How to
    Shoot](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/icon_S2_step1_20d0a161da.png
    "Suggestions for How to Shoot")


    ![](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/AI_hair_density_S1_02_f60369b14d.jpg)


    ## File Specs & Errors

    * Supported Formats & Dimensions


    |Type|Supported Dimensions|Supported File Size|Supported Formats|

    |  ----  | ----  | ----  | ----  |

    |AI Hair Density Detection|The image must be at least 100 pixels wide and
    tall, and no more than 4096 pixels in either dimension. If one side of your
    image is longer than 1080 pixels, it will be resized automatically to fit
    within that limit for analysis.|< 10MB|jpg/png|


    * Error Codes


    |Error Code|Description|

    |  ----  | ----  |

    |error_below_min_image_size|If your image is smaller than 100 pixels in
    width or height, it's too small to use|

    |error_face_position_invalid|Your face needs to be fully visible in the
    image, without any parts cut off|

    |error_face_position_too_small|The face in your photo is too small to
    analyze properly|

    |error_face_position_out_of_boundary|Your face is either too large or
    partially outside the edges of the photo|

    |error_insufficient_lighting|The lighting is too dim, which makes analysis
    difficult|

    |error_face_angle_invalid|Your face angle isn't quite right. For
    front-facing shots, keep your head within 10 degrees of straight. For
    side-facing shots, the angle should be more than 15 degrees|


    * Environment & Dependency


    | Sample Code Language / Tool | Recommended Runtime Versions |

    |---|---|

    | cURL | - bash >= 3.2</br>   - curl >= 7.58 (modern TLS/HTTP
    support)</br>   - jq >= 1.6 (robust JSON parsing) |

    | Node.js (JavaScript) | Node >= 18 (for global fetch) |

    | JavaScript | - Chrome / Edge >= 80</br>   - Firefox >= 74</br>   - Safari
    >= 13.1 |

    | PHP | PHP >= 7.4 (for modern TLS/compat), ext-curl (recommended) or
    allow_url_fopen=On + ext-openssl, ext-json |

    | Python | Python >= 3.10 (for f-strings), requests >= 2.20.0 |

    | Java | Java 11+ (for HttpClient), Jackson Databind >= 2.12.0 |


    ---


    ## JS Camera Kit

    {% partial file="/_partials/js-camera-kit.md" /%}


    ---


    ## Unit Consumption


    | AI Feature | Unit Consumed |

    |---|---|

    | AI Hair Density Detection V1.0 | 1 |


    ---
  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: AI-powered hair density detection features for analysis.
paths:
  /s2s/v2.0/task/hair-density-detection:
    post:
      summary: Run an AI Hair Density Detection task.
      description: >-
        Polling is required to check the status of the task. Refer to polling
        guide for details.
      tags:
        - V1.0
      security:
        - BearerAuthenticationV2: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BasicRunTaskV2'
      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-density-detection/{task_id}:
    get:
      summary: Check the status of a AI Hair Density Detection 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 a AI Hair Density Detection task status.
          content:
            application/json:
              schema:
                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:
                        allOf:
                          - type: object
                            properties:
                              timed:
                                type: number
                              hair_density:
                                $ref: >-
                                  #/components/schemas/BasicHairDensityRespHairDensity
        '400':
          $ref: '#/components/responses/InvalidTaskId'
        '401':
          $ref: '#/components/responses/InvalidApiKey'
        '500':
          $ref: '#/components/responses/TaskTimeout'
components:
  schemas:
    EngineErrorCode:
      type: string
      nullable: true
      enum:
        - exceed_max_filesize
        - invalid_parameter
        - error_download_image
        - error_download_mask
        - error_decode_image
        - error_decode_mask
        - error_nsfw_content_detected
        - error_no_face
        - error_pose
        - error_face_parsing
        - error_inference
        - exceed_nsfw_retry_limits
        - error_upload
        - unknown_internal_error
      description: >
        Errors:

        - `exceed_max_filesize` - Input file size exceeds the maximum limit

        - `invalid_parameter` - Invalid parameter value

        - `error_download_image` - Download source image error

        - `error_download_mask` - Download mask image error

        - `error_decode_image` - Decode source image error

        - `error_decode_mask` - Decode mask image error

        - `error_nsfw_content_detected` - NSFW content detected in source image

        - `error_no_face` - No face detected on source image

        - `error_pose` - Failed to detect pose on source image

        - `error_face_parsing` - Failed to do face segmentation on source image

        - `error_inference` - Inference pipeline error

        - `exceed_nsfw_retry_limits` - Exceed the retry limits to avoid
        generated NSFW image

        - `error_upload` - Upload result image error

        - `unknown_internal_error` - Others
    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'
    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
    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=
    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
    BasicRunTaskV2:
      title: BasicRunTaskV2
      anyOf:
        - $ref: '#/components/schemas/BasicRunTaskV2SrcFileUrl'
        - $ref: '#/components/schemas/BasicRunTaskV2SrcFileId'
    BasicHairDensityRespHairDensity:
      type: object
      properties:
        mapping:
          type: string
          description: float in string format
          minimum: '0'
          maximum: '3'
          example: '2.16'
        term:
          type: string
          enum:
            - Extremely Low Density
            - Low Density
            - Medium Density
            - High Density
  responses:
    BadRequestAndInvalidParameters:
      description: >-
        Can not process the request due to client error or invalid request
        parameters
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: integer
                description: Response status
              error:
                type: string
                description: Error message
                example: The operation could not be completed
              error_code:
                type: string
                enum:
                  - BadRequest
                  - InvalidParameters
                description: |
                  Error code:
                    * BadRequest - Unexpected request parameters or body
                    * InvalidParameters - Invalid request parameters or body
    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
                description: |
                  Error code:
                    * InvalidApiKey - API Key is not given or not valid
                    * InactiveApiKey - API Key is inactivated
                    * ExpiredApiKey - API Key is expired
    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
          description: |
            Error code:
              * CreditInsufficiency - Insufficient unit to run
              * BadRequest - Unexpected request parameter
              * InvalidStyleGroup - Invalid style group id
              * InvalidStyle - Invalid style id
              * InvalidParameters - Invalid request parameters
    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
                description: |
                  Error code:
                    * InvalidTaskId - Invalid task id
    TooManyRequests:
      description: Too many requests within a given amount of time
    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
                description: |
                  Error code:
                    * TaskTimeout - The task has no response in the expected time
  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'.
