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

    Imagine having an AI hair expert in your pocket. Our tech dives into your
    hair's texture, thickness, and curl pattern, picking from ten unique curl
    shapes and sorting them into nine clear types, from Straight to Super Kinky.
    You get a full hair profile, and brands can use those insights to deliver
    spot-on product recommendations and tips just for you.


    ## Integration Guide

    * How to Take Photos for AI Hair Type Detection

    * Take 3 Photos from left, front facing to right.
      - Just snap three quick selfies. One facing straight ahead, one turning about 45 degrees to the left, and one turning 45 degrees to the right. We're trying to catch the full look of your hair from all sides. Make sure your whole face and the upper boundary of your hair are clearly visible in each photo. Your face should take up around 50% to 80% of the image width. Not too small, not too close. That way, it's sharp enough for analysis. When you turn for the side shots, rotate your head left and right like you're saying 'no' (that's called yaw rotation). Keep your head level with no tilting up, down, or sideways. Skip any back or top-down angles because those wont work for us.
      - You can utilize the JS Camera Kit to snap photos. Make sure your hair is not tied up and let it hang in front of your chest. Turn your head to the right and hold still, and turn to the left to get 3 images to be analyzed.

    * How to Detect Hair Type by AI

    * Using the ***/s2s/v2.0/file*** API, please upload the following assets:
      - Photos from the front, the right side, and the left side.

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

    Run the hair-type detection task by sending in three images: one from the
    front, one from the right side, and one from the left side. Use their file
    IDs as the source inputs 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-type-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 Type Classification

    |Category|Thumbnail|Hair Type Classification|Description|

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

    |1|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t1.b19d4657.jpg)|Straight|
    This hair type is characterized by strands that lack natural curls and
    typically fall straight from the root to the tip|

    |2A|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t2A.351ef0a6.jpg)|Slight
    Wavy| This hair type features subtle, delicate waves with a smooth and
    tousled texture, but lacks volume at the roots|

    |2B|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t2B.daac62f4.jpg)|Medium
    Wavy| This hair type that showcases natural S-shaped waves that typically
    begin in the middle of the hair shaft and delicately hug the head, creating
    a subtle and sophisticated dimension|

    |2C|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t2C.10ef2132.jpg)|Thick
    Wavy|The waves in this hair type are characterized by a coarse texture and
    are shaped like the letter "S", starting at the root and continuing down the
    length of the hair. This hair type is prone to frizz|

    |3A|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t3A.073b6767.jpg)|Loose
    Curls|These curls are big, relaxed, and bouncy, and have a noticeable sheen
    from roots to ends|

    |3B|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t3B.06bf109b.jpg)|Medium
    Curls|This hair type consists of coarse, springy ringlets that are prone to
    frizz|

    |3C|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t3C.9091ea1e.jpg)|Tight
    Curls|These curls boast a dense and compact corkscrew shape, lending them
    plenty of volume|

    |4A|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t4A.cf742771.jpg)|Kinky
    Soft|This hair type is characterized by tightly packed, springy S-shaped
    coils|

    |4B|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t4B.4a6300fe.jpg)|Coily|Densely
    packed coils tightly wound into sharp, zigzag angles|

    |4C|![](https://d3ss46vukfdtpo.cloudfront.net/static/media/img_t4C.4ed5a7f8.jpg)|Extremely
    Coily|This hair type is characterized by tight, fluffy coils that are more
    susceptible to breakage|


    * Result Arguments

    * mapping: result is a string showing the detected hair type category. Here
    lists all the possible result strings in an array:
      ```json
      ["1 to 2a", "2a to 2b", "2b to 2c", "2c to 3a", "3a to 3b", "3b to 3c", "3c to 4a", "4a to 4b", "4b to 4c"]
      ```
    * term: a one-to-one mapping string between hair type categories and their
    classifications. Here lists all the possible result strings in an array:
      ```json
      ["Straight to Slight Wavy", "Slight to Medium Wavy", "Medium to Thick Wavy", "Thick Wavy to Loose Curls", "Loose to Medium Curls", "Medium to Tight Curls", "Tight Curls to Kinky Soft", "Kinky Soft to Coily", "Coily to Extremely Coily"]
      ```

    * Suggestions for How to Shoot

    ![Suggestions for How to
    Shoot](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/AI%20Hair%20Type%20Detection_how%20to%20shoot.png
    "Suggestions for How to Shoot")


    ![](https://bcw-media.s3.ap-northeast-1.amazonaws.com/strapi/assets/AI%20Skin%20Analysis_camera.png)


    ## File Specs & Errors

    * Supported Formats & Dimensions


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

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

    |AI Hair Type Detection|The image must be at least 320 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_mismatch_image_size|Make sure all your face photos (front, left, and
    right) are the same size|

    |error_below_min_image_size|If your image is smaller than 320 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" /%}
  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/youcamapps/youcam/privacy-policy.html
servers:
  - url: https://yce-api-01.makeupar.com
tags:
  - name: V1.0
    description: >-
      AI Hair Type Detection API allows you to detect the type of hair in images
      using three-angle input (front, right, left).
paths:
  /s2s/v2.0/task/hair-type-detection:
    post:
      summary: Run an Hair Type Detection task.
      description: Please refer to the polling guide for checking task status.
      tags:
        - V1.0
      security:
        - BearerAuthenticationV2: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BasicFaceAttrReqFaceThreeAngle'
      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':
          description: Too many requests within a given amount of time
          content:
            application/json:
              schema:
                type: object
  /s2s/v2.0/task/hair-type-detection/{task_id}:
    get:
      summary: Check an Hair Type Detection task status.
      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/TaskStatusResponseHairType'
        '400':
          $ref: '#/components/responses/InvalidTaskId'
        '401':
          $ref: '#/components/responses/InvalidApiKey'
        '500':
          $ref: '#/components/responses/TaskTimeout'
components:
  schemas:
    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'
    BasicFaceAttrReqFaceThreeAngleWithSrcFileUrls:
      title: Run task with 3 angle src file urls
      type: object
      required:
        - src_file_urls
      properties:
        src_file_urls:
          type: array
          minItems: 3
          maxItems: 3
          description: >-
            The file URLs from upload file API. The file IDs for the sequence of
            source images are 'frontFace', 'rightFace', and 'leftFace'. Should
            provide either 'src_file_urls' or 'src_file_ids'.
          example:
            - https://example.com/selfie.jpg
            - https://example.com/selfie.jpg
            - https://example.com/selfie.jpg
          items:
            type: string
    BasicFaceAttrReqFaceThreeAngleWithSrcFileIds:
      title: Run task with 3 angle src file IDs
      type: object
      required:
        - src_file_ids
      properties:
        src_file_ids:
          type: array
          minItems: 3
          maxItems: 3
          description: >-
            The file IDs from upload file API. The file IDs for the sequence of
            source images are 'frontFace', 'rightFace', and 'leftFace'. Should
            provide either 'src_file_urls' or 'src_file_ids'.
          example:
            - pfNK5PuRe0MrwLHcGA3DOmB1ahwfXTbYHjv+KoBIxbE=
            - pkVzplMv8Y1QPgHbqtKfyJmg+xJDUbTP16YijZ3qARNf
            - B5LNohvvO+7d/78Ymuhp6vMiSooN/5DX9oVuupzkKctf
          items:
            type: string
    BasicFaceAttrReqFaceThreeAngle:
      anyOf:
        - $ref: '#/components/schemas/BasicFaceAttrReqFaceThreeAngleWithSrcFileUrls'
        - $ref: '#/components/schemas/BasicFaceAttrReqFaceThreeAngleWithSrcFileIds'
    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
    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
    BasicFaceAttrRespHairType:
      type: object
      properties:
        mapping:
          type: string
          description: The key to map to a range of result
          enum:
            - 1 to 2a
            - 2a to 2b
            - 2b to 2c
            - 2c to 3a
            - 3a to 3b
            - 3b to 3c
            - 3c to 4a
            - 4a to 4b
            - 4b to 4c
        term:
          type: string
          description: 1-1 map to the "mapping"
          enum:
            - Straight to Slight Wavy
            - Slight to Medium Wavy
            - Medium to Thick Wavy
            - Thick Wavy to Loose Curls
            - Loose to Medium Curls
            - Medium to Tight Curls
            - Tight Curls to Kinky Soft
            - Kinky Soft to Coily
            - Coily to Extremely Coily
    TaskStatusResponseHairType:
      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:
                    hair_type:
                      $ref: '#/components/schemas/BasicFaceAttrRespHairType'
  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
                description: |
                  Error code:
                    * 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
    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'.
